Files
UnrealEngine/Engine/Source/ThirdParty/OpenVDB/Deploy/openvdb-12.0.0/include/openvdb/MetaMap.h
2025-05-18 13:04:45 +08:00

218 lines
7.4 KiB
C++

// Copyright Contributors to the OpenVDB Project
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENVDB_METADATA_METAMAP_HAS_BEEN_INCLUDED
#define OPENVDB_METADATA_METAMAP_HAS_BEEN_INCLUDED
#include "Metadata.h"
#include "Types.h"
#include "Exceptions.h"
#include <iosfwd>
#include <map>
namespace openvdb {
OPENVDB_USE_VERSION_NAMESPACE
namespace OPENVDB_VERSION_NAME {
/// Container that maps names (strings) to values of arbitrary types
class OPENVDB_API MetaMap
{
public:
using Ptr = SharedPtr<MetaMap>;
using ConstPtr = SharedPtr<const MetaMap>;
using MetadataMap = std::map<Name, Metadata::Ptr>;
using MetaIterator = MetadataMap::iterator;
using ConstMetaIterator = MetadataMap::const_iterator;
///< @todo this should really iterate over a map of Metadata::ConstPtrs
MetaMap() {}
MetaMap(const MetaMap& other);
virtual ~MetaMap() {}
/// Return a copy of this map whose fields are shared with this map.
MetaMap::Ptr copyMeta() const;
/// Return a deep copy of this map that shares no data with this map.
MetaMap::Ptr deepCopyMeta() const;
/// Assign a deep copy of another map to this map.
MetaMap& operator=(const MetaMap&);
/// Unserialize metadata from the given stream.
void readMeta(std::istream&);
/// Serialize metadata to the given stream.
void writeMeta(std::ostream&) const;
/// @brief Insert a new metadata field or overwrite the value of an existing field.
/// @details If a field with the given name doesn't already exist, add a new field.
/// Otherwise, if the new value's type is the same as the existing field's value type,
/// overwrite the existing value with new value.
/// @throw TypeError if a field with the given name already exists, but its value type
/// is not the same as the new value's
/// @throw ValueError if the given field name is empty.
void insertMeta(const Name&, const Metadata& value);
/// @brief Deep copy all of the metadata fields from the given map into this map.
/// @throw TypeError if any field in the given map has the same name as
/// but a different value type than one of this map's fields.
void insertMeta(const MetaMap&);
/// Remove the given metadata field if it exists.
void removeMeta(const Name&);
//@{
/// @brief Return a pointer to the metadata with the given name.
/// If no such field exists, return a null pointer.
Metadata::Ptr operator[](const Name&);
Metadata::ConstPtr operator[](const Name&) const;
//@}
//@{
/// @brief Return a pointer to a TypedMetadata object of type @c T and with the given name.
/// If no such field exists or if there is a type mismatch, return a null pointer.
template<typename T> typename T::Ptr getMetadata(const Name&);
template<typename T> typename T::ConstPtr getMetadata(const Name&) const;
//@}
/// @brief Return a reference to the value of type @c T stored in the given metadata field.
/// @throw LookupError if no field with the given name exists.
/// @throw TypeError if the given field is not of type @c T.
template<typename T> T& metaValue(const Name&);
template<typename T> const T& metaValue(const Name&) const;
// Functions for iterating over the metadata
MetaIterator beginMeta() { return mMeta.begin(); }
MetaIterator endMeta() { return mMeta.end(); }
ConstMetaIterator beginMeta() const { return mMeta.begin(); }
ConstMetaIterator endMeta() const { return mMeta.end(); }
void clearMetadata() { mMeta.clear(); }
size_t metaCount() const { return mMeta.size(); }
/// Return a string describing this metadata map. Prefix each line with @a indent.
std::string str(const std::string& indent = "") const;
/// Return @c true if the given map is equivalent to this map.
bool operator==(const MetaMap& other) const;
/// Return @c true if the given map is different from this map.
bool operator!=(const MetaMap& other) const { return !(*this == other); }
private:
/// @brief Return a pointer to TypedMetadata with the given template parameter.
/// @throw LookupError if no field with the given name is found.
/// @throw TypeError if the given field is not of type T.
template<typename T>
typename TypedMetadata<T>::Ptr getValidTypedMetadata(const Name&) const;
MetadataMap mMeta;
};
/// Write a MetaMap to an output stream
std::ostream& operator<<(std::ostream&, const MetaMap&);
////////////////////////////////////////
inline Metadata::Ptr
MetaMap::operator[](const Name& name)
{
MetaIterator iter = mMeta.find(name);
return (iter == mMeta.end() ? Metadata::Ptr() : iter->second);
}
inline Metadata::ConstPtr
MetaMap::operator[](const Name &name) const
{
ConstMetaIterator iter = mMeta.find(name);
return (iter == mMeta.end() ? Metadata::Ptr() : iter->second);
}
////////////////////////////////////////
template<typename T>
inline typename T::Ptr
MetaMap::getMetadata(const Name &name)
{
ConstMetaIterator iter = mMeta.find(name);
if (iter == mMeta.end()) return typename T::Ptr{};
// To ensure that we get valid conversion if the metadata pointers cross dso
// boundaries, we have to check the qualified typename and then do a static
// cast. This is slower than doing a dynamic_pointer_cast, but is safer when
// pointers cross dso boundaries.
if (iter->second->typeName() == T::staticTypeName()) {
return StaticPtrCast<T, Metadata>(iter->second);
} // else
return typename T::Ptr{};
}
template<typename T>
inline typename T::ConstPtr
MetaMap::getMetadata(const Name &name) const
{
ConstMetaIterator iter = mMeta.find(name);
if (iter == mMeta.end()) return typename T::ConstPtr{};
// To ensure that we get valid conversion if the metadata pointers cross dso
// boundaries, we have to check the qualified typename and then do a static
// cast. This is slower than doing a dynamic_pointer_cast, but is safer when
// pointers cross dso boundaries.
if (iter->second->typeName() == T::staticTypeName()) {
return StaticPtrCast<const T, const Metadata>(iter->second);
} // else
return typename T::ConstPtr{};
}
////////////////////////////////////////
template<typename T>
inline typename TypedMetadata<T>::Ptr
MetaMap::getValidTypedMetadata(const Name &name) const
{
ConstMetaIterator iter = mMeta.find(name);
if (iter == mMeta.end()) OPENVDB_THROW(LookupError, "Cannot find metadata " << name);
// To ensure that we get valid conversion if the metadata pointers cross dso
// boundaries, we have to check the qualified typename and then do a static
// cast. This is slower than doing a dynamic_pointer_cast, but is safer when
// pointers cross dso boundaries.
typename TypedMetadata<T>::Ptr m;
if (iter->second->typeName() == TypedMetadata<T>::staticTypeName()) {
m = StaticPtrCast<TypedMetadata<T>, Metadata>(iter->second);
}
if (!m) OPENVDB_THROW(TypeError, "Invalid type for metadata " << name);
return m;
}
////////////////////////////////////////
template<typename T>
inline T&
MetaMap::metaValue(const Name &name)
{
typename TypedMetadata<T>::Ptr m = getValidTypedMetadata<T>(name);
return m->value();
}
template<typename T>
inline const T&
MetaMap::metaValue(const Name &name) const
{
typename TypedMetadata<T>::Ptr m = getValidTypedMetadata<T>(name);
return m->value();
}
} // namespace OPENVDB_VERSION_NAME
} // namespace openvdb
#endif // OPENVDB_METADATA_METAMAP_HAS_BEEN_INCLUDED