1 /*
2  *  Copyright (c) 2012-2014, Bruno Levy
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  *  If you modify this software, you should include a notice giving the
30  *  name of the person performing the modification, the date of modification,
31  *  and the reason for such modification.
32  *
33  *  Contact: Bruno Levy
34  *
35  *     Bruno.Levy@inria.fr
36  *     http://www.loria.fr/~levy
37  *
38  *     ALICE Project
39  *     LORIA, INRIA Lorraine,
40  *     Campus Scientifique, BP 239
41  *     54506 VANDOEUVRE LES NANCY CEDEX
42  *     FRANCE
43  *
44  */
45 
46 #ifndef GEOGRAM_BASIC_ATTRIBUTES
47 #define GEOGRAM_BASIC_ATTRIBUTES
48 
49 
50 #include <geogram/basic/common.h>
51 #include <geogram/basic/memory.h>
52 #include <geogram/basic/numeric.h>
53 #include <geogram/basic/process.h>
54 #include <geogram/basic/geofile.h>
55 #include <geogram/basic/logger.h>
56 
57 #include <map>
58 #include <typeinfo>
59 #include <set>
60 #include <type_traits>
61 
62 /**
63  * \file geogram/basic/attributes.h
64  * \brief Generic mechanism for attributes.
65  */
66 
67 namespace GEO {
68 
69     class AttributeStore;
70 
71     /**
72      * \brief Base class for attributes. They are notified
73      *  whenever the AttributeStore is modified.
74      */
75     class GEOGRAM_API AttributeStoreObserver {
76     public:
77 
78         /**
79          * \brief Creates a new uninitialied AttributeStore.
80          */
AttributeStoreObserver()81         AttributeStoreObserver() :
82 	   base_addr_(nullptr), size_(0), dimension_(0),
83 	   disconnected_(false) {
84         }
85 
86         /**
87          * \brief Callback function, called by the AttributeStore
88          *  whenever it is modified.
89          * \param[in] base_addr new base address of the AttributeStore
90          * \param[in] size new number of items in the AttributeStore
91          * \param[in] dim  new dimension, i.e. number of elements per item
92          */
notify(Memory::pointer base_addr,index_t size,index_t dim)93         void notify(
94             Memory::pointer base_addr, index_t size, index_t dim
95         ) {
96             base_addr_ = base_addr;
97             size_ = size;
98             dimension_ = dim;
99         }
100 
101         /**
102          * \brief Gets the size.
103          * \return the number of items
104          */
size()105         index_t size() const {
106             return size_;
107         }
108 
109         /**
110          * \brief Gets the dimension.
111          * \return the number of elements per item
112          */
dimension()113         index_t dimension() const {
114             return dimension_;
115         }
116 
117         /**
118          * \brief Gets the total number of elements.
119          * \details This corresponds to one position past
120          *  the last valid index.
121          * \return the total number of elements.
122          */
nb_elements()123         index_t nb_elements() const {
124             return size_ * dimension_;
125         }
126 
127 	/**
128 	 * \brief Registers this observer to an AttributeStore.
129 	 * \param[in] store a pointer to the AttributeStore.
130 	 */
131         void register_me(AttributeStore* store);
132 
133 	/**
134 	 * \brief Unregisters this observer from an AttributeStore.
135 	 * \param[in] store a pointer to the AttributeStore.
136 	 */
137         void unregister_me(AttributeStore* store);
138 
139 	/**
140 	 * \brief Disconnects this AttributeStoreObserver from its
141 	 *  AttributeStore.
142 	 * \details This function is called whenever the AttributeManager is
143 	 *  destroyed before the Attributes (can occur when using Lua scripting
144 	 *  with Attribute wrapper objects).
145 	 */
disconnect()146 	void disconnect() {
147 	    base_addr_ = nullptr;
148 	    size_ = 0;
149 	    dimension_ = 0;
150 	    disconnected_ = true;
151 	}
152 
153     protected:
154         Memory::pointer base_addr_;
155         index_t size_;
156         index_t dimension_;
157 	bool disconnected_;
158     };
159 
160 
161     /*********************************************************************/
162 
163 
164     /**
165      * \brief Internal class for creating an AttributeStore
166      *  from the type name of its elements.
167      */
168     class GEOGRAM_API AttributeStoreCreator : public Counted {
169     public:
170 
171         /**
172          * \brief AttributeStoreCreator destructor.
173          */
174         virtual ~AttributeStoreCreator();
175 
176         /**
177          * \brief Creates a new attribute store.
178          * \param[in] dimension number of elements in each item
179          * \return a pointer to the newly created AttributeStore
180          */
181         virtual AttributeStore* create_attribute_store(index_t dimension) = 0;
182 
183 
184     private:
185         std::string element_type_name_;
186         std::string element_typeid_name_;
187     };
188 
189     /**
190      * \brief An automatic reference-counted pointer to
191      *  an AttributeStoreCreator.
192      */
193     typedef SmartPointer<AttributeStoreCreator> AttributeStoreCreator_var;
194 
195     /**
196      * \brief Notifies a set of AttributeStoreObservers
197      *  each time the stored array changes size and/or
198      *  base address and/or dimension.
199      */
200     class GEOGRAM_API AttributeStore {
201     public:
202         /**
203          * \brief AttributeStore constructor.
204          * \param[in] elemsize size of one element,
205          *  in bytes.
206          * \param[in] dim number of elements in
207          *  each item. Default is 1 for standard
208          *  attributes and can be greater for vector
209          *  attributes.
210          */
211         AttributeStore(index_t elemsize, index_t dim=1);
212 
213         /**
214          * \brief AttributeStore destructor.
215          */
216         virtual ~AttributeStore();
217 
218 
219         /**
220          * \brief Tests whether this AttributeStore stores
221          *  elements of a given type.
222          * \param[in] type_name the name of the type, as given by
223          *     typeid(T).name()
224          * \retval true if this AttributeStore stores elements
225          *   of type \p type_name
226          * \retval false otherwise
227          */
228         virtual bool elements_type_matches(
229             const std::string& type_name
230         ) const = 0;
231 
232         /**
233          * \brief Gets the typeid name of the element type stored
234          *  in this AttributeStore.
235          * \return the typeid name, as a string.
236          */
237         virtual std::string element_typeid_name() const = 0;
238 
239         /**
240          * \brief Gets the size.
241          * \return the number of items
242          */
size()243         index_t size() const {
244             return cached_size_;
245         }
246 
247 	/**
248 	 * \brief Gets the capacity.
249 	 * \return the number of items that can be stored without
250 	 *  a reallocation.
251 	 */
capacity()252 	index_t capacity() const {
253 	    return cached_capacity_;
254 	}
255 
256         /**
257          * \brief Resizes this AttributeStore
258          * \param[in] new_size new number of items
259          */
260         virtual void resize(index_t new_size) = 0;
261 
262         /**
263          * \brief Reserves memory.
264          * \param[in] new_capacity total number of items to
265 	 *  be stored.
266          */
267 	virtual void reserve(index_t new_capacity) = 0;
268 
269         /**
270          * \brief Resizes this AttributeStore to 0.
271          * \param[in] keep_memory if true, then memory
272          *  is kept reserved for future use.
273          */
274         virtual void clear(bool keep_memory = false) = 0;
275 
276         /**
277          * \brief Tests whether observers listen to this AttributeStore.
278          * \retval true if at least one observer is bound to this AttributeStore
279          * \retval false otherwise
280          */
has_observers()281         bool has_observers() const {
282             return !observers_.empty();
283         }
284 
285         /**
286          * \brief Gets the dimension.
287          * \details The dimension is 1 for standard attributes and
288          *  can be greater for vector attributes.
289          */
dimension()290         index_t dimension() const {
291             return dimension_;
292         }
293 
294         /**
295          * \brief Sets the dimension.
296          * \details The dimension is 1 for standard attributes and
297          *  can be greater for vector attributes. The existing
298          *  fields are kept. If the new dimension is greater than
299          *  the old one, then new fields are initialized to the default
300          *  value for the attribute type.
301          * \param[in] dim the new dimension
302          */
303         virtual void redim(index_t dim) = 0;
304 
305 
306         /**
307          * \brief Applies a permutation to the stored attributes.
308          * \details Applying a permutation to the data is equivalent
309          *  to:
310          * \code
311          * for(i=0; i<permutation.size(); i++) {
312          *    data2[i] = data[permutation[i]]
313          * }
314          * data = data2 ;
315          * \endcode
316          * But it is done in-place.
317          * \param[in] permutation the permutation.
318          *  It is temporarily changed during execution of the
319          *  function, but identical to the input on exit.
320          * \note This function uses memcpy(). If required, it
321          *  can be overloaded in derived classes.
322          */
323         virtual void apply_permutation(
324             const vector<index_t>& permutation
325         );
326 
327         /**
328          * \brief Compresses the stored attributes, by
329          *  applying an index mapping that fills-in the gaps.
330          * \details This is equivalent to:
331          * \code
332          * for(i=0; i<size(); i++) {
333          *    if(old2new[i] != index_t(-1)) {
334          *       data2[old2new[i]] = data[i];
335          *    }
336          * }
337          * data = data2 ;
338          * \endcode
339          * \param[in] old2new the index mapping to be applied.
340          * \pre old2new[i] <= i || old2new[i] == index_t(-1)
341          * \note This function uses memcpy(). If required, it
342          *  can be overloaded in derived classes.
343          */
344         virtual void compress(const vector<index_t>& old2new);
345 
346         /**
347          * \brief Zeroes all the memory associated with this
348          *  AttributeStore.
349          * \details Subclasses may overload this function for
350          *  attributes that have non "plain ordinary datatypes"
351          *  and that need a more elaborate initialization mechanism.
352          */
353         virtual void zero();
354 
355         /**
356          * \brief Creates a new AttributeStore that is a carbon copy
357          *  of this AttributeStore.
358          * \details Only the data is copied, observers are not copied.
359          */
360         virtual AttributeStore* clone() const = 0;
361 
362 
363         /**
364          * \brief Copies an item
365          * \param[in] to index of the destination item
366          * \param[in] from index of the source item
367          */
copy_item(index_t to,index_t from)368         void copy_item(index_t to, index_t from) {
369             geo_debug_assert(from < cached_size_);
370             geo_debug_assert(to < cached_size_);
371             index_t item_size = element_size_ * dimension_;
372             Memory::copy(
373                 cached_base_addr_+to*item_size,
374                 cached_base_addr_+from*item_size,
375                 item_size
376             );
377         }
378 
379         /**
380          * \brief Gets a pointer to the stored data.
381          * \return A pointer to the memory block
382          */
data()383         void* data() {
384             return cached_base_addr_;
385         }
386 
387         /**
388          * \brief Gets a pointer to the stored data.
389          * \return A const pointer to the memory block
390          */
data()391         const void* data() const {
392             return cached_base_addr_;
393         }
394 
395         /**
396          * \brief Gets the element size.
397          * \return the size of an element, in bytes
398          */
element_size()399         size_t element_size() const {
400             return size_t(element_size_);
401         }
402 
403         /**
404          * \brief Tests whether a given element type is registered in
405          *   the system.
406          * \param[in] element_type_name a const reference to a string
407          *   with the C++ type name
408          * \retval true if the element type was registered
409          * \retval false otherwise
410          */
element_type_name_is_known(const std::string & element_type_name)411         static bool element_type_name_is_known(
412             const std::string& element_type_name
413         ) {
414             return (
415                 type_name_to_creator_.find(element_type_name) !=
416                 type_name_to_creator_.end()
417             );
418         }
419 
420         /**
421          * \brief Tests whether a given element type is registered in
422          *   the system.
423          * \param[in] element_typeid_name a const reference to a string
424          *   with the mangled type, as given by typeid(T).name()
425          * \retval true if the element type was registered
426          * \retval false otherwise
427          */
element_typeid_name_is_known(const std::string & element_typeid_name)428         static bool element_typeid_name_is_known(
429             const std::string& element_typeid_name
430         ) {
431             return (
432                 typeid_name_to_type_name_.find(element_typeid_name) !=
433                 typeid_name_to_type_name_.end()
434             );
435         }
436 
437         /**
438          * \brief Creates an attribute store of a given type
439          * \param[in] element_type_name a const reference to a string with
440          *  the C++ type of the elements to be stored in the attribute
441          * \param[in] dimension number of elements in each item
442          */
create_attribute_store_by_element_type_name(const std::string & element_type_name,index_t dimension)443         static AttributeStore* create_attribute_store_by_element_type_name(
444             const std::string& element_type_name,
445             index_t dimension
446         ) {
447             geo_assert(element_type_name_is_known(element_type_name));
448             return type_name_to_creator_[element_type_name]->
449                 create_attribute_store(dimension);
450         }
451 
452         /**
453          * \brief Gets an element type name from its mangled name
454          * \param[in] element_typeid_name a const reference to a
455          *  string with the mangled type name, as given by typeid(T).name()
456          * \return a string with the C++ type name
457          * \pre element_typeid_name_is_known(element_typeid_name)
458          */
element_type_name_by_element_typeid_name(const std::string & element_typeid_name)459         static std::string element_type_name_by_element_typeid_name(
460             const std::string& element_typeid_name
461         ) {
462             geo_assert(element_typeid_name_is_known(element_typeid_name));
463             return typeid_name_to_type_name_[element_typeid_name];
464         }
465 
466         /**
467          * \brief Gets an element mangled type name from its C++ name.
468          * \param[in] element_type_name a reference to a string with
469          *  the C++ type name
470          * \return a string with the mangled type name, as given by
471          *  typeid(T).name()
472          * \pre element_type_name_is_known(element_type_name)
473          */
element_typeid_name_by_element_type_name(const std::string & element_type_name)474         static std::string element_typeid_name_by_element_type_name(
475             const std::string& element_type_name
476         ) {
477             geo_assert(element_type_name_is_known(element_type_name));
478             return type_name_to_typeid_name_[element_type_name];
479         }
480 
481         /**
482          * \brief Registers a new element type
483          * \note Internal use function, one should use
484          *  geo_register_attribute_type instead
485          * \param[in] creator a pointer to the AttributeStoreCreator
486          * \param[in] element_type_name a const reference to a string with the
487          *  C++ type name of the elements
488          * \param[in] element_typeid_name a const reference to a string with
489          *  the mangled type name of the elements, as given by typeid(T).name()
490          */
register_attribute_creator(AttributeStoreCreator * creator,const std::string & element_type_name,const std::string & element_typeid_name)491         static void register_attribute_creator(
492             AttributeStoreCreator* creator,
493             const std::string& element_type_name,
494             const std::string& element_typeid_name
495         ) {
496             if(element_type_name_is_known(element_type_name)) {
497                 Logger::warn("Attributes") << element_type_name
498                                            << " already registered"
499                                            << std::endl;
500                 if(element_typeid_name_is_known(element_typeid_name)) {
501                     bool already_registered_attribute_has_same_type = (
502                         type_name_to_typeid_name_[element_type_name] ==
503                         element_typeid_name
504                     );
505                     geo_assert(already_registered_attribute_has_same_type);
506                 }
507             }
508             type_name_to_creator_[element_type_name] = creator;
509             typeid_name_to_type_name_[element_typeid_name] = element_type_name;
510             type_name_to_typeid_name_[element_type_name] = element_typeid_name;
511         }
512 
513     protected:
514         /**
515          * \brief If size or base address differ from the
516          *  cached values, notify all the observers,
517          *  and update the cached base address and size.
518          * \param[in] base_addr the new base address
519          * \param[in] size the new size
520          * \param[in] dim the new dimension
521          */
522         virtual void notify(
523             Memory::pointer base_addr, index_t size, index_t dim
524         );
525 
526         /**
527          * \brief Registers an observer.
528          * \details All the registered observers are notified whenever
529          *  the size or base pointer in this AttributeStore change.
530          *  The function is thread-safe.
531          * \param[in] observer the AttributeStoreObserver to be
532          *  registered.
533          */
534         void register_observer(AttributeStoreObserver* observer);
535 
536         /**
537          * \brief Unregisters an observer.
538          * \param[in] observer the AttributeStoreObserver to be
539          *  unregistered.
540          *  The function is thread-safe.
541          * \pre \p observer is registered.
542          */
543         void unregister_observer(AttributeStoreObserver* observer);
544 
545 
546     protected:
547         index_t element_size_;
548         index_t dimension_;
549         Memory::pointer cached_base_addr_;
550         index_t cached_size_;
551 	index_t cached_capacity_;
552         std::set<AttributeStoreObserver*> observers_;
553         Process::spinlock lock_;
554 
555         static std::map<std::string, AttributeStoreCreator_var>
556             type_name_to_creator_;
557 
558         static std::map<std::string, std::string>
559             typeid_name_to_type_name_;
560 
561         static std::map<std::string, std::string>
562             type_name_to_typeid_name_;
563 
564         friend class AttributeStoreObserver;
565     };
566 
567     /*********************************************************************/
568 
569     /**
570      * \brief Stores an array of elements of a given type,
571      *  and notifies a set of AttributeStoreObservers each time the
572      *  storead array changes size and/or base address.
573      */
574     template <class T> class TypedAttributeStore : public AttributeStore {
575     public:
576 
577         /**
578          * \brief Creates a new empty attribute store.
579          * \param[in] dim number of elements in each item,
580          *  default value is 1, can be greater for vector
581          *  attributes.
582          */
583         TypedAttributeStore(index_t dim=1) :
AttributeStore(index_t (sizeof (T)),dim)584             AttributeStore(index_t(sizeof(T)),dim) {
585         }
586 
resize(index_t new_size)587         virtual void resize(index_t new_size) {
588             store_.resize(new_size*dimension_);
589             notify(
590                 store_.empty() ? nullptr : Memory::pointer(store_.data()),
591                 new_size,
592                 dimension_
593             );
594         }
595 
reserve(index_t new_capacity)596 	virtual void reserve(index_t new_capacity) {
597 	    if(new_capacity > capacity()) {
598 		store_.reserve(new_capacity*dimension_);
599 		cached_capacity_ = new_capacity;
600 		notify(
601 		    store_.empty() ? nullptr : Memory::pointer(store_.data()),
602 		    size(),
603 		    dimension_
604 		);
605 	    }
606 	}
607 
608 	virtual void clear(bool keep_memory=false) {
609             if(keep_memory) {
610                 store_.resize(0);
611             } else {
612                 store_.clear();
613             }
614             notify(nullptr, 0, dimension_);
615         }
616 
617 
redim(index_t dim)618         virtual void redim(index_t dim) {
619             if(dim == dimension()) {
620                 return;
621             }
622             vector<T> new_store(size()*dim);
623 	    new_store.reserve(capacity()*dim);
624             index_t copy_dim = std::min(dim, dimension());
625             for(index_t i = 0; i < size(); ++i) {
626                 for(index_t c = 0; c < copy_dim; ++c) {
627                     new_store[dim * i + c] = store_[dimension_ * i + c];
628                 }
629             }
630             store_.swap(new_store);
631             notify(
632                 store_.empty() ? nullptr : Memory::pointer(store_.data()),
633                 size(),
634                 dim
635             );
636         }
637 
elements_type_matches(const std::string & type_name)638         virtual bool elements_type_matches(const std::string& type_name) const {
639             return type_name == typeid(T).name();
640         }
641 
element_typeid_name()642         virtual std::string element_typeid_name() const {
643             return typeid(T).name();
644         }
645 
clone()646         virtual AttributeStore* clone() const {
647             TypedAttributeStore<T>* result =
648                 new TypedAttributeStore<T>(dimension());
649             result->resize(size());
650             result->store_ = store_;
651             return result;
652         }
653 
get_vector()654         vector<T>& get_vector() {
655             return store_;
656         }
657 
658     protected:
notify(Memory::pointer base_addr,index_t size,index_t dim)659         virtual void notify(
660             Memory::pointer base_addr, index_t size, index_t dim
661         ) {
662             AttributeStore::notify(base_addr, size, dim);
663             geo_assert(size*dim <= store_.size());
664         }
665 
666     private:
667         vector<T> store_;
668     };
669 
670     /*********************************************************************/
671 
672     /**
673      * \brief Implementation of AttributeStoreCreator for a specific type.
674      * \tparam T type of the elements
675      */
676     template <class T>
677     class TypedAttributeStoreCreator : public AttributeStoreCreator {
678     public:
679         /**
680          * \copydoc AttributeStoreCreator::create_attribute_store()
681          */
create_attribute_store(index_t dim)682         virtual AttributeStore* create_attribute_store(index_t dim) {
683             return new TypedAttributeStore<T>(dim);
684         }
685     };
686 
687     /*********************************************************************/
688 
689     /**
690      * \brief Helper class to register new attribute types
691      * \tparam T attribute element type
692      */
693     template <class T> class geo_register_attribute_type {
694     public:
695         /**
696          * \brief geo_register_attribute_type constructor
697          * \param[in] type_name a const reference to a string with
698          *  the C++ type name.
699          * \details If the attribute is already registered with the same
700          *  \p type_name and same \p T, then a warning message is issued.
701          *  If the attribute is already registered with the same \p type_name
702          *  but a different \p T, then an assertion failure is triggered.
703          */
geo_register_attribute_type(const std::string & type_name)704         geo_register_attribute_type(const std::string& type_name) {
705             AttributeStore::register_attribute_creator(
706                 new TypedAttributeStoreCreator<T>, type_name, typeid(T).name()
707             );
708 	    if(type_name == "bool") {
709 		GeoFile::register_ascii_attribute_serializer(
710 		    type_name,
711 		    read_ascii_attribute<bool>,
712 		    write_ascii_attribute<bool>
713 		);
714 	    } else {
715 		GeoFile::register_ascii_attribute_serializer(
716 		    type_name,
717 		    read_ascii_attribute<T>,
718 		    write_ascii_attribute<T>
719 		);
720 	    }
721         }
722     };
723 
724     /*********************************************************************/
725 
726     /**
727      * \brief Managers a set of attributes attached to
728      *  an object.
729      */
730     class GEOGRAM_API AttributesManager {
731     public:
732         /**
733          * \brief Constructs a new empty AttributesManager.
734          */
735         AttributesManager();
736 
737 
738         /**
739          * \brief AttributesManager destructor.
740          */
741         ~AttributesManager();
742 
743         /**
744          * \brief Gets the number of attributes.
745          * \return The number of attributes managed by this
746          *   AttributesManager.
747          */
nb()748         index_t nb() const {
749             return index_t(attributes_.size());
750         }
751 
752         /**
753          * \brief Gets the names of all the attributes in this
754          *   AttributeStore.
755          * \param[out] names a vector of all attribute names
756          */
757         void list_attribute_names(vector<std::string>& names) const;
758 
759         /**
760          * \brief Gets the size.
761          * \details All attributes stored in an AttributesManager have
762          *  the same number of items.
763          * \return the number of items of each attribute.
764          */
size()765         index_t size() const {
766             return size_;
767         }
768 
769 	/**
770 	 * \brief Gets the capacity.
771 	 * \return the number of items that can be stored without doing
772 	 *  a reallocation.
773 	 */
capacity()774 	index_t capacity() const {
775 	    return capacity_;
776 	}
777 
778         /**
779          * \brief Resizes all the attributes managed by this
780          *  AttributesManager.
781          * \param[in] new_size the new number of items for
782          *  all attributes.
783          */
784         void resize(index_t new_size);
785 
786 	/**
787 	 * \brief Pre-allocates memory for a number of items.
788 	 * \details Has effect only if new_capacity is larger
789 	 *  than current capacity.
790 	 * \param[in] new_capacity the number of items.
791 	 */
792 	void reserve(index_t new_capacity);
793 
794         /**
795          * \brief Clears this AttributesManager
796          * \param[in] keep_attributes if true, then all
797          *  attributes are resized to 0 but their names are
798          *  kept.
799          * \param[in] keep_memory if true, allocated memory
800          *  is kept reserved.
801          */
802         void clear(bool keep_attributes, bool keep_memory = false);
803 
804 
805         /**
806          * \brief Zeroes all the attributes.
807          */
808         void zero();
809 
810         /**
811          * \brief Binds an AttributeStore with the specified name.
812          *  Ownership of this AttributeStore is transferred to
813          *  the AttributesManager.
814          * \param[in] name the name
815          * \param[in] as a pointer to the AttributeStore to be bound
816          * \pre No AttributeStore is already bound to the same name
817          */
818         void bind_attribute_store(const std::string& name, AttributeStore* as);
819 
820         /**
821          * \brief Finds an AttributeStore by name.
822          * \param[in] name the name under which the AttributeStore was bound
823          * \return a pointer to the attribute store or nullptr if is is undefined.
824          */
825         AttributeStore* find_attribute_store(const std::string& name);
826 
827         /**
828          * \brief Finds an AttributeStore by name.
829          * \param[in] name the name under which the AttributeStore was bound
830          * \return a const pointer to the attribute store or nullptr if is is
831          *  undefined.
832          */
833         const AttributeStore* find_attribute_store(
834             const std::string& name
835         ) const;
836 
837 
838         /**
839          * \brief Tests whether an attribute is defined.
840          * \param[in] name name of the attribute
841          * \retval true if an attribute with the specified name exists
842          * \retval false otherwise
843          */
is_defined(const std::string & name)844         bool is_defined(const std::string& name) {
845             return (find_attribute_store(name) != nullptr);
846         }
847 
848         /**
849          * \brief Deletes an AttributeStore by name.
850          * \param[in] name the name of the attribute store
851          *  to be deleted.
852          */
853         void delete_attribute_store(const std::string& name);
854 
855         /**
856          * \brief Deletes an AttributeStore.
857          * \param[in] as a pointer to the attribute store
858          *  to be deleted.
859          */
860         void delete_attribute_store(AttributeStore* as);
861 
862         /**
863          * \brief Applies a permutation to the stored attributes.
864          * \details Applying a permutation to the data is equivalent
865          *  to:
866          * \code
867          * for(i=0; i<permutation.size(); i++) {
868          *    data2[i] = data[permutation[i]]
869          * }
870          * data = data2 ;
871          * \endcode
872          * But it is done in-place.
873          * \param[in] permutation the permutation.
874          *  It is temporarily changed during execution of the
875          *  function, but identical to the input on exit.
876          */
877         void apply_permutation(
878             const vector<index_t>& permutation
879         );
880 
881         /**
882          * \brief Compresses the stored attributes, by
883          *  applying an index mapping that fills-in the gaps.
884          * \details This is equivalent to:
885          * \code
886          * for(i=0; i<size(); i++) {
887          *    if(old2new[i] != index_t(-1)) {
888          *       data2[old2new[i]] = data[i];
889          *    }
890          * }
891          * data = data2 ;
892          * \endcode
893          * \param[in] old2new the index mapping to be applied.
894          * \pre old2new[i] <= i || old2new[i] == index_t(-1)
895          */
896         void compress(const vector<index_t>& old2new);
897 
898         /**
899          * \brief Copies all the attributes from another AttributesManager.
900          * \details Previous content of this AttributesManager is erased.
901          */
902         void copy(const AttributesManager& rhs);
903 
904 
905         /**
906          * \brief Copies all the attributes of an item into another one.
907          * \param[in] to index of the destination item
908          * \param[in] from index of the source item
909          * \note This function is not efficient.
910          */
911         void copy_item(index_t to, index_t from);
912 
913     private:
914         /**
915          * \brief Forbids copy.
916          * \details This is to make sure that client code does
917          *   not unintentionlly copies an AttributesManager (for
918          *   instance by passing it by-value to a function).
919          *   Use copy() instead.
920          */
921         AttributesManager(const AttributesManager& rhs);
922 
923         /**
924          * \brief Forbids copy.
925          * \details This is to make sure that client code does
926          *   not unintentionlly copies an AttributesManager (for
927          *   instance by passing it by-value to a function).
928          *   Use copy() instead.
929          */
930         const AttributesManager& operator=(const AttributesManager& rhs);
931 
932     private:
933         index_t size_;
934 	index_t capacity_;
935         std::map<std::string, AttributeStore*> attributes_;
936     } ;
937 
938 
939     /*********************************************************************/
940 
941 
942     /**
943      * \brief Base class for Attributes, that manipulates an
944      *  attribute stored in an AttributesManager.
945      */
946     template <class T> class AttributeBase : public AttributeStoreObserver {
947     public:
948 
949         /**
950          * \brief Creates an uninitialized (unbound) Attribute.
951          */
AttributeBase()952         AttributeBase() :
953             manager_(nullptr),
954             store_(nullptr) {
955         }
956 
957         /**
958          * \brief Creates or retrieves a persistent attribute attached to
959          *  a given AttributesManager.
960          * \details If the attribute already exists with the specified
961          *  name in the AttributesManager then it is retrieved, else
962          *  it is created and bound to the name.
963          * \param[in] manager a reference to the AttributesManager
964          * \param[in] name name of the attribute
965          */
AttributeBase(AttributesManager & manager,const std::string & name)966         AttributeBase(AttributesManager& manager, const std::string& name) :
967             manager_(nullptr),
968             store_(nullptr) {
969             bind(manager, name);
970         }
971 
972         /**
973          * \brief Tests whether an Attribute is bound.
974          * \retval true if this Attribute is bound
975          * \retval false otherwise
976          */
is_bound()977         bool is_bound() const {
978             return (store_ != nullptr && !disconnected_);
979         }
980 
981         /**
982          * \brief Unbinds this Attribute.
983          * \pre is_bound()
984          */
unbind()985         void unbind() {
986             geo_assert(is_bound());
987 	    // If the AttributeManager was destroyed before, do not
988 	    // do anything. This can occur in Lua scripting when using
989 	    // Attribute wrapper objects.
990 	    if(!disconnected_) {
991 		unregister_me(store_);
992 	    }
993             manager_ = nullptr;
994             store_ = nullptr;
995         }
996 
997         /**
998          * \brief Binds this Attribute to an AttributesManager.
999          * \details If the attribute already exists with the specified
1000          *  name in the AttributesManager then it is retrieved, else
1001          *  it is created and bound to the name.
1002          * \param[in] manager a reference to the AttributesManager
1003          * \param[in] name name of the attribute
1004          * \pre !is_bound()
1005          */
bind(AttributesManager & manager,const std::string & name)1006         void bind(AttributesManager& manager, const std::string& name) {
1007             geo_assert(!is_bound());
1008             manager_ = &manager;
1009             store_ = manager_->find_attribute_store(name);
1010             if(store_ == nullptr) {
1011                 store_ = new TypedAttributeStore<T>();
1012                 manager_->bind_attribute_store(name,store_);
1013             } else {
1014                 geo_assert(store_->elements_type_matches(typeid(T).name()));
1015             }
1016             register_me(store_);
1017         }
1018 
1019 
1020         /**
1021          * \brief Binds this Attribute to an AttributesManager if it
1022          *  already exists in the AttributesManager.
1023          * \param[in] manager a reference to the AttributesManager
1024          * \param[in] name name of the attribute
1025          * \pre !is_bound()
1026          */
bind_if_is_defined(AttributesManager & manager,const std::string & name)1027         void bind_if_is_defined(
1028             AttributesManager& manager, const std::string& name
1029         ) {
1030             geo_assert(!is_bound());
1031             manager_ = &manager;
1032             store_ = manager_->find_attribute_store(name);
1033             if(store_ != nullptr) {
1034                 geo_assert(store_->elements_type_matches(typeid(T).name()));
1035                 register_me(store_);
1036             }
1037         }
1038 
1039         /**
1040          * \brief Creates and binds a new vector attribute.
1041          * \param[in] manager the attribute manager
1042          * \param[in] name the name of the attribute
1043          * \param[in] dimension the number of elements per item
1044          */
create_vector_attribute(AttributesManager & manager,const std::string & name,index_t dimension)1045         void create_vector_attribute(
1046             AttributesManager& manager,
1047             const std::string& name,
1048             index_t dimension
1049         ) {
1050             geo_assert(!is_bound());
1051             manager_ = &manager;
1052             geo_assert(manager_->find_attribute_store(name) == nullptr);
1053             store_ = new TypedAttributeStore<T>(dimension);
1054             manager_->bind_attribute_store(name,store_);
1055             register_me(store_);
1056         }
1057 
1058         /**
1059          * \brief Destroys this attribute in the AttributesManager.
1060          * \details On exit, the attribute is no-longer accessible in
1061          *  the AttributesManager, its name is available again, and
1062          *  this attribute is in the unbound state.
1063          */
destroy()1064         void destroy() {
1065             geo_assert(is_bound());
1066             unregister_me(store_);
1067             manager_->delete_attribute_store(store_);
1068             store_ = nullptr;
1069             manager_ = nullptr;
1070         }
1071 
1072         /**
1073          * \brief Sets the dimension.
1074          * \details The dimension is 1 for standard attributes and
1075          *  can be greater for vector attributes. The existing
1076          *  fields are kept. If the new dimension is greater than
1077          *  the old one, then new fields are initialized to the default
1078          *  value for the attribute type.
1079          * \param[in] new_dim the new dimension
1080          */
redim(index_t new_dim)1081         void redim(index_t new_dim) {
1082             geo_assert(is_bound());
1083             store_->redim(new_dim);
1084         }
1085 
1086         /**
1087          * \brief Attribute destructor
1088          * \details
1089          *  The attribute is not destroyed, it can be retrieved later
1090          *  by binding with the same name. To destroy the attribute,
1091          *  use destroy() instead.
1092          */
~AttributeBase()1093         ~AttributeBase() {
1094             if(is_bound()) {
1095                 unbind();
1096             }
1097         }
1098 
1099 
1100         /**
1101          * \brief Tests whether an attribute with the specified name and with
1102          *  corresponding type exists in an AttributesManager.
1103          * \param[in] manager a reference to the AttributesManager
1104          * \param[in] name the name of the attribute
1105          * \param[in] dim dimension, or 0 if any dimension can match
1106          */
1107         static bool is_defined(
1108             AttributesManager& manager, const std::string& name,
1109             index_t dim = 0
1110         ) {
1111             AttributeStore* store = manager.find_attribute_store(name);
1112             return (
1113                 store != nullptr &&
1114                 store->elements_type_matches(typeid(T).name()) &&
1115                 ((dim == 0) || (store->dimension() == dim))
1116             );
1117         }
1118 
1119         /**
1120          * \brief Gets the size.
1121          * \return The number of items in this attribute.
1122          */
size()1123         index_t size() const {
1124             return size_;
1125         }
1126 
1127         /**
1128          * \brief Sets all the elements of this Attribute to
1129          *   zero.
1130          */
zero()1131         void zero() {
1132             geo_debug_assert(is_bound());
1133             store_->zero();
1134         }
1135 
1136         /**
1137          * \brief Tests whether get_vector() can be called on this
1138          *  Attribute.
1139          * \details get_vector() can be called if this attribute is
1140          *  bound and if type T corresponds to the type used to create
1141          *  the attribute.
1142          * \note Advanced users only. Most client code will not need
1143          *  to use this function.
1144          */
can_get_vector()1145         bool can_get_vector() {
1146             return(
1147                 dynamic_cast<TypedAttributeStore<T>*>(store_) != nullptr
1148             );
1149         }
1150 
1151         /**
1152          * \brief Gets a reference to the internal vector<T> used to
1153          *  store the attribute.
1154          * \details It is forbidden to modify the size of the returned
1155          *  vector.
1156          * \return a reference to the vector<T> used to store the
1157          *  attribute.
1158          * \note Advanced users only. Most client code will not need
1159          *  to use this function.
1160          */
get_vector()1161         vector<T>& get_vector() {
1162             TypedAttributeStore<T>* typed_store =
1163                 dynamic_cast<TypedAttributeStore<T>*>(store_);
1164             geo_assert(typed_store != nullptr);
1165             return typed_store->get_vector();
1166         }
1167 
1168         /**
1169          * \brief Gets a const reference to the internal vector<T> used to
1170          *  store the attribute.
1171          * \return a const reference to the vector<T> used to store the
1172          *  attribute.
1173          */
get_vector()1174         const vector<T>& get_vector() const {
1175             TypedAttributeStore<T>* typed_store =
1176                 dynamic_cast<TypedAttributeStore<T>*>(store_);
1177             geo_assert(typed_store != nullptr);
1178             return typed_store->get_vector();
1179         }
1180 
1181 	/**
1182 	 * \brief Gets the AttributeManager this Attribute is bound to.
1183 	 * \return a pointer to the attributes manager.
1184 	 */
manager()1185 	AttributesManager* manager() const {
1186 	    return manager_;
1187 	}
1188 
1189     protected:
1190         AttributesManager* manager_;
1191         AttributeStore* store_;
1192     } ;
1193 
1194     /*********************************************************************/
1195 
1196     /**
1197      * \brief Manages an attribute attached to a set of object.
1198      * \tparam T type of the attributes. Needs to be a basic type
1199      *  or a plain ordinary datatype (classes that do dynamic
1200      *  memory allocation are not allowed here).
1201      */
1202     template <class T> class Attribute : public AttributeBase<T> {
1203     public:
1204         typedef AttributeBase<T> superclass;
1205 
1206 	/**
1207 	 * \brief Tests at compile time whether type can be used
1208 	 *  in an Attribute. If not the case generates a compile-time
1209 	 *  error.
1210 	 */
static_test_type()1211 	static void static_test_type() {
1212 	    // Attributes are only implemented for classes that
1213 	    // can be copied with memcpy() and read/written to
1214 	    // files using fread()/fwrite()
1215 #if __GNUG__ && __GNUC__ < 5
1216 	    static_assert(
1217 		__has_trivial_copy(T),
1218 		"Attribute only implemented for types that can be copied with memcpy()"
1219 	    );
1220 #else
1221 	    static_assert(
1222 		std::is_trivially_copyable<T>::value,
1223 		"Attribute only implemented for types that can be copied with memcpy()"
1224 	    );
1225 #endif
1226 	}
1227 
1228         /**
1229          * \brief Creates an uninitialized (unbound) Attribute.
1230          */
Attribute()1231         Attribute() : superclass() {
1232 	    static_test_type();
1233         }
1234 
1235         /**
1236          * \brief Creates or retrieves a persistent attribute attached to
1237          *  a given AttributesManager.
1238          * \details If the attribute already exists with the specified
1239          *  name in the AttributesManager then it is retrieved, else
1240          *  it is created and bound to the name.
1241          * \param[in] manager a reference to the AttributesManager
1242          * \param[in] name name of the attribute
1243          */
Attribute(AttributesManager & manager,const std::string & name)1244         Attribute(AttributesManager& manager, const std::string& name) :
1245             superclass(manager, name) {
1246 	    static_test_type();
1247         }
1248 
1249         /**
1250          * \brief Gets a modifiable element by index
1251          * \param [in] i index of the element
1252          * \return a modifiable reference to the \p i%th element
1253          */
1254         T& operator[](index_t i) {
1255             geo_debug_assert(i < superclass::nb_elements());
1256             return ((T*)(void*)superclass::base_addr_)[i];
1257         }
1258 
1259         /**
1260          * \brief Gets an element by index
1261          * \param [in] i index of the element
1262          * \return a const reference to the \p i%th element
1263          */
1264         const T& operator[](index_t i) const {
1265             geo_debug_assert(i < superclass::nb_elements());
1266             return ((const T*)(void*)superclass::base_addr_)[i];
1267         }
1268 
1269         /**
1270          * \brief Sets all the elements in this attribute
1271          *   to a specified value.
1272          * \param[in] val the value
1273          */
fill(const T & val)1274         void fill(const T& val) {
1275             for(index_t i=0; i<superclass::nb_elements(); ++i) {
1276                 (*this)[i] = val;
1277             }
1278         }
1279 
1280 	/**
1281 	 * \brief Copies all the values from another attribute.
1282 	 * \param[in] rhs the attribute to be copied.
1283 	 * \details rhs needs to have the same size and dimension
1284 	 *  as this Attribute.
1285 	 */
copy(const Attribute<T> & rhs)1286 	void copy(const Attribute<T>& rhs) {
1287 	    geo_assert(rhs.size() == superclass::size());
1288 	    geo_assert(rhs.dimension() == superclass::dimension());
1289 	    for(index_t i=0; i<superclass::nb_elements(); ++i) {
1290 		(*this)[i] = rhs[i];
1291 	    }
1292 	}
1293 
1294 	/**
1295 	 * \brief Gets the pointer to the data.
1296 	 * \return a pointer to the stored array.
1297 	 */
data()1298 	T* data() {
1299 	    return (T*)AttributeStoreObserver::base_addr_;
1300 	}
1301 
1302 	/**
1303 	 * \brief Gets the pointer to the data.
1304 	 * \return a const pointer to the stored array.
1305 	 */
data()1306 	const T* data() const {
1307 	    return (const T*)AttributeStoreObserver::base_addr_;
1308 	}
1309 
1310 
1311     private:
1312         /**
1313          * \brief Forbids copy.
1314          */
1315         Attribute(const Attribute<T>& rhs);
1316         /**
1317          * \brief Forbids copy.
1318          */
1319         Attribute<T>& operator=(const Attribute<T>& rhs);
1320     };
1321 
1322     /*********************************************************************/
1323 
1324     /**
1325      * \brief Specialization of Attribute for booleans
1326      * \details Attribute needs a specialization for bool, since
1327      *   vector<bool> uses compressed storage (1 bit per boolean),
1328      *   that is not compatible with the attribute management
1329      *   mechanism. This wrapper class uses an Attribute<Numeric::uint8>
1330      *   and does the appropriate conversions, using an accessor class.
1331      */
1332     template <> class Attribute<bool> : public AttributeBase<Numeric::uint8> {
1333     public:
1334         typedef AttributeBase<Numeric::uint8> superclass;
1335 
Attribute()1336         Attribute() : superclass() {
1337         }
1338 
Attribute(AttributesManager & manager,const std::string & name)1339         Attribute(AttributesManager& manager, const std::string& name) :
1340             superclass(manager,name) {
1341         }
1342 
1343         class BoolAttributeAccessor;
1344 
1345 
1346         /**
1347          * \brief Accessor class for adapting Attribute<bool>
1348          *  indexing.
1349          */
1350         class ConstBoolAttributeAccessor {
1351         public:
1352             /**
1353              * \brief ConstBoolAttributeAccessor constructor.
1354              */
ConstBoolAttributeAccessor(const Attribute<bool> & attribute,index_t index)1355             ConstBoolAttributeAccessor(
1356                 const Attribute<bool>& attribute,
1357                 index_t index
1358             ) :
1359                 attribute_(&attribute),
1360                 index_(index) {
1361             }
1362 
1363             /**
1364              * \brief Converts a BoolAttributeAccessor to a bool.
1365              * \details Performs the actual lookup.
1366              */
1367             operator bool() const {
1368                 return (attribute_->element(index_) != 0);
1369             }
1370 
1371         private:
1372             const Attribute<bool>* attribute_;
1373             index_t index_;
1374 
1375             friend class BoolAttributeAccessor;
1376         };
1377 
1378         /**
1379          * \brief Accessor class for adapting Attribute<bool>
1380          *  indexing.
1381          */
1382         class BoolAttributeAccessor {
1383         public:
1384             /**
1385              * \brief BoolAttributeAccessor constructor.
1386              */
BoolAttributeAccessor(Attribute<bool> & attribute,index_t index)1387             BoolAttributeAccessor(
1388                 Attribute<bool>& attribute,
1389                 index_t index
1390             ) :
1391                 attribute_(&attribute),
1392                 index_(index) {
1393             }
1394 
1395             /**
1396              * \brief Converts a BoolAttributeAccessor to a bool.
1397              * \details Performs the actual lookup.
1398              */
1399             operator bool() const {
1400                 return (attribute_->element(index_) != 0);
1401             }
1402 
1403             /**
1404              * \brief Copy-constructor.
1405              * \param[in] rhs a const reference to the
1406              *  BoolAttributeAccessor to be copied.
1407              */
BoolAttributeAccessor(const BoolAttributeAccessor & rhs)1408             BoolAttributeAccessor(const BoolAttributeAccessor& rhs) {
1409                 attribute_ = rhs.attribute_;
1410                 index_ = rhs.index_;
1411             }
1412 
1413             /**
1414              * \brief Assigns a bool to a BoolAttributeAccessor.
1415              * \details Stores the boolean into the Attribute.
1416              */
1417             BoolAttributeAccessor& operator=(bool x) {
1418                 attribute_->element(index_) = Numeric::uint8(x);
1419                 return *this;
1420             }
1421 
1422             /**
1423              * \brief Copies a bool from another attribute.
1424              * \param[in] rhs a const reference to the BoolAttributeAccessor
1425              *  to be copied.
1426              */
1427             BoolAttributeAccessor& operator=(
1428                 const BoolAttributeAccessor& rhs
1429             ) {
1430                 if(&rhs != this) {
1431                     attribute_->element(index_) =
1432                         rhs.attribute_->element(rhs.index_);
1433                 }
1434                 return *this;
1435             }
1436 
1437             /**
1438              * \brief Copies a bool from another attribute.
1439              * \param[in] rhs a const reference to the
1440              *  ConstBoolAttributeAccessor to be copied.
1441              */
1442             BoolAttributeAccessor& operator=(
1443                 const ConstBoolAttributeAccessor& rhs
1444             ) {
1445                 attribute_->element(index_) =
1446                     rhs.attribute_->element(rhs.index_);
1447                 return *this;
1448             }
1449 
1450         private:
1451             Attribute<bool>* attribute_;
1452             index_t index_;
1453         };
1454 
1455 
1456         BoolAttributeAccessor operator[](index_t i) {
1457             return BoolAttributeAccessor(*this,i);
1458         }
1459 
1460         ConstBoolAttributeAccessor operator[](index_t i) const {
1461             return ConstBoolAttributeAccessor(*this,i);
1462         }
1463 
1464         /**
1465          * \brief Sets all the elements in this attribute
1466          *   to a specified value.
1467          * \param[in] val the value
1468          */
fill(bool val)1469         void fill(bool val) {
1470             for(index_t i=0; i<superclass::nb_elements(); ++i) {
1471                 element(i) = Numeric::uint8(val);
1472             }
1473         }
1474 
1475     protected:
1476 
1477         friend class BoolAttributeAccessor;
1478         friend class ConstBoolAttributeAccessor;
1479 
1480         /**
1481          * \brief Gets a modifiable element by index
1482          * \param [in] i index of the element
1483          * \return a modifiable reference to the \p i%th element
1484          */
element(index_t i)1485         Numeric::uint8& element(index_t i) {
1486             geo_debug_assert(i < superclass::nb_elements());
1487             return ((Numeric::uint8*)superclass::base_addr_)[i];
1488         }
1489 
1490         /**
1491          * \brief Gets an element by index
1492          * \param [in] i index of the element
1493          * \return a const reference to the \p i%th element
1494          */
element(index_t i)1495         const Numeric::uint8& element(index_t i) const {
1496             geo_debug_assert(i < superclass::nb_elements());
1497             return ((const Numeric::uint8*)superclass::base_addr_)[i];
1498         }
1499 
1500     private:
1501         /**
1502          * \brief Forbids copy.
1503          */
1504         Attribute(const Attribute<bool>& rhs);
1505         /**
1506          * \brief Forbids copy.
1507          */
1508         Attribute<bool>& operator=(const Attribute<bool>& rhs);
1509     } ;
1510 
1511     /***********************************************************/
1512 
1513     /**
1514      * \brief Access to an attribute as a double regardless its type.
1515      * \details The attribute can be an element of a vector attribute.
1516      */
1517     class GEOGRAM_API ReadOnlyScalarAttributeAdapter :
1518         public AttributeStoreObserver {
1519 
1520     public:
1521         /**
1522          * \brief Internal representation of the attribute.
1523          */
1524         enum ElementType {
1525             ET_NONE=0,
1526             ET_UINT8=1,
1527             ET_INT8=2,
1528             ET_UINT32=3,
1529             ET_INT32=4,
1530             ET_FLOAT32=5,
1531             ET_FLOAT64=6,
1532             ET_VEC2=7,
1533             ET_VEC3=8
1534         };
1535 
1536         /**
1537          * \brief ReadOnlyScalarAttributeAdapter constructor.
1538          */
ReadOnlyScalarAttributeAdapter()1539         ReadOnlyScalarAttributeAdapter() :
1540             manager_(nullptr),
1541             store_(nullptr),
1542             element_type_(ET_NONE),
1543             element_index_(index_t(-1)) {
1544         }
1545 
1546         /**
1547          * \brief ReadOnlyScalarAttributeAdapter constructor.
1548          * \details Retrieves a persistent attribute attached to
1549          *  a given AttributesManager.
1550          * \param[in] manager a reference to the AttributesManager
1551          * \param[in] name name of the attribute with an optional index,
1552          *   for instance, "foobar[5]" refers to the 5th coordinate of
1553          *   the "foobar" vector attribute.
1554          */
ReadOnlyScalarAttributeAdapter(const AttributesManager & manager,const std::string & name)1555         ReadOnlyScalarAttributeAdapter(
1556             const AttributesManager& manager, const std::string& name
1557         ) :
1558             manager_(nullptr),
1559             store_(nullptr) {
1560             bind_if_is_defined(manager, name);
1561         }
1562 
1563         /**
1564          * \brief Tests whether an Attribute is bound.
1565          * \retval true if this Attribute is bound
1566          * \retval false otherwise
1567          */
is_bound()1568         bool is_bound() const {
1569             return (store_ != nullptr);
1570         }
1571 
1572         /**
1573          * \brief Unbinds this Attribute.
1574          * \pre is_bound()
1575          */
unbind()1576         void unbind() {
1577             geo_assert(is_bound());
1578             unregister_me(const_cast<AttributeStore*>(store_));
1579             manager_ = nullptr;
1580             store_ = nullptr;
1581             element_type_ = ET_NONE;
1582             element_index_ = index_t(-1);
1583         }
1584 
1585         /**
1586          * \brief Binds this Attribute to an AttributesManager if it
1587          *  already exists in the AttributesManager.
1588          * \param[in] manager a reference to the AttributesManager
1589          * \param[in] name name of the attribute with an optional index,
1590          *   for instance, "foobar[5]" refers to the 5th coordinate of
1591          *   the "foobar" vector attribute.
1592          * \pre !is_bound()
1593          */
1594         void bind_if_is_defined(
1595             const AttributesManager& manager, const std::string& name
1596         );
1597 
1598         /**
1599          * \brief ReadonlyScalarAttributeAdapter destructor
1600          * \details
1601          *  The attribute is not destroyed, it can be retrieved later
1602          *  by binding with the same name. To destroy the attribute,
1603          *  use destroy() instead.
1604          */
~ReadOnlyScalarAttributeAdapter()1605         ~ReadOnlyScalarAttributeAdapter() {
1606             if(is_bound()) {
1607                 unbind();
1608             }
1609         }
1610 
1611         /**
1612          * \brief Tests whether an attribute with the specified name and with
1613          *  a type that can be converted to double exists in an
1614          *  AttributesManager.
1615          * \param[in] manager a reference to the AttributesManager
1616          * \param[in] name the name of the attribute with an optional index,
1617          *   for instance, "foobar[5]" refers to the 5th coordinate of
1618          *   the "foobar" vector attribute.
1619          */
1620         static bool is_defined(
1621             const AttributesManager& manager, const std::string& name
1622         );
1623 
1624         /**
1625          * \brief Gets the size.
1626          * \return The number of items in this attribute.
1627          */
size()1628         index_t size() const {
1629             return (store_ == nullptr) ? 0 : store_->size();
1630         }
1631 
1632         /**
1633          * \brief Gets the internal representation of the
1634          *  elements.
1635          * \return one of ET_NONE (if unbound), ET_UINT8,
1636          *  ET_INT8, ET_UINT32, ET_INT32, ET_FLOAT32,
1637          *  ET_FLOAT64, ET_VEC2, ET_VEC3
1638          */
element_type()1639         ElementType element_type() const {
1640             return element_type_;
1641         }
1642 
1643         /**
1644          * \brief Gets the element index.
1645          * \return the index of the elements accessed in
1646          *  the bound attribute, or 0 if the bound attribute
1647          *  is scalar.
1648          */
element_index()1649         index_t element_index() const {
1650             return element_index_;
1651         }
1652 
1653         /**
1654          * \brief Gets the AttributeStore.
1655          * \return a const pointer to the AttributeStore.
1656          */
attribute_store()1657         const AttributeStore* attribute_store() const {
1658             return store_;
1659         }
1660 
1661         /**
1662          * \brief Gets a property value
1663          * \param[in] i the index of the item
1664          * \return the value of the property, convertex
1665          *  into a double
1666          * \pre is_bound() && i < size()
1667          */
1668         double operator[](index_t i) {
1669             double result = 0.0;
1670             switch(element_type_) {
1671             case ET_UINT8:
1672                 result = get_element<Numeric::uint8>(i);
1673                 break;
1674             case ET_INT8:
1675                 result = get_element<Numeric::int8>(i);
1676                 break;
1677             case ET_UINT32:
1678                 result = get_element<Numeric::uint32>(i);
1679                 break;
1680             case ET_INT32:
1681                 result = get_element<Numeric::int32>(i);
1682                 break;
1683             case ET_FLOAT32:
1684                 result = get_element<Numeric::float32>(i);
1685                 break;
1686             case ET_FLOAT64:
1687                 result = get_element<Numeric::float64>(i);
1688                 break;
1689             case ET_VEC2:
1690                 result = get_element<Numeric::float64>(i,2);
1691                 break;
1692             case ET_VEC3:
1693                 result = get_element<Numeric::float64>(i,3);
1694                 break;
1695             case ET_NONE:
1696                 geo_assert_not_reached;
1697             }
1698             return result;
1699         }
1700 
1701         /**
1702          * \brief Tests whether a ReadOnlyScalarAttributeAdapter can
1703          *  be bound to a given attribute store.
1704          * \param[in] store a pointer to the attribute store.
1705          * \retval true if it can be bound
1706          * \retval false otherwise
1707          */
can_be_bound_to(const AttributeStore * store)1708         static bool can_be_bound_to(const AttributeStore* store) {
1709             return element_type(store) != ET_NONE;
1710         }
1711 
1712         /**
1713          * \brief Gets the number of scalar components per item in an
1714          *  AttributeStore.
1715          * \param[in] store a pointer to the attribute store.
1716          * \return the number of scalar components per item in an
1717          *  AttributeStore.
1718          */
1719         static index_t nb_scalar_elements_per_item(const AttributeStore* store);
1720 
1721     protected:
1722         /**
1723          * \brief Gets the base attribute name from a compound name.
1724          * \param[in] name the string with the attribute name and optional
1725          *  index. For instance, "foobar[5]" refers to the 5th coordinate of
1726          *  the "foobar" vector attribute.
1727          * \return the attribute name. For instance, for "foobar[5]", it
1728          *  returns "foobar".
1729          */
1730         static std::string attribute_base_name(const std::string& name);
1731 
1732         /**
1733          * \brief Gets the base attribute name from a compound name.
1734          * \param[in] name the string with the attribute name and optional
1735          *  index. For instance, "foobar[5]" refers to the 5th coordinate of
1736          *  the "foobar" vector attribute.
1737          * \return the index or zero if no index was specified. For instance,
1738          *  for "foobar[5]" it returns 5, and for "foobar" it returns 0
1739          */
1740         static index_t attribute_element_index(const std::string& name);
1741 
1742         /**
1743          * \brief Gets the element type stored in an AttributeStore.
1744          * \param[in] store a const pointer to the AttributeStore
1745          * \return one of ET_UINT8, ET_INT8, ET_UINT32, ET_INT32,
1746          *  ET_FLOAT32, ET_FLOAT64 if the type of the attribute is
1747          *  compatible with those types, or ET_NONE if it is incompatible.
1748          */
1749         static ElementType element_type(const AttributeStore* store);
1750 
1751         /**
1752          * \brief Gets an element.
1753          * \param[in] i index of the element
1754          * \param[in] multiplier multiplier applied to the index before fetching
1755          *  the raw pointer.
1756          */
1757         template <class T> double get_element(index_t i, index_t multiplier=1) {
1758             geo_debug_assert(is_bound());
1759             geo_debug_assert(i < size());
1760             return double(
1761                 static_cast<const T*>(store_->data())[
1762                     (i * store_->dimension() * multiplier) +
1763                     element_index_
1764                     ]
1765                 );
1766         }
1767 
1768     private:
1769         const AttributesManager* manager_;
1770         const AttributeStore* store_;
1771         ElementType element_type_;
1772         index_t element_index_;
1773     };
1774 
1775     /***********************************************************/
1776 }
1777 
1778 #endif
1779 
1780