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
159 template<typename CompType>
160 void addNewComponent(const std::string& name, uint size)
161 {
162 std::vector<std::any>& v = mMap[name];
163 v.resize(size, CompType());
164 mNeedToInitialize[name] = false;
165 mCompType.emplace(name, typeid(CompType));
166 }
167
173 void deleteComponent(const std::string& name)
174 {
175 mMap.erase(name);
176 mNeedToInitialize.erase(name);
177 mCompType.erase(name);
178 }
179
185 void assertComponentExists(const std::string& compName) const
186 {
187 (void) (compName);
188 assert(mMap.find(compName) != mMap.end());
189 }
190
196 bool componentExists(const std::string& compName) const
197 {
198 return (mMap.find(compName) != mMap.end());
199 }
200
206 std::vector<std::string> allComponentNames() const
207 {
208 std::vector<std::string> names;
209 names.reserve(mMap.size());
210 for (const auto& p : mMap)
211 names.push_back(p.first);
212 return names;
213 }
214
224 template<typename CompType>
225 bool isComponentOfType(const std::string& compName) const
226 {
227 std::type_index t(typeid(CompType));
228
229 return t == mCompType.at(compName);
230 }
231
241 std::type_index componentType(const std::string& compName) const
242 {
243 return mCompType.at(compName);
244 }
245
254 template<typename CompType>
255 std::vector<std::string> allComponentNamesOfType() const
256 {
257 std::vector<std::string> names;
258 std::type_index t(typeid(CompType));
259 for (const auto& p : mCompType) {
260 if (p.second == t)
261 names.push_back(p.first);
262 }
263 return names;
264 }
265
278 template<typename CompType>
279 const std::vector<std::any>& componentVector(
280 const std::string& compName) const
281 {
282 checkComponentType<CompType>(compName);
283 std::vector<std::any>& v =
284 const_cast<std::vector<std::any>&>(mMap.at(compName));
285 // if the component needs to be initialized (e.g. we made a resize)
286 if (mNeedToInitialize.at(compName)) {
287 for (std::any& a : v) {
288 if (!a.has_value())
289 a = CompType();
290 }
291 mNeedToInitialize.at(compName) = false;
292 }
293 return v;
294 }
295
311 template<typename CompType>
312 std::vector<std::any>& componentVector(const std::string& compName)
313 {
314 checkComponentType<CompType>(compName);
315 std::vector<std::any>& v = mMap.at(compName);
316 // if the component needs to be initialized (e.g. we made a resize)
317 if (mNeedToInitialize.at(compName)) {
318 for (std::any& a : v) {
319 if (!a.has_value())
320 a = CompType();
321 }
322 mNeedToInitialize.at(compName) = false;
323 }
324 return v;
325 }
326
327 void importSameCustomComponentFrom(
328 uint thisPos,
329 uint otherPos,
330 const std::string& compName,
331 const CustomComponentsVectorMap<true>& other)
332 {
333 if (other.componentExists(compName) && componentExists(compName)) {
334 if (other.componentType(compName) == componentType(compName)) {
335 mMap.at(compName)[thisPos] = other.mMap.at(compName)[otherPos];
336 }
337 }
338 }
339
340 template<typename CompType>
341 void serializeCustomComponentsOfType(std::ostream& os) const
342 {
343 std::vector<std::string> compNames =
344 allComponentNamesOfType<CompType>();
345 vcl::serialize(os, compNames);
346 for (const auto& name : compNames) {
347 bool b = mNeedToInitialize.at(name);
348 vcl::serialize(os, b);
349 const std::vector<std::any>& v = componentVector<CompType>(name);
351 }
352 }
353
354 template<typename CompType>
355 void deserializeCustomComponentsOfType(std::istream& is)
356 {
357 std::vector<std::string> compNames;
358 vcl::deserialize(is, compNames);
359 for (const auto& name : compNames) {
360 bool b;
361 vcl::deserialize(is, b);
362 std::vector<std::any> v;
364 mMap[name] = v;
365 mNeedToInitialize[name] = b;
366 mCompType.emplace(name, typeid(CompType));
367 }
368 }
369
370private:
371 template<typename CompType>
372 void checkComponentType(const std::string& compName) const
373 {
374 std::type_index t(typeid(CompType));
375 if (t != mCompType.at(compName)) {
376 throw BadCustomComponentTypeException(
377 "Expected type " + std::string(mCompType.at(compName).name()) +
378 " for " + compName + ", but was " + std::string(t.name()) +
379 ".");
380 }
381 }
382};
383
384} // namespace vcl::mesh::detail
385
386#endif // VCL_MESH_CONTAINERS_DETAIL_CUSTOM_COMPONENTS_VECTOR_MAP_H
A class representing a box in N-dimensional space.
Definition box.h:46