// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 #ifndef OPENVDB_METADATA_HAS_BEEN_INCLUDED #define OPENVDB_METADATA_HAS_BEEN_INCLUDED #include "version.h" #include "Exceptions.h" #include "Types.h" #include "math/Math.h" // for math::isZero() #include "util/Name.h" #include "util/Assert.h" #include #include #include #include namespace openvdb { OPENVDB_USE_VERSION_NAMESPACE namespace OPENVDB_VERSION_NAME { /// @brief Base class for storing metadata information in a grid. class OPENVDB_API Metadata { public: using Ptr = SharedPtr; using ConstPtr = SharedPtr; Metadata() {} virtual ~Metadata() {} // Disallow copying of instances of this class. Metadata(const Metadata&) = delete; Metadata& operator=(const Metadata&) = delete; /// Return the type name of the metadata. virtual Name typeName() const = 0; /// Return a copy of the metadata. virtual Metadata::Ptr copy() const = 0; /// Copy the given metadata into this metadata. virtual void copy(const Metadata& other) = 0; /// Return a textual representation of this metadata. virtual std::string str() const = 0; /// Return the boolean representation of this metadata (empty strings /// and zeroVals evaluate to false; most other values evaluate to true). virtual bool asBool() const = 0; /// Return @c true if the given metadata is equivalent to this metadata. bool operator==(const Metadata& other) const; /// Return @c true if the given metadata is different from this metadata. bool operator!=(const Metadata& other) const { return !(*this == other); } /// Return the size of this metadata in bytes. virtual Index32 size() const = 0; /// Unserialize this metadata from a stream. void read(std::istream&); /// Serialize this metadata to a stream. void write(std::ostream&) const; /// Create new metadata of the given type. static Metadata::Ptr createMetadata(const Name& typeName); /// Return @c true if the given type is known by the metadata type registry. static bool isRegisteredType(const Name& typeName); /// Clear out the metadata registry. static void clearRegistry(); /// Register the given metadata type along with a factory function. static void registerType(const Name& typeName, Metadata::Ptr (*createMetadata)()); static void unregisterType(const Name& typeName); protected: /// Read the size of the metadata from a stream. static Index32 readSize(std::istream&); /// Write the size of the metadata to a stream. void writeSize(std::ostream&) const; /// Read the metadata from a stream. virtual void readValue(std::istream&, Index32 numBytes) = 0; /// Write the metadata to a stream. virtual void writeValue(std::ostream&) const = 0; }; /// @brief Subclass to hold raw data of an unregistered type class OPENVDB_API UnknownMetadata: public Metadata { public: using ByteVec = std::vector; explicit UnknownMetadata(const Name& typ = ""): mTypeName(typ) {} Name typeName() const override { return mTypeName; } Metadata::Ptr copy() const override; void copy(const Metadata&) override; std::string str() const override { return (mBytes.empty() ? "" : ""); } bool asBool() const override { return !mBytes.empty(); } Index32 size() const override { return static_cast(mBytes.size()); } void setValue(const ByteVec& bytes) { mBytes = bytes; } const ByteVec& value() const { return mBytes; } protected: void readValue(std::istream&, Index32 numBytes) override; void writeValue(std::ostream&) const override; private: Name mTypeName; ByteVec mBytes; }; /// @brief Templated metadata class to hold specific types. template class TypedMetadata: public Metadata { public: using Ptr = SharedPtr>; using ConstPtr = SharedPtr>; TypedMetadata(); TypedMetadata(const T& value); TypedMetadata(const TypedMetadata& other); ~TypedMetadata() override; Name typeName() const override; Metadata::Ptr copy() const override; void copy(const Metadata& other) override; std::string str() const override; bool asBool() const override; Index32 size() const override { return static_cast(sizeof(T)); } /// Set this metadata's value. void setValue(const T&); /// Return this metadata's value. T& value(); const T& value() const; // Static specialized function for the type name. This function must be // template specialized for each type T. static Name staticTypeName() { return typeNameAsString(); } /// Create new metadata of this type. static Metadata::Ptr createMetadata(); static void registerType(); static void unregisterType(); static bool isRegisteredType(); protected: void readValue(std::istream&, Index32 numBytes) override; void writeValue(std::ostream&) const override; private: T mValue; }; /// Write a Metadata to an output stream std::ostream& operator<<(std::ostream& ostr, const Metadata& metadata); //////////////////////////////////////// inline void Metadata::writeSize(std::ostream& os) const { const Index32 n = this->size(); os.write(reinterpret_cast(&n), sizeof(Index32)); } inline Index32 Metadata::readSize(std::istream& is) { Index32 n = 0; is.read(reinterpret_cast(&n), sizeof(Index32)); return n; } inline void Metadata::read(std::istream& is) { const Index32 numBytes = this->readSize(is); this->readValue(is, numBytes); } inline void Metadata::write(std::ostream& os) const { this->writeSize(os); this->writeValue(os); } //////////////////////////////////////// template inline TypedMetadata::TypedMetadata() : mValue(T()) { } template inline TypedMetadata::TypedMetadata(const T &value) : mValue(value) { } template inline TypedMetadata::TypedMetadata(const TypedMetadata &other) : Metadata(), mValue(other.mValue) { } template inline TypedMetadata::~TypedMetadata() { } template inline Name TypedMetadata::typeName() const { return TypedMetadata::staticTypeName(); } template inline void TypedMetadata::setValue(const T& val) { mValue = val; } template inline T& TypedMetadata::value() { return mValue; } template inline const T& TypedMetadata::value() const { return mValue; } template inline Metadata::Ptr TypedMetadata::copy() const { Metadata::Ptr metadata(new TypedMetadata()); metadata->copy(*this); return metadata; } template inline void TypedMetadata::copy(const Metadata &other) { const TypedMetadata* t = dynamic_cast*>(&other); if (t == nullptr) OPENVDB_THROW(TypeError, "Incompatible type during copy"); mValue = t->mValue; } template inline void TypedMetadata::readValue(std::istream& is, [[maybe_unused]] Index32 numBytes) { OPENVDB_ASSERT(this->size() == numBytes); is.read(reinterpret_cast(&mValue), this->size()); } template inline void TypedMetadata::writeValue(std::ostream& os) const { os.write(reinterpret_cast(&mValue), this->size()); } template inline std::string TypedMetadata::str() const { std::ostringstream ostr; ostr << mValue; return ostr.str(); } template inline bool TypedMetadata::asBool() const { return !math::isZero(mValue); } template inline Metadata::Ptr TypedMetadata::createMetadata() { Metadata::Ptr ret(new TypedMetadata()); return ret; } template inline void TypedMetadata::registerType() { Metadata::registerType(TypedMetadata::staticTypeName(), TypedMetadata::createMetadata); } template inline void TypedMetadata::unregisterType() { Metadata::unregisterType(TypedMetadata::staticTypeName()); } template inline bool TypedMetadata::isRegisteredType() { return Metadata::isRegisteredType(TypedMetadata::staticTypeName()); } template<> inline std::string TypedMetadata::str() const { return (mValue ? "true" : "false"); } inline std::ostream& operator<<(std::ostream& ostr, const Metadata& metadata) { ostr << metadata.str(); return ostr; } using BoolMetadata = TypedMetadata; using DoubleMetadata = TypedMetadata; using FloatMetadata = TypedMetadata; using Int32Metadata = TypedMetadata; using Int64Metadata = TypedMetadata; using StringMetadata = TypedMetadata; using Vec2DMetadata = TypedMetadata; using Vec2IMetadata = TypedMetadata; using Vec2SMetadata = TypedMetadata; using Vec3DMetadata = TypedMetadata; using Vec3IMetadata = TypedMetadata; using Vec3SMetadata = TypedMetadata; using Vec4DMetadata = TypedMetadata; using Vec4IMetadata = TypedMetadata; using Vec4SMetadata = TypedMetadata; using Mat4SMetadata = TypedMetadata; using Mat4DMetadata = TypedMetadata; //////////////////////////////////////// template<> inline Index32 StringMetadata::size() const { return static_cast(mValue.size()); } template<> inline std::string StringMetadata::str() const { return mValue; } template<> inline void StringMetadata::readValue(std::istream& is, Index32 size) { mValue.resize(size, '\0'); is.read(&mValue[0], size); } template<> inline void StringMetadata::writeValue(std::ostream& os) const { os.write(reinterpret_cast(&mValue[0]), this->size()); } } // namespace OPENVDB_VERSION_NAME } // namespace openvdb #endif // OPENVDB_METADATA_HAS_BEEN_INCLUDED