1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #ifndef OPENVDB_METADATA_HAS_BEEN_INCLUDED
5 #define OPENVDB_METADATA_HAS_BEEN_INCLUDED
6 
7 #include "version.h"
8 #include "Exceptions.h"
9 #include "Types.h"
10 #include "math/Math.h" // for math::isZero()
11 #include "util/Name.h"
12 #include <cstdint>
13 #include <iostream>
14 #include <string>
15 #include <vector>
16 
17 
18 namespace openvdb {
19 OPENVDB_USE_VERSION_NAMESPACE
20 namespace OPENVDB_VERSION_NAME {
21 
22 /// @brief Base class for storing metadata information in a grid.
23 class OPENVDB_API Metadata
24 {
25 public:
26     using Ptr = SharedPtr<Metadata>;
27     using ConstPtr = SharedPtr<const Metadata>;
28 
Metadata()29     Metadata() {}
~Metadata()30     virtual ~Metadata() {}
31 
32     // Disallow copying of instances of this class.
33     Metadata(const Metadata&) = delete;
34     Metadata& operator=(const Metadata&) = delete;
35 
36     /// Return the type name of the metadata.
37     virtual Name typeName() const = 0;
38 
39     /// Return a copy of the metadata.
40     virtual Metadata::Ptr copy() const = 0;
41 
42     /// Copy the given metadata into this metadata.
43     virtual void copy(const Metadata& other) = 0;
44 
45     /// Return a textual representation of this metadata.
46     virtual std::string str() const = 0;
47 
48     /// Return the boolean representation of this metadata (empty strings
49     /// and zeroVals evaluate to false; most other values evaluate to true).
50     virtual bool asBool() const = 0;
51 
52     /// Return @c true if the given metadata is equivalent to this metadata.
53     bool operator==(const Metadata& other) const;
54     /// Return @c true if the given metadata is different from this metadata.
55     bool operator!=(const Metadata& other) const { return !(*this == other); }
56 
57     /// Return the size of this metadata in bytes.
58     virtual Index32 size() const = 0;
59 
60     /// Unserialize this metadata from a stream.
61     void read(std::istream&);
62     /// Serialize this metadata to a stream.
63     void write(std::ostream&) const;
64 
65     /// Create new metadata of the given type.
66     static Metadata::Ptr createMetadata(const Name& typeName);
67 
68     /// Return @c true if the given type is known by the metadata type registry.
69     static bool isRegisteredType(const Name& typeName);
70 
71     /// Clear out the metadata registry.
72     static void clearRegistry();
73 
74     /// Register the given metadata type along with a factory function.
75     static void registerType(const Name& typeName, Metadata::Ptr (*createMetadata)());
76     static void unregisterType(const Name& typeName);
77 
78 protected:
79     /// Read the size of the metadata from a stream.
80     static Index32 readSize(std::istream&);
81     /// Write the size of the metadata to a stream.
82     void writeSize(std::ostream&) const;
83 
84     /// Read the metadata from a stream.
85     virtual void readValue(std::istream&, Index32 numBytes) = 0;
86     /// Write the metadata to a stream.
87     virtual void writeValue(std::ostream&) const = 0;
88 };
89 
90 
91 /// @brief Subclass to hold raw data of an unregistered type
92 class OPENVDB_API UnknownMetadata: public Metadata
93 {
94 public:
95     using ByteVec = std::vector<uint8_t>;
96 
mTypeName(typ)97     explicit UnknownMetadata(const Name& typ = "<unknown>"): mTypeName(typ) {}
98 
typeName()99     Name typeName() const override { return mTypeName; }
100     Metadata::Ptr copy() const override;
101     void copy(const Metadata&) override;
str()102     std::string str() const override { return (mBytes.empty() ? "" : "<binary data>"); }
asBool()103     bool asBool() const override { return !mBytes.empty(); }
size()104     Index32 size() const override { return static_cast<Index32>(mBytes.size()); }
105 
setValue(const ByteVec & bytes)106     void setValue(const ByteVec& bytes) { mBytes = bytes; }
value()107     const ByteVec& value() const { return mBytes; }
108 
109 protected:
110     void readValue(std::istream&, Index32 numBytes) override;
111     void writeValue(std::ostream&) const override;
112 
113 private:
114     Name mTypeName;
115     ByteVec mBytes;
116 };
117 
118 
119 /// @brief Templated metadata class to hold specific types.
120 template<typename T>
121 class TypedMetadata: public Metadata
122 {
123 public:
124     using Ptr = SharedPtr<TypedMetadata<T>>;
125     using ConstPtr = SharedPtr<const TypedMetadata<T>>;
126 
127     TypedMetadata();
128     TypedMetadata(const T& value);
129     TypedMetadata(const TypedMetadata<T>& other);
130     ~TypedMetadata() override;
131 
132     Name typeName() const override;
133     Metadata::Ptr copy() const override;
134     void copy(const Metadata& other) override;
135     std::string str() const override;
136     bool asBool() const override;
size()137     Index32 size() const override { return static_cast<Index32>(sizeof(T)); }
138 
139     /// Set this metadata's value.
140     void setValue(const T&);
141     /// Return this metadata's value.
142     T& value();
143     const T& value() const;
144 
145     // Static specialized function for the type name. This function must be
146     // template specialized for each type T.
staticTypeName()147     static Name staticTypeName() { return typeNameAsString<T>(); }
148 
149     /// Create new metadata of this type.
150     static Metadata::Ptr createMetadata();
151 
152     static void registerType();
153     static void unregisterType();
154     static bool isRegisteredType();
155 
156 protected:
157     void readValue(std::istream&, Index32 numBytes) override;
158     void writeValue(std::ostream&) const override;
159 
160 private:
161     T mValue;
162 };
163 
164 /// Write a Metadata to an output stream
165 std::ostream& operator<<(std::ostream& ostr, const Metadata& metadata);
166 
167 
168 ////////////////////////////////////////
169 
170 
171 inline void
writeSize(std::ostream & os)172 Metadata::writeSize(std::ostream& os) const
173 {
174     const Index32 n = this->size();
175     os.write(reinterpret_cast<const char*>(&n), sizeof(Index32));
176 }
177 
178 
179 inline Index32
readSize(std::istream & is)180 Metadata::readSize(std::istream& is)
181 {
182     Index32 n = 0;
183     is.read(reinterpret_cast<char*>(&n), sizeof(Index32));
184     return n;
185 }
186 
187 
188 inline void
read(std::istream & is)189 Metadata::read(std::istream& is)
190 {
191     const Index32 numBytes = this->readSize(is);
192     this->readValue(is, numBytes);
193 }
194 
195 
196 inline void
write(std::ostream & os)197 Metadata::write(std::ostream& os) const
198 {
199     this->writeSize(os);
200     this->writeValue(os);
201 }
202 
203 
204 ////////////////////////////////////////
205 
206 
207 template <typename T>
208 inline
TypedMetadata()209 TypedMetadata<T>::TypedMetadata() : mValue(T())
210 {
211 }
212 
213 template <typename T>
214 inline
TypedMetadata(const T & value)215 TypedMetadata<T>::TypedMetadata(const T &value) : mValue(value)
216 {
217 }
218 
219 template <typename T>
220 inline
TypedMetadata(const TypedMetadata<T> & other)221 TypedMetadata<T>::TypedMetadata(const TypedMetadata<T> &other) :
222     Metadata(),
223     mValue(other.mValue)
224 {
225 }
226 
227 template <typename T>
228 inline
~TypedMetadata()229 TypedMetadata<T>::~TypedMetadata()
230 {
231 }
232 
233 template <typename T>
234 inline Name
typeName()235 TypedMetadata<T>::typeName() const
236 {
237     return TypedMetadata<T>::staticTypeName();
238 }
239 
240 template <typename T>
241 inline void
setValue(const T & val)242 TypedMetadata<T>::setValue(const T& val)
243 {
244     mValue = val;
245 }
246 
247 template <typename T>
248 inline T&
value()249 TypedMetadata<T>::value()
250 {
251     return mValue;
252 }
253 
254 template <typename T>
255 inline const T&
value()256 TypedMetadata<T>::value() const
257 {
258     return mValue;
259 }
260 
261 template <typename T>
262 inline Metadata::Ptr
copy()263 TypedMetadata<T>::copy() const
264 {
265     Metadata::Ptr metadata(new TypedMetadata<T>());
266     metadata->copy(*this);
267     return metadata;
268 }
269 
270 template <typename T>
271 inline void
copy(const Metadata & other)272 TypedMetadata<T>::copy(const Metadata &other)
273 {
274     const TypedMetadata<T>* t = dynamic_cast<const TypedMetadata<T>*>(&other);
275     if (t == nullptr) OPENVDB_THROW(TypeError, "Incompatible type during copy");
276     mValue = t->mValue;
277 }
278 
279 
280 template<typename T>
281 inline void
readValue(std::istream & is,Index32)282 TypedMetadata<T>::readValue(std::istream& is, Index32 /*numBytes*/)
283 {
284     //assert(this->size() == numBytes);
285     is.read(reinterpret_cast<char*>(&mValue), this->size());
286 }
287 
288 template<typename T>
289 inline void
writeValue(std::ostream & os)290 TypedMetadata<T>::writeValue(std::ostream& os) const
291 {
292     os.write(reinterpret_cast<const char*>(&mValue), this->size());
293 }
294 
295 template <typename T>
296 inline std::string
str()297 TypedMetadata<T>::str() const
298 {
299     std::ostringstream ostr;
300     ostr << mValue;
301     return ostr.str();
302 }
303 
304 template<typename T>
305 inline bool
asBool()306 TypedMetadata<T>::asBool() const
307 {
308     return !math::isZero(mValue);
309 }
310 
311 template <typename T>
312 inline Metadata::Ptr
createMetadata()313 TypedMetadata<T>::createMetadata()
314 {
315     Metadata::Ptr ret(new TypedMetadata<T>());
316     return ret;
317 }
318 
319 template <typename T>
320 inline void
registerType()321 TypedMetadata<T>::registerType()
322 {
323     Metadata::registerType(TypedMetadata<T>::staticTypeName(),
324                            TypedMetadata<T>::createMetadata);
325 }
326 
327 template <typename T>
328 inline void
unregisterType()329 TypedMetadata<T>::unregisterType()
330 {
331     Metadata::unregisterType(TypedMetadata<T>::staticTypeName());
332 }
333 
334 template <typename T>
335 inline bool
isRegisteredType()336 TypedMetadata<T>::isRegisteredType()
337 {
338     return Metadata::isRegisteredType(TypedMetadata<T>::staticTypeName());
339 }
340 
341 
342 template<>
343 inline std::string
str()344 TypedMetadata<bool>::str() const
345 {
346     return (mValue ? "true" : "false");
347 }
348 
349 
350 inline std::ostream&
351 operator<<(std::ostream& ostr, const Metadata& metadata)
352 {
353     ostr << metadata.str();
354     return ostr;
355 }
356 
357 
358 using BoolMetadata   = TypedMetadata<bool>;
359 using DoubleMetadata = TypedMetadata<double>;
360 using FloatMetadata  = TypedMetadata<float>;
361 using Int32Metadata  = TypedMetadata<int32_t>;
362 using Int64Metadata  = TypedMetadata<int64_t>;
363 using StringMetadata = TypedMetadata<std::string>;
364 using Vec2DMetadata  = TypedMetadata<Vec2d>;
365 using Vec2IMetadata  = TypedMetadata<Vec2i>;
366 using Vec2SMetadata  = TypedMetadata<Vec2s>;
367 using Vec3DMetadata  = TypedMetadata<Vec3d>;
368 using Vec3IMetadata  = TypedMetadata<Vec3i>;
369 using Vec3SMetadata  = TypedMetadata<Vec3s>;
370 using Vec4DMetadata  = TypedMetadata<Vec4d>;
371 using Vec4IMetadata  = TypedMetadata<Vec4i>;
372 using Vec4SMetadata  = TypedMetadata<Vec4s>;
373 using Mat4SMetadata  = TypedMetadata<Mat4s>;
374 using Mat4DMetadata  = TypedMetadata<Mat4d>;
375 
376 
377 ////////////////////////////////////////
378 
379 
380 template<>
381 inline Index32
size()382 StringMetadata::size() const
383 {
384     return static_cast<Index32>(mValue.size());
385 }
386 
387 
388 template<>
389 inline std::string
str()390 StringMetadata::str() const
391 {
392     return mValue;
393 }
394 
395 
396 template<>
397 inline void
readValue(std::istream & is,Index32 size)398 StringMetadata::readValue(std::istream& is, Index32 size)
399 {
400     mValue.resize(size, '\0');
401     is.read(&mValue[0], size);
402 }
403 
404 template<>
405 inline void
writeValue(std::ostream & os)406 StringMetadata::writeValue(std::ostream& os) const
407 {
408     os.write(reinterpret_cast<const char*>(&mValue[0]), this->size());
409 }
410 
411 } // namespace OPENVDB_VERSION_NAME
412 } // namespace openvdb
413 
414 #endif // OPENVDB_METADATA_HAS_BEEN_INCLUDED
415