// // Copyright Contributors to the MaterialX Project // SPDX-License-Identifier: Apache-2.0 // #ifndef MATERIALX_VALUE_H #define MATERIALX_VALUE_H /// @file /// Generic value classes #include #include #include MATERIALX_NAMESPACE_BEGIN /// A vector of integers. using IntVec = vector; /// A vector of booleans. using BoolVec = vector; /// A vector of floats. using FloatVec = vector; class Value; class AggregateValue; /// A shared pointer to a Value using ValuePtr = shared_ptr; /// A shared pointer to a const Value using ConstValuePtr = shared_ptr; /// A shared pointer to an Aggregate Value using AggregateValuePtr = shared_ptr; /// A shared pointer to a const Aggregate Value using ConstAggregateValuePtr = shared_ptr; class TypeDef; using ConstTypeDefPtr = shared_ptr; template class TypedValue; /// A generic, discriminated value, whose type may be queried dynamically. class MX_CORE_API Value { public: /// Float formats to use when converting values to strings. enum FloatFormat { FloatFormatDefault = 0, FloatFormatFixed = 1, FloatFormatScientific = 2 }; public: Value() { } virtual ~Value() { } /// Create a new value from an object of any valid MaterialX type. template static ValuePtr createValue(const T& data) { return std::make_shared>(data); } // Create a new value from a C-style string. static ValuePtr createValue(const char* data) { return createValue(data ? string(data) : EMPTY_STRING); } /// Create a new value instance from value and type strings. /// @return A shared pointer to a typed value, or an empty shared pointer /// if the conversion to the given data type cannot be performed. static ValuePtr createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef = nullptr); /// Create a deep copy of the value. virtual ValuePtr copy() const = 0; /// @name Data Accessors /// @{ /// Return true if this value is of the given type. template bool isA() const; /// Return our underlying data as an object of the given type. /// If the given type doesn't match our own data type, then an /// exception is thrown. template const T& asA() const; /// Return the type string for this value. virtual const string& getTypeString() const = 0; /// Return the value string for this value. virtual string getValueString() const = 0; /// Set float formatting for converting values to strings. /// Formats to use are FloatFormatFixed, FloatFormatScientific /// or FloatFormatDefault to set default format. static void setFloatFormat(FloatFormat format); /// Set float precision for converting values to strings. static void setFloatPrecision(int precision); /// Return the current float format. static FloatFormat getFloatFormat(); /// Return the current float precision. static int getFloatPrecision(); // Returns true if value data matches. virtual bool isEqual(ConstValuePtr other) const = 0; protected: template friend class ValueRegistry; using CreatorFunction = ValuePtr (*)(const string&); using CreatorMap = std::unordered_map; private: static CreatorMap _creatorMap; }; /// The class template for typed subclasses of Value template class TypedValue : public Value { public: MX_CORE_API TypedValue() : _data{} { } MX_CORE_API explicit TypedValue(const T& value) : _data(value) { } MX_CORE_API virtual ~TypedValue() { } /// Create a deep copy of the value. MX_CORE_API ValuePtr copy() const override { return Value::createValue(_data); } /// Set stored data object. MX_CORE_API void setData(const T& value) { _data = value; } /// Set stored data object. MX_CORE_API void setData(const TypedValue& value) { _data = value._data; } /// Return stored data object. MX_CORE_API const T& getData() const { return _data; } /// Return type string. MX_CORE_API const string& getTypeString() const override; /// Return value string. MX_CORE_API string getValueString() const override; // Returns true if value data matches. MX_CORE_API bool isEqual(ConstValuePtr other) const override { if (!other || !other->isA()) { return false; } return _data == other->asA(); } // // Static helper methods // /// Create a new value of this type from a value string. /// @return A shared pointer to a typed value, or an empty shared pointer /// if the conversion to the given data type cannot be performed. MX_CORE_API static ValuePtr createFromString(const string& value); public: MX_CORE_API static const string TYPE; private: T _data; }; /// A subclass for aggregate values with multiple members class MX_CORE_API AggregateValue : public Value { public: AggregateValue(const string& typeName) : _typeName(typeName) { } virtual ~AggregateValue() { } /// Create a deep copy of the value. ValuePtr copy() const override { auto result = createAggregateValue(_typeName); for (const auto& val : _data) { result->appendValue(val->copy()); } return result; } /// Append a member value to the aggregate. void appendValue(ConstValuePtr valuePtr) { _data.emplace_back(valuePtr); } const vector& getMembers() const { return _data; } /// Query an indexed member value from the aggregate. ConstValuePtr getMemberValue(size_t index) const { return _data[index]; } /// Return type string. const string& getTypeString() const override { return _typeName; } /// Return value string. string getValueString() const override; // Returns true if value data matches. bool isEqual(ConstValuePtr other) const override; // // Static helper methods // /// Create a new value from an object of any valid MaterialX type. static AggregateValuePtr createAggregateValue(const string& typeName) { return std::make_shared(typeName); } static AggregateValuePtr createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDefPtr); private: const string _typeName; vector _data; }; /// @class ScopedFloatFormatting /// An RAII class for controlling the float formatting of values. class MX_CORE_API ScopedFloatFormatting { public: explicit ScopedFloatFormatting(Value::FloatFormat format, int precision = -1); ~ScopedFloatFormatting(); private: Value::FloatFormat _format; int _precision; }; /// Return the type string associated with the given data type. template MX_CORE_API const string& getTypeString(); /// Convert the given data value to a value string. template MX_CORE_API string toValueString(const T& data); /// Convert the given value string to a data value of the given type. /// @throws ExceptionTypeError if the conversion cannot be performed. template MX_CORE_API T fromValueString(const string& value); /// Tokenize the string representation of a struct value i.e, "{1;2;3}" into a /// vector of substrings. /// Note: "{1;2;{3;4;5}}" will be split in to ["1", "2", "{3;4;5}"] MX_CORE_API StringVec parseStructValueString(const string& value); /// Forward declaration of specific template instantiations. /// Base types MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); /// Array types MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); /// Alias types MX_CORE_EXTERN_TEMPLATE(TypedValue); MX_CORE_EXTERN_TEMPLATE(TypedValue); MATERIALX_NAMESPACE_END #endif