430 lines
12 KiB
C++
430 lines
12 KiB
C++
/**
|
|
* 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 <algorithm>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <type_traits>
|
|
#include <typeinfo>
|
|
|
|
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<ValueType>,
|
|
* direct-initialized from std::forward<ValueType>(value). If
|
|
* std::is_copy_constructible<std::decay_t<ValueType>>::value is false, the program is ill-formed.
|
|
*/
|
|
template<typename ValueType>
|
|
any(const ValueType &value)
|
|
: content(new holder<typename std::remove_cv<
|
|
typename std::decay<const ValueType>::type>::type>(value))
|
|
{}
|
|
|
|
/**
|
|
* Constructs an object with initial content an object of type std::decay_t<ValueType>,
|
|
* direct-initialized from std::forward<ValueType>(value). If
|
|
* std::is_copy_constructible<std::decay_t<ValueType>>::value is false, the program is ill-formed.
|
|
*/
|
|
template<typename ValueType>
|
|
any(ValueType &&value,
|
|
typename std::enable_if<!std::is_same<any &, ValueType>::value>::type
|
|
* = 0,
|
|
typename std::enable_if<!std::is_const<ValueType>::value>::type * = 0)
|
|
: content(new holder<typename std::decay<ValueType>::type>(
|
|
static_cast<ValueType &&>(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<ValueType>(rhs)).swap(*this).
|
|
* This overload only participates in overload resolution if std::decay_t<ValueType> is not
|
|
* the same type as any and std::is_copy_constructible_v<std::decay_t<ValueType>> is true.
|
|
*
|
|
* @param rhs object whose contained value to assign
|
|
*/
|
|
template<class ValueType>
|
|
any &operator=(ValueType &&rhs)
|
|
{
|
|
any(static_cast<ValueType &&>(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<typename ValueType>
|
|
class holder : public placeholder {
|
|
public:
|
|
holder(const ValueType &value) : held(value) {}
|
|
|
|
holder(ValueType &&value) : held(static_cast<ValueType &&>(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<typename ValueType>
|
|
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<typename ValueType>
|
|
ValueType *
|
|
any_cast(any *operand) noexcept
|
|
{
|
|
return operand && operand->type() == typeid(ValueType) ? std::addressof(
|
|
static_cast<any::holder<typename std::remove_cv<ValueType>::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<typename ValueType>
|
|
inline const ValueType *
|
|
any_cast(const any *operand) noexcept
|
|
{
|
|
return any_cast<ValueType>(const_cast<any *>(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<typename ValueType>
|
|
ValueType
|
|
any_cast(any &operand)
|
|
{
|
|
typedef typename std::remove_reference<ValueType>::type nonref;
|
|
|
|
nonref *result = any_cast<nonref>(std::addressof(operand));
|
|
if (!result) throw bad_any_cast();
|
|
|
|
typedef typename std::conditional<
|
|
std::is_reference<ValueType>::value, ValueType,
|
|
typename std::add_lvalue_reference<ValueType>::type>::type ref_type;
|
|
|
|
return static_cast<ref_type>(*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<typename ValueType>
|
|
inline ValueType
|
|
any_cast(const any &operand)
|
|
{
|
|
typedef typename std::remove_reference<ValueType>::type nonref;
|
|
return any_cast<const nonref &>(const_cast<any &>(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<typename ValueType>
|
|
inline ValueType
|
|
any_cast(any &&operand)
|
|
{
|
|
static_assert(
|
|
std::is_rvalue_reference<ValueType &&>::value
|
|
|| std::is_const<
|
|
typename std::remove_reference<ValueType>::type>::value,
|
|
"any_cast shall not be used for getting nonconst references to "
|
|
"temporary objects");
|
|
|
|
return any_cast<ValueType>(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<typename ValueType>
|
|
inline Any(const ValueType &value) : value_(value)
|
|
{}
|
|
|
|
template<typename ValueType>
|
|
inline Any(
|
|
ValueType &&value,
|
|
typename std::enable_if<!std::is_same<Any &, ValueType>::value>::type
|
|
* = 0,
|
|
typename std::enable_if<!std::is_const<ValueType>::value>::type * = 0)
|
|
: value_(std::forward<ValueType &&>(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<typename ValueType>
|
|
Any &operator=(ValueType &&rhs)
|
|
{
|
|
Any(static_cast<ValueType &&>(rhs)).swap(*this);
|
|
return *this;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
inline auto Cast() const -> ValueType const
|
|
{
|
|
return any_cast<ValueType>(value_);
|
|
}
|
|
|
|
template<typename ValueType>
|
|
inline ValueType Cast() const &&
|
|
{
|
|
return any_cast<ValueType>(value_);
|
|
}
|
|
|
|
template<typename ValueType, typename U = ValueType>
|
|
inline auto CastOr(U &&default_value) const -> ValueType
|
|
{
|
|
try {
|
|
return any_cast<ValueType>(value_);
|
|
} catch (const bad_any_cast &e) {
|
|
return static_cast<ValueType>(default_value);
|
|
}
|
|
}
|
|
|
|
template<typename ValueType, typename U = ValueType>
|
|
inline auto CastOr(U &&default_value) -> ValueType
|
|
{
|
|
try {
|
|
return any_cast<ValueType>(value_);
|
|
} catch (const bad_any_cast &e) {
|
|
return static_cast<ValueType>(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 */
|