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 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  @param bIncludeDisabled - true if the view should include disabled components
201  @retval - view of components
202  **/
203  template<std::derived_from<base_component_t> component_t = base_component_t>
204  [[nodiscard]] auto view(bool bIncludeDisabled = false) noexcept;
205 
206  /**
207  @brief Get a view which may be used in a ranged-based for loop and consists of components of a given type with decreasing priority
208  @tparam component_t - component type which doesn't have to be a final class type, may be any base or super type
209  @param bIncludeDisabled - true if the view should include disabled components
210  @retval - view of components
211  **/
212  template<std::derived_from<base_component_t> component_t = base_component_t>
213  [[nodiscard]] auto view(bool bIncludeDisabled = false) const noexcept;
214 
215  /**
216  @brief Get component status
217  @param pRawComponent - raw component pointer which acts like a component's handle
218  @retval - component status
219  **/
220  [[nodiscard]] std::optional<flags<component_status>> get_component_status(
221  const base_component_t* pRawComponent) const noexcept;
222 
223  /**
224  @brief Set (override) a component status
225  @param pRawComponent - raw component pointer which acts like a component's handle
226  @param newStatus - new component status
227  @retval - true if a component has been found and a new value has been set
228  **/
229  [[maybe_unused]] bool set_component_status(
230  const base_component_t* pRawComponent,
231  flags<component_status> newStatus) noexcept;
232 
233  /**
234  @brief Add new component status flags to the current ones
235  @param pRawComponent - raw component pointer which acts like a component's handle
236  @param newStatuses - new component status flags
237  @retval - true if a component has been found and a new value has been set
238  **/
239  [[maybe_unused]] bool add_component_status(
240  const base_component_t* pRawComponent,
241  flags<component_status> newStatuses) noexcept;
242 
243  /**
244  @brief Add component status flags from the current ones
245  @param pRawComponent - raw component pointer which acts like a component's handle
246  @param statusesToRemove - component status flags to remove
247  @retval - true if a component has been found and a new value has been set
248  **/
249  [[maybe_unused]] bool remove_component_status(
250  const base_component_t* pRawComponent,
251  flags<component_status> statusesToRemove) noexcept;
252 
253  /**
254  @brief Get component priority
255  @param pRawComponent - raw component pointer which acts like a component's handle
256  @retval - component priority
257  **/
258  [[nodiscard]] std::optional<priority> get_component_priority(const base_component_t* pRawComponent) const noexcept;
259 
260  /**
261  @brief Set component priority
262  @param pRawComponent - raw component pointer which acts like a component's handle
263  @param eNewComponentPriority - new component priority
264  @retval - true if a component has been found and a new value has been set
265  **/
266  [[maybe_unused]] bool set_component_priority(
267  const base_component_t* pRawComponent,
268  priority eNewComponentPriority) noexcept;
269 
270  /**
271  @brief Check if container doesn't have any components
272  @retval - true if container doesn't have any components
273  **/
274  [[nodiscard]] bool empty() const noexcept;
275 
276  /**
277  @brief Clear the container, e.g. remove all the components
278  **/
279  void clear() noexcept;
280 
281 private:
282  /**
283  @brief Get a status of a given component
284  @param pRawComponent - raw component pointer which acts like a component's handle
285  @retval - status
286  **/
287  [[nodiscard]] std::optional<component_status_key> get_status(const base_component_t* pRawComponent) const noexcept;
288 
289  /**
290  @brief Set a status of a given component
291  @warning This method may change the container, and you shall not use it while iterating over it
292  @param pRawComponent - raw component pointer which acts like a component's handle
293  @param status - new component's status
294  @retval - true if the component is found and a status was set
295  **/
296  [[maybe_unused]] bool set_status(const base_component_t* pRawComponent, component_status_key status) noexcept;
297 
298  /**
299  @brief Iterate class data of a given type
300  @tparam component_t - final class type
301  @tparam callable_t - a callable that takes a class data
302  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
303  @retval - final class data object
304  **/
305  template<
306  std::derived_from<base_component_t> component_t,
307  callable_c<void, typename components<base_component_t>::class_data&> callable_t>
308  class_data& iterate_class_data(callable_t iterateClassDataFunction) noexcept;
309 
310  /**
311  @brief Iterate class data of a given type
312  @tparam component_t - final class type
313  @tparam callable_t - a callable that takes a class data
314  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
315  @retval - final class data object
316  **/
317  template<
318  std::derived_from<base_component_t> component_t,
319  callable_c<void, typename components<base_component_t>::class_data&> callable_t>
320  const class_data& iterate_class_data(callable_t iterateClassDataFunction) const noexcept;
321 
322  /**
323  @brief Get or add class data
324  @tparam component_t - final class type
325  @retval - final class data object
326  **/
327  template<std::derived_from<base_component_t> component_t>
328  class_data& get_or_add_class_data() noexcept;
329 
330  /**
331  @brief Get or add class data
332  @tparam component_t - final class type
333  @retval - final class data object
334  **/
335  template<std::derived_from<base_component_t> component_t>
336  const class_data& get_or_add_class_data() const noexcept;
337 
338  /**
339  @brief Iterate class data of a given type
340  @tparam callable_t - a callable that takes a class data
341  @param pRawComponent - an object used to identify a class type
342  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
343  @retval - final class data object
344  **/
345  template<callable_c<void, typename components<base_component_t>::class_data&> callable_t>
346  class_data& iterate_class_data(const base_component_t* pRawComponent, callable_t iterateClassDataFunction) noexcept;
347 
348  /**
349  @brief Iterate class data of a given type
350  @tparam callable_t - a callable that takes a class data
351  @param pRawComponent - an object used to identify a class type
352  @param iterateClassDataFunction - a function that iterates over a class data from base_component_t + 1 to component_t
353  @retval - final class data object
354  **/
355  template<callable_c<void, typename components<base_component_t>::class_data&> callable_t>
356  const class_data& iterate_class_data(const base_component_t* pRawComponent, callable_t iterateClassDataFunction)
357  const noexcept;
358 
359  /**
360  @brief Get or add class data
361  @param pRawComponent - an object used to identify a class type
362  @retval - final class data object
363  **/
364  class_data& get_or_add_class_data(const base_component_t* pRawComponent) noexcept;
365 
366  /**
367  @brief Get or add class data
368  @param pRawComponent - an object used to identify a class type
369  @retval - final class data object
370  **/
371  const class_data& get_or_add_class_data(const base_component_t* pRawComponent) const noexcept;
372 
373 private:
374  class_data m_RootClass;
375 };
376 
377 } // namespace qx
378 
379 template<>
380 struct std::hash<qx::component_status_key>
381 {
382  constexpr size_t operator()(const qx::component_status_key& status) const noexcept
383  {
384  size_t nHash = qx::get_hash<qx::time_ordered_priority_key>(status);
385  qx::hash_combine(nHash, status.get_status_flags());
386  return nHash;
387  }
388 };
389 
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
bool empty() const noexcept
Check if container doesn't have any components.
Definition: components.inl:298
auto view(bool bIncludeDisabled=false) 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 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.