GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/attributes.cpp
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 181 393 46.1%
Functions: 32 46 69.6%
Branches: 90 504 17.9%

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 3627 void AttributeStoreObserver::register_me(AttributeStore* store) {
49 3627 store->register_observer(this);
50 3627 }
51
52 3627 void AttributeStoreObserver::unregister_me(AttributeStore* store) {
53 3627 store->unregister_observer(this);
54 3627 }
55
56 /******************************************************************/
57
58 5526 AttributeStoreCreator::~AttributeStoreCreator() {
59 5526 }
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 2078 AttributeStore::AttributeStore(size_t elemsize, index_t dim) :
73 2078 element_size_(elemsize),
74 2078 dimension_(dim),
75 2078 cached_base_addr_(nullptr),
76 2078 cached_size_(0),
77 2078 cached_capacity_(0),
78 2078 lock_(GEOGRAM_SPINLOCK_INIT)
79 {
80 2078 }
81
82 2116625 void AttributeStore::notify(
83 Memory::pointer base_addr, index_t size, index_t dim
84 ) {
85 2116625 Process::acquire_spinlock(lock_);
86 2116625 if(
87
2/2
✓ Branch 0 taken 6695 times.
✓ Branch 1 taken 2109930 times.
2116625 size != cached_size_ ||
88
2/2
✓ Branch 0 taken 3669 times.
✓ Branch 1 taken 3026 times.
6695 base_addr != cached_base_addr_ ||
89
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 3440 times.
3669 dim != dimension_
90 ) {
91 2113185 cached_base_addr_ = base_addr;
92 2113185 cached_size_ = size;
93 2113185 dimension_ = dim;
94
2/2
✓ Branch 5 taken 1970725 times.
✓ Branch 6 taken 2113185 times.
4083910 for(auto cur : observers_) {
95 1970725 cur->notify(cached_base_addr_, cached_size_, dim);
96 }
97 }
98 2116625 Process::release_spinlock(lock_);
99 2116625 }
100
101 4156 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 2078 times.
4156 for(auto cur : observers_) {
107 cur->disconnect();
108 }
109 4156 }
110
111 3627 void AttributeStore::register_observer(AttributeStoreObserver* observer) {
112 3627 Process::acquire_spinlock(lock_);
113
2/8
✓ Branch 2 taken 3627 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3627 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
3627 geo_assert(observers_.find(observer) == observers_.end());
114 3627 observers_.insert(observer);
115 3627 observer->notify(cached_base_addr_, cached_size_, dimension_);
116 3627 Process::release_spinlock(lock_);
117 3627 }
118
119 3627 void AttributeStore::unregister_observer(AttributeStoreObserver* observer) {
120 3627 Process::acquire_spinlock(lock_);
121
1/2
✓ Branch 1 taken 3627 times.
✗ Branch 2 not taken.
3627 auto it = observers_.find(observer);
122
1/6
✗ Branch 2 not taken.
✓ Branch 3 taken 3627 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
3627 geo_assert(it != observers_.end());
123
1/2
✓ Branch 1 taken 3627 times.
✗ Branch 2 not taken.
3627 observers_.erase(it);
124 3627 Process::release_spinlock(lock_);
125 3627 }
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 14 void AttributeStore::apply_permutation(const vector<index_t>& permutation) {
165
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
14 geo_debug_assert(permutation.size() <= cached_size_);
166
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 if(lifecycle_.is_null()) {
167 14 Permutation::apply(
168 14 cached_base_addr_, permutation, element_size_ * dimension_
169 );
170 } else {
171 apply_permutation_with_lifecycle(permutation);
172 }
173 14 }
174
175 1398 void AttributeStore::compress(const vector<index_t>& old2new) {
176
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1398 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1398 geo_debug_assert(old2new.size() <= cached_size_);
177 1398 size_t item_size = size_t(element_size_) * dimension_;
178
2/2
✓ Branch 1 taken 7981104 times.
✓ Branch 2 taken 1398 times.
7982502 for(index_t i=0; i<old2new.size(); ++i) {
179 7981104 index_t j = old2new[i];
180
4/4
✓ Branch 0 taken 3799855 times.
✓ Branch 1 taken 4181249 times.
✓ Branch 2 taken 850927 times.
✓ Branch 3 taken 2948928 times.
7981104 if(j == NO_INDEX || j == i) {
181 5032176 continue;
182 }
183
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2948928 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2948928 geo_debug_assert(j <= i);
184
1/2
✓ Branch 1 taken 2948928 times.
✗ Branch 2 not taken.
2948928 if(lifecycle_.is_null()) {
185 2948928 Memory::copy(
186 2948928 cached_base_addr_+size_t(j)*item_size,
187 2948928 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 1398 }
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 429538 void AttributeStore::swap_items(index_t i, index_t j) {
214
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 429538 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
429538 geo_debug_assert(i < cached_size_);
215
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 429538 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
429538 geo_debug_assert(j < cached_size_);
216 429538 size_t item_size = element_size_ * dimension_;
217
1/2
✓ Branch 1 taken 429538 times.
✗ Branch 2 not taken.
429538 if(lifecycle_.is_null()) {
218 429538 void* temp = alloca(item_size);
219 429538 Memory::copy(
220 temp,
221 429538 cached_base_addr_+i*item_size,
222 item_size
223 );
224 429538 Memory::copy(
225 429538 cached_base_addr_+i*item_size,
226 429538 cached_base_addr_+j*item_size,
227 item_size
228 );
229 429538 Memory::copy(
230 429538 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 429538 }
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 2763 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 2763 times.
2763 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 2763 type_name_to_creator_[element_type_name] = creator;
273 2763 typeid_name_to_type_name_[element_typeid_name] = element_type_name;
274 2763 type_name_to_typeid_name_[element_type_name] = element_typeid_name;
275 2763 }
276
277 /*************************************************************************/
278
279 5761 AttributesManager::AttributesManager() : size_(0), capacity_(0) {
280 5761 }
281
282 5761 AttributesManager::~AttributesManager() {
283 5761 clear(false,false);
284 5761 }
285
286 6192668 void AttributesManager::resize(index_t new_size) {
287
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 6192359 times.
6192668 if(new_size == size_) {
288 309 return;
289 }
290
2/2
✓ Branch 5 taken 2108740 times.
✓ Branch 6 taken 6192359 times.
8301099 for(auto& cur : attributes_) {
291
1/2
✓ Branch 1 taken 2108740 times.
✗ Branch 2 not taken.
2108740 cur.second->resize(new_size);
292 }
293 6192359 size_ = new_size;
294 }
295
296 8524 void AttributesManager::reserve(index_t new_capacity) {
297
2/2
✓ Branch 0 taken 484 times.
✓ Branch 1 taken 8040 times.
8524 if(new_capacity <= capacity_) {
298 484 return;
299 }
300
2/2
✓ Branch 5 taken 3532 times.
✓ Branch 6 taken 8040 times.
11572 for(auto& cur : attributes_) {
301
1/2
✓ Branch 1 taken 3532 times.
✗ Branch 2 not taken.
3532 cur.second->reserve(new_capacity);
302 }
303 8040 capacity_ = new_capacity;
304 }
305
306 28 void AttributesManager::apply_permutation(
307 const vector<index_t>& permutation
308 ) {
309
2/2
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 28 times.
42 for(auto& cur : attributes_) {
310
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 cur.second->apply_permutation(permutation);
311 }
312 28 }
313
314 500 void AttributesManager::compress(
315 const vector<index_t>& old2new
316 ) {
317
2/2
✓ Branch 5 taken 1398 times.
✓ Branch 6 taken 500 times.
1898 for(auto& cur : attributes_) {
318
1/2
✓ Branch 1 taken 1398 times.
✗ Branch 2 not taken.
1398 cur.second->compress(old2new);
319 }
320 500 }
321
322
323 2078 void AttributesManager::bind_attribute_store(
324 const std::string& name, AttributeStore* as
325 ) {
326
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2078 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
2078 geo_assert(find_attribute_store(name) == nullptr);
327 2078 attributes_[name] = as;
328 2078 as->reserve(capacity_);
329 2078 as->resize(size_);
330 2078 }
331
332 754 void AttributesManager::list_attribute_names(
333 vector<std::string>& names
334 ) const {
335 754 names.clear();
336
2/2
✓ Branch 5 taken 681 times.
✓ Branch 6 taken 754 times.
1435 for(auto& cur : attributes_) {
337
1/2
✓ Branch 1 taken 681 times.
✗ Branch 2 not taken.
681 names.push_back(cur.first);
338 }
339 754 }
340
341 8837 AttributeStore* AttributesManager::find_attribute_store(
342 const std::string& name
343 ) {
344
1/2
✓ Branch 1 taken 8837 times.
✗ Branch 2 not taken.
8837 auto it = attributes_.find(name);
345
2/2
✓ Branch 2 taken 6199 times.
✓ Branch 3 taken 2638 times.
8837 if(it == attributes_.end()) {
346 6199 return nullptr;
347 }
348 2638 return it->second;
349 }
350
351 46 const AttributeStore* AttributesManager::find_attribute_store(
352 const std::string& name
353 ) const {
354
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 auto it = attributes_.find(name);
355
1/2
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
46 if(it == attributes_.end()) {
356 46 return nullptr;
357 }
358 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 236 void AttributesManager::delete_attribute_store(AttributeStore* as) {
408
1/2
✓ Branch 4 taken 437 times.
✗ Branch 5 not taken.
437 for(auto it=attributes_.begin(); it != attributes_.end(); ++it) {
409
2/2
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 201 times.
437 if(it->second == as) {
410
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 delete as;
411
1/2
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
236 attributes_.erase(it);
412 236 return;
413 }
414 }
415 geo_assert_not_reached;
416 }
417
418
419 9359 void AttributesManager::clear(bool keep_attributes, bool keep_memory) {
420
2/2
✓ Branch 0 taken 3171 times.
✓ Branch 1 taken 6188 times.
9359 if(keep_attributes) {
421
2/2
✓ Branch 5 taken 546 times.
✓ Branch 6 taken 3171 times.
3717 for(auto& cur : attributes_) {
422
1/2
✓ Branch 1 taken 546 times.
✗ Branch 2 not taken.
546 cur.second->clear(keep_memory);
423 }
424 } else {
425
2/2
✓ Branch 5 taken 1842 times.
✓ Branch 6 taken 6188 times.
8030 for(auto& cur : attributes_) {
426
1/2
✓ Branch 0 taken 1842 times.
✗ Branch 1 not taken.
1842 delete cur.second;
427 }
428 6188 attributes_.clear();
429 }
430 9359 size_ = 0;
431 9359 }
432
433 79 void AttributesManager::zero() {
434
2/2
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 79 times.
97 for(auto& cur : attributes_) {
435
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 cur.second->zero();
436 }
437 79 }
438
439 427 void AttributesManager::copy(const AttributesManager& rhs) {
440 427 clear(false, false);
441 427 reserve(rhs.capacity());
442 427 resize(rhs.size());
443
2/2
✓ Branch 5 taken 300 times.
✓ Branch 6 taken 427 times.
727 for(auto& cur : rhs.attributes_) {
444
2/4
✓ Branch 1 taken 300 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 300 times.
✗ Branch 5 not taken.
300 bind_attribute_store(cur.first, cur.second->clone());
445 }
446 427 }
447
448 536914 void AttributesManager::copy_item(index_t to, index_t from) {
449
2/2
✓ Branch 5 taken 786797 times.
✓ Branch 6 taken 536914 times.
1323711 for(auto& cur : attributes_) {
450
1/2
✓ Branch 1 taken 786797 times.
✗ Branch 2 not taken.
786797 cur.second->copy_item(to,from);
451 }
452 536914 }
453
454 1581050 void AttributesManager::swap_items(index_t i, index_t j) {
455
2/2
✓ Branch 5 taken 429538 times.
✓ Branch 6 taken 1581050 times.
2010588 for(auto& cur : attributes_) {
456
1/2
✓ Branch 1 taken 429538 times.
✗ Branch 2 not taken.
429538 cur.second->swap_items(i,j);
457 }
458 1581050 }
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