GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/attributes.h
Date: 2026-09-07 02:36:43
Exec Total Coverage
Lines: 282 347 81.3%
Functions: 148 364 40.7%
Branches: 101 314 32.2%

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
41 #ifndef GEOGRAM_BASIC_ATTRIBUTES
42 #define GEOGRAM_BASIC_ATTRIBUTES
43
44 #include <geogram/basic/common.h>
45 #include <geogram/basic/memory.h>
46 #include <geogram/basic/life_cycle.h>
47 #include <geogram/basic/numeric.h>
48 #include <geogram/basic/process.h>
49 #include <geogram/basic/geofile.h>
50 #include <geogram/basic/logger.h>
51
52 #include <map>
53 #include <typeinfo>
54 #include <set>
55 #include <type_traits>
56
57 /**
58 * \file geogram/basic/attributes.h
59 * \brief Generic mechanism for attributes.
60 */
61
62 namespace GEO {
63
64 class AttributeStore;
65
66 /**
67 * \brief Base class for attributes. They are notified
68 * whenever the AttributeStore is modified.
69 */
70 class GEOGRAM_API AttributeStoreObserver {
71 public:
72
73 /**
74 * \brief Creates a new uninitialied AttributeStore.
75 */
76 8450 AttributeStoreObserver() :
77 8450 base_addr_(nullptr), size_(0), dimension_(0),
78 8450 disconnected_(false) {
79 8450 }
80
81 /**
82 * \brief Callback function, called by the AttributeStore
83 * whenever it is modified.
84 * \param[in] base_addr new base address of the AttributeStore
85 * \param[in] size new number of items in the AttributeStore
86 * \param[in] dim new dimension, i.e. number of elements per item
87 */
88 1946164 void notify(
89 Memory::pointer base_addr, index_t size, index_t dim
90 ) {
91 1946164 base_addr_ = base_addr;
92 1946164 size_ = size;
93 1946164 dimension_ = dim;
94 1946164 }
95
96 /**
97 * \brief Gets the size.
98 * \return the number of items
99 */
100 index_t size() const {
101 return size_;
102 }
103
104 /**
105 * \brief Gets the dimension.
106 * \return the number of elements per item
107 */
108 594098497 index_t dimension() const {
109 594098497 return dimension_;
110 }
111
112 /**
113 * \brief Gets the total number of elements.
114 * \details This corresponds to one position past
115 * the last valid index.
116 * \return the total number of elements.
117 */
118 369779673 index_t nb_elements() const {
119 369779673 return size_ * dimension_;
120 }
121
122 /**
123 * \brief Gets a pointer to the storage
124 * \return a pointer to the first element
125 */
126 Memory::pointer base_addr() const {
127 return base_addr_;
128 }
129
130 /**
131 * \brief Registers this observer to an AttributeStore.
132 * \param[in] store a pointer to the AttributeStore.
133 */
134 void register_me(AttributeStore* store);
135
136 /**
137 * \brief Unregisters this observer from an AttributeStore.
138 * \param[in] store a pointer to the AttributeStore.
139 */
140 void unregister_me(AttributeStore* store);
141
142 /**
143 * \brief Disconnects this AttributeStoreObserver from its
144 * AttributeStore.
145 * \details This function is called whenever the AttributesManager is
146 * destroyed before the Attributes (can occur when using Lua scripting
147 * with Attribute wrapper objects).
148 */
149 void disconnect() {
150 base_addr_ = nullptr;
151 size_ = 0;
152 dimension_ = 0;
153 disconnected_ = true;
154 }
155
156 /**
157 * \brief Tests whether this AttributeStoreObserver was disconnected
158 * \retval true if this AttributeStoreObserver was disconnected,
159 * \retval false otherwise
160 * \see disconnect()
161 */
162 bool disconnected() const {
163 return disconnected_;
164 }
165
166 protected:
167 Memory::pointer base_addr_;
168 index_t size_;
169 index_t dimension_;
170 bool disconnected_;
171 };
172
173
174 /*********************************************************************/
175
176
177 /**
178 * \brief Internal class for creating an AttributeStore
179 * from the type name of its elements.
180 */
181 class GEOGRAM_API AttributeStoreCreator : public Counted {
182 public:
183
184 /**
185 * \brief AttributeStoreCreator destructor.
186 */
187 ~AttributeStoreCreator() override;
188
189 /**
190 * \brief Creates a new attribute store.
191 * \param[in] dimension number of elements in each item
192 * \return a pointer to the newly created AttributeStore
193 */
194 virtual AttributeStore* create_attribute_store(index_t dimension) = 0;
195
196 /**
197 * \brief Tests whether elements of this attribute can be trivially
198 * copyable
199 * \retval true if elements can be copied with memcpy and read, saved
200 * using fread(), fwrite
201 * \retval false otherwise
202 */
203 virtual bool elements_are_trivially_copyable() const = 0;
204
205 private:
206 std::string element_type_name_;
207 std::string element_typeid_name_;
208 };
209
210 /**
211 * \brief An automatic reference-counted pointer to
212 * an AttributeStoreCreator.
213 */
214 typedef SmartPointer<AttributeStoreCreator> AttributeStoreCreator_var;
215
216 /**
217 * \brief Notifies a set of AttributeStoreObservers
218 * each time the stored array changes size and/or
219 * base address and/or dimension.
220 */
221 class GEOGRAM_API AttributeStore {
222 public:
223 /**
224 * \brief AttributeStore constructor.
225 * \param[in] elemsize size of one element,
226 * in bytes.
227 * \param[in] dim number of elements in
228 * each item. Default is 1 for standard
229 * attributes and can be greater for vector
230 * attributes.
231 */
232 AttributeStore(size_t elemsize, index_t dim=1);
233
234 /**
235 * \brief AttributeStore destructor.
236 */
237 virtual ~AttributeStore();
238
239
240 /**
241 * \brief Tests whether this AttributeStore stores
242 * elements of a given type.
243 * \param[in] type_name the name of the type, as given by
244 * typeid(T).name()
245 * \retval true if this AttributeStore stores elements
246 * of type \p type_name
247 * \retval false otherwise
248 */
249 virtual bool elements_type_matches(
250 const std::string& type_name
251 ) const = 0;
252
253 /**
254 * \brief Gets the typeid name of the element type stored
255 * in this AttributeStore.
256 * \return the typeid name, as a string.
257 */
258 virtual std::string element_typeid_name() const = 0;
259
260 /**
261 * \brief Gets the user typeid name of the element type stored
262 * in this AttributeStore.
263 * \details May be different from element_typeid_name() for instance
264 * for Attribute<bool>, implemented using Numeric::uint8.
265 * \return the typeid name, as a string.
266 */
267 virtual std::string user_element_typeid_name() const = 0;
268
269 /**
270 * \brief Gets the size.
271 * \return the number of items
272 */
273 1429819 index_t size() const {
274 1429819 return cached_size_;
275 }
276
277 /**
278 * \brief Gets the capacity.
279 * \return the number of items that can be stored without
280 * a reallocation.
281 */
282 5958 index_t capacity() const {
283 5958 return cached_capacity_;
284 }
285
286 /**
287 * \brief Resizes this AttributeStore
288 * \param[in] new_size new number of items
289 */
290 virtual void resize(index_t new_size) = 0;
291
292 /**
293 * \brief Reserves memory.
294 * \param[in] new_capacity total number of items to
295 * be stored.
296 */
297 virtual void reserve(index_t new_capacity) = 0;
298
299 /**
300 * \brief Resizes this AttributeStore to 0.
301 * \param[in] keep_memory if true, then memory
302 * is kept reserved for future use.
303 */
304 virtual void clear(bool keep_memory = false) = 0;
305
306 /**
307 * \brief Tests whether observers listen to this AttributeStore.
308 * \retval true if at least one observer is bound to this AttributeStore
309 * \retval false otherwise
310 */
311 bool has_observers() const {
312 return !observers_.empty();
313 }
314
315 /**
316 * \brief Gets the dimension.
317 * \details The dimension is 1 for standard attributes and
318 * can be greater for vector attributes.
319 */
320 2074 index_t dimension() const {
321 2074 return dimension_;
322 }
323
324 /**
325 * \brief Sets the dimension.
326 * \details The dimension is 1 for standard attributes and
327 * can be greater for vector attributes. The existing
328 * fields are kept. If the new dimension is greater than
329 * the old one, then new fields are initialized to the default
330 * value for the attribute type.
331 * \param[in] dim the new dimension
332 */
333 virtual void redim(index_t dim) = 0;
334
335
336 /**
337 * \brief Applies a permutation to the stored attributes.
338 * \details Applying a permutation to the data is equivalent
339 * to:
340 * \code
341 * for(i=0; i<permutation.size(); i++) {
342 * data2[i] = data[permutation[i]]
343 * }
344 * data = data2 ;
345 * \endcode
346 * But it is done in-place.
347 * \param[in] permutation the permutation.
348 * It is temporarily changed during execution of the
349 * function, but identical to the input on exit.
350 */
351 virtual void apply_permutation(
352 const vector<index_t>& permutation
353 );
354
355
356 /**
357 * \brief Compresses the stored attributes, by
358 * applying an index mapping that fills-in the gaps.
359 * \details This is equivalent to:
360 * \code
361 * for(i=0; i<size(); i++) {
362 * if(old2new[i] != index_t(-1)) {
363 * data2[old2new[i]] = data[i];
364 * }
365 * }
366 * data = data2 ;
367 * \endcode
368 * \param[in] old2new the index mapping to be applied.
369 * \pre old2new[i] <= i || old2new[i] == index_t(-1)
370 */
371 virtual void compress(const vector<index_t>& old2new);
372
373 /**
374 * \brief Zeroes all the memory associated with this
375 * AttributeStore.
376 */
377 virtual void zero();
378
379 /**
380 * \brief Creates a new AttributeStore that is a carbon copy
381 * of this AttributeStore.
382 * \details Only the data is copied, observers are not copied.
383 */
384 virtual AttributeStore* clone() const = 0;
385
386
387 /**
388 * \brief Copies an item
389 * \param[in] to index of the destination item
390 * \param[in] from index of the source item
391 */
392 778797 void copy_item(index_t to, index_t from) {
393
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 778797 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
778797 geo_debug_assert(from < cached_size_);
394
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 778797 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
778797 geo_debug_assert(to < cached_size_);
395 778797 size_t item_size = element_size_ * dimension_;
396
1/2
✓ Branch 1 taken 778797 times.
✗ Branch 2 not taken.
778797 if(lifecycle_.is_null()) {
397 778797 Memory::copy(
398 778797 cached_base_addr_+to*item_size,
399 778797 cached_base_addr_+from*item_size,
400 item_size
401 );
402 } else {
403 lifecycle_->assign(
404 cached_base_addr_+to*item_size,
405 cached_base_addr_+from*item_size
406 );
407 }
408 778797 }
409
410 /**
411 * \brief Sets an item to zero
412 * \param[in] to index of the item
413 */
414 291740 void zero_item(index_t to) {
415
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 291740 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
291740 geo_debug_assert(to < cached_size_);
416 291740 size_t item_size = element_size_ * dimension_;
417
2/2
✓ Branch 1 taken 209840 times.
✓ Branch 2 taken 81900 times.
291740 if(lifecycle_.is_null()) {
418 209840 Memory::clear(
419 209840 cached_base_addr_+to*item_size,
420 item_size
421 );
422 } else {
423 81900 lifecycle_->reset(cached_base_addr_+to*item_size);
424 }
425 291740 }
426
427 /**
428 * \brief Scales an item
429 * \details item[to] *= s
430 * \param[in] to the index of the item
431 * \param[in] s the scaling factor
432 * \details default implementation does nothing
433 */
434 virtual void scale_item(index_t to, double s);
435
436 /**
437 * \brief Adds a scaled item to another item
438 * \detais item[to] += s * item[from]
439 * \param[in] to the item
440 * \param[in] s the scaling factor
441 * \param[in] from the item to be scaled and added
442 * \details default implementation does nothing
443 */
444 virtual void madd_item(index_t to, double s, index_t from);
445
446 /**
447 * \brief Swaps two items
448 * \param[in] i , j the indices of the items to be swapped
449 */
450 void swap_items(index_t i, index_t j);
451
452 /**
453 * \brief Gets a pointer to the stored data.
454 * \return A pointer to the memory block
455 */
456 39 void* data() {
457 39 return cached_base_addr_;
458 }
459
460 /**
461 * \brief Gets a pointer to the stored data.
462 * \return A const pointer to the memory block
463 */
464 const void* data() const {
465 return cached_base_addr_;
466 }
467
468 /**
469 * \brief Gets the element size.
470 * \return the size of an element, in bytes
471 */
472 37 size_t element_size() const {
473 37 return element_size_;
474 }
475
476 /**
477 * \brief Tests whether a given element type is registered in
478 * the system.
479 * \param[in] element_type_name a const reference to a string
480 * with the C++ type name
481 * \retval true if the element type was registered
482 * \retval false otherwise
483 */
484 2782 static bool element_type_name_is_known(
485 const std::string& element_type_name
486 ) {
487 return (
488
1/2
✓ Branch 1 taken 2782 times.
✗ Branch 2 not taken.
2782 type_name_to_creator_.find(element_type_name) !=
489 5564 type_name_to_creator_.end()
490 5564 );
491 }
492
493 /**
494 * \brief Tests whether a given element type is registered in
495 * the system.
496 * \param[in] element_typeid_name a const reference to a string
497 * with the mangled type, as given by typeid(T).name()
498 * \retval true if the element type was registered
499 * \retval false otherwise
500 */
501 111 static bool element_typeid_name_is_known(
502 const std::string& element_typeid_name
503 ) {
504 return (
505
1/2
✓ Branch 1 taken 111 times.
✗ Branch 2 not taken.
111 typeid_name_to_type_name_.find(element_typeid_name) !=
506 222 typeid_name_to_type_name_.end()
507 222 );
508 }
509
510 /**
511 * \brief Tests whether an element type is trivially copyable
512 * \param[in] element_type_name the type name of the elements, as
513 * registered to the system using geo_register_attribute_type<T>()
514 * \retval true if elements can be copied with memcpy(), read and write
515 * using fread() , fwrite()
516 * \retval false otherwise
517 * \pre the element type was registered using geo_register_attribute_type.
518 */
519 37 static bool element_by_type_name_is_trivially_copyable(
520 const std::string& element_type_name
521 ) {
522
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
37 geo_debug_assert(element_type_name_is_known(element_type_name));
523 return (
524 type_name_to_creator_[
525 element_type_name
526 37 ]->elements_are_trivially_copyable()
527 37 );
528 }
529
530 /**
531 * \brief Tests whether an element type is trivially copyable
532 * \param[in] element_typeid_name the type name of the elements, as
533 * given by typeid(T).name()
534 * \retval true if elements can be copied with memcpy(), read and write
535 * using fread() , fwrite()
536 * \retval false otherwise
537 * \pre the element type was registerd using geo_register_attribute_type.
538 */
539 37 static bool element_by_typeid_name_is_trivially_copyable(
540 const std::string& element_typeid_name
541 ) {
542
2/8
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
37 geo_debug_assert(element_typeid_name_is_known(element_typeid_name));
543 std::string element_type_name =
544
2/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
37 typeid_name_to_type_name_[element_typeid_name];
545
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
74 return element_by_type_name_is_trivially_copyable(element_type_name);
546 37 }
547
548 /**
549 * \brief Creates an attribute store of a given type
550 * \param[in] element_type_name a const reference to a string with
551 * the C++ type of the elements to be stored in the attribute
552 * \param[in] dimension number of elements in each item
553 */
554 2 static AttributeStore* create_attribute_store_by_element_type_name(
555 const std::string& element_type_name,
556 index_t dimension
557 ) {
558
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
2 geo_assert(element_type_name_is_known(element_type_name));
559 2 return type_name_to_creator_[element_type_name]->
560 2 create_attribute_store(dimension);
561 }
562
563 /**
564 * \brief Gets an element type name from its mangled name
565 * \param[in] element_typeid_name a const reference to a
566 * string with the mangled type name, as given by typeid(T).name()
567 * \return a string with the C++ type name
568 * \pre element_typeid_name_is_known(element_typeid_name)
569 */
570 37 static std::string element_type_name_by_element_typeid_name(
571 const std::string& element_typeid_name
572 ) {
573
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
37 geo_assert(element_typeid_name_is_known(element_typeid_name));
574 37 return typeid_name_to_type_name_[element_typeid_name];
575 }
576
577 /**
578 * \brief Gets an element mangled type name from its C++ name.
579 * \param[in] element_type_name a reference to a string with
580 * the C++ type name
581 * \return a string with the mangled type name, as given by
582 * typeid(T).name()
583 * \pre element_type_name_is_known(element_type_name)
584 */
585 static std::string element_typeid_name_by_element_type_name(
586 const std::string& element_type_name
587 ) {
588 geo_assert(element_type_name_is_known(element_type_name));
589 return type_name_to_typeid_name_[element_type_name];
590 }
591
592 /**
593 * \brief Registers a new element type
594 * \note Internal use function, one should use
595 * geo_register_attribute_type instead
596 * \param[in] creator a pointer to the AttributeStoreCreator
597 * \param[in] element_type_name a const reference to a string with the
598 * C++ type name of the elements
599 * \param[in] element_typeid_name a const reference to a string with
600 * the mangled type name of the elements, as given by typeid(T).name()
601 */
602 static void register_attribute_creator(
603 AttributeStoreCreator* creator,
604 const std::string& element_type_name,
605 const std::string& element_typeid_name
606 );
607
608 /**
609 * \brief Gets the LifeCycle.
610 * \details The LifeCycle know how to construct, destroy, copy-construct
611 * or copy objects.
612 * \return a pointer to the LifeCycle or nullptr if datatype is a
613 * POD (Plain Ordinary Datatype).
614 */
615 LifeCycle* lifecycle() const {
616 return lifecycle_;
617 }
618
619 protected:
620
621 /**
622 * \brief implementation of apply_permutation() used when there is a
623 * lifecycle, that is, when attribute type is not trivially copyable.
624 * \see apply_permutation()
625 */
626 void apply_permutation_with_lifecycle(
627 const vector<index_t>& permutation
628 );
629
630 /**
631 * \brief If size or base address differ from the
632 * cached values, notify all the observers,
633 * and update the cached base address and size.
634 * \param[in] base_addr the new base address
635 * \param[in] size the new size
636 * \param[in] dim the new dimension
637 */
638 virtual void notify(
639 Memory::pointer base_addr, index_t size, index_t dim
640 );
641
642 /**
643 * \brief Registers an observer.
644 * \details All the registered observers are notified whenever
645 * the size or base pointer in this AttributeStore change.
646 * The function is thread-safe.
647 * \param[in] observer the AttributeStoreObserver to be
648 * registered.
649 */
650 void register_observer(AttributeStoreObserver* observer);
651
652 /**
653 * \brief Unregisters an observer.
654 * \param[in] observer the AttributeStoreObserver to be
655 * unregistered.
656 * The function is thread-safe.
657 * \pre \p observer is registered.
658 */
659 void unregister_observer(AttributeStoreObserver* observer);
660
661
662 protected:
663 size_t element_size_;
664 index_t dimension_;
665 Memory::pointer cached_base_addr_;
666 index_t cached_size_;
667 index_t cached_capacity_;
668 LifeCycle_var lifecycle_;
669 std::set<AttributeStoreObserver*> observers_;
670 Process::spinlock lock_;
671
672 static std::map<std::string, AttributeStoreCreator_var>
673 type_name_to_creator_;
674
675 static std::map<std::string, std::string>
676 typeid_name_to_type_name_;
677
678 static std::map<std::string, std::string>
679 type_name_to_typeid_name_;
680
681 friend class AttributeStoreObserver;
682 };
683
684 /*********************************************************************/
685
686 /**
687 * \brief Stores an array of elements of a given type,
688 * and notifies a set of AttributeStoreObservers each time the
689 * storead array changes size and/or base address.
690 * \tparam ST storage type for the elements
691 */
692 template <class ST> class TypedAttributeStore : public AttributeStore {
693 public:
694
695 /**
696 * \brief Creates a new empty attribute store.
697 * \param[in] dim number of elements in each item,
698 * default value is 1, can be greater for vector
699 * attributes.
700 * \param[in] user_type_info optional user type (default is typeid(ST)
701 * \details \p user_type_info is used for instance by Attribute<bool>,
702 * with bool as user type and Numeric::uint8 as storage type
703 */
704 3122 TypedAttributeStore(
705 index_t dim=1, const std::type_info& user_type_info = typeid(ST)
706 ) :
707 AttributeStore(sizeof(ST),dim),
708 3122 storage_type_(typeid(ST)),
709 3122 user_type_(user_type_info) {
710 if(!std::is_trivially_copyable<ST>::value) {
711
3/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
1 lifecycle_ = new GenericLifeCycle<ST>();
712 }
713 3122 }
714
715 3088724 void resize(index_t new_size) override {
716 3088724 store_.resize(new_size*dimension_);
717
2/2
✓ Branch 0 taken 1078 times.
✓ Branch 1 taken 2029964 times.
6176224 notify(
718 6176224 store_.empty() ? nullptr : Memory::pointer(store_.data()),
719 new_size,
720 dimension_
721 );
722 3088724 }
723
724 7622 void reserve(index_t new_capacity) override {
725
2/2
✓ Branch 1 taken 4493 times.
✓ Branch 2 taken 1054 times.
7622 if(new_capacity > capacity()) {
726 6448 store_.reserve(new_capacity*dimension_);
727 6448 cached_capacity_ = new_capacity;
728
2/2
✓ Branch 1 taken 1586 times.
✓ Branch 2 taken 2907 times.
16954 notify(
729 10506 store_.empty() ? nullptr : Memory::pointer(store_.data()),
730 size(),
731 dimension_
732 );
733 }
734 7622 }
735
736 670 void clear(bool keep_memory=false) override {
737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 535 times.
670 if(keep_memory) {
738 store_.resize(0);
739 } else {
740 670 store_.clear();
741 }
742 670 notify(nullptr, 0, dimension_);
743 670 }
744
745 700 void redim(index_t dim) override {
746
2/2
✓ Branch 1 taken 289 times.
✓ Branch 2 taken 411 times.
700 if(dim == dimension()) {
747 289 return;
748 }
749
1/2
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
411 vector<ST> new_store(size()*dim);
750
1/2
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
411 new_store.reserve(capacity()*dim);
751 411 index_t copy_dim = std::min(dim, dimension());
752
2/2
✓ Branch 1 taken 231278 times.
✓ Branch 2 taken 411 times.
231689 for(index_t i = 0; i < size(); ++i) {
753
2/2
✓ Branch 0 taken 466328 times.
✓ Branch 1 taken 231278 times.
697606 for(index_t c = 0; c < copy_dim; ++c) {
754
2/6
✓ Branch 1 taken 466328 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 466328 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
466328 new_store[dim * i + c] = store_[dimension_ * i + c];
755 }
756 }
757 411 store_.swap(new_store);
758
3/4
✓ Branch 1 taken 229 times.
✓ Branch 2 taken 182 times.
✓ Branch 4 taken 411 times.
✗ Branch 5 not taken.
1004 notify(
759 593 store_.empty() ? nullptr : Memory::pointer(store_.data()),
760 size(),
761 dim
762 );
763 411 }
764
765 3837 bool elements_type_matches(const std::string& type_name) const override {
766 return (
767
2/2
✓ Branch 2 taken 855 times.
✓ Branch 3 taken 1094 times.
5547 type_name == storage_type_.name() ||
768
1/2
✓ Branch 2 taken 855 times.
✗ Branch 3 not taken.
1710 type_name == user_type_.name()
769 3837 );
770 }
771
772 74 std::string element_typeid_name() const override {
773
1/2
✓ Branch 2 taken 74 times.
✗ Branch 3 not taken.
148 return storage_type_.name();
774 }
775
776 37 std::string user_element_typeid_name() const override {
777
1/2
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
74 return user_type_.name();
778 }
779
780 527 AttributeStore* clone() const override {
781
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 295 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
527 TypedAttributeStore<ST>* result =
782
1/2
✓ Branch 3 taken 295 times.
✗ Branch 4 not taken.
527 new TypedAttributeStore<ST>(dimension(), user_type_);
783 527 result->resize(size());
784 527 result->store_ = store_;
785 527 result->lifecycle_ = lifecycle_;
786 527 return result;
787 }
788
789 vector<ST>& get_vector() {
790 return store_;
791 }
792
793 5120 void scale_item(index_t to, double s) override {
794
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 5120 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
5120 geo_assert(to < size());
795
2/2
✓ Branch 0 taken 15360 times.
✓ Branch 1 taken 5120 times.
20480 for(index_t i=0; i<dimension_; ++i) {
796 15360 scale_value(store_[to*dimension_+i], s);
797 }
798 5120 }
799
800 593700 void madd_item(index_t to, double s, index_t from) override {
801
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 593700 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
593700 geo_assert(from < size());
802
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 593700 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
593700 geo_assert(to < size());
803
2/2
✓ Branch 0 taken 1453500 times.
✓ Branch 1 taken 593700 times.
2047200 for(index_t i=0; i<dimension_; ++i) {
804 1453500 madd_value(
805 1453500 store_[to*dimension_+i], s, store_[from*dimension_+i]
806 );
807 }
808 593700 }
809
810 protected:
811 3096253 void notify(
812 Memory::pointer base_addr, index_t size, index_t dim
813 ) override {
814 3096253 AttributeStore::notify(base_addr, size, dim);
815
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2036481 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
3096253 geo_assert(size*dim <= store_.size());
816 3096253 }
817
818 template<class TT> static void scale_value(TT& to, double s) {
819 geo_argused(to);
820 geo_argused(s);
821 }
822
823 static void scale_value(uint8_t& to, double s) {
824 to = uint8_t(double(to)*s != 0.0);
825 }
826
827 static void scale_value(int32_t& to, double s) {
828 to = int32_t(double(to)*s);
829 }
830
831 static void scale_value(uint32_t& to, double s) {
832 to = uint32_t(double(to)*s);
833 }
834
835 static void scale_value(float& to, double s) {
836 to = float(double(to)*s);
837 }
838
839 15360 static void scale_value(double& to, double s) {
840 15360 to *= s;
841 15360 }
842
843 163800 template<class TT> static void madd_value(TT& to, double s, TT& from) {
844 163800 geo_argused(to);
845 163800 geo_argused(s);
846 163800 geo_argused(from);
847 163800 }
848
849 static void madd_value(uint8_t& to, double s, uint8_t& from) {
850 to = uint8_t(double(to) + s*double(from) != 0.0);
851 }
852
853 static void madd_value(int32_t& to, double s, int32_t& from) {
854 to = int32_t(double(to) + s*double(from));
855 }
856
857 static void madd_value(uint32_t& to, double s, uint32_t& from) {
858 to = uint32_t(double(to) + s*double(from));
859 }
860
861 static void madd_value(float& to, double s, float& from) {
862 to = float(double(to) + s*double(from));
863 }
864
865 1289700 static void madd_value(double& to, double s, double& from) {
866 1289700 to += s*from;
867 1289700 }
868
869 private:
870 vector<ST> store_;
871 const std::type_info& storage_type_;
872 const std::type_info& user_type_;
873 };
874
875 /*********************************************************************/
876
877 /**
878 * \brief Implementation of AttributeStoreCreator for a specific type.
879 * \tparam UT type of the elements (user)
880 * \tparam ST type of the elements (storage), default is UT
881 */
882 template <class UT, class ST=UT>
883 class TypedAttributeStoreCreator : public AttributeStoreCreator {
884 public:
885 /**
886 * \copydoc AttributeStoreCreator::create_attribute_store()
887 */
888 4 AttributeStore* create_attribute_store(index_t dim) override{
889
2/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
8 return new TypedAttributeStore<ST>(dim,typeid(UT));
890 }
891
892 /**
893 * \copydoc AttributeStoreCreator::elements_are_trivially_copyable()
894 */
895 74 bool elements_are_trivially_copyable() const override {
896 74 return(std::is_trivially_copyable<ST>::value);
897 }
898 };
899
900 /*********************************************************************/
901
902 /**
903 * \brief Helper class to register new attribute types
904 * \tparam UT attribute element type (user)
905 * \tparam ST attribute element type (storage), default is UT
906 * It can be different: for instance, for bool we use
907 * Numeric::uint8 (to avoid the std::vector<bool> insanity !!).
908 */
909 template <class UT, class ST=UT> class geo_register_attribute_type {
910 public:
911 /**
912 * \brief geo_register_attribute_type constructor
913 * \param[in] type_name a const reference to a string with
914 * the C++ type name.
915 * \details If the attribute is already registered with the same
916 * \p type_name and same \p T, then a warning message is issued.
917 * If the attribute is already registered with the same \p type_name
918 * but a different \p T, then an assertion failure is triggered.
919 */
920 5480 geo_register_attribute_type(const std::string& type_name) {
921
2/6
✓ Branch 1 taken 2741 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2741 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
5480 AttributeStore::register_attribute_creator(
922
1/2
✓ Branch 1 taken 2741 times.
✗ Branch 2 not taken.
5480 new TypedAttributeStoreCreator<UT,ST>,
923
1/2
✓ Branch 2 taken 2741 times.
✗ Branch 3 not taken.
10960 type_name, typeid(UT).name()
924 );
925
2/2
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 2492 times.
5480 if(type_name == "bool") {
926 498 GeoFile::register_ascii_attribute_serializer(
927 type_name,
928 read_ascii_attribute<bool>,
929 write_ascii_attribute<bool>
930 );
931 } else {
932 4982 GeoFile::register_ascii_attribute_serializer(
933 type_name,
934 read_ascii_attribute<UT>,
935 write_ascii_attribute<UT>
936 );
937 }
938 5480 }
939 };
940
941 /*********************************************************************/
942
943 /**
944 * \brief Manages a set of attributes attached to
945 * an object.
946 */
947 class GEOGRAM_API AttributesManager {
948 public:
949 /**
950 * \brief Constructs a new empty AttributesManager.
951 */
952 AttributesManager();
953
954
955 /**
956 * \brief AttributesManager destructor.
957 */
958 ~AttributesManager();
959
960 /**
961 * \brief Gets the number of attributes.
962 * \return The number of attributes managed by this
963 * AttributesManager.
964 */
965 2874 index_t nb() const {
966 2874 return index_t(attributes_.size());
967 }
968
969 /**
970 * \brief Gets the names of all the attributes in this
971 * AttributeStore.
972 * \param[out] names a vector of all attribute names
973 */
974 void list_attribute_names(vector<std::string>& names) const;
975
976 /**
977 * \brief Gets the size.
978 * \details All attributes stored in an AttributesManager have
979 * the same number of items.
980 * \return the number of items of each attribute.
981 */
982 1602 index_t size() const {
983 1602 return size_;
984 }
985
986 /**
987 * \brief Gets the capacity.
988 * \return the number of items that can be stored without doing
989 * a reallocation.
990 */
991 6144708 index_t capacity() const {
992 6144708 return capacity_;
993 }
994
995 /**
996 * \brief Resizes all the attributes managed by this
997 * AttributesManager.
998 * \param[in] new_size the new number of items for
999 * all attributes.
1000 */
1001 void resize(index_t new_size);
1002
1003 /**
1004 * \brief Pre-allocates memory for a number of items.
1005 * \details Has effect only if new_capacity is larger
1006 * than current capacity.
1007 * \param[in] new_capacity the number of items.
1008 */
1009 void reserve(index_t new_capacity);
1010
1011 /**
1012 * \brief Clears this AttributesManager
1013 * \param[in] keep_attributes if true, then all
1014 * attributes are resized to 0 but their names are
1015 * kept.
1016 * \param[in] keep_memory if true, allocated memory
1017 * is kept reserved.
1018 */
1019 void clear(bool keep_attributes, bool keep_memory = false);
1020
1021
1022 /**
1023 * \brief Zeroes all the attributes.
1024 */
1025 void zero();
1026
1027 /**
1028 * \brief Binds an AttributeStore with the specified name.
1029 * Ownership of this AttributeStore is transferred to
1030 * the AttributesManager.
1031 * \param[in] name the name
1032 * \param[in] as a pointer to the AttributeStore to be bound
1033 * \pre No AttributeStore is already bound to the same name
1034 */
1035 void bind_attribute_store(const std::string& name, AttributeStore* as);
1036
1037 /**
1038 * \brief Finds an AttributeStore by name.
1039 * \param[in] name the name under which the AttributeStore was bound
1040 * \return a pointer to the attribute store or nullptr
1041 * if is is undefined.
1042 */
1043 AttributeStore* find_attribute_store(const std::string& name);
1044
1045 /**
1046 * \brief Reads a double-typed attribute into a vector.
1047 * \param[out] out receives size() * dim values.
1048 * \param[out] dim the dimension of the attribute.
1049 * \retval false if no attribute \p name exists or it is not double-typed.
1050 */
1051 bool get_doubles(
1052 const std::string& name, vector<double>& out, index_t& dim
1053 ) const;
1054
1055 /**
1056 * \brief Writes a double-typed attribute, creating it if needed.
1057 * \retval false on type or size mismatch
1058 * (in.size() must be size() * dim).
1059 */
1060 bool set_doubles(
1061 const std::string& name, const vector<double>& in, index_t dim
1062 );
1063
1064 /**
1065 * \brief Finds an AttributeStore by name.
1066 * \param[in] name the name under which the AttributeStore was bound
1067 * \return a const pointer to the attribute store or nullptr if is is
1068 * undefined.
1069 */
1070 const AttributeStore* find_attribute_store(
1071 const std::string& name
1072 ) const;
1073
1074
1075 /**
1076 * \brief Tests whether an attribute is defined.
1077 * \param[in] name name of the attribute
1078 * \retval true if an attribute with the specified name exists
1079 * \retval false otherwise
1080 */
1081 46 bool is_defined(const std::string& name) const {
1082 46 return (find_attribute_store(name) != nullptr);
1083 }
1084
1085 /**
1086 * \brief Deletes an AttributeStore by name.
1087 * \param[in] name the name of the attribute store
1088 * to be deleted.
1089 */
1090 void delete_attribute_store(const std::string& name);
1091
1092 /**
1093 * \brief Deletes an AttributeStore.
1094 * \param[in] as a pointer to the attribute store
1095 * to be deleted.
1096 */
1097 void delete_attribute_store(AttributeStore* as);
1098
1099 /**
1100 * \brief Applies a permutation to the stored attributes.
1101 * \details Applying a permutation to the data is equivalent
1102 * to:
1103 * \code
1104 * for(i=0; i<permutation.size(); i++) {
1105 * data2[i] = data[permutation[i]]
1106 * }
1107 * data = data2 ;
1108 * \endcode
1109 * But it is done in-place.
1110 * \param[in] permutation the permutation.
1111 * It is temporarily changed during execution of the
1112 * function, but identical to the input on exit.
1113 */
1114 void apply_permutation(
1115 const vector<index_t>& permutation
1116 );
1117
1118 /**
1119 * \brief Compresses the stored attributes, by
1120 * applying an index mapping that fills-in the gaps.
1121 * \details This is equivalent to:
1122 * \code
1123 * for(i=0; i<size(); i++) {
1124 * if(old2new[i] != index_t(-1)) {
1125 * data2[old2new[i]] = data[i];
1126 * }
1127 * }
1128 * data = data2 ;
1129 * \endcode
1130 * \param[in] old2new the index mapping to be applied.
1131 * \pre old2new[i] <= i || old2new[i] == index_t(-1)
1132 */
1133 void compress(const vector<index_t>& old2new);
1134
1135 /**
1136 * \brief Copies all the attributes from another AttributesManager.
1137 * \details Previous content of this AttributesManager is erased.
1138 */
1139 void copy(const AttributesManager& rhs);
1140
1141
1142 /**
1143 * \brief Copies all the attributes of an item into another one.
1144 * \param[in] to index of the destination item
1145 * \param[in] from index of the source item
1146 * \note This function is not efficient.
1147 */
1148 void copy_item(index_t to, index_t from);
1149
1150 /**
1151 * \brief Swaps all the attributes of two items
1152 * \param[in] i , j the indices of the two items to be swapped
1153 * \note This function is not efficient.
1154 */
1155 void swap_items(index_t i, index_t j);
1156
1157
1158 /**
1159 * \brief Sets an item to zero
1160 * \param[in] to index of the item
1161 */
1162 void zero_item(index_t to);
1163
1164 /**
1165 * \brief Scales an item
1166 * \details item[to] *= s
1167 * \param[in] to the index of the item
1168 * \param[in] s the scaling factor
1169 * \details default implementation does nothing
1170 */
1171 void scale_item(index_t to, double s);
1172
1173 /**
1174 * \brief Adds a scaled item to another item
1175 * \detais item[to] += s * item[from]
1176 * \param[in] to the item
1177 * \param[in] s the scaling factor
1178 * \param[in] from the item to be scaled and added
1179 * \details default implementation does nothing
1180 */
1181 void madd_item(index_t to, double s, index_t from);
1182
1183 /**
1184 * \brief Copies an attribute.
1185 * \param[in] name the attribute to copy
1186 * \param[in] new_name new name of the attribute
1187 * \retval \c false and does nothing if \p old_name
1188 * attribute doesn't exist or if \p new_name attribute already exists.
1189 * \retval \c true if the copy occurs succesfully.
1190 */
1191 bool copy_attribute(
1192 const std::string& name, const std::string& new_name
1193 );
1194
1195 /**
1196 * \brief Renames an attribute.
1197 * \param[in] old_name current name of the attribute
1198 * \param[in] new_name new name of the attribute
1199 * \retval \c false and does nothing if \p old_name
1200 * attribute doesn't exist or if \p new_name attribute already exists.
1201 * \retval \c true if renaming occurs succesfully.
1202 */
1203 bool rename_attribute(
1204 const std::string& old_name, const std::string& new_name
1205 );
1206
1207 private:
1208 /**
1209 * \brief Forbids copy.
1210 * \details This is to make sure that client code does
1211 * not unintentionlly copies an AttributesManager (for
1212 * instance by passing it by-value to a function).
1213 * Use copy() instead.
1214 */
1215 AttributesManager(const AttributesManager& rhs) = delete;
1216
1217 /**
1218 * \brief Forbids copy.
1219 * \details This is to make sure that client code does
1220 * not unintentionlly copies an AttributesManager (for
1221 * instance by passing it by-value to a function).
1222 * Use copy() instead.
1223 */
1224 const AttributesManager& operator=(const AttributesManager& rhs) = delete;
1225
1226 private:
1227 index_t size_;
1228 index_t capacity_;
1229 std::map<std::string, AttributeStore*> attributes_;
1230 } ;
1231
1232
1233 /*********************************************************************/
1234
1235
1236 /**
1237 * \brief Base class for Attributes, that manipulates an
1238 * attribute stored in an AttributesManager.
1239 * \tparam UT user element type
1240 * \tparam ST stored element type (default = UT)
1241 */
1242 template <class UT, class ST = UT>
1243 class AttributeBase : public AttributeStoreObserver {
1244 public:
1245
1246 /**
1247 * \brief Creates an uninitialized (unbound) Attribute.
1248 */
1249 13056 AttributeBase() :
1250 13056 manager_(nullptr),
1251 13056 store_(nullptr),
1252 13056 existed_already_(false) {
1253 13056 }
1254
1255 /**
1256 * \brief Creates or retrieves a persistent attribute attached to
1257 * a given AttributesManager.
1258 * \details If the attribute already exists with the specified
1259 * name in the AttributesManager then it is retrieved, else
1260 * it is created and bound to the name.
1261 * \param[in] manager a reference to the AttributesManager
1262 * \param[in] name name of the attribute
1263 */
1264 1988 AttributeBase(AttributesManager& manager, const std::string& name) :
1265 1988 manager_(nullptr),
1266 1988 store_(nullptr),
1267 1988 existed_already_(false) {
1268 1988 bind(manager, name);
1269 1988 }
1270
1271 /**
1272 * \brief Tests whether an Attribute is bound.
1273 * \retval true if this Attribute is bound
1274 * \retval false otherwise
1275 */
1276 1933479996 bool is_bound() const {
1277
3/4
✓ Branch 0 taken 366282685 times.
✓ Branch 1 taken 600457313 times.
✓ Branch 2 taken 366282685 times.
✗ Branch 3 not taken.
1933479996 return (store_ != nullptr && !disconnected_);
1278 }
1279
1280 /**
1281 * \brief Tests whether the latest bound attribute existed already
1282 * \retval true if the latest bound attribute existed already in the
1283 * AttributeManager
1284 * \retval false if the latest bound attribute was created in the
1285 * AttributeManager when bound
1286 */
1287 bool existed_already() const {
1288 return existed_already_;
1289 }
1290
1291 /**
1292 * \brief Unbinds this Attribute.
1293 * \pre is_bound()
1294 */
1295 6743 void unbind() {
1296
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 3372 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
6743 geo_assert(is_bound());
1297 // If the AttributesManager was destroyed before, do not
1298 // do anything. This can occur in Lua scripting when using
1299 // Attribute wrapper objects.
1300
1/2
✓ Branch 0 taken 3372 times.
✗ Branch 1 not taken.
6743 if(!disconnected_) {
1301 6743 unregister_me(store_);
1302 }
1303 6743 manager_ = nullptr;
1304 6743 store_ = nullptr;
1305 6743 existed_already_ = false;
1306 6743 }
1307
1308 /**
1309 * \brief Binds this Attribute to an AttributesManager.
1310 * \details If the attribute already exists with the specified
1311 * name in the AttributesManager then it is retrieved, else
1312 * it is created and bound to the name.
1313 * \param[in] manager a reference to the AttributesManager
1314 * \param[in] name name of the attribute
1315 * \pre !is_bound()
1316 */
1317 2409 void bind(AttributesManager& manager, const std::string& name) {
1318
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2343 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
2409 geo_assert(!is_bound());
1319 2409 manager_ = &manager;
1320 2409 store_ = manager_->find_attribute_store(name);
1321
2/2
✓ Branch 0 taken 831 times.
✓ Branch 1 taken 1512 times.
2409 if(store_ == nullptr) {
1322
2/6
✓ Branch 2 taken 831 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 831 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
897 store_ = new TypedAttributeStore<ST>(1,typeid(UT));
1323 897 manager_->bind_attribute_store(name,store_);
1324 897 existed_already_ = false;
1325 } else {
1326
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1512 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1512 geo_assert(can_bind_to(store_));
1327 1512 existed_already_ = true;
1328 }
1329 2409 register_me(store_);
1330 2409 }
1331
1332
1333 /**
1334 * \brief Binds this Attribute to an AttributesManager if it
1335 * already exists in the AttributesManager.
1336 * \param[in] manager a reference to the AttributesManager
1337 * \param[in] name name of the attribute
1338 * \pre !is_bound()
1339 * \return \c true if this Attribute was successfully bound
1340 */
1341 5456 bool bind_if_is_defined(
1342 AttributesManager& manager, const std::string& name
1343 ) {
1344
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2728 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
5456 geo_assert(!is_bound());
1345 5456 manager_ = &manager;
1346 5456 store_ = manager_->find_attribute_store(name);
1347
2/2
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 2397 times.
5456 if(store_ != nullptr) {
1348
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 331 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
662 geo_assert(can_bind_to(store_));
1349 662 register_me(store_);
1350 662 existed_already_ = true;
1351 662 return true;
1352 }
1353 4794 existed_already_ = false;
1354 4794 return false;
1355 }
1356
1357 /**
1358 * \brief Binds this Attribute to an AttributesManager if it
1359 * already exists in the AttributesManager and types are compatible.
1360 * \param[in] manager a reference to the AttributesManager
1361 * \param[in] name name of the attribute
1362 * \pre !is_bound()
1363 * \return \c true if this Attribute was successfully bound
1364 */
1365 bool bind_if_is_compatible(
1366 AttributesManager& manager, const std::string& name
1367 ) {
1368 if( is_bound() ) {
1369 unbind();
1370 }
1371 store_ = manager.find_attribute_store(name);
1372 if(store_ != nullptr) {
1373 existed_already_ = true;
1374 if(!can_bind_to(store_)) {
1375 store_ = nullptr;
1376 return false;
1377 }
1378 manager_ = &manager;
1379 register_me(store_);
1380 return true;
1381 }
1382 existed_already_ = false;
1383 return false;
1384 }
1385
1386 /**
1387 * \brief Creates and binds a new vector attribute.
1388 * \param[in] manager the attribute manager
1389 * \param[in] name the name of the attribute
1390 * \param[in] dimension the number of elements per item
1391 */
1392 1864 void create_vector_attribute(
1393 AttributesManager& manager,
1394 const std::string& name,
1395 index_t dimension
1396 ) {
1397
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 932 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1864 geo_assert(!is_bound());
1398 1864 manager_ = &manager;
1399
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 932 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1864 geo_assert(manager_->find_attribute_store(name) == nullptr);
1400
2/6
✓ Branch 2 taken 932 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 932 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1864 store_ = new TypedAttributeStore<ST>(dimension,typeid(UT));
1401 1864 manager_->bind_attribute_store(name,store_);
1402 1864 register_me(store_);
1403 1864 }
1404
1405 /**
1406 * \brief Destroys this attribute in the AttributesManager.
1407 * \details On exit, the attribute is no-longer accessible in
1408 * the AttributesManager, its name is available again, and
1409 * this attribute is in the unbound state.
1410 */
1411 468 void destroy() {
1412
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 234 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
468 geo_assert(is_bound());
1413 468 unregister_me(store_);
1414 468 manager_->delete_attribute_store(store_);
1415 468 store_ = nullptr;
1416 468 manager_ = nullptr;
1417 468 }
1418
1419 /**
1420 * \brief Sets the dimension.
1421 * \details The dimension is 1 for standard attributes and
1422 * can be greater for vector attributes. The existing
1423 * fields are kept. If the new dimension is greater than
1424 * the old one, then new fields are initialized to the default
1425 * value for the attribute type.
1426 * \param[in] new_dim the new dimension
1427 */
1428 1400 void redim(index_t new_dim) {
1429
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 700 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1400 geo_assert(is_bound());
1430 1400 store_->redim(new_dim);
1431 1400 }
1432
1433 /**
1434 * \brief Attribute destructor
1435 * \details
1436 * The attribute is not destroyed, it can be retrieved later
1437 * by binding with the same name. To destroy the attribute,
1438 * use destroy() instead.
1439 */
1440 16899 ~AttributeBase() {
1441
2/2
✓ Branch 1 taken 2264 times.
✓ Branch 2 taken 6186 times.
16899 if(is_bound()) {
1442 4527 unbind();
1443 }
1444 16899 }
1445
1446
1447 /**
1448 * \brief Tests whether an attribute with the specified name and with
1449 * corresponding type exists in an AttributesManager.
1450 * \param[in] manager a reference to the AttributesManager
1451 * \param[in] name the name of the attribute
1452 * \param[in] dim dimension, or 0 if any dimension can match
1453 */
1454 106 static bool is_defined(
1455 AttributesManager& manager, const std::string& name,
1456 index_t dim = 0
1457 ) {
1458 106 AttributeStore* store = manager.find_attribute_store(name);
1459 return (
1460 106 store != nullptr &&
1461
3/6
✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 106 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 106 times.
106 can_bind_to(store) &&
1462 ((dim == 0) || (store->dimension() == dim))
1463 106 );
1464 }
1465
1466 /**
1467 * \brief Gets the size.
1468 * \return The number of items in this attribute.
1469 */
1470 index_t size() const {
1471 return size_;
1472 }
1473
1474 /**
1475 * \brief Sets all the elements of this Attribute to
1476 * zero.
1477 */
1478 void zero() {
1479 geo_debug_assert(is_bound());
1480 store_->zero();
1481 }
1482
1483 /**
1484 * \brief Tests whether get_vector() can be called on this
1485 * Attribute.
1486 * \details get_vector() can be called if this attribute is
1487 * bound and if type T corresponds to the type used to create
1488 * the attribute.
1489 * \note Advanced users only. Most client code will not need
1490 * to use this function.
1491 */
1492 bool can_get_vector() {
1493 return(
1494 dynamic_cast<TypedAttributeStore<ST>*>(store_) != nullptr
1495 );
1496 }
1497
1498 /**
1499 * \brief Gets a reference to the internal vector<T> used to
1500 * store the attribute.
1501 * \details It is forbidden to modify the size of the returned
1502 * vector.
1503 * \return a reference to the vector<T> used to store the
1504 * attribute.
1505 * \note Advanced users only. Most client code will not need
1506 * to use this function.
1507 */
1508 vector<ST>& get_vector() {
1509 TypedAttributeStore<ST>* typed_store =
1510 dynamic_cast<TypedAttributeStore<ST>*>(store_);
1511 geo_assert(typed_store != nullptr);
1512 return typed_store->get_vector();
1513 }
1514
1515 /**
1516 * \brief Gets a const reference to the internal vector<T> used to
1517 * store the attribute.
1518 * \return a const reference to the vector<T> used to store the
1519 * attribute.
1520 */
1521 const vector<ST>& get_vector() const {
1522 TypedAttributeStore<ST>* typed_store =
1523 dynamic_cast<TypedAttributeStore<ST>*>(store_);
1524 geo_assert(typed_store != nullptr);
1525 return typed_store->get_vector();
1526 }
1527
1528 /**
1529 * \brief Gets the AttributesManager this Attribute is bound to.
1530 * \return a pointer to the attributes manager.
1531 */
1532 AttributesManager* manager() const {
1533 return manager_;
1534 }
1535
1536 protected:
1537
1538 /**
1539 * \brief Tests whether this Attribute can be bound to an AttributeStore
1540 * \param[in] store the AttributeStore
1541 * \retval true if \p store has elements with a compatible type
1542 * \retval false otherwise
1543 */
1544 2865 static bool can_bind_to(const AttributeStore* store) {
1545 return (
1546
4/12
✓ Branch 2 taken 1949 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1949 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1949 times.
✓ Branch 10 taken 1949 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
11460 store->elements_type_matches(typeid(UT).name()) ||
1547
2/14
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1949 times.
✓ Branch 12 taken 1949 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
2865 store->elements_type_matches(typeid(ST).name())
1548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1949 times.
5730 );
1549 }
1550
1551 protected:
1552 AttributesManager* manager_;
1553 AttributeStore* store_;
1554 bool existed_already_;
1555 } ;
1556
1557 /*********************************************************************/
1558
1559 /**
1560 * \brief Manages an attribute attached to a set of object.
1561 * \tparam T type of the attributes. Needs to be a basic type
1562 * or a plain ordinary datatype (classes that do dynamic
1563 * memory allocation are not allowed here).
1564 */
1565 template <class T> class Attribute : public AttributeBase<T> {
1566 public:
1567 typedef AttributeBase<T> superclass;
1568
1569 /**
1570 * \brief Creates an uninitialized (unbound) Attribute.
1571 */
1572 12936 Attribute() : superclass() {
1573 12936 }
1574
1575 /**
1576 * \brief Creates or retrieves a persistent attribute attached to
1577 * a given AttributesManager.
1578 * \details If the attribute already exists with the specified
1579 * name in the AttributesManager then it is retrieved, else
1580 * it is created and bound to the name.
1581 * \param[in] manager a reference to the AttributesManager
1582 * \param[in] name name of the attribute
1583 */
1584 954 Attribute(AttributesManager& manager, const std::string& name) :
1585 954 superclass(manager, name) {
1586 954 }
1587
1588 /**
1589 * \brief Gets a modifiable element by index
1590 * \param [in] i index of the element
1591 * \return a modifiable reference to the \p i%th element
1592 */
1593 300949804 T& operator[](index_t i) {
1594
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 255205128 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
300949804 geo_debug_assert(superclass::is_bound());
1595
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 255205128 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
300949804 geo_debug_assert(i < superclass::nb_elements());
1596 300949804 return ((T*)(void*)superclass::base_addr_)[i];
1597 }
1598
1599 /**
1600 * \brief Gets an element by index
1601 * \param [in] i index of the element
1602 * \return a const reference to the \p i%th element
1603 */
1604 217281221 const T& operator[](index_t i) const {
1605
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 110152413 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
217281221 geo_debug_assert(superclass::is_bound());
1606
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 110152413 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
217281221 geo_debug_assert(i < superclass::nb_elements());
1607 217281221 return ((const T*)(void*)superclass::base_addr_)[i];
1608 }
1609
1610 /**
1611 * \brief Sets all the elements in this attribute
1612 * to a specified value.
1613 * \param[in] val the value
1614 */
1615 void fill(const T& val) {
1616 geo_debug_assert(superclass::is_bound());
1617 for(index_t i=0; i<superclass::nb_elements(); ++i) {
1618 (*this)[i] = val;
1619 }
1620 }
1621
1622 /**
1623 * \brief Copies all the values from another attribute.
1624 * \param[in] rhs the attribute to be copied.
1625 * \details rhs needs to have the same size and dimension
1626 * as this Attribute.
1627 */
1628 void copy(const Attribute<T>& rhs) {
1629 geo_assert(rhs.size() == superclass::size());
1630 geo_assert(rhs.dimension() == superclass::dimension());
1631 for(index_t i=0; i<superclass::nb_elements(); ++i) {
1632 (*this)[i] = rhs[i];
1633 }
1634 }
1635
1636 /**
1637 * \brief Gets the pointer to the data.
1638 * \return a pointer to the stored array.
1639 */
1640 T* data() {
1641 return (T*)AttributeStoreObserver::base_addr_;
1642 }
1643
1644 /**
1645 * \brief Gets the pointer to the data.
1646 * \return a const pointer to the stored array.
1647 */
1648 const T* data() const {
1649 return (const T*)AttributeStoreObserver::base_addr_;
1650 }
1651
1652
1653 private:
1654 /**
1655 * \brief Forbids copy.
1656 */
1657 Attribute(const Attribute<T>& rhs) = delete;
1658 /**
1659 * \brief Forbids copy.
1660 */
1661 Attribute<T>& operator=(const Attribute<T>& rhs) = delete;
1662 };
1663
1664 /*********************************************************************/
1665
1666 /**
1667 * \brief Specialization of Attribute for booleans
1668 * \details Attribute needs a specialization for bool, since
1669 * vector<bool> uses compressed storage (1 bit per boolean),
1670 * that is not compatible with the attribute management
1671 * mechanism. This wrapper class uses an Attribute<Numeric::uint8>
1672 * and does the appropriate conversions, using an accessor class.
1673 */
1674 template <> class Attribute<bool> :
1675 public AttributeBase<bool,Numeric::uint8> {
1676 public:
1677 typedef AttributeBase<bool,Numeric::uint8> superclass;
1678
1679 60 Attribute() : superclass() {
1680 60 }
1681
1682 1028 Attribute(AttributesManager& manager, const std::string& name) :
1683 1028 superclass(manager,name) {
1684 1028 }
1685
1686 class BoolAttributeAccessor;
1687
1688 /**
1689 * \brief Accessor class for adapting Attribute<bool>
1690 * indexing.
1691 */
1692 class ConstBoolAttributeAccessor {
1693 public:
1694 /**
1695 * \brief ConstBoolAttributeAccessor constructor.
1696 */
1697 518392 ConstBoolAttributeAccessor(
1698 const Attribute<bool>& attribute,
1699 index_t index
1700 518392 ) :
1701 518392 attribute_(&attribute),
1702 518392 index_(index) {
1703 518392 }
1704
1705 /**
1706 * \brief Converts a BoolAttributeAccessor to a bool.
1707 * \details Performs the actual lookup.
1708 */
1709 518392 operator bool() const {
1710 518392 return (attribute_->element(index_) != 0);
1711 }
1712
1713 private:
1714 const Attribute<bool>* attribute_;
1715 index_t index_;
1716
1717 friend class BoolAttributeAccessor;
1718 };
1719
1720 /**
1721 * \brief Accessor class for adapting Attribute<bool>
1722 * indexing.
1723 */
1724 class BoolAttributeAccessor {
1725 public:
1726 /**
1727 * \brief BoolAttributeAccessor constructor.
1728 */
1729 3903740 BoolAttributeAccessor(
1730 Attribute<bool>& attribute,
1731 index_t index
1732 3903740 ) :
1733 3903740 attribute_(&attribute),
1734 3903740 index_(index) {
1735 3903740 }
1736
1737 /**
1738 * \brief Converts a BoolAttributeAccessor to a bool.
1739 * \details Performs the actual lookup.
1740 */
1741 2065082 operator bool() const {
1742 2065082 return (attribute_->element(index_) != 0);
1743 }
1744
1745 /**
1746 * \brief Copy-constructor.
1747 * \param[in] rhs a const reference to the
1748 * BoolAttributeAccessor to be copied.
1749 */
1750 BoolAttributeAccessor(const BoolAttributeAccessor& rhs) {
1751 attribute_ = rhs.attribute_;
1752 index_ = rhs.index_;
1753 }
1754
1755 /**
1756 * \brief Assigns a bool to a BoolAttributeAccessor.
1757 * \details Stores the boolean into the Attribute.
1758 */
1759 1838658 BoolAttributeAccessor& operator=(bool x) {
1760 1838658 attribute_->element(index_) = Numeric::uint8(x);
1761 1838658 return *this;
1762 }
1763
1764 /**
1765 * \brief Copies a bool from another attribute.
1766 * \param[in] rhs a const reference to the BoolAttributeAccessor
1767 * to be copied.
1768 */
1769 BoolAttributeAccessor& operator=(
1770 const BoolAttributeAccessor& rhs
1771 ) {
1772 if(&rhs != this) {
1773 attribute_->element(index_) =
1774 rhs.attribute_->element(rhs.index_);
1775 }
1776 return *this;
1777 }
1778
1779 /**
1780 * \brief Copies a bool from another attribute.
1781 * \param[in] rhs a const reference to the
1782 * ConstBoolAttributeAccessor to be copied.
1783 */
1784 BoolAttributeAccessor& operator=(
1785 const ConstBoolAttributeAccessor& rhs
1786 ) {
1787 attribute_->element(index_) =
1788 rhs.attribute_->element(rhs.index_);
1789 return *this;
1790 }
1791
1792 private:
1793 Attribute<bool>* attribute_;
1794 index_t index_;
1795 };
1796
1797
1798 3903740 BoolAttributeAccessor operator[](index_t i) {
1799 3903740 return BoolAttributeAccessor(*this,i);
1800 }
1801
1802 518392 ConstBoolAttributeAccessor operator[](index_t i) const {
1803 518392 return ConstBoolAttributeAccessor(*this,i);
1804 }
1805
1806 /**
1807 * \brief Sets all the elements in this attribute
1808 * to a specified value.
1809 * \param[in] val the value
1810 */
1811 void fill(bool val) {
1812 for(index_t i=0; i<superclass::nb_elements(); ++i) {
1813 element(i) = Numeric::uint8(val);
1814 }
1815 }
1816
1817 /**
1818 * \brief Copies all the values from another attribute.
1819 * \param[in] rhs the attribute to be copied.
1820 * \details rhs needs to have the same size and dimension
1821 * as this Attribute.
1822 */
1823 void copy(const Attribute<bool>& rhs) {
1824 geo_assert(rhs.size() == superclass::size());
1825 geo_assert(rhs.dimension() == superclass::dimension());
1826 for(index_t i=0; i<superclass::nb_elements(); ++i) {
1827 element(i) = rhs.element(i);
1828 }
1829 }
1830
1831 protected:
1832
1833 friend class BoolAttributeAccessor;
1834 friend class ConstBoolAttributeAccessor;
1835
1836 /**
1837 * \brief Gets a modifiable element by index
1838 * \param [in] i index of the element
1839 * \return a modifiable reference to the \p i%th element
1840 */
1841 3903740 Numeric::uint8& element(index_t i) {
1842
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 3903740 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
3903740 geo_debug_assert(i < superclass::nb_elements());
1843 3903740 return ((Numeric::uint8*)superclass::base_addr_)[i];
1844 }
1845
1846 /**
1847 * \brief Gets an element by index
1848 * \param [in] i index of the element
1849 * \return a const reference to the \p i%th element
1850 */
1851 518392 const Numeric::uint8& element(index_t i) const {
1852
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 518392 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
518392 geo_debug_assert(i < superclass::nb_elements());
1853 518392 return ((const Numeric::uint8*)superclass::base_addr_)[i];
1854 }
1855
1856 private:
1857 /**
1858 * \brief Forbids copy.
1859 */
1860 Attribute(const Attribute<bool>& rhs) = delete;
1861 /**
1862 * \brief Forbids copy.
1863 */
1864 Attribute<bool>& operator=(const Attribute<bool>& rhs) = delete;
1865 } ;
1866
1867 /***********************************************************/
1868
1869 /**
1870 * \brief Access to an attribute as a double regardless its type.
1871 * \details The attribute can be an element of a vector attribute.
1872 */
1873 class GEOGRAM_API ScalarAttributeAdapterBase :
1874 public AttributeStoreObserver {
1875
1876 public:
1877 /**
1878 * \brief Internal representation of the attribute.
1879 */
1880 enum ElementType {
1881 ET_NONE=0,
1882 ET_UINT8=1,
1883 ET_INT8=2,
1884 ET_UINT32=3,
1885 ET_INT32=4,
1886 ET_FLOAT32=5,
1887 ET_FLOAT64=6,
1888 ET_VEC2=7,
1889 ET_VEC3=8
1890 };
1891
1892
1893 /**
1894 * \brief Accessor class used by ScalarAttributeAdapter to
1895 * implement indexing operator.
1896 */
1897 class Accessor {
1898 public:
1899 Accessor(
1900 ScalarAttributeAdapterBase& attribute,
1901 index_t index
1902 ) : attribute_(attribute), index_(index) {
1903 }
1904
1905 operator double() const {
1906 return attribute_.get_element_as_double(index_);
1907 }
1908
1909 void operator=(double x) {
1910 attribute_.set_element_as_double(index_, x);
1911 }
1912
1913 private:
1914 ScalarAttributeAdapterBase& attribute_;
1915 index_t index_;
1916 };
1917
1918 /**
1919 * \brief Accessor class used by ScalarAttributeAdapter to
1920 * implement indexing operator (const version).
1921 */
1922 class ConstAccessor {
1923 public:
1924 ConstAccessor(
1925 const ScalarAttributeAdapterBase& attribute,
1926 index_t index
1927 ) : attribute_(attribute), index_(index) {
1928 }
1929
1930 operator double() const {
1931 return attribute_.get_element_as_double(index_);
1932 }
1933
1934 private:
1935 const ScalarAttributeAdapterBase& attribute_;
1936 index_t index_;
1937 };
1938
1939 /**
1940 * \brief ScalarAttributeAdapterBase constructor.
1941 */
1942 ScalarAttributeAdapterBase() :
1943 manager_(nullptr),
1944 store_(nullptr),
1945 element_type_(ET_NONE),
1946 element_index_(index_t(-1)) {
1947 }
1948
1949 /**
1950 * \brief ScalarAttributeAdapterBase constructor.
1951 * \details Retrieves a persistent attribute attached to
1952 * a given AttributesManager.
1953 * \param[in] manager a reference to the AttributesManager
1954 * \param[in] name name of the attribute with an optional index,
1955 * for instance, "foobar[5]" refers to the 5th coordinate of
1956 * the "foobar" vector attribute.
1957 */
1958 ScalarAttributeAdapterBase(
1959 const AttributesManager& manager, const std::string& name
1960 ) :
1961 manager_(nullptr),
1962 store_(nullptr) {
1963 bind_if_is_defined(manager, name);
1964 }
1965
1966 /**
1967 * \brief Tests whether an Attribute is bound.
1968 * \retval true if this Attribute is bound
1969 * \retval false otherwise
1970 */
1971 bool is_bound() const {
1972 return (store_ != nullptr);
1973 }
1974
1975 /**
1976 * \brief Unbinds this Attribute.
1977 * \pre is_bound()
1978 */
1979 void unbind() {
1980 geo_assert(is_bound());
1981 unregister_me(const_cast<AttributeStore*>(store_));
1982 manager_ = nullptr;
1983 store_ = nullptr;
1984 element_type_ = ET_NONE;
1985 element_index_ = index_t(-1);
1986 }
1987
1988 /**
1989 * \brief Binds this Attribute to an AttributesManager if it
1990 * already exists in the AttributesManager.
1991 * \param[in] manager a reference to the AttributesManager
1992 * \param[in] name name of the attribute with an optional index,
1993 * for instance, "foobar[5]" refers to the 5th coordinate of
1994 * the "foobar" vector attribute.
1995 * \pre !is_bound()
1996 */
1997 void bind_if_is_defined(
1998 const AttributesManager& manager, const std::string& name
1999 );
2000
2001 /**
2002 * \brief ReadonlyScalarAttributeAdapterBase destructor
2003 * \details
2004 * The attribute is not destroyed, it can be retrieved later
2005 * by binding with the same name. To destroy the attribute,
2006 * use destroy() instead.
2007 */
2008 ~ScalarAttributeAdapterBase() {
2009 if(is_bound()) {
2010 unbind();
2011 }
2012 }
2013
2014 /**
2015 * \brief Tests whether an attribute with the specified name and with
2016 * a type that can be converted to double exists in an
2017 * AttributesManager.
2018 * \param[in] manager a reference to the AttributesManager
2019 * \param[in] name the name of the attribute with an optional index,
2020 * for instance, "foobar[5]" refers to the 5th coordinate of
2021 * the "foobar" vector attribute.
2022 */
2023 static bool is_defined(
2024 const AttributesManager& manager, const std::string& name
2025 );
2026
2027 /**
2028 * \brief Gets the size.
2029 * \return The number of items in this attribute.
2030 */
2031 index_t size() const {
2032 return (store_ == nullptr) ? 0 : store_->size();
2033 }
2034
2035 /**
2036 * \brief Gets the internal representation of the
2037 * elements.
2038 * \return one of ET_NONE (if unbound), ET_UINT8,
2039 * ET_INT8, ET_UINT32, ET_INT32, ET_FLOAT32,
2040 * ET_FLOAT64, ET_VEC2, ET_VEC3
2041 */
2042 ElementType element_type() const {
2043 return element_type_;
2044 }
2045
2046 /**
2047 * \brief Gets the element index.
2048 * \return the index of the elements accessed in
2049 * the bound attribute, or 0 if the bound attribute
2050 * is scalar.
2051 */
2052 index_t element_index() const {
2053 return element_index_;
2054 }
2055
2056 /**
2057 * \brief Gets the AttributeStore.
2058 * \return a const pointer to the AttributeStore.
2059 */
2060 const AttributeStore* attribute_store() const {
2061 return store_;
2062 }
2063
2064
2065 /**
2066 * \brief Tests whether a ScalarAttributeAdapterBase can
2067 * be bound to a given attribute store.
2068 * \param[in] store a pointer to the attribute store.
2069 * \retval true if it can be bound
2070 * \retval false otherwise
2071 */
2072 static bool can_be_bound_to(const AttributeStore* store) {
2073 return element_type(store) != ET_NONE;
2074 }
2075
2076 /**
2077 * \brief Gets the number of scalar components per item in an
2078 * AttributeStore.
2079 * \param[in] store a pointer to the attribute store.
2080 * \return the number of scalar components per item in an
2081 * AttributeStore.
2082 */
2083 static index_t nb_scalar_elements_per_item(const AttributeStore* store);
2084
2085 protected:
2086 /**
2087 * \brief Gets the base attribute name from a compound name.
2088 * \param[in] name the string with the attribute name and optional
2089 * index. For instance, "foobar[5]" refers to the 5th coordinate of
2090 * the "foobar" vector attribute.
2091 * \return the attribute name. For instance, for "foobar[5]", it
2092 * returns "foobar".
2093 */
2094 static std::string attribute_base_name(const std::string& name);
2095
2096 /**
2097 * \brief Gets the base attribute name from a compound name.
2098 * \param[in] name the string with the attribute name and optional
2099 * index. For instance, "foobar[5]" refers to the 5th coordinate of
2100 * the "foobar" vector attribute.
2101 * \return the index or zero if no index was specified. For instance,
2102 * for "foobar[5]" it returns 5, and for "foobar" it returns 0
2103 */
2104 static index_t attribute_element_index(const std::string& name);
2105
2106 /**
2107 * \brief Gets the element type stored in an AttributeStore.
2108 * \param[in] store a const pointer to the AttributeStore
2109 * \return one of ET_UINT8, ET_INT8, ET_UINT32, ET_INT32,
2110 * ET_FLOAT32, ET_FLOAT64 if the type of the attribute is
2111 * compatible with those types, or ET_NONE if it is incompatible.
2112 */
2113 static ElementType element_type(const AttributeStore* store);
2114
2115 /**
2116 * \brief Gets an attribute value
2117 * \param[in] i the index of the item
2118 * \return the value of the property, convertex
2119 * into a double
2120 * \pre is_bound() && i < size()
2121 */
2122 double get_element_as_double(index_t i) const {
2123 double result = 0.0;
2124 switch(element_type()) {
2125 case ET_UINT8:
2126 result = double(get_element<Numeric::uint8>(i));
2127 break;
2128 case ET_INT8:
2129 result = double(get_element<Numeric::int8>(i));
2130 break;
2131 case ET_UINT32:
2132 result = double(get_element<Numeric::uint32>(i));
2133 break;
2134 case ET_INT32:
2135 result = double(get_element<Numeric::int32>(i));
2136 break;
2137 case ET_FLOAT32:
2138 result = double(get_element<Numeric::float32>(i));
2139 break;
2140 case ET_FLOAT64:
2141 result = double(get_element<Numeric::float64>(i));
2142 break;
2143 case ET_VEC2:
2144 result = double(get_element<Numeric::float64>(i,2));
2145 break;
2146 case ET_VEC3:
2147 result = double(get_element<Numeric::float64>(i,3));
2148 break;
2149 case ET_NONE:
2150 geo_assert_not_reached;
2151 }
2152 return result;
2153 }
2154
2155 /**
2156 * \brief Gets an element.
2157 * \details Stored element type needs to match T,
2158 * no verification is made
2159 * \param[in] i index of the element
2160 * \param[in] multiplier multiplier applied to the index before fetching
2161 * the raw pointer.
2162 */
2163 template <class T> T get_element(index_t i,index_t multiplier=1) const {
2164 geo_debug_assert(is_bound());
2165 geo_debug_assert(i < size());
2166 return static_cast<const T*>(store_->data())[
2167 (i * store_->dimension() * multiplier) +
2168 element_index_
2169 ];
2170 }
2171
2172 /**
2173 * \brief Sets an attribute value
2174 * \param[in] i the index of the element
2175 * \param[in] value the new value of the element
2176 * \pre is_bound() && i < size()
2177 */
2178 double set_element_as_double(index_t i, double value) {
2179 double result = 0.0;
2180 switch(element_type()) {
2181 case ET_UINT8:
2182 set_element<Numeric::uint8>(Numeric::uint8(value), i);
2183 break;
2184 case ET_INT8:
2185 set_element<Numeric::int8>(Numeric::int8(value),i);
2186 break;
2187 case ET_UINT32:
2188 set_element<Numeric::uint32>(Numeric::uint32(value),i);
2189 break;
2190 case ET_INT32:
2191 set_element<Numeric::int32>(Numeric::int32(value),i);
2192 break;
2193 case ET_FLOAT32:
2194 set_element<Numeric::float32>(Numeric::float32(value),i);
2195 break;
2196 case ET_FLOAT64:
2197 set_element<Numeric::float64>(Numeric::float64(value),i);
2198 break;
2199 case ET_VEC2:
2200 set_element<Numeric::float64>(Numeric::float64(value),i,2);
2201 break;
2202 case ET_VEC3:
2203 set_element<Numeric::float64>(Numeric::float64(value),i,3);
2204 break;
2205 case ET_NONE:
2206 geo_assert_not_reached;
2207 }
2208 return result;
2209 }
2210
2211 /**
2212 * \brief Sets an element.
2213 * \details Stored element type needs to match T,
2214 * no verification is made
2215 * \param[in] value the value of the element to be stored
2216 * \param[in] i index of the element
2217 * \param[in] multiplier multiplier applied to the index before fetching
2218 * the raw pointer.
2219 */
2220 template <class T> void set_element(
2221 T value, index_t i, index_t multiplier=1
2222 ) const {
2223 geo_debug_assert(is_bound());
2224 geo_debug_assert(i < size());
2225 const_cast<T*>(static_cast<const T*>(store_->data()))[
2226 (i * store_->dimension() * multiplier) +
2227 element_index_
2228 ] = value;
2229 }
2230
2231 protected:
2232 const AttributesManager* manager_;
2233 const AttributeStore* store_;
2234 ElementType element_type_;
2235 index_t element_index_;
2236 };
2237
2238 /***********************************************************/
2239
2240 /**
2241 * \brief Readonly access to an attribute as a double regardless its type.
2242 * \details The attribute can be an element of a vector attribute.
2243 */
2244 class ReadOnlyScalarAttributeAdapter : public ScalarAttributeAdapterBase {
2245 public:
2246 ReadOnlyScalarAttributeAdapter() : ScalarAttributeAdapterBase() {
2247 }
2248
2249 ReadOnlyScalarAttributeAdapter(
2250 const AttributesManager& manager, const std::string& name
2251 ) : ScalarAttributeAdapterBase(manager, name) {
2252 }
2253
2254 /**
2255 * \brief Gets a property value
2256 * \param[in] i the index of the item
2257 * \return the value of the property, convertex
2258 * into a double
2259 * \pre is_bound() && i < size()
2260 */
2261 double operator[](index_t i) {
2262 return get_element_as_double(i);
2263 }
2264 };
2265
2266 /***********************************************************/
2267
2268 /**
2269 * \brief Readwrite access to an attribute as a double regardless its type.
2270 * \details The attribute can be an element of a vector attribute.
2271 */
2272 class ReadWriteScalarAttributeAdapter : public ScalarAttributeAdapterBase {
2273 public:
2274 ReadWriteScalarAttributeAdapter() : ScalarAttributeAdapterBase() {
2275 }
2276
2277 ReadWriteScalarAttributeAdapter(
2278 const AttributesManager& manager, const std::string& name
2279 ) : ScalarAttributeAdapterBase(manager, name) {
2280 }
2281
2282 Accessor operator[](index_t i) {
2283 return Accessor(*this, i);
2284 }
2285
2286 ConstAccessor operator[](index_t i) const {
2287 return ConstAccessor(*this, i);
2288 }
2289
2290 protected:
2291 };
2292
2293
2294 }
2295
2296 #endif
2297