update kiwano::any

This commit is contained in:
Nomango 2019-10-13 01:29:47 +08:00
parent 01f44fef80
commit 720d1fd6e0
1 changed files with 165 additions and 28 deletions

View File

@ -21,6 +21,7 @@
#pragma once #pragma once
#include <typeinfo> #include <typeinfo>
#include <type_traits> #include <type_traits>
#include <exception>
namespace kiwano namespace kiwano
{ {
@ -28,6 +29,18 @@ namespace kiwano
inline namespace core inline namespace core
{ {
class bad_any_cast : public std::exception
{
public:
bad_any_cast() {}
virtual const char* what() const override
{
return "bad and cast";
}
};
class any class any
{ {
public: public:
@ -38,11 +51,11 @@ public:
template < template <
typename _Ty, typename _Ty,
typename _Decayed = typename std::decay<_Ty>::type, typename _Decayed = typename std::decay<_Ty>::type,
typename = typename std::enable_if<std::is_copy_constructible<_Decayed>::value>::type typename std::enable_if<std::is_copy_constructible<_Decayed>::value, int>::type = 0
> >
any(_Ty&& val) : storage_{} any(_Ty&& val) : storage_{}
{ {
emplace<_Decayed>(std::forward<_Ty&&>(val)); emplace<_Decayed>(std::forward<_Ty>(val));
} }
template < template <
@ -57,22 +70,7 @@ public:
any(const any& rhs) : storage_{} any(const any& rhs) : storage_{}
{ {
if (rhs.has_value()) copy_from(rhs);
{
typeinfo() = rhs.typeinfo();
storage_.is_small_ = rhs.storage_.is_small_;
if (rhs.has_small_type())
{
small_rtti() = rhs.small_rtti();
small_rtti().copy(small_data(), rhs.small_data());
}
else
{
big_rtti() = rhs.big_rtti();
big_data() = big_rtti().copy(rhs.big_data());
}
}
} }
any(any&& rhs) noexcept : storage_{} any(any&& rhs) noexcept : storage_{}
@ -100,7 +98,10 @@ public:
return typeinfo() != nullptr; return typeinfo() != nullptr;
} }
template <typename _Decayed, typename... _Args> template <
typename _Decayed,
typename... _Args
>
void emplace(_Args&&... args) void emplace(_Args&&... args)
{ {
reset(); reset();
@ -119,6 +120,58 @@ public:
tidy(); tidy();
} }
template <typename _Ty>
_Ty* cast_pointer() noexcept
{
return const_cast<_Ty*>(const_cast<const any*>(this)->cast_pointer<_Ty>());
}
template <typename _Ty>
const _Ty* cast_pointer() const noexcept
{
static_assert(!std::is_void<_Ty>::value, "kiwano::any cannot contain void");
const type_info* const info = typeinfo();
if (info && (*info == typeid(std::decay<_Ty>::type)))
{
if (has_small_type())
{
return static_cast<const _Ty*>(small_data());
}
else
{
return static_cast<const _Ty*>(big_data());
}
}
return nullptr;
}
template <typename _Ty>
_Ty cast()
{
using _Decayed = typename std::decay<_Ty>::type;
const auto ptr = cast_pointer<_Decayed>();
if (!ptr)
{
throw bad_any_cast{};
}
return static_cast<_Ty>(*ptr);
}
template <typename _Ty>
_Ty cast() const
{
using _Decayed = typename std::decay<_Ty>::type;
const auto ptr = cast_pointer<_Decayed>();
if (!ptr)
{
throw bad_any_cast{};
}
return static_cast<_Ty>(*ptr);
}
any& operator=(const any& rhs) any& operator=(const any& rhs)
{ {
*this = any(rhs); *this = any(rhs);
@ -143,7 +196,10 @@ protected:
return storage_.small_.info_; return storage_.small_.info_;
} }
template <typename _Decayed, typename... _Args> template <
typename _Decayed,
typename... _Args
>
void store(std::true_type, _Args&&... args) void store(std::true_type, _Args&&... args)
{ {
storage_.is_small_ = true; storage_.is_small_ = true;
@ -153,7 +209,10 @@ protected:
::new (small_data()) _Decayed(std::forward<_Args>(args)...); ::new (small_data()) _Decayed(std::forward<_Args>(args)...);
} }
template <typename _Decayed, typename... _Args> template <
typename _Decayed,
typename... _Args
>
void store(std::false_type, _Args&&... args) void store(std::false_type, _Args&&... args)
{ {
storage_.is_small_ = false; storage_.is_small_ = false;
@ -180,6 +239,26 @@ protected:
} }
} }
void copy_from(const any& rhs)
{
if (rhs.has_value())
{
typeinfo() = rhs.typeinfo();
storage_.is_small_ = rhs.storage_.is_small_;
if (rhs.has_small_type())
{
small_rtti() = rhs.small_rtti();
small_rtti().copy(small_data(), rhs.small_data());
}
else
{
big_rtti() = rhs.big_rtti();
big_data() = big_rtti().copy(rhs.big_data());
}
}
}
void move_from(any&& rhs) noexcept void move_from(any&& rhs) noexcept
{ {
if (rhs.has_value()) if (rhs.has_value())
@ -196,10 +275,10 @@ protected:
{ {
big_rtti() = rhs.big_rtti(); big_rtti() = rhs.big_rtti();
big_data() = rhs.big_data(); big_data() = rhs.big_data();
}
rhs.typeinfo() = nullptr; rhs.typeinfo() = nullptr;
} }
} }
}
inline void* small_data() inline void* small_data()
{ {
@ -227,10 +306,10 @@ protected:
} }
protected: protected:
static const auto ANY_SPACE_SIZE = 16U; static const auto ANY_SMALL_SPACE_SIZE = 16U;
template <typename _Ty> template <typename _Ty>
struct decayed_is_small : public std::bool_constant<sizeof(_Ty) <= ANY_SPACE_SIZE> struct decayed_is_small : public std::bool_constant<sizeof(_Ty) <= ANY_SMALL_SPACE_SIZE>
{ {
}; };
@ -274,7 +353,7 @@ protected:
{ {
using destroy_func = void(void*); using destroy_func = void(void*);
using copy_func = void* (void*, const void*); using copy_func = void* (void*, const void*);
using move_func = void*(void*, const void*); using move_func = void*(void*, void*);
small_storage_rtti() small_storage_rtti()
{ {
@ -310,9 +389,9 @@ protected:
} }
template <typename _Ty> template <typename _Ty>
static void* move_impl(void* const target, const void* const ptr) noexcept static void* move_impl(void* const target, void* const ptr) noexcept
{ {
return ::new (static_cast<_Ty*>(target)) _Ty(std::move(*static_cast<const _Ty*>(ptr))); return ::new (static_cast<_Ty*>(target)) _Ty(std::move(*static_cast<_Ty*>(ptr)));
} }
destroy_func* destroy; destroy_func* destroy;
@ -346,7 +425,7 @@ protected:
{ {
const type_info* info_; const type_info* info_;
small_storage_rtti rtti_; small_storage_rtti rtti_;
char buffer_[ANY_SPACE_SIZE]; char buffer_[ANY_SMALL_SPACE_SIZE];
}; };
struct big_storage struct big_storage
@ -369,6 +448,64 @@ protected:
storage storage_; storage storage_;
}; };
//
// any_cast functions
//
template <typename _Ty>
_Ty* any_cast(any* const a) noexcept
{
return a->cast_pointer<_Ty>();
} }
template <typename _Ty>
const _Ty* any_cast(const any* const a) noexcept
{
return a->cast_pointer<_Ty>();
}
template <typename _Ty>
_Ty any_cast(any& a)
{
const auto ptr = any_cast<std::decay<_Ty>::type>(&a);
if (!ptr)
{
throw bad_any_cast{};
}
return static_cast<_Ty>(*ptr);
}
template <typename _Ty>
const _Ty any_cast(const any& a)
{
const auto ptr = any_cast<std::decay<_Ty>::type>(&a);
if (!ptr)
{
throw bad_any_cast{};
}
return static_cast<_Ty>(*ptr);
}
template <typename _Ty>
_Ty any_cast(any&& a)
{
_Ty* ptr = a.cast_pointer<_Ty>();
if (!ptr)
{
throw bad_any_cast{};
}
return static_cast<_Ty>(std::move(*ptr));
}
} // namespace core
} // namespace kiwano
namespace std
{
inline void swap(kiwano::core::any& lhs, kiwano::core::any& rhs) noexcept
{
lhs.swap(rhs);
}
} }