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>::SClassData& components<base_component_t>::SClassData::get_or_add_class_data(
15  class_identificator 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<SClassData>();
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<status> statusFlags) noexcept
32 {
33  if (!pComponent)
34  return nullptr;
35 
36  auto pRawComponent = pComponent.get();
37  SClassData& classData = get_or_add_class_data(
38  pRawComponent,
39  [ePriority, statusFlags, pRawComponent](SClassData& classData)
40  {
41  classData.priorityCache.emplace(ePriority, typename SClassData::SCacheData(pRawComponent, statusFlags));
42  });
43  classData.components.push_back(std::move(pComponent));
44  return pRawComponent;
45 }
46 
47 template<std::derived_from<rtti_pure_base> base_component_t>
48 std::unique_ptr<base_component_t> components<base_component_t>::remove(const base_component_t* pRawComponent) noexcept
49 {
50  if (!pRawComponent)
51  return nullptr;
52 
53  SClassData& classData = get_or_add_class_data(
54  pRawComponent,
55  [pRawComponent](SClassData& classData)
56  {
57  std::erase_if(
58  classData.priorityCache,
59  [pRawComponent](const auto& pair)
60  {
61  return pair.second.pComponent == pRawComponent;
62  });
63  });
64 
65  const auto it = std::ranges::find_if(
66  classData.components,
67  [pRawComponent](const pointer_type& pointer)
68  {
69  return pointer.get() == pRawComponent;
70  });
71 
72  if (it == classData.components.end())
73  return nullptr;
74 
75  std::unique_ptr<base_component_t> pComponent = std::move(*it);
76  classData.components.erase(it);
77  return pComponent;
78 }
79 
80 template<std::derived_from<rtti_pure_base> base_component_t>
81 template<std::derived_from<base_component_t> component_t>
83 {
84  SClassData& classData = get_or_add_class_data<component_t>();
85  const auto it = std::ranges::find_if(
86  classData.priorityCache,
87  [](const auto& pair)
88  {
89  return !pair.second.statusFlags.contains(status::disabled);
90  });
91 
92  return it != classData.priorityCache.end() ? static_cast<component_t*>(it->second.pComponent) : nullptr;
93 }
94 
95 template<std::derived_from<rtti_pure_base> base_component_t>
96 template<std::derived_from<base_component_t> component_t>
97 const component_t* components<base_component_t>::try_get() const noexcept
98 {
99  return QX_CONST_CAST_THIS()->template try_get<component_t>();
100 }
101 
102 template<std::derived_from<rtti_pure_base> base_component_t>
103 base_component_t* components<base_component_t>::try_get(class_identificator id) noexcept
104 {
105  // we could improve it from O(N) to O(log(N)) if we could use id->is_derived_from(id) without an object itself
106  // we will do it when a reflection system is fully implemented
107  const auto it = std::ranges::find_if(
108  m_RootClass.priorityCache,
109  [id](const auto& pair)
110  {
111  return !pair.second.statusFlags.contains(status::disabled)
112  && pair.second.pComponent->is_derived_from_id(id);
113  });
114 
115  return it != m_RootClass.priorityCache.end() ? it->second.pComponent : nullptr;
116 }
117 
118 template<std::derived_from<rtti_pure_base> base_component_t>
119 const base_component_t* components<base_component_t>::try_get(class_identificator id) const noexcept
120 {
121  return QX_CONST_CAST_THIS()->try_get(id);
122 }
123 
124 template<std::derived_from<rtti_pure_base> base_component_t>
125 template<std::derived_from<base_component_t> component_t>
126 component_t& components<base_component_t>::get() noexcept
127 {
128  SClassData& classData = get_or_add_class_data<component_t>();
129  const auto it = std::ranges::find_if(
130  classData.priorityCache,
131  [](const auto& pair)
132  {
133  return !pair.second.statusFlags.contains(status::disabled);
134  });
135 
136  return *static_cast<component_t*>(it->second.pComponent);
137 }
138 
139 template<std::derived_from<rtti_pure_base> base_component_t>
140 template<std::derived_from<base_component_t> component_t>
141 const component_t& components<base_component_t>::get() const noexcept
142 {
143  return QX_CONST_CAST_THIS()->template get<component_t>();
144 }
145 
146 template<std::derived_from<rtti_pure_base> base_component_t>
147 template<std::derived_from<base_component_t> component_t>
149 {
150  SClassData& classData = get_or_add_class_data<component_t>();
151  return classData.priorityCache
152  | std::views::filter(
153  [](const auto& pair)
154  {
155  return pair.second.pComponent->template is_derived_from<component_t>()
156  && !pair.second.statusFlags.contains(status::disabled);
157  })
158  | std::views::transform(
159  [](auto& pair) -> component_t&
160  {
161  return *static_cast<component_t*>(pair.second.pComponent);
162  });
163 }
164 
165 template<std::derived_from<rtti_pure_base> base_component_t>
166 template<std::derived_from<base_component_t> component_t>
168 {
169  const SClassData& classData = get_or_add_class_data<component_t>();
170  return classData.priorityCache
171  | std::views::filter(
172  [](const auto& pair)
173  {
174  return pair.second.pComponent->template is_derived_from<component_t>()
175  && !pair.second.statusFlags.contains(status::disabled);
176  })
177  | std::views::transform(
178  [](const auto& pair) -> const component_t&
179  {
180  return *static_cast<const component_t*>(pair.second.pComponent);
181  });
182 }
183 
184 template<std::derived_from<rtti_pure_base> base_component_t>
185 std::optional<priority> components<base_component_t>::get_priority(const base_component_t* pRawComponent) const noexcept
186 {
187  if (!pRawComponent)
188  return std::nullopt;
189 
190  auto it = std::ranges::find_if(
191  m_RootClass.priorityCache,
192  [pRawComponent](const auto& pair)
193  {
194  return pair.second.pComponent == pRawComponent;
195  });
196 
197  return it != m_RootClass.priorityCache.end() ? std::optional<priority>(it->first) : std::nullopt;
198 }
199 
200 
201 template<std::derived_from<rtti_pure_base> base_component_t>
202 bool components<base_component_t>::set_priority(const base_component_t* pRawComponent, priority ePriority) noexcept
203 {
204  if (!pRawComponent)
205  return false;
206 
207  bool bChanged = true;
208  get_or_add_class_data(
209  pRawComponent,
210  [pRawComponent, ePriority, &bChanged](SClassData& classData)
211  {
212  const auto it = std::ranges::find_if(
213  classData.priorityCache,
214  [pRawComponent](const auto& pair)
215  {
216  return pair.second.pComponent == pRawComponent;
217  });
218 
219  if (it == classData.priorityCache.end())
220  {
221  bChanged = false;
222  return;
223  }
224 
225  if (it->first != ePriority)
226  {
227  classData.priorityCache.emplace(ePriority, it->second);
228  classData.priorityCache.erase(it);
229  }
230  });
231 
232  return bChanged;
233 }
234 
235 template<std::derived_from<rtti_pure_base> base_component_t>
236 std::optional<flags<status>> components<base_component_t>::get_status(
237  const base_component_t* pRawComponent) const noexcept
238 {
239  if (!pRawComponent)
240  return std::nullopt;
241 
242  auto it = std::ranges::find_if(
243  m_RootClass.priorityCache,
244  [pRawComponent](const auto& pair)
245  {
246  return pair.second.pComponent == pRawComponent;
247  });
248 
249  return it != m_RootClass.priorityCache.end() ? std::optional<flags<status>>(it->second.statusFlags) : std::nullopt;
250 }
251 
252 
253 template<std::derived_from<rtti_pure_base> base_component_t>
254 bool components<base_component_t>::set_status(const base_component_t* pRawComponent, flags<status> status) noexcept
255 {
256  if (!pRawComponent)
257  return false;
258 
259  bool bChanged = true;
260  get_or_add_class_data(
261  pRawComponent,
262  [pRawComponent, status, &bChanged](SClassData& classData)
263  {
264  const auto it = std::ranges::find_if(
265  classData.priorityCache,
266  [pRawComponent](const auto& pair)
267  {
268  return pair.second.pComponent == pRawComponent;
269  });
270 
271  if (it == classData.priorityCache.end())
272  {
273  bChanged = false;
274  return;
275  }
276 
277  it->second.statusFlags = status;
278  });
279 
280  return bChanged;
281 }
282 
283 template<std::derived_from<rtti_pure_base> base_component_t>
285 {
286  return m_RootClass.priorityCache.empty();
287 }
288 
289 template<std::derived_from<rtti_pure_base> base_component_t>
291 {
292  m_RootClass.derivedClasses.clear();
293  m_RootClass.components.clear();
294  m_RootClass.priorityCache.clear();
295 }
296 
297 } // namespace qx
component_t * add(std::unique_ptr< component_t > pComponent, priority ePriority=priority::normal, flags< status > statusFlags=status::default_value) noexcept
Add a component.
Definition: components.inl:28
std::unique_ptr< base_component_t > remove(const base_component_t *pRawComponent) noexcept
Remove the component from the container.
Definition: components.inl:48
bool set_priority(const base_component_t *pRawComponent, priority ePriority) noexcept
Set a priority of a given component.
Definition: components.inl:202
component_t * try_get() noexcept
Try to get a component of the given type with the highest priority.
Definition: components.inl:82
std::optional< priority > get_priority(const base_component_t *pRawComponent) const noexcept
Get a priority of a given component.
Definition: components.inl:185
void clear() noexcept
Clear the container, e.g. remove all the components.
Definition: components.inl:290
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:148
bool empty() const noexcept
Check if container doesn't have any components.
Definition: components.inl:284
std::optional< flags< status > > get_status(const base_component_t *pRawComponent) const noexcept
Get a status of a given component.
Definition: components.inl:236
component_t & get() noexcept
Get a component of the given type with the highest priority (no existence checks are performed)
Definition: components.inl:126
bool set_status(const base_component_t *pRawComponent, flags< status > status) noexcept
Set a status of a given component.
Definition: components.inl:254
priority
User may use the predefined values or the custom ones, for ex. "normal - 1", this type is supposed to...
Definition: priority.h:26