meta/runtime/any.h
2024-03-04 18:21:58 +08:00

330 lines
9.9 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 META_ANY_H
#define META_ANY_H
#include <algorithm>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <typeinfo>
namespace meta {
namespace reflection {
/**
* 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);
}
}// namespace reflection
}// namespace meta
#endif /* META_ANY_H */