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