iteration_mixins.h
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4#include <type_traits>
5
7
9
10#include "derived.h"
11
12namespace
13{
14 template <typename F, typename Ret, typename A, typename... Rest>
15 A helper(Ret (F::*)(A, Rest...));
16
17 template <typename F, typename Ret, typename A, typename... Rest>
18 A helper(Ret (F::*)(A, Rest...) const);
19
20 // volatile or lvalue/rvalue *this not required for lambdas (phew)
21
22 template <typename FuncT>
23 struct first_argument
24 {
25 using type = decltype(helper(&FuncT::operator()));
26 };
27
28 template <typename FuncT>
29 using first_argument_t = typename first_argument<FuncT>::type;
30} // namespace
31
33{
34
35 // Helper functions to implement the forEach*() method at the current level.
36
37 // Handle functions with different return type.
38 template <class FunctionT, class ChildT>
39 bool
40 call(FunctionT&& func, ChildT&& child)
41 {
42 if constexpr (std::is_same_v<decltype(func(child)), bool>)
43 {
44 if (!func(child))
45 {
46 return false;
47 }
48 return true;
49 }
50 else
51 {
52 func(child);
53 return true;
54 }
55 }
56
57 // Single-valued containers.
58 template <class ContainerT, class FunctionT>
59 bool
60 forEachChildSingle(ContainerT& container, FunctionT&& func)
61 {
62 for (auto& child : container)
63 {
64 if (not call(func, child))
65 {
66 return false;
67 }
68 }
69 return true;
70 }
71
72 // Pair-valued containers.
73 template <class ContainerT, class FunctionT>
74 bool
75 forEachChildPair(ContainerT& container, FunctionT&& func)
76 {
77 for (auto& [_, child] : container)
78 {
79 if (not call(func, child))
80 {
81 return false;
82 }
83 }
84 return true;
85 }
86
87 // see: https://en.cppreference.com/w/cpp/types/void_t
88
89 // primary template handles types that have no nested ::type member:
90 template <class, class = void>
91 struct has_mapped_type : std::false_type
92 {
93 };
94
95 // specialization recognizes types that do have a nested ::type member:
96 template <class T>
97 struct has_mapped_type<T, std::void_t<typename T::mapped_type>> : std::true_type
98 {
99 };
100
101 template <class ContainerT, class FunctionT>
102 bool
103 forEachChild(ContainerT& container, FunctionT&& func)
104 {
106 {
107 return forEachChildPair(container, func);
108 }
109 else
110 {
111 return forEachChildSingle(container, func);
112 }
113 }
114
115 template <class FunctionT, class ParentT, class ChildT>
116 bool
118 FunctionT&& func,
119 ParentT& parent,
120 bool single,
121 ChildT* child)
122 {
123 auto childFn = [&id, &func](auto& child) { return child.forEachInstanceIn(id, func); };
124 if (single)
125 {
126 return child ? childFn(*child) : true;
127 }
128 else
129 {
130 return parent.forEachChild(childFn);
131 }
132 }
133
134 // We use auto instead of, e.g. DerivedT::EntitySnapshotT,
135 // as we cannot use the typedef before DerivedT was completely defined.
136
137 template <class DerivedT>
139 {
140 // not: using EntitySnapshotT = typename DerivedT::EntitySnapshotT;
141
142 /**
143 * @param func Function like: bool process(EntityInstanceT& instance)>
144 */
145 template <class InstanceFunctionT>
146 bool
147 forEachInstance(InstanceFunctionT&& func)
148 {
149 return derived<DerivedT>(this).forEachSnapshot(
150 [&func](auto& snapshot) -> bool { return snapshot.forEachInstance(func); });
151 }
152
153 /**
154 * @param func Function like: bool process(const EntityInstanceT& instance)
155 */
156 template <class InstanceFunctionT>
157 bool
158 forEachInstance(InstanceFunctionT&& func) const
159 {
160 return derived<DerivedT>(this).forEachSnapshot(
161 [&func](const auto& snapshot) -> bool { return snapshot.forEachInstance(func); });
162 }
163
164 /**
165 * @brief Call `func` on the data of each instance converted to Aron DTO class.
166 *
167 * @code
168 * ().forEachEntityInstanceAs([](my::arondto::CoolData data)
169 * {
170 * ...
171 * });
172 * @endcode
173 *
174 * The Aron DTO type is deduced from the passed function's first argument.
175 *
176 * @param func Function like: `bool process(my::arondto::CoolData data)`
177 */
178 template <class AronDtoFunctionT>
179 bool
180 forEachInstanceAs(AronDtoFunctionT&& func) const
181 {
182 using AronDtoT = typename std::remove_const_t<
183 std::remove_reference_t<first_argument_t<AronDtoFunctionT>>>;
184
185 return derived<DerivedT>(this).forEachInstance(
186 [&func](const auto& instance)
187 { return func(instance.template dataAs<AronDtoT>()); });
188 }
189
190 /**
191 * @brief Call `func` on each instance with its data converted to Aron DTO class.
192 *
193 * @code
194 * ().forEachEntityInstanceWithDataAs(
195 * [](armem::wm::EntityInstanceBase<my::arondto::CoolData> instance)
196 * {
197 * const armarx::armem::MemoryID id = instance.id();
198 * const armarx::DateTime timestamp = instance.id().timestamp;
199 * const armarx::arondto::Duration& data = instance.data();
200 * ...
201 * });
202 * @endcode
203 *
204 * Compared to forEachInstanceAs(), this function allows accessing the full metadata of the
205 * instances in addition to the payload data converted to the ARON DTO.
206 *
207 * The Aron DTO type is deduced from the passed function's signature.
208 *
209 * @param func Function like:
210 * `bool process(armem::wm::EntityInstanceBase<my::arondto::CoolData> instance)`
211 */
212 template <class EntityInstanceBaseAronDtoFunctionT>
213 bool
214 forEachInstanceWithDataAs(EntityInstanceBaseAronDtoFunctionT&& func) const
215 {
216 using AronDtoT = typename std::remove_reference_t<
217 first_argument_t<EntityInstanceBaseAronDtoFunctionT>>::DataT;
218
219 return derived<DerivedT>(this).forEachInstance(
220 [&func](const auto& instance)
221 { return func(instance.template withDataAs<AronDtoT>()); });
222 }
223 };
224
225 template <class DerivedT>
227 {
228 /**
229 * @param func Function like: bool process(EntitySnapshotT& snapshot)>
230 */
231 template <class SnapshotFunctionT>
232 bool
233 forEachSnapshot(SnapshotFunctionT&& func)
234 {
235 return derived<DerivedT>(this).forEachEntity([&func](auto& entity) -> bool
236 { return entity.forEachSnapshot(func); });
237 }
238
239 /**
240 * @param func Function like: bool process(const EntitySnapshotT& snapshot)
241 */
242 template <class SnapshotFunctionT>
243 bool
244 forEachSnapshot(SnapshotFunctionT&& func) const
245 {
246 return derived<DerivedT>(this).forEachEntity([&func](const auto& entity) -> bool
247 { return entity.forEachSnapshot(func); });
248 }
249 };
250
251 template <class DerivedT>
253 {
254 /**
255 * @param func Function like: bool process(EntityT& entity)>
256 */
257 template <class FunctionT>
258 bool
259 forEachEntity(FunctionT&& func)
260 {
261 return derived<DerivedT>(this).forEachProviderSegment(
262 [&func](auto& providerSegment) -> bool
263 { return providerSegment.forEachEntity(func); });
264 }
265
266 /**
267 * @param func Function like: bool process(const EntityT& entity)
268 */
269 template <class FunctionT>
270 bool
271 forEachEntity(FunctionT&& func) const
272 {
273 return derived<DerivedT>(this).forEachProviderSegment(
274 [&func](const auto& providerSegment) -> bool
275 { return providerSegment.forEachEntity(func); });
276 }
277 };
278
279 template <class DerivedT>
281 {
282 /**
283 * @param func Function like: bool process(ProviderSegmentT& providerSegment)>
284 */
285 template <class FunctionT>
286 bool
287 forEachProviderSegment(FunctionT&& func)
288 {
289 return derived<DerivedT>(this).forEachCoreSegment(
290 [&func](auto& coreSegment) -> bool
291 { return coreSegment.forEachProviderSegment(func); });
292 }
293
294 /**
295 * @param func Function like: bool process(const ProviderSegmentT& providerSegment)
296 */
297 template <class FunctionT>
298 bool
299 forEachProviderSegment(FunctionT&& func) const
300 {
301 return derived<DerivedT>(this).forEachCoreSegment(
302 [&func](const auto& coreSegment) -> bool
303 { return coreSegment.forEachProviderSegment(func); });
304 }
305 };
306
307} // namespace armarx::armem::base::detail
class A(deque< T, A >)) ARMARX_OVERLOAD_STD_HASH_FOR_ITERABLE((class T
Enables hashing of std::list.
bool forEachChildPair(ContainerT &container, FunctionT &&func)
DerivedT & derived(ThisT *t)
Definition derived.h:8
bool forEachChildSingle(ContainerT &container, FunctionT &&func)
bool call(FunctionT &&func, ChildT &&child)
bool forEachInstanceIn(const MemoryID &id, FunctionT &&func, ParentT &parent, bool single, ChildT *child)
bool forEachChild(ContainerT &container, FunctionT &&func)
bool forEachInstanceWithDataAs(EntityInstanceBaseAronDtoFunctionT &&func) const
Call func on each instance with its data converted to Aron DTO class.
bool forEachInstanceAs(AronDtoFunctionT &&func) const
Call func on the data of each instance converted to Aron DTO class.
bool forEachInstance(InstanceFunctionT &&func) const
bool forEachSnapshot(SnapshotFunctionT &&func) const