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