#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2023 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_SUPPORT_ANY_H #define NUCLEX_SUPPORT_ANY_H #include "Nuclex/Support/Config.h" #if !defined(NUCLEX_SUPPORT_SOURCE) #warning Nuclex::Support::Any has been deprecated in favor of C++17 std::any #endif #include #include namespace Nuclex { namespace Support { // ------------------------------------------------------------------------------------------- // /// Opaquely wraps a value of an arbitrary type /// /// This library targets C++14, where std::any hadn't been introduced yet. /// If you are targeting C++17 or later, there is no need to use this class. /// class NUCLEX_SUPPORT_TYPE Any { /// An instance that is empty public: const static Any Empty; #pragma region struct GenericValueHolder /// Base class to the holder for the value wrapped by the any protected: struct GenericValueHolder { /// Immediately releases all resources owned by the instance public: virtual ~GenericValueHolder() {} /// Creates a clone of the instance, also copying the value /// The cloned instance public: virtual GenericValueHolder *Clone() const = 0; /// Returns the type stored in the wrapper /// The type the wrapper is storing public: virtual const std::type_info &GetType() const = 0; }; #pragma endregion // struct GenericValueHolder #pragma region struct ValueHolder /// Strongly typed container for the value the any is carrying private: template struct ValueHolder : public GenericValueHolder { /// Initializes a new value holder for the specified value /// Value the holder will carry public: ValueHolder(const TValue &value) : value(value) {} /// Immediately releases all resources owned by the instance public: virtual ~ValueHolder() {} /// Creates a clone of the instance, also copying the value /// The cloned instance public: ValueHolder *Clone() const override { return new ValueHolder(this->value); } /// Returns the type stored in the wrapper /// The type the wrapper is storing public: const std::type_info &GetType() const override { return typeid(TValue); } /// Retrieves the value stored in the value holder /// The value stored in the value holder public: const TValue &Get() const { return this->value; } /// Value that is being carried by the any private: TValue value; }; #pragma endregion // struct ValueHolder /// Initializes a new any not holding a value public: NUCLEX_SUPPORT_API Any() : valueHolder(nullptr) {} /// Initializes a new any containing the specified value /// Value that will be carried by the any public: template Any(const TValue &value) : valueHolder(new ValueHolder::type>(value)) {} /// Initializes a new any copying the contents of an existing instance /// Other instance that will be copied public: NUCLEX_SUPPORT_API Any(const Any &other) : valueHolder(cloneOrPropagateNull(other.valueHolder)) {} /// Initializes a new any taking over an existing instance /// Other instance that will be taken over public: NUCLEX_SUPPORT_API Any(Any &&other) : valueHolder(other.valueHolder) { other.valueHolder = nullptr; } /// Frees all memory used by the instance public: NUCLEX_SUPPORT_API ~Any() { delete this->valueHolder; } /// Checks whether the Any is currently holding a value /// True if the Any holds a value, false otherwise public: NUCLEX_SUPPORT_API bool HasValue() const { return (this->valueHolder != nullptr); } /// Destroys the contents of the Any public: NUCLEX_SUPPORT_API void Reset() { delete this->valueHolder; this->valueHolder = nullptr; } /// Assigns the contents of another any to this instance /// Other any whose contents will be assigned to this one /// The current any after the value has been assigned public: NUCLEX_SUPPORT_API Any &operator =(const Any &other) { if(other.valueHolder == nullptr) { delete this->valueHolder; this->valueHolder = nullptr; } else { //std::unique_ptr clone(other.valueHolder->Clone()); GenericValueHolder *clone = other.valueHolder->Clone(); delete this->valueHolder; //this->valueHolder = clone.release(); this->valueHolder = clone; } return *this; } /// Moves the contents of another any to this instance /// Other any whose contents will be moved to this one /// The current any after the value has been moved public: NUCLEX_SUPPORT_API Any &operator =(Any &&other) { delete this->valueHolder; this->valueHolder = other.valueHolder; other.valueHolder = nullptr; return *this; } /// Retrieves the value stored in the any /// Type of value that will be retrieved from the any /// The value stored by the any public: template const TValue &Get() const { typedef ValueHolder TValueHolder; const std::type_info &type = typeid(typename std::decay::type); if(type != valueHolder->GetType()) { throw std::bad_cast(); // "Type is different from the value stored by the 'Any' instance" } return static_cast(this->valueHolder)->Get(); } /// Creates a clone of an existing value holder only if it's non-null /// Existing value holder to clone or null /// A clone of the existing value holder or a null pointer private: static GenericValueHolder *cloneOrPropagateNull(GenericValueHolder *other) { if(other == nullptr) { return nullptr; } else { return other->Clone(); } } /// Value holder that carries the value stored in the any private: GenericValueHolder *valueHolder; //private: std::uint8_t memory[sizeof(ValueHolder)]; }; // ------------------------------------------------------------------------------------------- // /// Extracts the value stored in the any /// Type of the value that will be retrieved /// Any whose stored value will be retrieved /// The value that is stored inside the any template const TValue &any_cast(const Any &any) { return any.Get(); } // ------------------------------------------------------------------------------------------- // }} // namespace Nuclex::Support #endif // NUCLEX_SUPPORT_ANY_H