qxLib
components.inl
Go to the documentation of this file.
1 /**
2 
3  @file components.inl
4  @author Khrapov
5  @date 7.03.2021
6  @copyright © Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 template<std::derived_from<rtti_pure_base> base_component_t>
14 typename components<base_component_t>::class_data& components<base_component_t>::class_data::get_or_add_class_data(
15  class_id id) noexcept
16 {
17  if (const auto it = derivedClasses.find(id); it != derivedClasses.end())
18  return *it->second.get();
19 
20  auto pClassData = std::make_unique<class_data>();
21  auto pRawClassData = pClassData.get();
22  derivedClasses[id] = std::move(pClassData);
23  return *pRawClassData;
24 }
25 
26 template<std::derived_from<rtti_pure_base> base_component_t>
27 template<std::derived_from<base_component_t> component_t>
29  std::unique_ptr<component_t> pComponent,
30  priority ePriority,
31  flags<component_status> statusFlags) noexcept
32 {
33  if (!pComponent)
34  return nullptr;
35 
36  auto pRawComponent = pComponent.get();
37  class_data& classData = get_or_add_class_data(
38  pRawComponent,
39  [ePriority, statusFlags, pRawComponent](class_data& classData)
40  {
41  status status;
42  status.ePriority = ePriority;
43  status.statusFlags = statusFlags;
44  classData.priorityCache.emplace(status, pRawComponent);
45  });
46  classData.components.push_back(std::move(pComponent));
47  return pRawComponent;
48 }
49 
50 template<std::derived_from<rtti_pure_base> base_component_t>
51 std::unique_ptr<base_component_t> components<base_component_t>::remove(const base_component_t* pRawComponent) noexcept
52 {
53  if (!pRawComponent)
54  return nullptr;
55 
56  class_data& classData = get_or_add_class_data(
57  pRawComponent,
58  [pRawComponent](class_data& classData)
59  {
60  std::erase_if(
61  classData.priorityCache,
62  [pRawComponent](const auto& pair)
63  {
64  return pair.second == pRawComponent;
65  });
66  });
67 
68  const auto it = std::ranges::find_if(
69  classData.components,
70  [pRawComponent](const pointer_type& pointer)
71  {
72  return pointer.get() == pRawComponent;
73  });
74 
75  if (it == classData.components.end())
76  return nullptr;
77 
78  std::unique_ptr<base_component_t> pComponent = std::move(*it);
79  classData.components.erase(it);
80  return pComponent;
81 }
82 
83 template<std::derived_from<rtti_pure_base> base_component_t>
84 template<std::derived_from<base_component_t> component_t>
85 component_t* components<base_component_t>::try_get(bool bIncludeDisabled) noexcept
86 {
87  class_data& classData = get_or_add_class_data<component_t>();
88  const auto it = std::ranges::find_if(
89  classData.priorityCache,
90  [bIncludeDisabled](const auto& pair)
91  {
92  return bIncludeDisabled || !pair.first.statusFlags.contains(component_status::disabled);
93  });
94 
95  return it != classData.priorityCache.end() ? static_cast<component_t*>(it->second) : nullptr;
96 }
97 
98 template<std::derived_from<rtti_pure_base> base_component_t>
99 template<std::derived_from<base_component_t> component_t>
100 const component_t* components<base_component_t>::try_get(bool bIncludeDisabled) const noexcept
101 {
102  return QX_CONST_CAST_THIS()->template try_get<component_t>(bIncludeDisabled);
103 }
104 
105 template<std::derived_from<rtti_pure_base> base_component_t>
106 template<std::derived_from<base_component_t> component_t>
107 component_t* components<base_component_t>::try_get(class_id id, bool bIncludeDisabled) noexcept
108 {
109  // we could improve it from O(N) to O(log(N)) if we could use id->is_derived_from(id) without an object itself
110  // we will do it when a reflection system is fully implemented
111  const auto it = std::ranges::find_if(
112  m_RootClass.priorityCache,
113  [id, bIncludeDisabled](const auto& pair)
114  {
115  return (bIncludeDisabled || !pair.first.statusFlags.contains(component_status::disabled))
116  && pair.second->is_derived_from_id(id);
117  });
118 
119  return it != m_RootClass.priorityCache.end() ? rtti_cast<component_t>(it->second) : nullptr;
120 }
121 
122 template<std::derived_from<rtti_pure_base> base_component_t>
123 template<std::derived_from<base_component_t> component_t>
124 const component_t* components<base_component_t>::try_get(class_id id, bool bIncludeDisabled) const noexcept
125 {
126  return QX_CONST_CAST_THIS()->template try_get<component_t>(id, bIncludeDisabled);
127 }
128 
129 template<std::derived_from<rtti_pure_base> base_component_t>
130 template<std::derived_from<base_component_t> component_t>
131 component_t& components<base_component_t>::get(bool bIncludeDisabled) noexcept
132 {
133  return *try_get<component_t>(bIncludeDisabled);
134 }
135 
136 template<std::derived_from<rtti_pure_base> base_component_t>
137 template<std::derived_from<base_component_t> component_t>
138 const component_t& components<base_component_t>::get(bool bIncludeDisabled) const noexcept
139 {
140  return QX_CONST_CAST_THIS()->template get<component_t>(bIncludeDisabled);
141 }
142 
143 template<std::derived_from<rtti_pure_base> base_component_t>
144 template<std::derived_from<base_component_t> component_t>
145 base_component_t& components<base_component_t>::get(class_id id, bool bIncludeDisabled) noexcept
146 {
147  return *try_get<component_t>(id, bIncludeDisabled);
148 }
149 
150 template<std::derived_from<rtti_pure_base> base_component_t>
151 template<std::derived_from<base_component_t> component_t>
152 const base_component_t& components<base_component_t>::get(class_id id, bool bIncludeDisabled) const noexcept
153 {
154  return QX_CONST_CAST_THIS()->template get<component_t>(id, bIncludeDisabled);
155 }
156 
157 template<std::derived_from<rtti_pure_base> base_component_t>
158 template<std::derived_from<base_component_t> component_t>
160 {
161  class_data& classData = get_or_add_class_data<component_t>();
162  return classData.priorityCache
163  | std::views::filter(
164  [](const auto& pair)
165  {
166  return pair.second->template is_derived_from<component_t>()
167  && !pair.first.statusFlags.contains(component_status::disabled);
168  })
169  | std::views::transform(
170  [](auto& pair) -> component_t&
171  {
172  return *static_cast<component_t*>(pair.second);
173  });
174 }
175 
176 template<std::derived_from<rtti_pure_base> base_component_t>
177 template<std::derived_from<base_component_t> component_t>
179 {
180  const class_data& classData = get_or_add_class_data<component_t>();
181  return classData.priorityCache
182  | std::views::filter(
183  [](const auto& pair)
184  {
185  return pair.second->template is_derived_from<component_t>()
186  && !pair.first.statusFlags.contains(component_status::disabled);
187  })
188  | std::views::transform(
189  [](const auto& pair) -> const component_t&
190  {
191  return *static_cast<const component_t*>(pair.second);
192  });
193 }
194 
195 template<std::derived_from<rtti_pure_base> base_component_t>
196 std::optional<flags<component_status>> components<base_component_t>::get_component_status(
197  const base_component_t* pRawComponent) const noexcept
198 {
199  std::optional<status> optComponentStatus = get_status(pRawComponent);
200  return optComponentStatus ? std::optional(optComponentStatus->statusFlags) : std::nullopt;
201 }
202 
203 template<std::derived_from<rtti_pure_base> base_component_t>
205  const base_component_t* pRawComponent,
206  flags<component_status> newStatus) noexcept
207 {
208  std::optional<status> optComponentStatus = get_status(pRawComponent);
209  if (!optComponentStatus)
210  return false;
211 
212  optComponentStatus->statusFlags = newStatus;
213  return set_status(pRawComponent, *optComponentStatus);
214 }
215 
216 template<std::derived_from<rtti_pure_base> base_component_t>
218  const base_component_t* pRawComponent,
219  flags<component_status> newStatuses) noexcept
220 {
221  std::optional<flags<component_status>> optComponentStatus = get_component_status(pRawComponent);
222  if (!optComponentStatus)
223  return false;
224 
225  optComponentStatus->add(newStatuses);
226  return set_component_status(pRawComponent, *optComponentStatus);
227 }
228 
229 template<std::derived_from<rtti_pure_base> base_component_t>
231  const base_component_t* pRawComponent,
232  flags<component_status> statusesToRemove) noexcept
233 {
234  std::optional<flags<component_status>> optComponentStatus = get_component_status(pRawComponent);
235  if (!optComponentStatus)
236  return false;
237 
238  optComponentStatus->remove(statusesToRemove);
239  return set_component_status(pRawComponent, *optComponentStatus);
240 }
241 
242 template<std::derived_from<rtti_pure_base> base_component_t>
244  const base_component_t* pRawComponent) const noexcept
245 {
246  std::optional<status> optComponentStatus = get_status(pRawComponent);
247  return optComponentStatus ? std::optional(optComponentStatus->ePriority) : std::nullopt;
248 }
249 
250 template<std::derived_from<rtti_pure_base> base_component_t>
252  const base_component_t* pRawComponent,
253  priority eNewComponentPriority) noexcept
254 {
255  std::optional<status> optComponentStatus = get_status(pRawComponent);
256  if (!optComponentStatus)
257  return false;
258 
259  optComponentStatus->ePriority = eNewComponentPriority;
260  return set_status(pRawComponent, *optComponentStatus);
261 }
262 
263 template<std::derived_from<rtti_pure_base> base_component_t>
265 {
266  return m_RootClass.priorityCache.empty();
267 }
268 
269 template<std::derived_from<rtti_pure_base> base_component_t>
271 {
272  m_RootClass.derivedClasses.clear();
273  m_RootClass.components.clear();
274  m_RootClass.priorityCache.clear();
275 }
276 
277 template<std::derived_from<rtti_pure_base> base_component_t>
278 std::optional<typename components<base_component_t>::status> components<base_component_t>::get_status(
279  const base_component_t* pRawComponent) const noexcept
280 {
281  if (!pRawComponent)
282  return std::nullopt;
283 
284  auto it = std::ranges::find_if(
285  m_RootClass.priorityCache,
286  [pRawComponent](const auto& pair)
287  {
288  return pair.second == pRawComponent;
289  });
290 
291  return it != m_RootClass.priorityCache.end() ? std::optional<status>(it->first) : std::nullopt;
292 }
293 
294 
295 template<std::derived_from<rtti_pure_base> base_component_t>
296 bool components<base_component_t>::set_status(const base_component_t* pRawComponent, status status) noexcept
297 {
298  if (!pRawComponent)
299  return false;
300 
301  bool bChanged = true;
302  get_or_add_class_data(
303  pRawComponent,
304  [pRawComponent, status, &bChanged](class_data& classData)
305  {
306  const auto it = std::ranges::find_if(
307  classData.priorityCache,
308  [pRawComponent](const auto& pair)
309  {
310  return pair.second == pRawComponent;
311  });
312 
313  if (it == classData.priorityCache.end())
314  {
315  bChanged = false;
316  return;
317  }
318 
319  if (it->first != status)
320  {
321  classData.priorityCache.emplace(status, it->second);
322  classData.priorityCache.erase(it);
323  }
324  });
325 
326  return bChanged;
327 }
328 
329 } // namespace qx
Class id, unique for each class using qx rtti system.
Definition: class_id.h:27
Container for components system.
Definition: components.h:46
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:131
std::unique_ptr< base_component_t > remove(const base_component_t *pRawComponent) noexcept
Remove the component from the container.
Definition: components.inl:51
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:217
bool set_component_priority(const base_component_t *pRawComponent, priority eNewComponentPriority) noexcept
Set component priority.
Definition: components.inl:251
void clear() noexcept
Clear the container, e.g. remove all the components.
Definition: components.inl:270
component_t * try_get(bool bIncludeDisabled=false) noexcept
Try to get a component of the given type with the highest priority.
Definition: components.inl:85
bool set_component_status(const base_component_t *pRawComponent, flags< component_status > newStatus) noexcept
Set (override) a component status.
Definition: components.inl:204
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:159
bool empty() const noexcept
Check if container doesn't have any components.
Definition: components.inl:264
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:230
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:28
std::optional< flags< component_status > > get_component_status(const base_component_t *pRawComponent) const noexcept
Get component status.
Definition: components.inl:196
std::optional< priority > get_component_priority(const base_component_t *pRawComponent) const noexcept
Get component priority.
Definition: components.inl:243
#define QX_CONST_CAST_THIS()
This macro is made for situations where you have a const method and you need exactly the same method ...
Definition: common.h:97
priority
User may use the predefined values or the custom ones, for ex. "normal - 1", this type is supposed to...
Definition: priority.h:26