1 // Copyright Contributors to the OpenVDB Project 2 // SPDX-License-Identifier: MPL-2.0 3 4 /// @file points/AttributeArrayString.h 5 /// 6 /// @author Dan Bailey 7 /// 8 /// @brief Attribute array storage for string data using Descriptor Metadata. 9 10 #ifndef OPENVDB_POINTS_ATTRIBUTE_ARRAY_STRING_HAS_BEEN_INCLUDED 11 #define OPENVDB_POINTS_ATTRIBUTE_ARRAY_STRING_HAS_BEEN_INCLUDED 12 13 #include "AttributeArray.h" 14 #include <memory> 15 #include <deque> 16 #include <unordered_map> 17 18 19 namespace openvdb { 20 OPENVDB_USE_VERSION_NAMESPACE 21 namespace OPENVDB_VERSION_NAME { 22 namespace points { 23 24 25 //////////////////////////////////////// 26 27 28 namespace attribute_traits 29 { 30 template <bool Truncate> struct StringTypeTrait { using Type = Index; }; 31 template<> struct StringTypeTrait</*Truncate=*/true> { using Type = uint16_t; }; 32 } 33 34 35 template <bool Truncate> 36 struct StringCodec 37 { 38 using ValueType = Index; 39 40 template <typename T> 41 struct Storage { using Type = typename attribute_traits::StringTypeTrait<Truncate>::Type; }; 42 43 template<typename StorageType> static void decode(const StorageType&, ValueType&); 44 template<typename StorageType> static void encode(const ValueType&, StorageType&); 45 static const char* name() { return Truncate ? "str_trnc" : "str"; } 46 }; 47 48 49 using StringAttributeArray = TypedAttributeArray<Index, StringCodec<false>>; 50 51 52 //////////////////////////////////////// 53 54 55 /// Class to compute a string->index map from all string:N metadata 56 class OPENVDB_API StringMetaCache 57 { 58 public: 59 using UniquePtr = std::unique_ptr<StringMetaCache>; 60 using ValueMap = std::unordered_map<Name, Index>; 61 62 StringMetaCache() = default; 63 explicit StringMetaCache(const MetaMap& metadata); 64 65 /// Return @c true if no string elements in metadata 66 bool empty() const { return mCache.empty(); } 67 /// Returns the number of string elements in metadata 68 size_t size() const { return mCache.size(); } 69 70 /// Clears and re-populates the cache 71 void reset(const MetaMap& metadata); 72 73 /// Insert a new element in the cache 74 void insert(const Name& key, Index index); 75 76 /// Retrieve the value map (string -> index) 77 const ValueMap& map() const { return mCache; } 78 79 private: 80 ValueMap mCache; 81 }; // StringMetaCache 82 83 84 //////////////////////////////////////// 85 86 87 /// Class to help with insertion of keyed string values into metadata 88 class OPENVDB_API StringMetaInserter 89 { 90 public: 91 using UniquePtr = std::unique_ptr<StringMetaInserter>; 92 93 explicit StringMetaInserter(MetaMap& metadata); 94 95 /// Returns @c true if key exists 96 bool hasKey(const Name& key) const; 97 /// Returns @c true if index exists 98 bool hasIndex(Index index) const; 99 100 /// @brief Insert the string into the metadata using the hint if non-zero 101 /// @param name the string to insert 102 /// @param hint requested index to use if non-zero and not already in use 103 /// @note the hint can be used to insert non-sequentially so as to avoid an 104 /// expensive re-indexing of string keys 105 /// @return the chosen index which will match hint if the hint was used 106 Index insert(const Name& name, Index hint = Index(0)); 107 108 /// Reset the cache from the metadata 109 void resetCache(); 110 111 private: 112 using IndexPairArray = std::deque<std::pair<Index, Index>>; 113 114 MetaMap& mMetadata; 115 IndexPairArray mIdBlocks; 116 StringMetaCache mCache; 117 }; // StringMetaInserter 118 119 120 //////////////////////////////////////// 121 122 123 template <bool Truncate> 124 template<typename StorageType> 125 inline void 126 StringCodec<Truncate>::decode(const StorageType& data, ValueType& val) 127 { 128 val = static_cast<ValueType>(data); 129 } 130 131 132 template <bool Truncate> 133 template<typename StorageType> 134 inline void 135 StringCodec<Truncate>::encode(const ValueType& val, StorageType& data) 136 { 137 data = static_cast<ValueType>(val); 138 } 139 140 141 //////////////////////////////////////// 142 143 144 inline bool isString(const AttributeArray& array) 145 { 146 return array.isType<StringAttributeArray>(); 147 } 148 149 150 //////////////////////////////////////// 151 152 153 class OPENVDB_API StringAttributeHandle 154 { 155 public: 156 using Ptr = std::shared_ptr<StringAttributeHandle>;//SharedPtr<StringAttributeHandle>; 157 using UniquePtr = std::unique_ptr<StringAttributeHandle>; 158 159 static Ptr create(const AttributeArray& array, const MetaMap& metadata, const bool preserveCompression = true); 160 161 StringAttributeHandle( const AttributeArray& array, 162 const MetaMap& metadata, 163 const bool preserveCompression = true); 164 165 Index stride() const { return mHandle.stride(); } 166 Index size() const { return mHandle.size(); } 167 168 bool isUniform() const { return mHandle.isUniform(); } 169 bool hasConstantStride() const { return mHandle.hasConstantStride(); } 170 171 Name get(Index n, Index m = 0) const; 172 void get(Name& name, Index n, Index m = 0) const; 173 174 /// @brief Returns a reference to the array held in the Handle. 175 const AttributeArray& array() const; 176 177 protected: 178 AttributeHandle<Index, StringCodec<false>> mHandle; 179 const MetaMap& mMetadata; 180 }; // class StringAttributeHandle 181 182 183 //////////////////////////////////////// 184 185 186 class OPENVDB_API StringAttributeWriteHandle : public StringAttributeHandle 187 { 188 public: 189 using Ptr = std::shared_ptr<StringAttributeWriteHandle>;//SharedPtr<StringAttributeWriteHandle>; 190 using UniquePtr = std::unique_ptr<StringAttributeWriteHandle>; 191 192 static Ptr create(AttributeArray& array, const MetaMap& metadata, const bool expand = true); 193 194 StringAttributeWriteHandle( AttributeArray& array, 195 const MetaMap& metadata, 196 const bool expand = true); 197 198 /// @brief If this array is uniform, replace it with an array of length size(). 199 /// @param fill if true, assign the uniform value to each element of the array. 200 void expand(bool fill = true); 201 202 /// @brief Set membership for the whole array and attempt to collapse 203 void collapse(); 204 /// @brief Set membership for the whole array and attempt to collapse 205 /// @param name Name of the String 206 void collapse(const Name& name); 207 208 /// Compact the existing array to become uniform if all values are identical 209 bool compact(); 210 211 /// @brief Fill the existing array with the given value. 212 /// @note Identical to collapse() except a non-uniform array will not become uniform. 213 void fill(const Name& name); 214 215 /// Set the value of the index to @a name 216 void set(Index n, const Name& name); 217 void set(Index n, Index m, const Name& name); 218 219 /// Reset the value cache from the metadata 220 void resetCache(); 221 222 /// @brief Returns a reference to the array held in the Write Handle. 223 AttributeArray& array(); 224 225 /// @brief Returns whether or not the metadata cache contains a given value. 226 /// @param name Name of the String. 227 bool contains(const Name& name) const; 228 229 private: 230 /// Retrieve the index of this string value from the cache 231 /// @note throws if name does not exist in cache 232 Index getIndex(const Name& name) const; 233 234 StringMetaCache mCache; 235 AttributeWriteHandle<Index, StringCodec<false>> mWriteHandle; 236 }; // class StringAttributeWriteHandle 237 238 239 //////////////////////////////////////// 240 241 242 } // namespace points 243 } // namespace OPENVDB_VERSION_NAME 244 } // namespace openvdb 245 246 #endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_STRING_HAS_BEEN_INCLUDED 247 248