Visual Computing Library  devel
Loading...
Searching...
No Matches
pointer_container_component.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_COMPONENTS_BASE_POINTER_CONTAINER_COMPONENT_H
24#define VCL_MESH_COMPONENTS_BASE_POINTER_CONTAINER_COMPONENT_H
25
26#include "container_component.h"
27
28#include <vclib/mesh/iterators/components/index_from_pointer_iterator.h>
29
30#include <vclib/base.h>
31
32namespace vcl::comp {
33
35
77template<
78 typename DerivedComponent, // CRTP pattern, derived class
79 uint COMP_ID, // component id
80 typename Elem, // element type for which the pointers are stored
81 int N, // container size
82 typename ParentElemType, // parent element type
83 bool VERT, // true if component vertical
84 bool OPT, // true if component vertical and optional
85 bool TTVN> // true if container size tied to vertex number
86class PointerContainerComponent :
87 public ContainerComponent<
88 DerivedComponent,
89 COMP_ID,
90 Elem*,
91 N,
92 void,
93 ParentElemType,
94 VERT,
95 OPT,
96 TTVN,
97 Elem>
98{
99 using Base = ContainerComponent<
100 DerivedComponent,
101 COMP_ID,
102 Elem*,
103 N,
104 void,
105 ParentElemType,
106 VERT,
107 OPT,
108 TTVN,
109 Elem>;
110
111public:
120 template<typename T>
121 auto pointers() const requires std::is_same_v<T, Elem>
122 {
123 return View(
124 ConstIterator(Base::container().begin()),
125 ConstIterator(Base::container().end()));
126 }
127
128protected:
129 using Base::container;
130
131 using Iterator = Base::ConstIterator;
132 using ConstIterator = ConstPointerIterator<typename Base::ConstIterator>;
133 using ConstIndexIterator = IndexFromPointerIterator<ConstIterator>;
134
135 /*
136 * This member function is called when we need to update the pointers in
137 * this container after a reallocation (the pointer of the first element of
138 * the container of Elem is changed).
139 *
140 * This is necessary when, for example, the original container of Elements
141 * has been reallocated. When this happens, the all the Elements have been
142 * moved in another portion of memory, and all the pointers to that Elements
143 * must be updated. Since in this container are stored pointers to Elements,
144 * we need to update them.
145 *
146 * To update them, we need to know the oldBase (the pointer to the first
147 * Element of the reallocated Container before the reallocation). We can
148 * then compute, for each pointer, the difference w.r.t. the old address of
149 * the first element of the Container, and update the the pointer
150 * accordingly using the new base of the Container, which is computed
151 * trough the parent mesh.
152 *
153 * When we perform an append operation, we need to update the pointers
154 * taking into account also the offset: when we append a new element in a
155 * container, only its pointers must be updated. To update from the old
156 * pointers to the new ones, we need to know how many elements were in the
157 * container BEFORE the append operation, and this becomes the offset to
158 * be applied to the pointers of the newly appended elements.
159 */
160 void updateReferences(const Elem* oldBase, std::size_t offset = 0)
161 {
162 const Elem* newBase = baseOfElemContainer();
163
164 auto& baseContainer = Base::container();
165
166 for (uint j = 0; j < baseContainer.size();
167 ++j) { // for each pointer in this container
168 if (baseContainer.at(j) != nullptr) {
169 size_t diff =
170 baseContainer.at(j) - oldBase; // offset w.r.t. the old base
171
172 // update the pointer using newBase
173 baseContainer.at(j) = (Elem*) newBase + diff + offset;
174 }
175 }
176 }
177
178 /*
179 * This member function is called when we need to update the pointers in
180 * this containers, usually after a compaction of the container (but not
181 * always).
182 *
183 * In this case, the address of the first element in the container is not
184 * changed, but may change the position of each element inside the
185 * container. The function takes the base pointer of the first element of
186 * the container, and a vector that stores, for each old element position,
187 * the new position in the container (UINT_NULL if the element has been
188 * removed and must be left unreferenced).
189 */
190 void updateReferences(const std::vector<uint>& newIndices)
191 {
192 const Elem* base = baseOfElemContainer();
193
194 auto& baseContainer = Base::container();
195
196 for (uint j = 0; j < baseContainer.size(); ++j) {
197 if (baseContainer.at(j) != nullptr) {
198 size_t diff = baseContainer.at(j) - base;
199 if (newIndices[diff] == UINT_NULL) { // element has been removed
200 baseContainer.at(j) = nullptr;
201 }
202 else { // the new pointer will be base + newIndices[diff]
203 baseContainer.at(j) = (Elem*) base + newIndices[diff];
204 }
205 }
206 }
207 }
208
209private:
210 const Elem* baseOfElemContainer() const
211 {
212 return &(Base::parentElement()
213 ->parentMesh()
214 ->template element<Elem::ELEMENT_ID>(0));
215 }
216};
217
219
220} // namespace vcl::comp
221
222#endif // VCL_MESH_COMPONENTS_BASE_POINTER_CONTAINER_COMPONENT_H