Visual Computing Library  devel
Loading...
Searching...
No Matches
custom_components_vector_map.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_MESH_CONTAINERS_DETAIL_CUSTOM_COMPONENTS_VECTOR_MAP_H
24#define VCL_MESH_CONTAINERS_DETAIL_CUSTOM_COMPONENTS_VECTOR_MAP_H
25
26#include <vclib/mesh/exceptions.h>
27
28#include <vclib/base.h>
29
30#include <any>
31#include <string>
32#include <typeindex>
33#include <unordered_map>
34#include <vector>
35
36namespace vcl::mesh::detail {
37
64template<bool HasCustomComponent>
65class CustomComponentsVectorMap
66{
67};
68
69template<>
70class CustomComponentsVectorMap<true>
71{
72 // the actual map containing, for each name of a custom component, the
73 // vector of values (a value for each element(vertex/face...) of the mesh)
74 std::unordered_map<std::string, std::vector<std::any>> mMap;
75 // map that stores if some custom components need to be initialized.
76 // this happens when we resize the container of an element: we need to
77 // resize also the vectors of the custom components, but we cannot
78 // initialize them with the right type (because we don't know it in resize
79 // phase). The initialization will be made when the type is known (get of
80 // the custom component vector).
81 mutable std::unordered_map<std::string, bool> mNeedToInitialize;
82 // types used for each custom component
83 std::unordered_map<std::string, std::type_index> mCompType;
84
85public:
89 void clear()
90 {
91 mMap.clear();
92 mNeedToInitialize.clear();
93 mCompType.clear();
94 }
95
100 void reserve(uint size)
101 {
102 for (auto& p : mMap) {
103 p.second.reserve(size);
104 }
105 }
106
112 void resize(uint size)
113 {
114 for (auto& p : mMap) {
115 // At this call, we don't know statically the types of each custom
116 // component, therefore we cannot initialize them (std::any of each
117 // vector will be in an invalid state). Therefore, we mark all the
118 // resized custom components as 'needToInitialize'. Initiaization
119 // will be made just on the uninitialized values of the vectors at
120 // the first access of each custom component.
121 if (p.second.size() < size)
122 mNeedToInitialize.at(p.first) = true;
123 p.second.resize(size);
124 }
125 }
126
139 void compact(const std::vector<uint>& newIndices)
140 {
141 for (auto& p : mMap) {
142 compactVector(p.second, newIndices);
143 }
144 }
145
146 void swapCustomComponents(uint i, uint j)
147 {
148 for (auto& p : mMap) {
149 std::swap(p.second[i], p.second[j]);
150 }
151 }
152
166 template<typename CompType>
167 void addNewComponent(const std::string& name, uint size)
168 {
169 std::vector<std::any>& v = mMap[name];
170 v.resize(size, CompType());
171 mNeedToInitialize[name] = false;
172 mCompType.emplace(name, typeid(CompType));
173 }
174
180 void deleteComponent(const std::string& name)
181 {
182 mMap.erase(name);
183 mNeedToInitialize.erase(name);
184 mCompType.erase(name);
185 }
186
192 void assertComponentExists(const std::string& compName) const
193 {
194 (void) (compName);
195 assert(mMap.find(compName) != mMap.end());
196 }
197
203 bool componentExists(const std::string& compName) const
204 {
205 return (mMap.find(compName) != mMap.end());
206 }
207
213 std::vector<std::string> allComponentNames() const
214 {
215 std::vector<std::string> names;
216 names.reserve(mMap.size());
217 for (const auto& p : mMap)
218 names.push_back(p.first);
219 return names;
220 }
221
231 template<typename CompType>
232 bool isComponentOfType(const std::string& compName) const
233 {
234 std::type_index t(typeid(CompType));
235
236 return t == mCompType.at(compName);
237 }
238
248 std::type_index componentType(const std::string& compName) const
249 {
250 return mCompType.at(compName);
251 }
252
261 template<typename CompType>
262 std::vector<std::string> allComponentNamesOfType() const
263 {
264 std::vector<std::string> names;
265 std::type_index t(typeid(CompType));
266 for (const auto& p : mCompType) {
267 if (p.second == t)
268 names.push_back(p.first);
269 }
270 return names;
271 }
272
285 template<typename CompType>
286 const std::vector<std::any>& componentVector(
287 const std::string& compName) const
288 {
289 checkComponentType<CompType>(compName);
290 std::vector<std::any>& v =
291 const_cast<std::vector<std::any>&>(mMap.at(compName));
292 // if the component needs to be initialized (e.g. we made a resize)
293 if (mNeedToInitialize.at(compName)) {
294 for (std::any& a : v) {
295 if (!a.has_value())
296 a = CompType();
297 }
298 mNeedToInitialize.at(compName) = false;
299 }
300 return v;
301 }
302
318 template<typename CompType>
319 std::vector<std::any>& componentVector(const std::string& compName)
320 {
321 checkComponentType<CompType>(compName);
322 std::vector<std::any>& v = mMap.at(compName);
323 // if the component needs to be initialized (e.g. we made a resize)
324 if (mNeedToInitialize.at(compName)) {
325 for (std::any& a : v) {
326 if (!a.has_value())
327 a = CompType();
328 }
329 mNeedToInitialize.at(compName) = false;
330 }
331 return v;
332 }
333
334 void importSameCustomComponentFrom(
335 uint thisPos,
336 uint otherPos,
337 const std::string& compName,
338 const CustomComponentsVectorMap<true>& other)
339 {
340 if (other.componentExists(compName) && componentExists(compName)) {
341 if (other.componentType(compName) == componentType(compName)) {
342 mMap.at(compName)[thisPos] = other.mMap.at(compName)[otherPos];
343 }
344 }
345 }
346
347 template<typename CompType>
348 void serializeCustomComponentsOfType(std::ostream& os) const
349 {
350 std::vector<std::string> compNames =
351 allComponentNamesOfType<CompType>();
352 vcl::serialize(os, compNames);
353 for (const auto& name : compNames) {
354 bool b = mNeedToInitialize.at(name);
355 vcl::serialize(os, b);
356 const std::vector<std::any>& v = componentVector<CompType>(name);
358 }
359 }
360
361 template<typename CompType>
362 void deserializeCustomComponentsOfType(std::istream& is)
363 {
364 std::vector<std::string> compNames;
365 vcl::deserialize(is, compNames);
366 for (const auto& name : compNames) {
367 bool b;
368 vcl::deserialize(is, b);
369 std::vector<std::any> v;
371 mMap[name] = v;
372 mNeedToInitialize[name] = b;
373 mCompType.emplace(name, typeid(CompType));
374 }
375 }
376
377private:
378 template<typename CompType>
379 void checkComponentType(const std::string& compName) const
380 {
381 std::type_index t(typeid(CompType));
382 if (t != mCompType.at(compName)) {
383 throw BadCustomComponentTypeException(
384 "Expected type " + std::string(mCompType.at(compName).name()) +
385 " for " + compName + ", but was " + std::string(t.name()) +
386 ".");
387 }
388 }
389};
390
391} // namespace vcl::mesh::detail
392
393#endif // VCL_MESH_CONTAINERS_DETAIL_CUSTOM_COMPONENTS_VECTOR_MAP_H
A class representing a box in N-dimensional space.
Definition box.h:46