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