nana/include/nana/any.hpp

160 lines
3.6 KiB
C++

/**
* Any
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file nana/any.hpp
*
* @brief An implementation of experimental library any of C++ standard(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html#any)
*/
#ifndef NANA_ANY_HPP
#define NANA_ANY_HPP
#include <typeinfo>
#include <type_traits>
#include "c++defines.hpp"
namespace nana
{
class bad_any_cast
: public std::bad_cast
{
};
class any
{
class content_interface
{
public:
virtual ~content_interface() = default;
virtual const std::type_info& type() const noexcept = 0;
virtual content_interface* clone() const = 0;
};
template<typename Value>
class holder : public content_interface
{
holder& operator=(const holder&) = delete;
public:
holder(const Value& other)
: value(other)
{}
holder(Value&& other)
: value(static_cast<Value&&>(other))
{}
public:
const std::type_info& type() const noexcept override
{
return typeid(Value);
}
content_interface* clone() const override
{
return new holder(value);
}
public:
Value value; //representation accessable for friend of any
};
public:
//constructors and destructor
any() noexcept;
any(const any& other);
any(any&& other) noexcept;
template<typename Value>
any(Value && value,
typename std::enable_if<!std::is_same<any&, Value>::value>::type * = nullptr,
typename std::enable_if<!std::is_const<Value>::value>::type* = nullptr)
: content_(new holder<typename std::decay<Value>::type>(static_cast<Value&&>(value)))
{
}
~any();
//assignments
any& operator=(const any& other);
any& operator=(any&& other) noexcept;
template<class Value>
any& operator=(Value&& other)
{
any(other).swap(*this);
return *this;
}
//modifiers
void clear() noexcept;
void swap(any& other) noexcept;
//observers
bool empty() const noexcept;
const std::type_info& type() const noexcept;
private:
template<typename Value>
friend Value* any_cast(any*) noexcept;
private:
content_interface * content_;
};
// Non-member functions
inline void swap(any& x, any& y) noexcept
{
x.swap(y);
}
template<typename Value>
Value any_cast(const any& operand)
{
using value_type = typename std::remove_reference<Value>::type;
return any_cast<const value_type&>(const_cast<any&>(operand));
}
template<typename Value>
Value any_cast(any& operand)
{
using value_type = typename std::remove_reference<Value>::type;
auto value_ptr = any_cast<value_type>(&operand);
if (!value_ptr)
throw bad_any_cast();
using ref_type = typename std::conditional<std::is_reference<Value>::value, Value, typename std::add_lvalue_reference<Value>::type>::type;
return static_cast<ref_type>(*value_ptr);
}
template<typename Value>
Value any_cast(any && operand)
{
static_assert(std::is_rvalue_reference<Value&&>::value || std::is_const<typename ::std::remove_reference<Value>::type>::value, "nana::any_cast shall not be used for getting non-const reference to temporary objects");
return any_cast<Value>(operand);
}
template<typename Value>
const Value* any_cast(const any* operand) noexcept
{
return any_cast<Value>(const_cast<any*>(operand));
}
template<typename Value>
Value* any_cast(any* operand) noexcept
{
if (!operand)
return nullptr;
auto holder = dynamic_cast<any::holder<typename std::decay<Value>::type>*>(operand->content_);
return (holder ? &holder->value : nullptr);
}
}//end namespace nana
#endif