qxLib
components.h
Go to the documentation of this file.
1 /**
2 
3  @file components.h
4  @author Khrapov
5  @date 7.03.2021
6  @copyright © Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 #pragma once
10 
11 #include <qx/macros/common.h>
12 #include <qx/priority.h>
13 #include <qx/rtti/rtti.h>
14 #include <qx/rtti/rtti_cast.h>
15 
16 #include <atomic>
17 #include <map>
18 #include <optional>
19 #include <ranges>
20 #include <unordered_map>
21 
22 namespace qx
23 {
24 
25 enum class component_status
26 {
27  default_value = 0,
28  disabled = 1 << 0,
29 };
30 
31 /**
32 
33  @class component_status_key
34  @brief A class that acts like time_ordered_priority_key but has a status field
35  @author Khrapov
36  @date 10.08.2025
37 
38  **/
40 {
41 public:
42  constexpr component_status_key() noexcept = default;
43 
44  /**
45  @brief status object constructor
46  @param ePriority - key priority
47  @param eStatusFlags - object status
48  **/
49  component_status_key(priority ePriority, flags<component_status> eStatusFlags) noexcept;
50 
51  /**
52  @brief Get object status
53  @retval - object status
54  **/
55  constexpr flags<component_status> get_status_flags() const noexcept;
56 
57  /**
58  @brief Set object status
59  @param eStatusFlags - object status
60  **/
61  constexpr void set_status_flags(flags<component_status> eStatusFlags) noexcept;
62 
63  using time_ordered_priority_key::operator<;
64  constexpr bool operator==(const component_status_key&) const noexcept = default;
65 
66 private:
67  flags<component_status> m_eStatusFlags = component_status::default_value;
68 };
69 
70 /**
71 
72  @class components
73  @brief Container for components system
74  @details Stores components and allows them to be accessed by a template argument or a class id.
75  Each component has a priority, which is used to iterate through a sequence of objects of a type (final or any super type)
76  or to use getter methods, where a component with the highest priority will be given.
77  You can use qx::priority::disabled to exclude the component from iteration or getters result.
78  @tparam base_component_t - base component type
79  @author Khrapov
80  @date 9.03.2021
81 
82 **/
83 template<std::derived_from<rtti_pure_base> base_component_t>
85 {
86 public:
87  using pointer_type = std::unique_ptr<base_component_t>;
88 
89 private:
90  struct class_data
91  {
92  std::unordered_map<class_id, std::unique_ptr<class_data>> derivedClasses;
93  std::vector<pointer_type> components;
94  std::multimap<component_status_key, base_component_t*> priorityCache;
95 
96  [[nodiscard]] class_data& get_or_add_class_data(class_id id) noexcept;
97  };
98 
99 public:
100  /**
101  @brief Add a component
102  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
103  @param pComponent - component object
104  @param ePriority - initial component priority
105  @param statusFlags - initial component status
106  @retval - raw component pointer which acts like a component's handle
107  **/
108  template<std::derived_from<base_component_t> component_t>
109  [[maybe_unused]] component_t* add(
110  std::unique_ptr<component_t> pComponent,
111  priority ePriority = priority::normal,
112  flags<component_status> statusFlags = component_status::default_value) noexcept;
113 
114  /**
115  @brief Remove the component from the container
116  @param pRawComponent - raw component pointer which acts like a component's handle
117  @retval - component object
118  **/
119  [[maybe_unused]] std::unique_ptr<base_component_t> remove(const base_component_t* pRawComponent) noexcept;
120 
121  /**
122  @brief Try to get a component of the given type with the highest priority
123  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
124  @param bIncludeDisabled - true if a search should include disabled components
125  @retval - component pointer or nullptr
126  **/
127  template<std::derived_from<base_component_t> component_t>
128  [[nodiscard]] component_t* try_get(bool bIncludeDisabled = false) noexcept;
129 
130  /**
131  @brief Try to get a component of the given type with the highest priority
132  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
133  @param bIncludeDisabled - true if a search should include disabled components
134  @retval - component pointer or nullptr
135  **/
136  template<std::derived_from<base_component_t> component_t>
137  [[nodiscard]] const component_t* try_get(bool bIncludeDisabled = false) const noexcept;
138 
139  /**
140  @brief Try to get a component of the given type id with the highest priority
141  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
142  @param id - type id
143  @param bIncludeDisabled - true if a search should include disabled components
144  @retval - component pointer or nullptr
145  **/
146  template<std::derived_from<base_component_t> component_t = base_component_t>
147  [[nodiscard]] component_t* try_get(class_id id, bool bIncludeDisabled = false) noexcept;
148 
149  /**
150  @brief Try to get a component of the given type id with the highest priority
151  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
152  @param id - type id
153  @param bIncludeDisabled - true if a search should include disabled components
154  @retval - component pointer or nullptr
155  **/
156  template<std::derived_from<base_component_t> component_t = base_component_t>
157  [[nodiscard]] const component_t* try_get(class_id id, bool bIncludeDisabled = false) const noexcept;
158 
159  /**
160  @brief Get a component of the given type with the highest priority (no existence checks are performed)
161  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
162  @param bIncludeDisabled - true if a search should include disabled components
163  @retval - component reference
164  **/
165  template<std::derived_from<base_component_t> component_t>
166  [[nodiscard]] component_t& get(bool bIncludeDisabled = false) noexcept;
167 
168  /**
169  @brief Get a component of the given type with the highest priority (no existence checks are performed)
170  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
171  @param bIncludeDisabled - true if a search should include disabled components
172  @retval - component reference
173  **/
174  template<std::derived_from<base_component_t> component_t>
175  [[nodiscard]] const component_t& get(bool bIncludeDisabled = false) const noexcept;
176 
177  /**
178  @brief Get a component of the given type with the highest priority (no existence checks are performed)
179  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
180  @param id - type id
181  @param bIncludeDisabled - true if a search should include disabled components
182  @retval - component reference
183  **/
184  template<std::derived_from<base_component_t> component_t = base_component_t>
185  [[nodiscard]] base_component_t& get(class_id id, bool bIncludeDisabled = false) noexcept;
186 
187  /**
188  @brief Get a component of the given type with the highest priority (no existence checks are performed)
189  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
190  @param id - type id
191  @param bIncludeDisabled - true if a search should include disabled components
192  @retval - component reference
193  **/
194  template<std::derived_from<base_component_t> component_t = base_component_t>
195  [[nodiscard]] const base_component_t& get(class_id id, bool bIncludeDisabled = false) const noexcept;
196 
197  /**
198  @brief Get a view which may be used in a ranged-based for loop and consists of components of a given type with decreasing non-disabled priority
199  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
200  @retval - view of components
201  **/
202  template<std::derived_from<base_component_t> component_t = base_component_t>
203  [[nodiscard]] auto view() noexcept;
204 
205  /**
206  @brief Get a view which may be used in a ranged-based for loop and consists of components of a given type with decreasing non-disabled priority
207  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
208  @retval - view of components
209  **/
210  template<std::derived_from<base_component_t> component_t = base_component_t>
211  [[nodiscard]] auto view() const noexcept;
212 
213  /**
214  @brief Get component status
215  @param pRawComponent - raw component pointer which acts like a component's handle
216  @retval - component status
217  **/
218  [[nodiscard]] std::optional<flags<component_status>> get_component_status(
219  const base_component_t* pRawComponent) const noexcept;
220 
221  /**
222  @brief Set (override) a component status
223  @param pRawComponent - raw component pointer which acts like a component's handle
224  @param newStatus - new component status
225  @retval - true if a component has been found and a new value has been set
226  **/
227  [[maybe_unused]] bool set_component_status(
228  const base_component_t* pRawComponent,
229  flags<component_status> newStatus) noexcept;
230 
231  /**
232  @brief Add new component status flags to the current ones
233  @param pRawComponent - raw component pointer which acts like a component's handle
234  @param newStatuses - new component status flags
235  @retval - true if a component has been found and a new value has been set
236  **/
237  [[maybe_unused]] bool add_component_status(
238  const base_component_t* pRawComponent,
239  flags<component_status> newStatuses) noexcept;
240 
241  /**
242  @brief Add component status flags from the current ones
243  @param pRawComponent - raw component pointer which acts like a component's handle
244  @param statusesToRemove - component status flags to remove
245  @retval - true if a component has been found and a new value has been set
246  **/
247  [[maybe_unused]] bool remove_component_status(
248  const base_component_t* pRawComponent,
249  flags<component_status> statusesToRemove) noexcept;
250 
251  /**
252  @brief Get component priority
253  @param pRawComponent - raw component pointer which acts like a component's handle
254  @retval - component priority
255  **/
256  [[nodiscard]] std::optional<priority> get_component_priority(const base_component_t* pRawComponent) const noexcept;
257 
258  /**
259  @brief Set component priority
260  @param pRawComponent - raw component pointer which acts like a component's handle
261  @param eNewComponentPriority - new component priority
262  @retval - true if a component has been found and a new value has been set
263  **/
264  [[maybe_unused]] bool set_component_priority(
265  const base_component_t* pRawComponent,
266  priority eNewComponentPriority) noexcept;
267 
268  /**
269  @brief Check if container doesn't have any components
270  @retval - true if container doesn't have any components
271  **/
272  [[nodiscard]] bool empty() const noexcept;
273 
274  /**
275  @brief Clear the container, e.g. remove all the components
276  **/
277  void clear() noexcept;
278 
279 private:
280  /**
281  @brief Get a status of a given component
282  @param pRawComponent - raw component pointer which acts like a component's handle
283  @retval - status
284  **/
285  [[nodiscard]] std::optional<component_status_key> get_status(const base_component_t* pRawComponent) const noexcept;
286 
287  /**
288  @brief Set a status of a given component
289  @warning This method may change the container, and you shall not use it while iterating over it
290  @param pRawComponent - raw component pointer which acts like a component's handle
291  @param status - new component's status
292  @retval - true if the component is found and a status was set
293  **/
294  [[maybe_unused]] bool set_status(const base_component_t* pRawComponent, component_status_key status) noexcept;
295 
296  /**
297  @brief Iterate class data of a given type
298  @tparam component_t - final class type
299  @tparam callable_t - a callable that takes a class data
300  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
301  @retval - final class data object
302  **/
303  template<
304  std::derived_from<base_component_t> component_t,
305  callable_c<void, typename components<base_component_t>::class_data&> callable_t>
306  class_data& iterate_class_data(callable_t iterateClassDataFunction) noexcept;
307 
308  /**
309  @brief Iterate class data of a given type
310  @tparam component_t - final class type
311  @tparam callable_t - a callable that takes a class data
312  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
313  @retval - final class data object
314  **/
315  template<
316  std::derived_from<base_component_t> component_t,
317  callable_c<void, typename components<base_component_t>::class_data&> callable_t>
318  const class_data& iterate_class_data(callable_t iterateClassDataFunction) const noexcept;
319 
320  /**
321  @brief Get or add class data
322  @tparam component_t - final class type
323  @retval - final class data object
324  **/
325  template<std::derived_from<base_component_t> component_t>
326  class_data& get_or_add_class_data() noexcept;
327 
328  /**
329  @brief Get or add class data
330  @tparam component_t - final class type
331  @retval - final class data object
332  **/
333  template<std::derived_from<base_component_t> component_t>
334  const class_data& get_or_add_class_data() const noexcept;
335 
336  /**
337  @brief Iterate class data of a given type
338  @tparam callable_t - a callable that takes a class data
339  @param pRawComponent - an object used to identify a class type
340  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
341  @retval - final class data object
342  **/
343  template<callable_c<void, typename components<base_component_t>::class_data&> callable_t>
344  class_data& iterate_class_data(const base_component_t* pRawComponent, callable_t iterateClassDataFunction) noexcept;
345 
346  /**
347  @brief Iterate class data of a given type
348  @tparam callable_t - a callable that takes a class data
349  @param pRawComponent - an object used to identify a class type
350  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
351  @retval - final class data object
352  **/
353  template<callable_c<void, typename components<base_component_t>::class_data&> callable_t>
354  const class_data& iterate_class_data(const base_component_t* pRawComponent, callable_t iterateClassDataFunction)
355  const noexcept;
356 
357  /**
358  @brief Get or add class data
359  @param pRawComponent - an object used to identify a class type
360  @retval - final class data object
361  **/
362  class_data& get_or_add_class_data(const base_component_t* pRawComponent) noexcept;
363 
364  /**
365  @brief Get or add class data
366  @param pRawComponent - an object used to identify a class type
367  @retval - final class data object
368  **/
369  const class_data& get_or_add_class_data(const base_component_t* pRawComponent) const noexcept;
370 
371 private:
372  class_data m_RootClass;
373 };
374 
375 } // namespace qx
376 
377 template<>
378 struct std::hash<qx::component_status_key>
379 {
380  constexpr size_t operator()(const qx::component_status_key& status) const noexcept
381  {
382  size_t nHash = qx::get_hash<qx::time_ordered_priority_key>(status);
383  qx::hash_combine(nHash, status.get_status_flags());
384  return nHash;
385  }
386 };
387 
Class id, unique for each class using qx rtti system.
Definition: class_id.h:27
A class that acts like time_ordered_priority_key but has a status field.
Definition: components.h:40
constexpr void set_status_flags(flags< component_status > eStatusFlags) noexcept
Set object status.
Definition: components.inl:45
constexpr flags< component_status > get_status_flags() const noexcept
Get object status.
Definition: components.inl:40
Container for components system.
Definition: components.h:85
component_t & get(bool bIncludeDisabled=false) noexcept
Get a component of the given type with the highest priority (no existence checks are performed)
Definition: components.inl:165
std::unique_ptr< base_component_t > remove(const base_component_t *pRawComponent) noexcept
Remove the component from the container.
Definition: components.inl:85
bool add_component_status(const base_component_t *pRawComponent, flags< component_status > newStatuses) noexcept
Add new component status flags to the current ones.
Definition: components.inl:251
bool set_component_priority(const base_component_t *pRawComponent, priority eNewComponentPriority) noexcept
Set component priority.
Definition: components.inl:285
void clear() noexcept
Clear the container, e.g. remove all the components.
Definition: components.inl:304
component_t * try_get(bool bIncludeDisabled=false) noexcept
Try to get a component of the given type with the highest priority.
Definition: components.inl:119
bool set_component_status(const base_component_t *pRawComponent, flags< component_status > newStatus) noexcept
Set (override) a component status.
Definition: components.inl:238
auto view() noexcept
Get a view which may be used in a ranged-based for loop and consists of components of a given type wi...
Definition: components.inl:193
bool empty() const noexcept
Check if container doesn't have any components.
Definition: components.inl:298
bool remove_component_status(const base_component_t *pRawComponent, flags< component_status > statusesToRemove) noexcept
Add component status flags from the current ones.
Definition: components.inl:264
component_t * add(std::unique_ptr< component_t > pComponent, priority ePriority=priority::normal, flags< component_status > statusFlags=component_status::default_value) noexcept
Add a component.
Definition: components.inl:65
std::optional< flags< component_status > > get_component_status(const base_component_t *pRawComponent) const noexcept
Get component status.
Definition: components.inl:230
std::optional< priority > get_component_priority(const base_component_t *pRawComponent) const noexcept
Get component priority.
Definition: components.inl:277
A class that can be used as a key in ordered containers so that items are ordered in descending order...
Definition: priority.h:47
priority
User may use the predefined values or the custom ones, for ex. "normal - 1", this type is supposed to...
Definition: priority.h:27
RTTI system based on polymorphism.