/** * Port of boost::any for C++11 compilers. * See http://www.boost.org/libs/any for Documentation. * * See also: * + http://en.cppreference.com/w/cpp/any * + http://en.cppreference.com/w/cpp/experimental/any * + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any * + https://cplusplus.github.io/LWG/lwg-active.html#2509 * * Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. * Copyright Claudio Fantacci, 2018. All rights reserved. * * what: variant type boost::any * who: contributed by Kevlin Henney, * with features contributed and bugs found by Antony Polukhin, Ed Brey, Mark Rodgers, Peter Dimov and James Curran, * with C++11 compiler port by Claudio Fantacci * when: July 2001, April 2013 - May 2013, September 2018 * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE.md or copy at http://www.boost.org/LICENSE_1_0.txt) */ #pragma once #ifndef SLED_ANY_H #define SLED_ANY_H #include #include #include #include #include namespace sled { /** * The class any describes a type-safe container for single values of any type. * An object of class any stores an instance of any type that satisfies the * constructor requirements or is empty, and this is referred to as the state * of the class any object. The stored instance is called the contained object. * Two states are equivalent if they are either both empty or if both are not * empty and if the contained objects are equivalent. * The non-member any_cast functions provide type-safe access to the contained object. */ class any final { public: /** * Constructs an empty object. */ any() noexcept : content(0) {} /** * Copies content of other into a new instance, so that any content is equivalent * in both type and value to those of other prior to the constructor call, * or empty if other is empty. */ any(const any &other) : content(other.content ? other.content->clone() : 0) {} /** * Moves content of other into a new instance, so that any content is equivalent * in both type and value to those of other prior to the constructor call, * or empty if other is empty. */ any(any &&other) noexcept : content(other.content) { other.content = 0; } /** * Constructs an object with initial content an object of type std::decay_t, * direct-initialized from std::forward(value). If * std::is_copy_constructible>::value is false, the program is ill-formed. */ template any(const ValueType &value) : content(new holder::type>::type>(value)) {} /** * Constructs an object with initial content an object of type std::decay_t, * direct-initialized from std::forward(value). If * std::is_copy_constructible>::value is false, the program is ill-formed. */ template any(ValueType &&value, typename std::enable_if::value>::type * = 0, typename std::enable_if::value>::type * = 0) : content(new holder::type>( static_cast(value))) {} /** * Destruct the object. */ ~any() noexcept { delete content; } /** * Assigns contents to the contained value. * Assigns by copying the state of rhs, as if by any(rhs).swap(*this). * * @param rhs object whose contained value to assign */ any &operator=(const any &rhs) { any(rhs).swap(*this); return *this; } /** * Assigns contents to the contained value. * Assigns by moving the state of rhs, as if by any(std::move(rhs)).swap(*this). * rhs is left in a valid but unspecified state after the assignment. * * @param rhs object whose contained value to assign */ any &operator=(any &&rhs) noexcept { rhs.swap(*this); any().swap(rhs); return *this; } /** * Assigns contents to the contained value. * Assigns the type and value of rhs, as if by any(std::forward(rhs)).swap(*this). * This overload only participates in overload resolution if std::decay_t is not * the same type as any and std::is_copy_constructible_v> is true. * * @param rhs object whose contained value to assign */ template any &operator=(ValueType &&rhs) { any(static_cast(rhs)).swap(*this); return *this; } /** * If not empty, destroys the contained object. */ void reset() noexcept { any().swap(*this); } /** * Swaps the content of two any objects. * * @param other object to swap with */ any &swap(any &rhs) noexcept { std::swap(content, rhs.content); return *this; } /** * Checks whether the object contains a value. * * @return true if instance contains a value, otherwise false. */ bool has_value() const noexcept { return content; } /** * Queries the contained type. * * The typeid of the contained value if instance is non-empty, otherwise typeid(void). */ const std::type_info &type() const noexcept { return content ? content->type() : typeid(void); } private: class placeholder { public: virtual ~placeholder() {} public: virtual const std::type_info &type() const noexcept = 0; virtual placeholder *clone() const = 0; }; template class holder : public placeholder { public: holder(const ValueType &value) : held(value) {} holder(ValueType &&value) : held(static_cast(value)) {} virtual const std::type_info &type() const noexcept { return typeid(ValueType); } virtual placeholder *clone() const { return new holder(held); } ValueType held; private: holder &operator=(const holder &); }; private: template friend ValueType *any_cast(any *) noexcept; placeholder *content; }; /** * Overloads the std::swap algorithm for std::any. Swaps the content of two any objects by calling lhs.swap(rhs). * * @param lhs objects to swap * @param rhs objects to swap */ inline void swap(any &lhs, any &rhs) noexcept { lhs.swap(rhs); } /** * Defines a type of object to be thrown by the value-returning forms of libanyboost::any_cast on failure. */ class bad_any_cast : public std::bad_cast { public: /** * Returns the explanatory string. * * Pointer to a null-terminated string with explanatory information. The pointer is guaranteed to be * valid at least until the exception object from which it is obtained is destroyed, or until a * non-const member function on the exception object is called. */ virtual const char *what() const noexcept override { return "bad any_cast"; } }; /** * Performs type-safe access to the contained object. * * Throws libanyboost::bad_any_cast if the typeid of the requested * ValueType does not match that of the contents of operand. * * @param operand target any object */ template ValueType * any_cast(any *operand) noexcept { return operand && operand->type() == typeid(ValueType) ? std::addressof( static_cast::type> *>(operand->content) ->held) : 0; } /** * Performs type-safe access to the contained object. * * Throws libanyboost::bad_any_cast if the typeid of the requested * ValueType does not match that of the contents of operand. * * @param operand target any object */ template inline const ValueType * any_cast(const any *operand) noexcept { return any_cast(const_cast(operand)); } /** * Performs type-safe access to the contained object. * * Throws libanyboost::bad_any_cast if the typeid of the requested * ValueType does not match that of the contents of operand. * * @param operand target any object */ template ValueType any_cast(any &operand) { typedef typename std::remove_reference::type nonref; nonref *result = any_cast(std::addressof(operand)); if (!result) throw bad_any_cast(); typedef typename std::conditional< std::is_reference::value, ValueType, typename std::add_lvalue_reference::type>::type ref_type; return static_cast(*result); } /** * Performs type-safe access to the contained object. * * Throws libanyboost::bad_any_cast if the typeid of the requested * ValueType does not match that of the contents of operand. * * @param operand target any object */ template inline ValueType any_cast(const any &operand) { typedef typename std::remove_reference::type nonref; return any_cast(const_cast(operand)); } /** * Performs type-safe access to the contained object. * * Throws libanyboost::bad_any_cast if the typeid of the requested * ValueType does not match that of the contents of operand. * * @param operand target any object */ template inline ValueType any_cast(any &&operand) { static_assert( std::is_rvalue_reference::value || std::is_const< typename std::remove_reference::type>::value, "any_cast shall not be used for getting nonconst references to " "temporary objects"); return any_cast(operand); } class Any final { public: inline Any() {} inline Any(const Any &other) : value_(other.value_) {} inline Any(Any &&other) noexcept : value_(std::move(other.value_)) {} template inline Any(const ValueType &value) : value_(value) {} template inline Any( ValueType &&value, typename std::enable_if::value>::type * = 0, typename std::enable_if::value>::type * = 0) : value_(std::forward(value)) {} // ~Any() noexcept {} Any &operator=(const Any &rhs) { Any(rhs).swap(*this); return *this; } Any &operator=(Any &&rhs) noexcept { rhs.swap(*this); Any().swap(rhs); return *this; } template Any &operator=(ValueType &&rhs) { Any(static_cast(rhs)).swap(*this); return *this; } template inline auto Cast() const -> ValueType const { return any_cast(value_); } template inline ValueType Cast() const && { return any_cast(value_); } template inline auto CastOr(U &&default_value) const -> ValueType { try { return any_cast(value_); } catch (const bad_any_cast &e) { return static_cast(default_value); } } template inline auto CastOr(U &&default_value) -> ValueType { try { return any_cast(value_); } catch (const bad_any_cast &e) { return static_cast(default_value); } } void Reset() noexcept { Any().swap(*this); } bool HasValue() const noexcept { return value_.has_value(); } const std::type_info &Type() const noexcept { return value_.type(); } Any &swap(Any &rhs) noexcept { std::swap(value_, rhs.value_); return *this; } any value_; private: }; }// namespace sled #endif /* SLED_ANY_H */