EntityQueryProcessorBase.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <iterator>
5#include <limits>
6
9
10#include <RobotAPI/interface/armem/query.h>
14
16
21
23{
24
25 template <class _EntityT, class _ResultEntityT>
27 public BaseQueryProcessorBase<_EntityT, _ResultEntityT, armem::query::data::EntityQuery>
28 {
29 protected:
30 using Base =
32
33 public:
34 using EntityT = _EntityT;
35 using EntitySnapshotT = typename EntityT::EntitySnapshotT;
36
37 using ResultEntityT = _ResultEntityT;
38 using ResultSnapshotT = typename ResultEntityT::EntitySnapshotT;
39
40
41 public:
42 using Base::process;
43
44 virtual void
46 const armem::query::data::EntityQuery& query,
47 const EntityT& entity) const override
48 {
49 if (auto q = dynamic_cast<const armem::query::data::entity::All*>(&query))
50 {
51 process(result, *q, entity);
52 }
53 else if (auto q = dynamic_cast<const armem::query::data::entity::Single*>(&query))
54 {
55 process(result, *q, entity);
56 }
57 else if (auto q = dynamic_cast<const armem::query::data::entity::TimeRange*>(&query))
58 {
59 process(result, *q, entity);
60 }
61 else if (auto q = dynamic_cast<const armem::query::data::entity::IndexRange*>(&query))
62 {
63 process(result, *q, entity);
64 }
65 else if (auto q = dynamic_cast<const armem::query::data::entity::TimeApprox*>(&query))
66 {
67 process(result, *q, entity);
68 }
69 else if (auto q =
70 dynamic_cast<const armem::query::data::entity::BeforeOrAtTime*>(&query))
71 {
72 process(result, *q, entity);
73 }
74 else if (auto q = dynamic_cast<const armem::query::data::entity::BeforeTime*>(&query))
75 {
76 process(result, *q, entity);
77 }
78 else
79 {
80 throw armem::error::UnknownQueryType("entity snapshot", query);
81 }
82 }
83
84 virtual void
86 const armem::query::data::entity::All& query,
87 const EntityT& entity) const
88 {
89 (void)query;
90 // Copy this entitiy and its contents.
91
92 entity.forEachSnapshot([this, &result](const EntitySnapshotT& snapshot)
93 { this->addResultSnapshot(result, snapshot); });
94 }
95
96 virtual void
98 const armem::query::data::entity::Single& query,
99 const EntityT& entity) const
100 {
101 if (query.timestamp.timeSinceEpoch.microSeconds < 0)
102 {
103 if (auto snapshot = entity.findLatestSnapshot())
104 {
105 this->addResultSnapshot(result, *snapshot);
106 }
107 }
108 else
109 {
110 const Time time = armarx::fromIce<Time>(query.timestamp);
111 if (auto snapshot = entity.findSnapshot(time))
112 {
113 this->addResultSnapshot(result, *snapshot);
114 }
115 else
116 {
117 // Leave empty.
118#if 0
119 std::stringstream ss;
120 ss << "Failed to retrieve snapshot with timestamp "
122 << " from entity " << entity.id() << ".\n"
123 << "Entity has timestamps: ";
124 for (const Time& t : entity.getTimestamps())
125 {
126 ss << "\n- " << armem::toDateTimeMilliSeconds(t);
127 }
128 ARMARX_IMPORTANT << ss.str();
129#endif
130 }
131 }
132 }
133
134 virtual void
136 const armem::query::data::entity::TimeRange& query,
137 const EntityT& entity) const
138 {
139 if (query.minTimestamp.timeSinceEpoch.microSeconds <=
140 query.maxTimestamp.timeSinceEpoch.microSeconds ||
141 query.minTimestamp.timeSinceEpoch.microSeconds < 0 ||
142 query.maxTimestamp.timeSinceEpoch.microSeconds < 0)
143 {
144 const Time min = armarx::fromIce<Time>(query.minTimestamp);
145 const Time max = armarx::fromIce<Time>(query.maxTimestamp);
146 process(result, min, max, entity, query);
147 }
148 }
149
150 virtual void
152 const armem::query::data::entity::IndexRange& query,
153 const EntityT& entity) const
154 {
155 entity.forEachSnapshotInIndexRange(query.first,
156 query.last,
157 [this, &result](const EntitySnapshotT& snapshot)
158 { this->addResultSnapshot(result, snapshot); });
159 }
160
161 virtual void
163 const Time& min,
164 const Time& max,
165 const EntityT& entity,
166 const armem::query::data::EntityQuery& query) const
167 {
168 (void)query;
169 entity.forEachSnapshotInTimeRange(min,
170 max,
171 [this, &result](const EntitySnapshotT& snapshot)
172 { this->addResultSnapshot(result, snapshot); });
173 }
174
175 virtual void
177 const armem::query::data::entity::BeforeOrAtTime& query,
178 const EntityT& entity) const
179 {
180 const Time referenceTimestamp = armarx::fromIce<Time>(query.timestamp);
182
183 if (auto beforeOrAt = entity.findLatestSnapshotBeforeOrAt(referenceTimestamp))
184 {
185 this->addResultSnapshot(result, *beforeOrAt);
186 }
187 }
188
189 virtual void
191 const armem::query::data::entity::BeforeTime& query,
192 const EntityT& entity) const
193 {
194 const Time referenceTimestamp = armarx::fromIce<Time>(query.timestamp);
196
197 // Collect snapshots in reverse order (newest first) with early termination
198 std::vector<const EntitySnapshotT*> snapshots;
199 const size_t maxEntries = (query.maxEntries < 0)
200 ? std::numeric_limits<size_t>::max()
201 : static_cast<size_t>(query.maxEntries);
202
203 entity.forEachSnapshotBeforeReverse(
204 referenceTimestamp,
205 [&snapshots, maxEntries](const EntitySnapshotT& s)
206 {
207 snapshots.push_back(&s);
208 return snapshots.size() < maxEntries; // Stop when we have enough
209 });
210
211 // Add in chronological order (reverse of what we collected)
212 for (auto it = snapshots.rbegin(); it != snapshots.rend(); ++it)
213 {
214 this->addResultSnapshot(result, **it);
215 }
216 }
217
218 virtual void
220 const armem::query::data::entity::TimeApprox& query,
221 const EntityT& entity) const
222 {
223 const Time referenceTimestamp = armarx::fromIce<Time>(query.timestamp);
225
226 // elements have to be in range [t_ref - eps, t_ref + eps] if eps is positive
227 const auto isInRange = [&](const Time& t) -> bool
228 {
229 return query.eps.microSeconds <= 0 or
230 std::abs((t - referenceTimestamp).toMicroSeconds()) <=
231 query.eps.microSeconds;
232 };
233
234 // last element before or at timestamp
235 if (auto beforeOrAt = entity.findLatestSnapshotBeforeOrAt(referenceTimestamp))
236 {
237 const auto timestampOfMatchBefore = beforeOrAt->id().timestamp;
238 const auto isPerfectMatch = timestampOfMatchBefore == referenceTimestamp;
239 if (isInRange(timestampOfMatchBefore))
240 {
241 this->addResultSnapshot(result, *beforeOrAt);
242 }
243
244 // earsly stop, not necessary to also get the next since the match is perfect
245 if (isPerfectMatch)
246 {
247 return;
248 }
249
250 // first element after or at timestamp (or at because of fewer checks, we can assure that there is not element at)
251 const auto after = entity.findFirstSnapshotAfterOrAt(referenceTimestamp);
252 if (after)
253 {
254 const auto timestampOfMatchAfter = after->id().timestamp;
255 if (isInRange(timestampOfMatchAfter))
256 {
257 this->addResultSnapshot(result, *after);
258 }
259 }
260 }
261 }
262
263
264 protected:
265 virtual void addResultSnapshot(ResultEntityT& result,
266 const EntitySnapshotT& snapshot) const = 0;
267 };
268} // namespace armarx::armem::server::query_proc::base
std::string timestamp()
Indicates that an entity's history was queried, but is empty.
Definition ArMemError.h:174
_ResultEntityT process(const armem::query::data::EntityQuery &query, const _EntityT &data) const
virtual void addResultSnapshot(ResultEntityT &result, const EntitySnapshotT &snapshot) const =0
virtual void process(ResultEntityT &result, const armem::query::data::EntityQuery &query, const EntityT &entity) const override
Process the query and populate result.
BaseQueryProcessorBase< _EntityT, _ResultEntityT, armem::query::data::EntityQuery > Base
virtual void process(ResultEntityT &result, const armem::query::data::entity::TimeRange &query, const EntityT &entity) const
virtual void process(ResultEntityT &result, const armem::query::data::entity::Single &query, const EntityT &entity) const
virtual void process(ResultEntityT &result, const Time &min, const Time &max, const EntityT &entity, const armem::query::data::EntityQuery &query) const
virtual void process(ResultEntityT &result, const armem::query::data::entity::BeforeTime &query, const EntityT &entity) const
virtual void process(ResultEntityT &result, const armem::query::data::entity::TimeApprox &query, const EntityT &entity) const
virtual void process(ResultEntityT &result, const armem::query::data::entity::All &query, const EntityT &entity) const
virtual void process(ResultEntityT &result, const armem::query::data::entity::IndexRange &query, const EntityT &entity) const
virtual void process(ResultEntityT &result, const armem::query::data::entity::BeforeOrAtTime &query, const EntityT &entity) const
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define q
std::string toDateTimeMilliSeconds(const Time &time, int decimals=6)
Returns timeas e.g.
Definition Time.cpp:35
armarx::core::time::DateTime Time
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
void fromIce(const std::map< IceKeyT, IceValueT > &iceMap, boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)