Geogram  Version 1.9.1-rc
A programming library of geometric algorithms
attributes.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2000-2022 Inria
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * * Neither the name of the ALICE Project-Team nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * Contact: Bruno Levy
30  *
31  * https://www.inria.fr/fr/bruno-levy
32  *
33  * Inria,
34  * Domaine de Voluceau,
35  * 78150 Le Chesnay - Rocquencourt
36  * FRANCE
37  *
38  */
39 
40 
41 #ifndef GEOGRAM_BASIC_ATTRIBUTES
42 #define GEOGRAM_BASIC_ATTRIBUTES
43 
44 
45 #include <geogram/basic/common.h>
46 #include <geogram/basic/memory.h>
47 #include <geogram/basic/numeric.h>
48 #include <geogram/basic/process.h>
49 #include <geogram/basic/geofile.h>
50 #include <geogram/basic/logger.h>
51 
52 #include <map>
53 #include <typeinfo>
54 #include <set>
55 #include <type_traits>
56 
62 namespace GEO {
63 
64  class AttributeStore;
65 
70  class GEOGRAM_API AttributeStoreObserver {
71  public:
72 
77  base_addr_(nullptr), size_(0), dimension_(0),
78  disconnected_(false) {
79  }
80 
88  void notify(
89  Memory::pointer base_addr, index_t size, index_t dim
90  ) {
91  base_addr_ = base_addr;
92  size_ = size;
93  dimension_ = dim;
94  }
95 
100  index_t size() const {
101  return size_;
102  }
103 
108  index_t dimension() const {
109  return dimension_;
110  }
111 
119  return size_ * dimension_;
120  }
121 
127 
133 
141  void disconnect() {
142  base_addr_ = nullptr;
143  size_ = 0;
144  dimension_ = 0;
145  disconnected_ = true;
146  }
147 
148  protected:
149  Memory::pointer base_addr_;
150  index_t size_;
151  index_t dimension_;
152  bool disconnected_;
153  };
154 
155 
156  /*********************************************************************/
157 
158 
163  class GEOGRAM_API AttributeStoreCreator : public Counted {
164  public:
165 
170 
177 
178 
179  private:
180  std::string element_type_name_;
181  std::string element_typeid_name_;
182  };
183 
189 
195  class GEOGRAM_API AttributeStore {
196  public:
206  AttributeStore(index_t elemsize, index_t dim=1);
207 
211  virtual ~AttributeStore();
212 
213 
223  virtual bool elements_type_matches(
224  const std::string& type_name
225  ) const = 0;
226 
232  virtual std::string element_typeid_name() const = 0;
233 
238  index_t size() const {
239  return cached_size_;
240  }
241 
247  index_t capacity() const {
248  return cached_capacity_;
249  }
250 
255  virtual void resize(index_t new_size) = 0;
256 
262  virtual void reserve(index_t new_capacity) = 0;
263 
269  virtual void clear(bool keep_memory = false) = 0;
270 
276  bool has_observers() const {
277  return !observers_.empty();
278  }
279 
285  index_t dimension() const {
286  return dimension_;
287  }
288 
298  virtual void redim(index_t dim) = 0;
299 
300 
318  virtual void apply_permutation(
319  const vector<index_t>& permutation
320  );
321 
339  virtual void compress(const vector<index_t>& old2new);
340 
348  virtual void zero();
349 
355  virtual AttributeStore* clone() const = 0;
356 
357 
363  void copy_item(index_t to, index_t from) {
364  geo_debug_assert(from < cached_size_);
365  geo_debug_assert(to < cached_size_);
366  index_t item_size = element_size_ * dimension_;
367  Memory::copy(
368  cached_base_addr_+to*item_size,
369  cached_base_addr_+from*item_size,
370  item_size
371  );
372  }
373 
378  void zero_item(index_t to) {
379  geo_debug_assert(to < cached_size_);
380  index_t item_size = element_size_ * dimension_;
382  cached_base_addr_+to*item_size,
383  item_size
384  );
385  }
386 
394  virtual void scale_item(index_t to, double s);
395 
404  virtual void madd_item(index_t to, double s, index_t from);
405 
411 
416  void* data() {
417  return cached_base_addr_;
418  }
419 
424  const void* data() const {
425  return cached_base_addr_;
426  }
427 
432  size_t element_size() const {
433  return size_t(element_size_);
434  }
435 
445  const std::string& element_type_name
446  ) {
447  return (
448  type_name_to_creator_.find(element_type_name) !=
449  type_name_to_creator_.end()
450  );
451  }
452 
462  const std::string& element_typeid_name
463  ) {
464  return (
465  typeid_name_to_type_name_.find(element_typeid_name) !=
466  typeid_name_to_type_name_.end()
467  );
468  }
469 
477  const std::string& element_type_name,
478  index_t dimension
479  ) {
480  geo_assert(element_type_name_is_known(element_type_name));
481  return type_name_to_creator_[element_type_name]->
482  create_attribute_store(dimension);
483  }
484 
493  const std::string& element_typeid_name
494  ) {
495  geo_assert(element_typeid_name_is_known(element_typeid_name));
496  return typeid_name_to_type_name_[element_typeid_name];
497  }
498 
508  const std::string& element_type_name
509  ) {
510  geo_assert(element_type_name_is_known(element_type_name));
511  return type_name_to_typeid_name_[element_type_name];
512  }
513 
525  AttributeStoreCreator* creator,
526  const std::string& element_type_name,
527  const std::string& element_typeid_name
528  ) {
529  if(element_type_name_is_known(element_type_name)) {
530  Logger::warn("Attributes") << element_type_name
531  << " already registered"
532  << std::endl;
533  if(element_typeid_name_is_known(element_typeid_name)) {
534  bool already_registered_attribute_has_same_type = (
535  type_name_to_typeid_name_[element_type_name] ==
536  element_typeid_name
537  );
538  geo_assert(already_registered_attribute_has_same_type);
539  }
540  }
541  type_name_to_creator_[element_type_name] = creator;
542  typeid_name_to_type_name_[element_typeid_name] = element_type_name;
543  type_name_to_typeid_name_[element_type_name] = element_typeid_name;
544  }
545 
546  protected:
555  virtual void notify(
556  Memory::pointer base_addr, index_t size, index_t dim
557  );
558 
568 
577 
578 
579  protected:
580  index_t element_size_;
581  index_t dimension_;
582  Memory::pointer cached_base_addr_;
583  index_t cached_size_;
584  index_t cached_capacity_;
585  std::set<AttributeStoreObserver*> observers_;
586  Process::spinlock lock_;
587 
588  static std::map<std::string, AttributeStoreCreator_var>
589  type_name_to_creator_;
590 
591  static std::map<std::string, std::string>
592  typeid_name_to_type_name_;
593 
594  static std::map<std::string, std::string>
595  type_name_to_typeid_name_;
596 
597  friend class AttributeStoreObserver;
598  };
599 
600  /*********************************************************************/
601 
607  template <class T> class TypedAttributeStore : public AttributeStore {
608  public:
609 
617  AttributeStore(index_t(sizeof(T)),dim) {
618  }
619 
620  void resize(index_t new_size) override {
621  store_.resize(new_size*dimension_);
622  notify(
623  store_.empty() ? nullptr : Memory::pointer(store_.data()),
624  new_size,
625  dimension_
626  );
627  }
628 
629  void reserve(index_t new_capacity) override {
630  if(new_capacity > capacity()) {
631  store_.reserve(new_capacity*dimension_);
632  cached_capacity_ = new_capacity;
633  notify(
634  store_.empty() ? nullptr : Memory::pointer(store_.data()),
635  size(),
636  dimension_
637  );
638  }
639  }
640 
641  void clear(bool keep_memory=false) override {
642  if(keep_memory) {
643  store_.resize(0);
644  } else {
645  store_.clear();
646  }
647  notify(nullptr, 0, dimension_);
648  }
649 
650 
651  void redim(index_t dim) override {
652  if(dim == dimension()) {
653  return;
654  }
655  vector<T> new_store(size()*dim);
656  new_store.reserve(capacity()*dim);
657  index_t copy_dim = std::min(dim, dimension());
658  for(index_t i = 0; i < size(); ++i) {
659  for(index_t c = 0; c < copy_dim; ++c) {
660  new_store[dim * i + c] = store_[dimension_ * i + c];
661  }
662  }
663  store_.swap(new_store);
664  notify(
665  store_.empty() ? nullptr : Memory::pointer(store_.data()),
666  size(),
667  dim
668  );
669  }
670 
672  const std::string& type_name
673  ) const override {
674  return type_name == typeid(T).name();
675  }
676 
677  std::string element_typeid_name() const override {
678  return typeid(T).name();
679  }
680 
681  AttributeStore* clone() const override {
682  TypedAttributeStore<T>* result =
684  result->resize(size());
685  result->store_ = store_;
686  return result;
687  }
688 
689  vector<T>& get_vector() {
690  return store_;
691  }
692 
693  void scale_item(index_t to, double s) override {
694  geo_assert(to < size());
695  for(index_t i=0; i<dimension_; ++i) {
696  scale_value(store_[to*dimension_+i], s);
697  }
698  }
699 
700  void madd_item(index_t to, double s, index_t from) override {
701  geo_assert(from < size());
702  geo_assert(to < size());
703  for(index_t i=0; i<dimension_; ++i) {
704  madd_value(
705  store_[to*dimension_+i], s, store_[from*dimension_+i]
706  );
707  }
708  }
709 
710  protected:
711  void notify(
712  Memory::pointer base_addr, index_t size, index_t dim
713  ) override {
714  AttributeStore::notify(base_addr, size, dim);
715  geo_assert(size*dim <= store_.size());
716  }
717 
718  template<class TT> static void scale_value(TT& to, double s) {
719  geo_argused(to);
720  geo_argused(s);
721  }
722 
723  static void scale_value(uint8_t& to, double s) {
724  to = uint8_t(double(to)*s != 0.0);
725  }
726 
727  static void scale_value(int32_t& to, double s) {
728  to = int32_t(double(to)*s);
729  }
730 
731  static void scale_value(uint32_t& to, double s) {
732  to = uint32_t(double(to)*s);
733  }
734 
735  static void scale_value(float& to, double s) {
736  to = float(double(to)*s);
737  }
738 
739  static void scale_value(double& to, double s) {
740  to *= s;
741  }
742 
743  template<class TT> static void madd_value(TT& to, double s, TT& from) {
744  geo_argused(to);
745  geo_argused(s);
746  geo_argused(from);
747  }
748 
749  static void madd_value(uint8_t& to, double s, uint8_t& from) {
750  to = uint8_t(double(to) + s*double(from) != 0.0);
751  }
752 
753  static void madd_value(int32_t& to, double s, int32_t& from) {
754  to = int32_t(double(to) + s*double(from));
755  }
756 
757  static void madd_value(uint32_t& to, double s, uint32_t& from) {
758  to = uint32_t(double(to) + s*double(from));
759  }
760 
761  static void madd_value(float& to, double s, float& from) {
762  to = float(double(to) + s*double(from));
763  }
764 
765  static void madd_value(double& to, double s, double& from) {
766  to += s*from;
767  }
768 
769 
770  private:
771  vector<T> store_;
772  };
773 
774  /*********************************************************************/
775 
780  template <class T>
782  public:
787  return new TypedAttributeStore<T>(dim);
788  }
789  };
790 
791  /*********************************************************************/
792 
797  template <class T> class geo_register_attribute_type {
798  public:
808  geo_register_attribute_type(const std::string& type_name) {
810  new TypedAttributeStoreCreator<T>, type_name, typeid(T).name()
811  );
812  if(type_name == "bool") {
814  type_name,
817  );
818  } else {
820  type_name,
821  read_ascii_attribute<T>,
822  write_ascii_attribute<T>
823  );
824  }
825  }
826  };
827 
828  /*********************************************************************/
829 
834  class GEOGRAM_API AttributesManager {
835  public:
840 
841 
846 
852  index_t nb() const {
853  return index_t(attributes_.size());
854  }
855 
862 
869  index_t size() const {
870  return size_;
871  }
872 
878  index_t capacity() const {
879  return capacity_;
880  }
881 
888  void resize(index_t new_size);
889 
896  void reserve(index_t new_capacity);
897 
906  void clear(bool keep_attributes, bool keep_memory = false);
907 
908 
912  void zero();
913 
922  void bind_attribute_store(const std::string& name, AttributeStore* as);
923 
930  AttributeStore* find_attribute_store(const std::string& name);
931 
939  const std::string& name
940  ) const;
941 
942 
949  bool is_defined(const std::string& name) const {
950  return (find_attribute_store(name) != nullptr);
951  }
952 
958  void delete_attribute_store(const std::string& name);
959 
966 
983  const vector<index_t>& permutation
984  );
985 
1001  void compress(const vector<index_t>& old2new);
1002 
1007  void copy(const AttributesManager& rhs);
1008 
1009 
1016  void copy_item(index_t to, index_t from);
1017 
1024 
1025 
1030  void zero_item(index_t to);
1031 
1039  void scale_item(index_t to, double s);
1040 
1049  void madd_item(index_t to, double s, index_t from);
1050 
1060  const std::string& name, const std::string& new_name
1061  );
1062 
1072  const std::string& old_name, const std::string& new_name
1073  );
1074 
1075  private:
1084 
1092  const AttributesManager& operator=(const AttributesManager& rhs);
1093 
1094  private:
1095  index_t size_;
1096  index_t capacity_;
1097  std::map<std::string, AttributeStore*> attributes_;
1098  } ;
1099 
1100 
1101  /*********************************************************************/
1102 
1103 
1108  template <class T> class AttributeBase : public AttributeStoreObserver {
1109  public:
1110 
1115  manager_(nullptr),
1116  store_(nullptr) {
1117  }
1118 
1128  AttributeBase(AttributesManager& manager, const std::string& name) :
1129  manager_(nullptr),
1130  store_(nullptr) {
1131  bind(manager, name);
1132  }
1133 
1139  bool is_bound() const {
1140  return (store_ != nullptr && !disconnected_);
1141  }
1142 
1147  void unbind() {
1148  geo_assert(is_bound());
1149  // If the AttributesManager was destroyed before, do not
1150  // do anything. This can occur in Lua scripting when using
1151  // Attribute wrapper objects.
1152  if(!disconnected_) {
1153  unregister_me(store_);
1154  }
1155  manager_ = nullptr;
1156  store_ = nullptr;
1157  }
1158 
1168  void bind(AttributesManager& manager, const std::string& name) {
1169  geo_assert(!is_bound());
1170  manager_ = &manager;
1171  store_ = manager_->find_attribute_store(name);
1172  if(store_ == nullptr) {
1173  store_ = new TypedAttributeStore<T>();
1174  manager_->bind_attribute_store(name,store_);
1175  } else {
1176  geo_assert(store_->elements_type_matches(typeid(T).name()));
1177  }
1178  register_me(store_);
1179  }
1180 
1181 
1191  AttributesManager& manager, const std::string& name
1192  ) {
1193  geo_assert(!is_bound());
1194  manager_ = &manager;
1195  store_ = manager_->find_attribute_store(name);
1196  if(store_ != nullptr) {
1197  geo_assert(store_->elements_type_matches(typeid(T).name()));
1198  register_me(store_);
1199  return true;
1200  }
1201  return false;
1202  }
1203 
1213  AttributesManager& manager, const std::string& name
1214  ) {
1215  if( is_bound() ) {
1216  unbind();
1217  }
1218  store_ = manager.find_attribute_store(name);
1219  if(store_ != nullptr) {
1220  if( !store_->elements_type_matches(typeid(T).name()) ) {
1221  store_ = nullptr;
1222  return false;
1223  }
1224  manager_ = &manager;
1225  register_me(store_);
1226  return true;
1227  }
1228  return false;
1229  }
1230 
1239  const std::string& name,
1241  ) {
1242  geo_assert(!is_bound());
1243  manager_ = &manager;
1244  geo_assert(manager_->find_attribute_store(name) == nullptr);
1245  store_ = new TypedAttributeStore<T>(dimension);
1246  manager_->bind_attribute_store(name,store_);
1247  register_me(store_);
1248  }
1249 
1256  void destroy() {
1257  geo_assert(is_bound());
1258  unregister_me(store_);
1259  manager_->delete_attribute_store(store_);
1260  store_ = nullptr;
1261  manager_ = nullptr;
1262  }
1263 
1273  void redim(index_t new_dim) {
1274  geo_assert(is_bound());
1275  store_->redim(new_dim);
1276  }
1277 
1286  if(is_bound()) {
1287  unbind();
1288  }
1289  }
1290 
1291 
1299  static bool is_defined(
1300  AttributesManager& manager, const std::string& name,
1301  index_t dim = 0
1302  ) {
1304  return (
1305  store != nullptr &&
1306  store->elements_type_matches(typeid(T).name()) &&
1307  ((dim == 0) || (store->dimension() == dim))
1308  );
1309  }
1310 
1315  index_t size() const {
1316  return size_;
1317  }
1318 
1323  void zero() {
1325  store_->zero();
1326  }
1327 
1338  return(
1339  dynamic_cast<TypedAttributeStore<T>*>(store_) != nullptr
1340  );
1341  }
1342 
1354  TypedAttributeStore<T>* typed_store =
1355  dynamic_cast<TypedAttributeStore<T>*>(store_);
1356  geo_assert(typed_store != nullptr);
1357  return typed_store->get_vector();
1358  }
1359 
1366  const vector<T>& get_vector() const {
1367  TypedAttributeStore<T>* typed_store =
1368  dynamic_cast<TypedAttributeStore<T>*>(store_);
1369  geo_assert(typed_store != nullptr);
1370  return typed_store->get_vector();
1371  }
1372 
1378  return manager_;
1379  }
1380 
1381  protected:
1382  AttributesManager* manager_;
1383  AttributeStore* store_;
1384  } ;
1385 
1386  /*********************************************************************/
1387 
1394  template <class T> class Attribute : public AttributeBase<T> {
1395  public:
1396  typedef AttributeBase<T> superclass;
1397 
1403  static void static_test_type() {
1404  // Attributes are only implemented for classes that
1405  // can be copied with memcpy() and read/written to
1406  // files using fread()/fwrite()
1407 #if __GNUG__ && __GNUC__ < 5 && !__clang__
1408  static_assert(
1409  __has_trivial_copy(T),
1410  "Attribute only implemented for types that can be copied with memcpy()"
1411  );
1412 #else
1413  static_assert(
1414  std::is_trivially_copyable<T>::value,
1415  "Attribute only implemented for types that can be copied with memcpy()"
1416  );
1417 #endif
1418  }
1419 
1424  static_test_type();
1425  }
1426 
1436  Attribute(AttributesManager& manager, const std::string& name) :
1437  superclass(manager, name) {
1438  static_test_type();
1439  }
1440 
1448  return ((T*)(void*)superclass::base_addr_)[i];
1449  }
1450 
1456  const T& operator[](index_t i) const {
1458  return ((const T*)(void*)superclass::base_addr_)[i];
1459  }
1460 
1466  void fill(const T& val) {
1467  for(index_t i=0; i<superclass::nb_elements(); ++i) {
1468  (*this)[i] = val;
1469  }
1470  }
1471 
1478  void copy(const Attribute<T>& rhs) {
1479  geo_assert(rhs.size() == superclass::size());
1481  for(index_t i=0; i<superclass::nb_elements(); ++i) {
1482  (*this)[i] = rhs[i];
1483  }
1484  }
1485 
1490  T* data() {
1491  return (T*)AttributeStoreObserver::base_addr_;
1492  }
1493 
1498  const T* data() const {
1499  return (const T*)AttributeStoreObserver::base_addr_;
1500  }
1501 
1502 
1503  private:
1507  Attribute(const Attribute<T>& rhs);
1511  Attribute<T>& operator=(const Attribute<T>& rhs);
1512  };
1513 
1514  /*********************************************************************/
1515 
1524  template <> class Attribute<bool> : public AttributeBase<Numeric::uint8> {
1525  public:
1527 
1528  Attribute() : superclass() {
1529  }
1530 
1531  Attribute(AttributesManager& manager, const std::string& name) :
1532  superclass(manager,name) {
1533  }
1534 
1535  class BoolAttributeAccessor;
1536 
1537 
1542  class ConstBoolAttributeAccessor {
1543  public:
1548  const Attribute<bool>& attribute,
1549  index_t index
1550  ) :
1551  attribute_(&attribute),
1552  index_(index) {
1553  }
1554 
1559  operator bool() const {
1560  return (attribute_->element(index_) != 0);
1561  }
1562 
1563  private:
1564  const Attribute<bool>* attribute_;
1565  index_t index_;
1566 
1567  friend class BoolAttributeAccessor;
1568  };
1569 
1574  class BoolAttributeAccessor {
1575  public:
1580  Attribute<bool>& attribute,
1581  index_t index
1582  ) :
1583  attribute_(&attribute),
1584  index_(index) {
1585  }
1586 
1591  operator bool() const {
1592  return (attribute_->element(index_) != 0);
1593  }
1594 
1600  BoolAttributeAccessor(const BoolAttributeAccessor& rhs) {
1601  attribute_ = rhs.attribute_;
1602  index_ = rhs.index_;
1603  }
1604 
1609  BoolAttributeAccessor& operator=(bool x) {
1610  attribute_->element(index_) = Numeric::uint8(x);
1611  return *this;
1612  }
1613 
1619  BoolAttributeAccessor& operator=(
1620  const BoolAttributeAccessor& rhs
1621  ) {
1622  if(&rhs != this) {
1623  attribute_->element(index_) =
1624  rhs.attribute_->element(rhs.index_);
1625  }
1626  return *this;
1627  }
1628 
1634  BoolAttributeAccessor& operator=(
1635  const ConstBoolAttributeAccessor& rhs
1636  ) {
1637  attribute_->element(index_) =
1638  rhs.attribute_->element(rhs.index_);
1639  return *this;
1640  }
1641 
1642  private:
1643  Attribute<bool>* attribute_;
1644  index_t index_;
1645  };
1646 
1647 
1648  BoolAttributeAccessor operator[](index_t i) {
1649  return BoolAttributeAccessor(*this,i);
1650  }
1651 
1652  ConstBoolAttributeAccessor operator[](index_t i) const {
1653  return ConstBoolAttributeAccessor(*this,i);
1654  }
1655 
1661  void fill(bool val) {
1662  for(index_t i=0; i<superclass::nb_elements(); ++i) {
1663  element(i) = Numeric::uint8(val);
1664  }
1665  }
1666 
1667  protected:
1668 
1669  friend class BoolAttributeAccessor;
1670  friend class ConstBoolAttributeAccessor;
1671 
1679  return ((Numeric::uint8*)superclass::base_addr_)[i];
1680  }
1681 
1687  const Numeric::uint8& element(index_t i) const {
1689  return ((const Numeric::uint8*)superclass::base_addr_)[i];
1690  }
1691 
1692  private:
1696  Attribute(const Attribute<bool>& rhs);
1700  Attribute<bool>& operator=(const Attribute<bool>& rhs);
1701  } ;
1702 
1703  /***********************************************************/
1704 
1709  class GEOGRAM_API ScalarAttributeAdapterBase :
1710  public AttributeStoreObserver {
1711 
1712  public:
1717  ET_NONE=0,
1718  ET_UINT8=1,
1719  ET_INT8=2,
1720  ET_UINT32=3,
1721  ET_INT32=4,
1722  ET_FLOAT32=5,
1723  ET_FLOAT64=6,
1724  ET_VEC2=7,
1725  ET_VEC3=8
1726  };
1727 
1728 
1733  class Accessor {
1734  public:
1735  Accessor(
1736  ScalarAttributeAdapterBase& attribute,
1737  index_t index
1738  ) : attribute_(attribute), index_(index) {
1739  }
1740 
1741  operator double() const {
1742  return attribute_.get_element_as_double(index_);
1743  }
1744 
1745  void operator=(double x) {
1746  attribute_.set_element_as_double(index_, x);
1747  }
1748 
1749  private:
1750  ScalarAttributeAdapterBase& attribute_;
1751  index_t index_;
1752  };
1753 
1759  public:
1760  ConstAccessor(
1761  const ScalarAttributeAdapterBase& attribute,
1762  index_t index
1763  ) : attribute_(attribute), index_(index) {
1764  }
1765 
1766  operator double() const {
1767  return attribute_.get_element_as_double(index_);
1768  }
1769 
1770  private:
1771  const ScalarAttributeAdapterBase& attribute_;
1772  index_t index_;
1773  };
1774 
1779  manager_(nullptr),
1780  store_(nullptr),
1781  element_type_(ET_NONE),
1782  element_index_(index_t(-1)) {
1783  }
1784 
1795  const AttributesManager& manager, const std::string& name
1796  ) :
1797  manager_(nullptr),
1798  store_(nullptr) {
1799  bind_if_is_defined(manager, name);
1800  }
1801 
1807  bool is_bound() const {
1808  return (store_ != nullptr);
1809  }
1810 
1815  void unbind() {
1816  geo_assert(is_bound());
1817  unregister_me(const_cast<AttributeStore*>(store_));
1818  manager_ = nullptr;
1819  store_ = nullptr;
1820  element_type_ = ET_NONE;
1821  element_index_ = index_t(-1);
1822  }
1823 
1834  const AttributesManager& manager, const std::string& name
1835  );
1836 
1845  if(is_bound()) {
1846  unbind();
1847  }
1848  }
1849 
1859  static bool is_defined(
1860  const AttributesManager& manager, const std::string& name
1861  );
1862 
1867  index_t size() const {
1868  return (store_ == nullptr) ? 0 : store_->size();
1869  }
1870 
1879  return element_type_;
1880  }
1881 
1889  return element_index_;
1890  }
1891 
1897  return store_;
1898  }
1899 
1900 
1908  static bool can_be_bound_to(const AttributeStore* store) {
1909  return element_type(store) != ET_NONE;
1910  }
1911 
1920 
1921  protected:
1930  static std::string attribute_base_name(const std::string& name);
1931 
1940  static index_t attribute_element_index(const std::string& name);
1941 
1950 
1958  double get_element_as_double(index_t i) const {
1959  double result = 0.0;
1960  switch(element_type()) {
1961  case ET_UINT8:
1962  result = double(get_element<Numeric::uint8>(i));
1963  break;
1964  case ET_INT8:
1965  result = double(get_element<Numeric::int8>(i));
1966  break;
1967  case ET_UINT32:
1968  result = double(get_element<Numeric::uint32>(i));
1969  break;
1970  case ET_INT32:
1971  result = double(get_element<Numeric::int32>(i));
1972  break;
1973  case ET_FLOAT32:
1974  result = double(get_element<Numeric::float32>(i));
1975  break;
1976  case ET_FLOAT64:
1977  result = double(get_element<Numeric::float64>(i));
1978  break;
1979  case ET_VEC2:
1980  result = double(get_element<Numeric::float64>(i,2));
1981  break;
1982  case ET_VEC3:
1983  result = double(get_element<Numeric::float64>(i,3));
1984  break;
1985  case ET_NONE:
1987  }
1988  return result;
1989  }
1990 
1999  template <class T> T get_element(index_t i,index_t multiplier=1) const {
2000  geo_debug_assert(is_bound());
2001  geo_debug_assert(i < size());
2002  return static_cast<const T*>(store_->data())[
2003  (i * store_->dimension() * multiplier) +
2004  element_index_
2005  ];
2006  }
2007 
2014  double set_element_as_double(index_t i, double value) {
2015  double result = 0.0;
2016  switch(element_type()) {
2017  case ET_UINT8:
2018  set_element<Numeric::uint8>(Numeric::uint8(value), i);
2019  break;
2020  case ET_INT8:
2021  set_element<Numeric::int8>(Numeric::int8(value),i);
2022  break;
2023  case ET_UINT32:
2024  set_element<Numeric::uint32>(Numeric::uint32(value),i);
2025  break;
2026  case ET_INT32:
2027  set_element<Numeric::int32>(Numeric::int32(value),i);
2028  break;
2029  case ET_FLOAT32:
2030  set_element<Numeric::float32>(Numeric::float32(value),i);
2031  break;
2032  case ET_FLOAT64:
2033  set_element<Numeric::float64>(Numeric::float64(value),i);
2034  break;
2035  case ET_VEC2:
2036  set_element<Numeric::float64>(Numeric::float64(value),i,2);
2037  break;
2038  case ET_VEC3:
2039  set_element<Numeric::float64>(Numeric::float64(value),i,3);
2040  break;
2041  case ET_NONE:
2043  }
2044  return result;
2045  }
2046 
2056  template <class T> void set_element(
2057  T value, index_t i, index_t multiplier=1
2058  ) const {
2059  geo_debug_assert(is_bound());
2060  geo_debug_assert(i < size());
2061  const_cast<T*>(static_cast<const T*>(store_->data()))[
2062  (i * store_->dimension() * multiplier) +
2063  element_index_
2064  ] = value;
2065  }
2066 
2067  protected:
2068  const AttributesManager* manager_;
2069  const AttributeStore* store_;
2070  ElementType element_type_;
2071  index_t element_index_;
2072  };
2073 
2074  /***********************************************************/
2075 
2081  public:
2083  }
2084 
2086  const AttributesManager& manager, const std::string& name
2087  ) : ScalarAttributeAdapterBase(manager, name) {
2088  }
2089 
2097  double operator[](index_t i) {
2098  return get_element_as_double(i);
2099  }
2100  };
2101 
2102  /***********************************************************/
2103 
2109  public:
2111  }
2112 
2114  const AttributesManager& manager, const std::string& name
2115  ) : ScalarAttributeAdapterBase(manager, name) {
2116  }
2117 
2118  Accessor operator[](index_t i) {
2119  return Accessor(*this, i);
2120  }
2121 
2122  ConstAccessor operator[](index_t i) const {
2123  return ConstAccessor(*this, i);
2124  }
2125 
2126  protected:
2127  };
2128 
2129 
2130 }
2131 
2132 #endif
#define geo_assert_not_reached
Sets a non reachable point in the program.
Definition: assert.h:177
#define geo_assert(x)
Verifies that a condition is met.
Definition: assert.h:149
#define geo_debug_assert(x)
Verifies that a condition is met.
Definition: assert.h:196
Base class for Attributes, that manipulates an attribute stored in an AttributesManager.
Definition: attributes.h:1108
void create_vector_attribute(AttributesManager &manager, const std::string &name, index_t dimension)
Creates and binds a new vector attribute.
Definition: attributes.h:1237
~AttributeBase()
Attribute destructor.
Definition: attributes.h:1285
index_t size() const
Gets the size.
Definition: attributes.h:1315
AttributeBase(AttributesManager &manager, const std::string &name)
Creates or retrieves a persistent attribute attached to a given AttributesManager.
Definition: attributes.h:1128
void zero()
Sets all the elements of this Attribute to zero.
Definition: attributes.h:1323
bool is_bound() const
Tests whether an Attribute is bound.
Definition: attributes.h:1139
void unbind()
Unbinds this Attribute.
Definition: attributes.h:1147
void redim(index_t new_dim)
Sets the dimension.
Definition: attributes.h:1273
void destroy()
Destroys this attribute in the AttributesManager.
Definition: attributes.h:1256
bool bind_if_is_compatible(AttributesManager &manager, const std::string &name)
Binds this Attribute to an AttributesManager if it already exists in the AttributesManager and tyopes...
Definition: attributes.h:1212
static bool is_defined(AttributesManager &manager, const std::string &name, index_t dim=0)
Tests whether an attribute with the specified name and with corresponding type exists in an Attribute...
Definition: attributes.h:1299
bool can_get_vector()
Tests whether get_vector() can be called on this Attribute.
Definition: attributes.h:1337
AttributesManager * manager() const
Gets the AttributesManager this Attribute is bound to.
Definition: attributes.h:1377
const vector< T > & get_vector() const
Gets a const reference to the internal vector<T> used to store the attribute.
Definition: attributes.h:1366
vector< T > & get_vector()
Gets a reference to the internal vector<T> used to store the attribute.
Definition: attributes.h:1353
AttributeBase()
Creates an uninitialized (unbound) Attribute.
Definition: attributes.h:1114
void bind(AttributesManager &manager, const std::string &name)
Binds this Attribute to an AttributesManager.
Definition: attributes.h:1168
bool bind_if_is_defined(AttributesManager &manager, const std::string &name)
Binds this Attribute to an AttributesManager if it already exists in the AttributesManager.
Definition: attributes.h:1190
Internal class for creating an AttributeStore from the type name of its elements.
Definition: attributes.h:163
~AttributeStoreCreator() override
AttributeStoreCreator destructor.
virtual AttributeStore * create_attribute_store(index_t dimension)=0
Creates a new attribute store.
Base class for attributes. They are notified whenever the AttributeStore is modified.
Definition: attributes.h:70
AttributeStoreObserver()
Creates a new uninitialied AttributeStore.
Definition: attributes.h:76
void register_me(AttributeStore *store)
Registers this observer to an AttributeStore.
index_t size() const
Gets the size.
Definition: attributes.h:100
void notify(Memory::pointer base_addr, index_t size, index_t dim)
Callback function, called by the AttributeStore whenever it is modified.
Definition: attributes.h:88
index_t nb_elements() const
Gets the total number of elements.
Definition: attributes.h:118
void disconnect()
Disconnects this AttributeStoreObserver from its AttributeStore.
Definition: attributes.h:141
void unregister_me(AttributeStore *store)
Unregisters this observer from an AttributeStore.
index_t dimension() const
Gets the dimension.
Definition: attributes.h:108
Notifies a set of AttributeStoreObservers each time the stored array changes size and/or base address...
Definition: attributes.h:195
AttributeStore(index_t elemsize, index_t dim=1)
AttributeStore constructor.
bool has_observers() const
Tests whether observers listen to this AttributeStore.
Definition: attributes.h:276
void zero_item(index_t to)
Sets an item to zero.
Definition: attributes.h:378
virtual ~AttributeStore()
AttributeStore destructor.
static std::string element_typeid_name_by_element_type_name(const std::string &element_type_name)
Gets an element mangled type name from its C++ name.
Definition: attributes.h:507
static void register_attribute_creator(AttributeStoreCreator *creator, const std::string &element_type_name, const std::string &element_typeid_name)
Registers a new element type.
Definition: attributes.h:524
const void * data() const
Gets a pointer to the stored data.
Definition: attributes.h:424
index_t size() const
Gets the size.
Definition: attributes.h:238
virtual void clear(bool keep_memory=false)=0
Resizes this AttributeStore to 0.
virtual void notify(Memory::pointer base_addr, index_t size, index_t dim)
If size or base address differ from the cached values, notify all the observers, and update the cache...
index_t capacity() const
Gets the capacity.
Definition: attributes.h:247
virtual void madd_item(index_t to, double s, index_t from)
Adds a scaled item to another item \detais item[to] += s * item[from].
static bool element_type_name_is_known(const std::string &element_type_name)
Tests whether a given element type is registered in the system.
Definition: attributes.h:444
virtual void compress(const vector< index_t > &old2new)
Compresses the stored attributes, by applying an index mapping that fills-in the gaps.
virtual std::string element_typeid_name() const =0
Gets the typeid name of the element type stored in this AttributeStore.
void copy_item(index_t to, index_t from)
Copies an item.
Definition: attributes.h:363
static bool element_typeid_name_is_known(const std::string &element_typeid_name)
Tests whether a given element type is registered in the system.
Definition: attributes.h:461
void register_observer(AttributeStoreObserver *observer)
Registers an observer.
virtual void apply_permutation(const vector< index_t > &permutation)
Applies a permutation to the stored attributes.
virtual void resize(index_t new_size)=0
Resizes this AttributeStore.
virtual AttributeStore * clone() const =0
Creates a new AttributeStore that is a carbon copy of this AttributeStore.
virtual void scale_item(index_t to, double s)
Scales an item.
static AttributeStore * create_attribute_store_by_element_type_name(const std::string &element_type_name, index_t dimension)
Creates an attribute store of a given type.
Definition: attributes.h:476
void unregister_observer(AttributeStoreObserver *observer)
Unregisters an observer.
virtual void redim(index_t dim)=0
Sets the dimension.
index_t dimension() const
Gets the dimension.
Definition: attributes.h:285
static std::string element_type_name_by_element_typeid_name(const std::string &element_typeid_name)
Gets an element type name from its mangled name.
Definition: attributes.h:492
virtual bool elements_type_matches(const std::string &type_name) const =0
Tests whether this AttributeStore stores elements of a given type.
void swap_items(index_t i, index_t j)
Swaps two items.
void * data()
Gets a pointer to the stored data.
Definition: attributes.h:416
size_t element_size() const
Gets the element size.
Definition: attributes.h:432
virtual void reserve(index_t new_capacity)=0
Reserves memory.
virtual void zero()
Zeroes all the memory associated with this AttributeStore.
BoolAttributeAccessor(Attribute< bool > &attribute, index_t index)
BoolAttributeAccessor constructor.
Definition: attributes.h:1579
BoolAttributeAccessor & operator=(const ConstBoolAttributeAccessor &rhs)
Copies a bool from another attribute.
Definition: attributes.h:1634
BoolAttributeAccessor & operator=(bool x)
Assigns a bool to a BoolAttributeAccessor.
Definition: attributes.h:1609
BoolAttributeAccessor(const BoolAttributeAccessor &rhs)
Copy-constructor.
Definition: attributes.h:1600
BoolAttributeAccessor & operator=(const BoolAttributeAccessor &rhs)
Copies a bool from another attribute.
Definition: attributes.h:1619
ConstBoolAttributeAccessor(const Attribute< bool > &attribute, index_t index)
ConstBoolAttributeAccessor constructor.
Definition: attributes.h:1547
Specialization of Attribute for booleans.
Definition: attributes.h:1524
Numeric::uint8 & element(index_t i)
Gets a modifiable element by index.
Definition: attributes.h:1677
const Numeric::uint8 & element(index_t i) const
Gets an element by index.
Definition: attributes.h:1687
void fill(bool val)
Sets all the elements in this attribute to a specified value.
Definition: attributes.h:1661
Manages an attribute attached to a set of object.
Definition: attributes.h:1394
T & operator[](index_t i)
Gets a modifiable element by index.
Definition: attributes.h:1446
Attribute(AttributesManager &manager, const std::string &name)
Creates or retrieves a persistent attribute attached to a given AttributesManager.
Definition: attributes.h:1436
Attribute()
Creates an uninitialized (unbound) Attribute.
Definition: attributes.h:1423
const T & operator[](index_t i) const
Gets an element by index.
Definition: attributes.h:1456
void fill(const T &val)
Sets all the elements in this attribute to a specified value.
Definition: attributes.h:1466
T * data()
Gets the pointer to the data.
Definition: attributes.h:1490
void copy(const Attribute< T > &rhs)
Copies all the values from another attribute.
Definition: attributes.h:1478
const T * data() const
Gets the pointer to the data.
Definition: attributes.h:1498
static void static_test_type()
Tests at compile time whether type can be used in an Attribute. If not the case generates a compile-t...
Definition: attributes.h:1403
Managers a set of attributes attached to an object.
Definition: attributes.h:834
void delete_attribute_store(AttributeStore *as)
Deletes an AttributeStore.
AttributeStore * find_attribute_store(const std::string &name)
Finds an AttributeStore by name.
void compress(const vector< index_t > &old2new)
Compresses the stored attributes, by applying an index mapping that fills-in the gaps.
void zero_item(index_t to)
Sets an item to zero.
void copy(const AttributesManager &rhs)
Copies all the attributes from another AttributesManager.
AttributesManager()
Constructs a new empty AttributesManager.
index_t nb() const
Gets the number of attributes.
Definition: attributes.h:852
bool rename_attribute(const std::string &old_name, const std::string &new_name)
Renames an attribute.
void scale_item(index_t to, double s)
Scales an item.
void apply_permutation(const vector< index_t > &permutation)
Applies a permutation to the stored attributes.
void bind_attribute_store(const std::string &name, AttributeStore *as)
Binds an AttributeStore with the specified name. Ownership of this AttributeStore is transferred to t...
void list_attribute_names(vector< std::string > &names) const
Gets the names of all the attributes in this AttributeStore.
~AttributesManager()
AttributesManager destructor.
void copy_item(index_t to, index_t from)
Copies all the attributes of an item into another one.
void madd_item(index_t to, double s, index_t from)
Adds a scaled item to another item \detais item[to] += s * item[from].
bool is_defined(const std::string &name) const
Tests whether an attribute is defined.
Definition: attributes.h:949
void swap_items(index_t i, index_t j)
Swaps all the attributes of two items.
index_t size() const
Gets the size.
Definition: attributes.h:869
void clear(bool keep_attributes, bool keep_memory=false)
Clears this AttributesManager.
index_t capacity() const
Gets the capacity.
Definition: attributes.h:878
void delete_attribute_store(const std::string &name)
Deletes an AttributeStore by name.
bool copy_attribute(const std::string &name, const std::string &new_name)
Copies an attribute.
const AttributeStore * find_attribute_store(const std::string &name) const
Finds an AttributeStore by name.
void zero()
Zeroes all the attributes.
void reserve(index_t new_capacity)
Pre-allocates memory for a number of items.
void resize(index_t new_size)
Resizes all the attributes managed by this AttributesManager.
Base class for reference-counted objects.
Definition: counted.h:71
static void register_ascii_attribute_serializer(const std::string &type_name, AsciiAttributeSerializer read, AsciiAttributeSerializer write)
Declares a new attribute type that can be read from and written to ascii files.
static std::ostream & warn(const std::string &feature)
Gets the stream to send warning messages.
Readonly access to an attribute as a double regardless its type.
Definition: attributes.h:2080
double operator[](index_t i)
Gets a property value.
Definition: attributes.h:2097
Readwrite access to an attribute as a double regardless its type.
Definition: attributes.h:2108
Accessor class used by ScalarAttributeAdapter to implement indexing operator.
Definition: attributes.h:1733
Accessor class used by ScalarAttributeAdapter to implement indexing operator (const version).
Definition: attributes.h:1758
Access to an attribute as a double regardless its type.
Definition: attributes.h:1710
index_t element_index() const
Gets the element index.
Definition: attributes.h:1888
T get_element(index_t i, index_t multiplier=1) const
Gets an element.
Definition: attributes.h:1999
ElementType
Internal representation of the attribute.
Definition: attributes.h:1716
static std::string attribute_base_name(const std::string &name)
Gets the base attribute name from a compound name.
void bind_if_is_defined(const AttributesManager &manager, const std::string &name)
Binds this Attribute to an AttributesManager if it already exists in the AttributesManager.
bool is_bound() const
Tests whether an Attribute is bound.
Definition: attributes.h:1807
static index_t nb_scalar_elements_per_item(const AttributeStore *store)
Gets the number of scalar components per item in an AttributeStore.
double get_element_as_double(index_t i) const
Gets an attribute value.
Definition: attributes.h:1958
~ScalarAttributeAdapterBase()
ReadonlyScalarAttributeAdapterBase destructor.
Definition: attributes.h:1844
static ElementType element_type(const AttributeStore *store)
Gets the element type stored in an AttributeStore.
ScalarAttributeAdapterBase()
ScalarAttributeAdapterBase constructor.
Definition: attributes.h:1778
static bool can_be_bound_to(const AttributeStore *store)
Tests whether a ScalarAttributeAdapterBase can be bound to a given attribute store.
Definition: attributes.h:1908
void unbind()
Unbinds this Attribute.
Definition: attributes.h:1815
static bool is_defined(const AttributesManager &manager, const std::string &name)
Tests whether an attribute with the specified name and with a type that can be converted to double ex...
ScalarAttributeAdapterBase(const AttributesManager &manager, const std::string &name)
ScalarAttributeAdapterBase constructor.
Definition: attributes.h:1794
double set_element_as_double(index_t i, double value)
Sets an attribute value.
Definition: attributes.h:2014
void set_element(T value, index_t i, index_t multiplier=1) const
Sets an element.
Definition: attributes.h:2056
const AttributeStore * attribute_store() const
Gets the AttributeStore.
Definition: attributes.h:1896
static index_t attribute_element_index(const std::string &name)
Gets the base attribute name from a compound name.
index_t size() const
Gets the size.
Definition: attributes.h:1867
ElementType element_type() const
Gets the internal representation of the elements.
Definition: attributes.h:1878
A smart pointer with reference-counted copy semantics.
Definition: smart_pointer.h:76
Implementation of AttributeStoreCreator for a specific type.
Definition: attributes.h:781
AttributeStore * create_attribute_store(index_t dim) override
Creates a new attribute store.
Definition: attributes.h:786
Stores an array of elements of a given type, and notifies a set of AttributeStoreObservers each time ...
Definition: attributes.h:607
void scale_item(index_t to, double s) override
Scales an item.
Definition: attributes.h:693
TypedAttributeStore(index_t dim=1)
Creates a new empty attribute store.
Definition: attributes.h:616
void notify(Memory::pointer base_addr, index_t size, index_t dim) override
If size or base address differ from the cached values, notify all the observers, and update the cache...
Definition: attributes.h:711
void clear(bool keep_memory=false) override
Resizes this AttributeStore to 0.
Definition: attributes.h:641
void resize(index_t new_size) override
Resizes this AttributeStore.
Definition: attributes.h:620
std::string element_typeid_name() const override
Gets the typeid name of the element type stored in this AttributeStore.
Definition: attributes.h:677
void reserve(index_t new_capacity) override
Reserves memory.
Definition: attributes.h:629
bool elements_type_matches(const std::string &type_name) const override
Tests whether this AttributeStore stores elements of a given type.
Definition: attributes.h:671
void madd_item(index_t to, double s, index_t from) override
Adds a scaled item to another item \detais item[to] += s * item[from].
Definition: attributes.h:700
void redim(index_t dim) override
Sets the dimension.
Definition: attributes.h:651
AttributeStore * clone() const override
Creates a new AttributeStore that is a carbon copy of this AttributeStore.
Definition: attributes.h:681
Helper class to register new attribute types.
Definition: attributes.h:797
geo_register_attribute_type(const std::string &type_name)
geo_register_attribute_type constructor
Definition: attributes.h:808
Functions to read and write structured files.
Common include file, providing basic definitions. Should be included before anything else by all head...
Generic logging mechanism.
Types and functions for memory manipulation.
byte * pointer
Pointer to unsigned byte(s)
Definition: memory.h:104
void clear(void *addr, size_t size)
Clears a memory block.
Definition: memory.h:116
void copy(void *to, const void *from, size_t size)
Copies a memory block.
Definition: memory.h:129
float float32
Definition: numeric.h:147
uint8_t uint8
Definition: numeric.h:135
int8_t int8
Definition: numeric.h:123
double float64
Definition: numeric.h:150
int32_t int32
Definition: numeric.h:129
uint32_t uint32
Definition: numeric.h:141
std::atomic_flag spinlock
A lightweight synchronization structure.
Definition: thread_sync.h:149
Global Vorpaline namespace.
Definition: basic.h:55
bool write_ascii_attribute< bool >(FILE *file, Memory::pointer base_addr, index_t nb_elements)
Writes an ASCII attribute to a file.
Definition: geofile.h:228
void geo_argused(const T &)
Suppresses compiler warnings about unused parameters.
Definition: argused.h:60
geo_index_t index_t
The type for storing and manipulating indices.
Definition: numeric.h:329
SmartPointer< AttributeStoreCreator > AttributeStoreCreator_var
An automatic reference-counted pointer to an AttributeStoreCreator.
Definition: attributes.h:188
bool read_ascii_attribute< bool >(FILE *file, Memory::pointer base_addr, index_t nb_elements)
Reads an ASCII attribute from a file.
Definition: geofile.h:204
Types and functions for numbers manipulation.
Function and classes for process manipulation.