GCC Code Coverage Report


Directory: ./
File: basic/attributes.cpp
Date: 2026-09-27 03:22:43
Exec Total Coverage
Lines: 182 393 46.3%
Functions: 32 46 69.6%
Branches: 91 504 18.1%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #include <geogram/basic/attributes.h>
41 #include <geogram/basic/permutation.h>
42 #include <geogram/basic/string.h>
43 #include <geogram/basic/geometry.h>
44 #include <algorithm>
45
46 namespace GEO {
47
48 3776 void AttributeStoreObserver::register_me(AttributeStore* store) {
49 3776 store->register_observer(this);
50 3776 }
51
52 3776 void AttributeStoreObserver::unregister_me(AttributeStore* store) {
53 3776 store->unregister_observer(this);
54 3776 }
55
56 /******************************************************************/
57
58 5570 AttributeStoreCreator::~AttributeStoreCreator() {
59 5570 }
60
61 /******************************************************************/
62
63 std::map<std::string, AttributeStoreCreator_var>
64 AttributeStore::type_name_to_creator_;
65
66 std::map<std::string, std::string>
67 AttributeStore::typeid_name_to_type_name_;
68
69 std::map<std::string, std::string>
70 AttributeStore::type_name_to_typeid_name_;
71
72 2068 AttributeStore::AttributeStore(size_t elemsize, index_t dim) :
73 2068 element_size_(elemsize),
74 2068 dimension_(dim),
75 2068 cached_base_addr_(nullptr),
76 2068 cached_size_(0),
77 2068 cached_capacity_(0),
78 2068 lock_(GEOGRAM_SPINLOCK_INIT)
79 {
80 2068 }
81
82 2036515 void AttributeStore::notify(
83 Memory::pointer base_addr, index_t size, index_t dim
84 ) {
85 2036515 Process::acquire_spinlock(lock_);
86 2036515 if(
87
2/2
✓ Branch 0 taken 6647 times.
✓ Branch 1 taken 2029868 times.
2036515 size != cached_size_ ||
88
2/2
✓ Branch 0 taken 3664 times.
✓ Branch 1 taken 2983 times.
6647 base_addr != cached_base_addr_ ||
89
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 3435 times.
3664 dim != dimension_
90 ) {
91 2033080 cached_base_addr_ = base_addr;
92 2033080 cached_size_ = size;
93 2033080 dimension_ = dim;
94
2/2
✓ Branch 5 taken 1942431 times.
✓ Branch 6 taken 2033080 times.
3975511 for(auto cur : observers_) {
95 1942431 cur->notify(cached_base_addr_, cached_size_, dim);
96 }
97 }
98 2036515 Process::release_spinlock(lock_);
99 2036515 }
100
101 4136 AttributeStore::~AttributeStore() {
102 // Disconnect all the attributes, for the special case where
103 // the AttributeStore is destroyed before the Attributes, can
104 // occur for instance when using Lua scripting with Attribute wrapper
105 // objects.
106
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 2068 times.
4136 for(auto cur : observers_) {
107 ✗ cur->disconnect();
108 }
109 4136 }
110
111 3776 void AttributeStore::register_observer(AttributeStoreObserver* observer) {
112 3776 Process::acquire_spinlock(lock_);
113
2/8
✓ Branch 2 taken 3776 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3776 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
3776 geo_assert(observers_.find(observer) == observers_.end());
114 3776 observers_.insert(observer);
115 3776 observer->notify(cached_base_addr_, cached_size_, dimension_);
116 3776 Process::release_spinlock(lock_);
117 3776 }
118
119 3776 void AttributeStore::unregister_observer(AttributeStoreObserver* observer) {
120 3776 Process::acquire_spinlock(lock_);
121
1/2
✓ Branch 1 taken 3776 times.
✗ Branch 2 not taken.
3776 auto it = observers_.find(observer);
122
1/6
✗ Branch 2 not taken.
✓ Branch 3 taken 3776 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
3776 geo_assert(it != observers_.end());
123
1/2
✓ Branch 1 taken 3776 times.
✗ Branch 2 not taken.
3776 observers_.erase(it);
124 3776 Process::release_spinlock(lock_);
125 3776 }
126
127 ✗ void AttributeStore::apply_permutation_with_lifecycle(
128 const vector<index_t>& permutation_in
129 ) {
130 ✗ Memory::pointer pdata = cached_base_addr_;
131 ✗ vector<index_t>& perm = const_cast<vector<index_t>&>(permutation_in);
132 ✗ geo_debug_assert(Permutation::is_valid(perm));
133 ✗ size_t item_size = element_size_ * dimension_;
134 ✗ Memory::pointer temp = static_cast<Memory::pointer>(alloca(item_size));
135 ✗ for(index_t k = 0; k < perm.size(); ++k) {
136 ✗ if(Permutation::is_marked(perm, k)) {
137 ✗ continue;
138 }
139 ✗ index_t i = k;
140 ✗ index_t j = perm[k];
141
142 ✗ lifecycle_->copy_construct_array(
143 ✗ temp, pdata + i * item_size, dimension_
144 );
145
146 ✗ Permutation::mark(perm, k);
147 ✗ while(j != k) {
148 ✗ lifecycle_->assign_array(
149 ✗ pdata + i * item_size, pdata + j * item_size, dimension_
150 );
151 ✗ index_t nj = perm[j];
152 ✗ Permutation::mark(perm, j);
153 ✗ i = j;
154 ✗ j = nj;
155 }
156 ✗ lifecycle_->assign_array(pdata + i * item_size, temp, dimension_);
157 ✗ lifecycle_->destroy_array(temp, dimension_);
158 }
159 ✗ for(index_t k = 0; k < perm.size(); ++k) {
160 ✗ Permutation::unmark(perm, k);
161 }
162 ✗ }
163
164 17 void AttributeStore::apply_permutation(const vector<index_t>& permutation) {
165
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
17 geo_debug_assert(permutation.size() <= cached_size_);
166
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 if(lifecycle_.is_null()) {
167 17 Permutation::apply(
168 17 cached_base_addr_, permutation, element_size_ * dimension_
169 );
170 } else {
171 ✗ apply_permutation_with_lifecycle(permutation);
172 }
173 17 }
174
175 1391 void AttributeStore::compress(const vector<index_t>& old2new) {
176
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1391 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1391 geo_debug_assert(old2new.size() <= cached_size_);
177 1391 size_t item_size = size_t(element_size_) * dimension_;
178
2/2
✓ Branch 1 taken 7877240 times.
✓ Branch 2 taken 1391 times.
7878631 for(index_t i=0; i<old2new.size(); ++i) {
179 7877240 index_t j = old2new[i];
180
4/4
✓ Branch 0 taken 3747925 times.
✓ Branch 1 taken 4129315 times.
✓ Branch 2 taken 799097 times.
✓ Branch 3 taken 2948828 times.
7877240 if(j == NO_INDEX || j == i) {
181 4928412 continue;
182 }
183
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2948828 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2948828 geo_debug_assert(j <= i);
184
1/2
✓ Branch 1 taken 2948828 times.
✗ Branch 2 not taken.
2948828 if(lifecycle_.is_null()) {
185 2948828 Memory::copy(
186 2948828 cached_base_addr_+size_t(j)*item_size,
187 2948828 cached_base_addr_+size_t(i)*item_size,
188 item_size
189 );
190 } else {
191 ✗ lifecycle_->assign_array(
192 ✗ cached_base_addr_+size_t(j)*item_size,
193 ✗ cached_base_addr_+size_t(i)*item_size,
194 dimension_
195 );
196 }
197 }
198 1391 }
199
200 18 void AttributeStore::zero() {
201
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 if(lifecycle_.is_null()) {
202 18 Memory::clear(
203 18 cached_base_addr_, element_size_ * dimension_ * cached_size_
204 );
205 } else {
206 ✗ index_t nb_elements = cached_size_ * dimension_;
207 ✗ for(index_t i=0; i<nb_elements; ++i) {
208 ✗ lifecycle_->reset(cached_base_addr_ + i * element_size_);
209 }
210 }
211 18 }
212
213 402612 void AttributeStore::swap_items(index_t i, index_t j) {
214
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 402612 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
402612 geo_debug_assert(i < cached_size_);
215
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 402612 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
402612 geo_debug_assert(j < cached_size_);
216 402612 size_t item_size = element_size_ * dimension_;
217
1/2
✓ Branch 1 taken 402612 times.
✗ Branch 2 not taken.
402612 if(lifecycle_.is_null()) {
218 402612 void* temp = alloca(item_size);
219 402612 Memory::copy(
220 temp,
221 402612 cached_base_addr_+i*item_size,
222 item_size
223 );
224 402612 Memory::copy(
225 402612 cached_base_addr_+i*item_size,
226 402612 cached_base_addr_+j*item_size,
227 item_size
228 );
229 402612 Memory::copy(
230 402612 cached_base_addr_+j*item_size,
231 temp,
232 item_size
233 );
234 } else {
235 ✗ for(index_t c=0; c<dimension_; ++c) {
236 ✗ lifecycle_->swap(
237 ✗ cached_base_addr_+i*item_size+c*element_size(),
238 ✗ cached_base_addr_+j*item_size+c*element_size()
239 );
240 }
241 }
242 402612 }
243
244 ✗ void AttributeStore::scale_item(index_t to, double s) {
245 ✗ geo_argused(to);
246 ✗ geo_argused(s);
247 ✗ }
248
249 ✗ void AttributeStore::madd_item(index_t to, double s, index_t from) {
250 ✗ geo_argused(to);
251 ✗ geo_argused(s);
252 ✗ geo_argused(from);
253 ✗ }
254
255 2785 void AttributeStore::register_attribute_creator(
256 AttributeStoreCreator* creator,
257 const std::string& element_type_name,
258 const std::string& element_typeid_name
259 ) {
260
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2785 times.
2785 if(element_type_name_is_known(element_type_name)) {
261 ✗ Logger::warn("Attributes") << element_type_name
262 ✗ << " already registered"
263 ✗ << std::endl;
264 ✗ if(element_typeid_name_is_known(element_typeid_name)) {
265 bool already_registered_attribute_has_same_type = (
266 ✗ type_name_to_typeid_name_[element_type_name] ==
267 element_typeid_name
268 );
269 ✗ geo_assert(already_registered_attribute_has_same_type);
270 }
271 }
272 2785 type_name_to_creator_[element_type_name] = creator;
273 2785 typeid_name_to_type_name_[element_typeid_name] = element_type_name;
274 2785 type_name_to_typeid_name_[element_type_name] = element_typeid_name;
275 2785 }
276
277 /*************************************************************************/
278
279 5782 AttributesManager::AttributesManager() : size_(0), capacity_(0) {
280 5782 }
281
282 5782 AttributesManager::~AttributesManager() {
283 5782 clear(false,false);
284 5782 }
285
286 6642956 void AttributesManager::resize(index_t new_size) {
287
2/2
✓ Branch 0 taken 305 times.
✓ Branch 1 taken 6642651 times.
6642956 if(new_size == size_) {
288 305 return;
289 }
290
2/2
✓ Branch 5 taken 2028697 times.
✓ Branch 6 taken 6642651 times.
8671348 for(auto& cur : attributes_) {
291
1/2
✓ Branch 1 taken 2028697 times.
✗ Branch 2 not taken.
2028697 cur.second->resize(new_size);
292 }
293 6642651 size_ = new_size;
294 }
295
296 8547 void AttributesManager::reserve(index_t new_capacity) {
297
2/2
✓ Branch 0 taken 480 times.
✓ Branch 1 taken 8067 times.
8547 if(new_capacity <= capacity_) {
298 480 return;
299 }
300
2/2
✓ Branch 5 taken 3494 times.
✓ Branch 6 taken 8067 times.
11561 for(auto& cur : attributes_) {
301
1/2
✓ Branch 1 taken 3494 times.
✗ Branch 2 not taken.
3494 cur.second->reserve(new_capacity);
302 }
303 8067 capacity_ = new_capacity;
304 }
305
306 32 void AttributesManager::apply_permutation(
307 const vector<index_t>& permutation
308 ) {
309
2/2
✓ Branch 5 taken 17 times.
✓ Branch 6 taken 32 times.
49 for(auto& cur : attributes_) {
310
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 cur.second->apply_permutation(permutation);
311 }
312 32 }
313
314 498 void AttributesManager::compress(
315 const vector<index_t>& old2new
316 ) {
317
2/2
✓ Branch 5 taken 1391 times.
✓ Branch 6 taken 498 times.
1889 for(auto& cur : attributes_) {
318
1/2
✓ Branch 1 taken 1391 times.
✗ Branch 2 not taken.
1391 cur.second->compress(old2new);
319 }
320 498 }
321
322
323 2068 void AttributesManager::bind_attribute_store(
324 const std::string& name, AttributeStore* as
325 ) {
326
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2068 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
2068 geo_assert(find_attribute_store(name) == nullptr);
327 2068 attributes_[name] = as;
328 2068 as->reserve(capacity_);
329 2068 as->resize(size_);
330 2068 }
331
332 752 void AttributesManager::list_attribute_names(
333 vector<std::string>& names
334 ) const {
335 752 names.clear();
336
2/2
✓ Branch 5 taken 674 times.
✓ Branch 6 taken 752 times.
1426 for(auto& cur : attributes_) {
337
1/2
✓ Branch 1 taken 674 times.
✗ Branch 2 not taken.
674 names.push_back(cur.first);
338 }
339 752 }
340
341 9083 AttributeStore* AttributesManager::find_attribute_store(
342 const std::string& name
343 ) {
344
1/2
✓ Branch 1 taken 9083 times.
✗ Branch 2 not taken.
9083 auto it = attributes_.find(name);
345
2/2
✓ Branch 2 taken 6298 times.
✓ Branch 3 taken 2785 times.
9083 if(it == attributes_.end()) {
346 6298 return nullptr;
347 }
348 2785 return it->second;
349 }
350
351 48 const AttributeStore* AttributesManager::find_attribute_store(
352 const std::string& name
353 ) const {
354
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 auto it = attributes_.find(name);
355
2/2
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 1 times.
48 if(it == attributes_.end()) {
356 47 return nullptr;
357 }
358 1 return it->second;
359 }
360
361 ✗ bool AttributesManager::get_doubles(
362 const std::string& name, vector<double>& out, index_t& dim
363 ) const {
364 ✗ const AttributeStore* store = find_attribute_store(name);
365 ✗ if(
366 ✗ store == nullptr ||
367 ✗ !store->elements_type_matches(typeid(double).name())
368 ) {
369 ✗ return false;
370 }
371 ✗ dim = store->dimension();
372 ✗ const double* p = static_cast<const double*>(store->data());
373 ✗ out.assign(p, p + store->size() * dim);
374 ✗ return true;
375 }
376
377 ✗ bool AttributesManager::set_doubles(
378 const std::string& name, const vector<double>& in, index_t dim
379 ) {
380 ✗ AttributeStore* store = find_attribute_store(name);
381 ✗ if(store == nullptr) {
382 ✗ if(in.size() != size_t(size()) * dim) {
383 ✗ return false; // do not create on size mismatch
384 }
385 ✗ store = new TypedAttributeStore<double>(dim);
386 ✗ bind_attribute_store(name, store); // sizes it to size_, takes ownership
387 }
388 ✗ if(
389 ✗ !store->elements_type_matches(typeid(double).name()) ||
390 ✗ store->dimension() != dim ||
391 ✗ in.size() != size_t(store->size()) * dim
392 ) {
393 ✗ return false;
394 }
395 ✗ Memory::copy(store->data(), in.data(), in.size() * sizeof(double));
396 ✗ return true;
397 }
398
399
400 ✗ void AttributesManager::delete_attribute_store(const std::string& name) {
401 ✗ auto it = attributes_.find(name);
402 ✗ geo_assert(it != attributes_.end());
403 ✗ delete it->second;
404 ✗ attributes_.erase(it);
405 ✗ }
406
407 234 void AttributesManager::delete_attribute_store(AttributeStore* as) {
408
1/2
✓ Branch 4 taken 435 times.
✗ Branch 5 not taken.
435 for(auto it=attributes_.begin(); it != attributes_.end(); ++it) {
409
2/2
✓ Branch 1 taken 234 times.
✓ Branch 2 taken 201 times.
435 if(it->second == as) {
410
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 delete as;
411
1/2
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
234 attributes_.erase(it);
412 234 return;
413 }
414 }
415 ✗ geo_assert_not_reached;
416 }
417
418
419 9392 void AttributesManager::clear(bool keep_attributes, bool keep_memory) {
420
2/2
✓ Branch 0 taken 3190 times.
✓ Branch 1 taken 6202 times.
9392 if(keep_attributes) {
421
2/2
✓ Branch 5 taken 542 times.
✓ Branch 6 taken 3190 times.
3732 for(auto& cur : attributes_) {
422
1/2
✓ Branch 1 taken 542 times.
✗ Branch 2 not taken.
542 cur.second->clear(keep_memory);
423 }
424 } else {
425
2/2
✓ Branch 5 taken 1834 times.
✓ Branch 6 taken 6202 times.
8036 for(auto& cur : attributes_) {
426
1/2
✓ Branch 0 taken 1834 times.
✗ Branch 1 not taken.
1834 delete cur.second;
427 }
428 6202 attributes_.clear();
429 }
430 9392 size_ = 0;
431 9392 }
432
433 78 void AttributesManager::zero() {
434
2/2
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 78 times.
96 for(auto& cur : attributes_) {
435
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 cur.second->zero();
436 }
437 78 }
438
439 420 void AttributesManager::copy(const AttributesManager& rhs) {
440 420 clear(false, false);
441 420 reserve(rhs.capacity());
442 420 resize(rhs.size());
443
2/2
✓ Branch 5 taken 295 times.
✓ Branch 6 taken 420 times.
715 for(auto& cur : rhs.attributes_) {
444
2/4
✓ Branch 1 taken 295 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 295 times.
✗ Branch 5 not taken.
295 bind_attribute_store(cur.first, cur.second->clone());
445 }
446 420 }
447
448 532923 void AttributesManager::copy_item(index_t to, index_t from) {
449
2/2
✓ Branch 5 taken 778815 times.
✓ Branch 6 taken 532923 times.
1311738 for(auto& cur : attributes_) {
450
1/2
✓ Branch 1 taken 778815 times.
✗ Branch 2 not taken.
778815 cur.second->copy_item(to,from);
451 }
452 532923 }
453
454 1704945 void AttributesManager::swap_items(index_t i, index_t j) {
455
2/2
✓ Branch 5 taken 402612 times.
✓ Branch 6 taken 1704945 times.
2107557 for(auto& cur : attributes_) {
456
1/2
✓ Branch 1 taken 402612 times.
✗ Branch 2 not taken.
402612 cur.second->swap_items(i,j);
457 }
458 1704945 }
459
460 209840 void AttributesManager::zero_item(index_t i) {
461
2/2
✓ Branch 5 taken 291740 times.
✓ Branch 6 taken 209840 times.
501580 for(auto& cur : attributes_) {
462
1/2
✓ Branch 1 taken 291740 times.
✗ Branch 2 not taken.
291740 cur.second->zero_item(i);
463 }
464 209840 }
465
466 5120 void AttributesManager::scale_item(index_t i, double s) {
467
2/2
✓ Branch 5 taken 5120 times.
✓ Branch 6 taken 5120 times.
10240 for(auto& cur : attributes_) {
468
1/2
✓ Branch 1 taken 5120 times.
✗ Branch 2 not taken.
5120 cur.second->scale_item(i,s);
469 }
470 5120 }
471
472 429900 void AttributesManager::madd_item(index_t i, double s, index_t j) {
473
2/2
✓ Branch 5 taken 593700 times.
✓ Branch 6 taken 429900 times.
1023600 for(auto& cur : attributes_) {
474
1/2
✓ Branch 1 taken 593700 times.
✗ Branch 2 not taken.
593700 cur.second->madd_item(i,s,j);
475 }
476 429900 }
477
478 ✗ bool AttributesManager::copy_attribute(
479 const std::string& name, const std::string& new_name
480 ) {
481 ✗ const auto old_itr = attributes_.find(name);
482 ✗ if( old_itr == attributes_.end() ) {
483 ✗ return false;
484 }
485 ✗ const AttributeStore* store = old_itr->second;
486
487 ✗ const auto new_itr = attributes_.find(new_name);
488 ✗ if( new_itr != attributes_.end() ) {
489 ✗ AttributeStore* new_store = new_itr->second;
490 ✗ if( !store->elements_type_matches(
491 ✗ new_store->element_typeid_name())
492 ) {
493 ✗ return false;
494 }
495 ✗ if(
496 ✗ (store->size() != new_store->size()) &&
497 ✗ (store->dimension() != new_store->dimension()) &&
498 ✗ (store->element_size() != new_store->element_size())
499 ) {
500 ✗ return false;
501 }
502
503 ✗ geo_debug_assert(store->lifecycle() == new_store->lifecycle());
504 ✗ if(store->lifecycle() == nullptr) {
505 ✗ memcpy(
506 new_store->data(), store->data(),
507 ✗ store->size() * store->dimension() * store->element_size()
508 );
509 } else {
510 ✗ store->lifecycle()->assign_array(
511 ✗ Memory::pointer(new_store->data()),
512 ✗ Memory::const_pointer(store->data()),
513 ✗ store->size() * store->dimension()
514 );
515 }
516 } else {
517 ✗ AttributeStore* new_store = store->clone();
518 ✗ attributes_[new_name] = new_store;
519 }
520
521 ✗ return true;
522 }
523
524 ✗ bool AttributesManager::rename_attribute(
525 const std::string& old_name, const std::string& new_name
526 ) {
527 ✗ const auto old_itr = attributes_.find(old_name);
528 ✗ if( old_itr == attributes_.end() ) {
529 ✗ return false;
530 }
531 ✗ const auto new_itr = attributes_.find(new_name);
532 ✗ if( new_itr != attributes_.end() ) {
533 ✗ return false;
534 }
535 ✗ attributes_[new_name] = old_itr->second;
536 ✗ attributes_.erase(old_itr);
537 ✗ return true;
538 }
539
540
541 /************************************************************************/
542
543 ✗ index_t ScalarAttributeAdapterBase::nb_scalar_elements_per_item(
544 const AttributeStore* store
545 ) {
546 ✗ ElementType et = element_type(store);
547 ✗ if(et == ET_NONE) {
548 ✗ return 0;
549 }
550 ✗ index_t result = store->dimension();
551 ✗ if(et == ET_VEC2) {
552 ✗ result *= 2;
553 ✗ } else if(et == ET_VEC3) {
554 ✗ result *= 3;
555 }
556 ✗ return result;
557 }
558
559 ✗ std::string ScalarAttributeAdapterBase::attribute_base_name(
560 const std::string& name
561 ) {
562 ✗ size_t pos = name.find('[');
563 ✗ if(pos == std::string::npos) {
564 ✗ return name;
565 }
566 ✗ return name.substr(0,pos);
567 }
568
569 ✗ index_t ScalarAttributeAdapterBase::attribute_element_index(
570 const std::string& name
571 ) {
572 ✗ index_t result = 0;
573 ✗ size_t pos = name.find('[');
574 ✗ if(pos != std::string::npos) {
575 try {
576 ✗ if(pos+2 > name.length()) {
577 ✗ result = NO_INDEX;
578 } else {
579 ✗ result = String::to_uint(
580 ✗ name.substr(pos+1, name.length()-pos-2)
581 );
582 }
583 ✗ } catch(...) {
584 ✗ result = NO_INDEX;
585 ✗ }
586 }
587 ✗ return result;
588 }
589
590 ScalarAttributeAdapterBase::ElementType
591 ✗ ScalarAttributeAdapterBase::element_type(const AttributeStore* store) {
592 ✗ if(store->element_typeid_name() == typeid(Numeric::uint8).name()) {
593 ✗ return ET_UINT8;
594 }
595
596 ✗ if(
597 ✗ store->element_typeid_name() == typeid(char).name() ||
598 ✗ store->element_typeid_name() == typeid(Numeric::int8).name()
599 ) {
600 ✗ return ET_INT8;
601 }
602
603 ✗ if(
604 ✗ store->element_typeid_name() == typeid(Numeric::uint32).name() ||
605 ✗ store->element_typeid_name() == typeid(index_t).name() ||
606 ✗ store->element_typeid_name() == typeid(unsigned int).name()
607 ) {
608 ✗ return ET_UINT32;
609 }
610
611 ✗ if(
612 ✗ store->element_typeid_name() == typeid(Numeric::int32).name() ||
613 ✗ store->element_typeid_name() == typeid(int).name()
614 ) {
615 ✗ return ET_INT32;
616 }
617
618 ✗ if(
619 ✗ store->element_typeid_name() == typeid(Numeric::float32).name() ||
620 ✗ store->element_typeid_name() == typeid(float).name()
621 ) {
622 ✗ return ET_FLOAT32;
623 }
624
625 ✗ if(
626 ✗ store->element_typeid_name() == typeid(Numeric::float64).name() ||
627 ✗ store->element_typeid_name() == typeid(double).name()
628 ) {
629 ✗ return ET_FLOAT64;
630 }
631
632 ✗ if(store->element_typeid_name() == typeid(vec2).name()) {
633 ✗ return ET_VEC2;
634 }
635
636 ✗ if(store->element_typeid_name() == typeid(vec3).name()) {
637 ✗ return ET_VEC3;
638 }
639
640 ✗ return ET_NONE;
641 }
642
643 ✗ void ScalarAttributeAdapterBase::bind_if_is_defined(
644 const AttributesManager& manager, const std::string& name
645 ) {
646 ✗ geo_assert(!is_bound());
647 ✗ manager_ = &manager;
648 ✗ element_index_ = attribute_element_index(name);
649 ✗ store_ = manager_->find_attribute_store(attribute_base_name(name));
650
651 ✗ if(store_ == nullptr || element_index_ == NO_INDEX) {
652 ✗ store_ = nullptr;
653 ✗ element_index_ = NO_INDEX;
654 ✗ return;
655 }
656
657 ✗ element_type_ = element_type(store_);
658
659 ✗ if(element_type_ == ET_NONE) {
660 ✗ store_ = nullptr;
661 ✗ element_index_ = NO_INDEX;
662 ✗ return;
663 }
664
665 // Test element_index_ validity: should be smaller than
666 // store's dimension (or 2*store dimension if a vec2,
667 // or 3*store's dimension if a vec3)
668 ✗ if(element_index_ >= nb_scalar_elements_per_item(store_)) {
669 ✗ store_ = nullptr;
670 ✗ element_index_ = NO_INDEX;
671 ✗ element_type_ = ET_NONE;
672 ✗ return;
673 }
674
675 ✗ register_me(const_cast<AttributeStore*>(store_));
676 }
677
678 ✗ bool ScalarAttributeAdapterBase::is_defined(
679 const AttributesManager& manager, const std::string& name
680 ) {
681 ✗ std::string attribute_name = attribute_base_name(name);
682 ✗ const AttributeStore* store = manager.find_attribute_store(
683 attribute_name
684 );
685
686 ✗ if(store == nullptr) {
687 ✗ return false;
688 }
689
690 ✗ index_t element_index = attribute_element_index(name);
691 ✗ if(element_index == NO_INDEX) {
692 ✗ return false;
693 }
694
695 ✗ if(element_index >= nb_scalar_elements_per_item(store)) {
696 ✗ return false;
697 }
698
699 ✗ if(element_type(store) == ET_NONE) {
700 ✗ return false;
701 }
702
703 ✗ return true;
704 ✗ }
705
706 /************************************************************************/
707
708 }
709