Magic_Game/src/kiwano/core/Any.h

465 lines
11 KiB
C++

// Copyright (c) 2016-2018 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include <typeinfo>
#include <type_traits>
#include <exception>
namespace kiwano
{
/// \~chinese
/// @brief 可储存单个任意对象的容器
class Any
{
public:
Any()
: storage_{}
{
}
template <typename _Ty, typename _Decayed = typename std::decay<_Ty>::type,
typename std::enable_if<std::is_copy_constructible<_Decayed>::value, int>::type = 0>
Any(_Ty&& val)
: storage_{}
{
Emplace<_Decayed>(std::forward<_Ty>(val));
}
template <typename _Ty, typename... _Args>
Any(_Args&&... args)
: storage_{}
{
using _Decayed = typename std::decay<_Ty>::type;
Clear();
EmplaceDecayed<_Decayed>(std::forward<_Args>(args)...);
}
Any(const Any& rhs)
: storage_{}
{
CopyFrom(rhs);
}
Any(Any&& rhs) noexcept
: storage_{}
{
MoveFrome(std::move(rhs));
}
~Any()
{
Clear();
}
/// \~chinese
/// @brief 获取含有对象类型
inline const type_info& GetType() const noexcept
{
const type_info* const info = GetTypeinfo();
if (info)
{
return *info;
}
return typeid(void);
}
/// \~chinese
/// @brief 是否含有对象
inline bool HasValue() const noexcept
{
return GetTypeinfo() != nullptr;
}
/// \~chinese
/// @brief 从参数构造对象
template <typename _Ty, typename... _Args>
void Emplace(_Args&&... args)
{
using _Decayed = typename std::decay<_Ty>::type;
Clear();
EmplaceDecayed<_Decayed>(std::forward<_Args>(args)...);
}
/// \~chinese
/// @brief 交换容器
void Swap(Any& rhs) noexcept
{
Any old = std::move(rhs);
rhs = std::move(*this);
*this = std::move(old);
}
/// \~chinese
/// @brief 销毁所含对象
inline void Clear() noexcept
{
Tidy();
}
/// \~chinese
/// @brief 转换为指定类型的指针
template <typename _Ty>
_Ty* CastPtr() noexcept
{
return const_cast<_Ty*>(const_cast<const Any*>(this)->CastPtr<_Ty>());
}
/// \~chinese
/// @brief 转换为指定类型的指针
template <typename _Ty>
const _Ty* CastPtr() const noexcept
{
static_assert(!std::is_void<_Ty>::value, "oc::Any cannot contain void");
const type_info* const info = GetTypeinfo();
if (info && (*info == typeid(std::decay<_Ty>::type)))
{
if (HasSmallType())
{
return static_cast<const _Ty*>(GetSmallData());
}
else
{
return static_cast<const _Ty*>(GetBigData());
}
}
return nullptr;
}
/// \~chinese
/// @brief 转换为指定类型
/// @throw std::bad_cast 转换失败时抛出
template <typename _Ty>
_Ty Cast()
{
using _Decayed = typename std::decay<_Ty>::type;
const auto ptr = CastPtr<_Decayed>();
if (!ptr)
{
throw std::bad_cast();
}
return static_cast<_Ty>(*ptr);
}
/// \~chinese
/// @brief 转换为指定类型
/// @throw std::bad_cast 转换失败时抛出
template <typename _Ty>
_Ty Cast() const
{
using _Decayed = typename std::decay<_Ty>::type;
const auto ptr = CastPtr<_Decayed>();
if (!ptr)
{
throw std::bad_cast();
}
return static_cast<_Ty>(*ptr);
}
Any& operator=(const Any& rhs)
{
*this = Any(rhs);
return (*this);
}
Any& operator=(Any&& rhs) noexcept
{
Clear();
MoveFrome(std::move(rhs));
return (*this);
}
private:
const type_info*& GetTypeinfo()
{
return storage_.small_.info_;
}
const type_info* GetTypeinfo() const
{
return storage_.small_.info_;
}
template <typename _Decayed, typename... _Args>
inline void EmplaceDecayed(_Args&&... args)
{
Store<_Decayed>(IsSmallSize<_Decayed>{}, std::forward<_Args>(args)...);
}
template <typename _Decayed, typename... _Args>
void Store(std::true_type, _Args&&... args)
{
storage_.is_small_ = true;
GetTypeinfo() = &typeid(_Decayed);
GetSmallRTTI() = SmallStorageRTTI::make<_Decayed>();
::new (GetSmallData()) _Decayed(std::forward<_Args>(args)...);
}
template <typename _Decayed, typename... _Args>
void Store(std::false_type, _Args&&... args)
{
storage_.is_small_ = false;
GetTypeinfo() = &typeid(_Decayed);
GetBigRTTI() = BigStorageRTTI::make<_Decayed>();
GetBigData() = ::new _Decayed(std::forward<_Args>(args)...);
}
void Tidy() noexcept
{
if (HasValue())
{
if (HasSmallType())
{
GetSmallRTTI().destroy(GetSmallData());
}
else
{
GetBigRTTI().destroy(GetBigData());
GetBigData() = nullptr;
}
GetTypeinfo() = nullptr;
}
}
void CopyFrom(const Any& rhs)
{
if (rhs.HasValue())
{
GetTypeinfo() = rhs.GetTypeinfo();
storage_.is_small_ = rhs.storage_.is_small_;
if (rhs.HasSmallType())
{
GetSmallRTTI() = rhs.GetSmallRTTI();
GetSmallRTTI().copy(GetSmallData(), rhs.GetSmallData());
}
else
{
GetBigRTTI() = rhs.GetBigRTTI();
GetBigData() = GetBigRTTI().copy(rhs.GetBigData());
}
}
}
void MoveFrome(Any&& rhs) noexcept
{
if (rhs.HasValue())
{
GetTypeinfo() = rhs.GetTypeinfo();
storage_.is_small_ = rhs.storage_.is_small_;
if (rhs.HasSmallType())
{
GetSmallRTTI() = rhs.GetSmallRTTI();
GetSmallRTTI().move(GetSmallData(), rhs.GetSmallData());
}
else
{
GetBigRTTI() = rhs.GetBigRTTI();
GetBigData() = rhs.GetBigData();
rhs.GetTypeinfo() = nullptr;
}
}
}
inline void* GetSmallData()
{
return storage_.small_.buffer_;
}
inline const void* GetSmallData() const
{
return storage_.small_.buffer_;
}
inline void*& GetBigData()
{
return storage_.big_.ptr_;
}
inline void* GetBigData() const
{
return storage_.big_.ptr_;
}
inline bool HasSmallType() const
{
return storage_.is_small_;
}
private:
static const auto ANY_SMALL_SPACE_SIZE = 8U;
template <typename _Ty>
struct IsSmallSize : public std::bool_constant<sizeof(_Ty) <= ANY_SMALL_SPACE_SIZE>
{
};
struct BigStorageRTTI
{
using DestroyFunc = void(void*);
using CopyFunc = void*(const void*);
BigStorageRTTI()
{
destroy = nullptr;
copy = nullptr;
}
template <typename _Ty>
static inline BigStorageRTTI make()
{
BigStorageRTTI rtti;
rtti.destroy = &BigStorageRTTI::Destroy<_Ty>;
rtti.copy = &BigStorageRTTI::Copy<_Ty>;
return rtti;
}
template <typename _Ty>
static void Destroy(void* const ptr) noexcept
{
::delete static_cast<_Ty*>(ptr);
}
template <typename _Ty>
static void* Copy(const void* const ptr) noexcept
{
return ::new _Ty(*static_cast<const _Ty*>(ptr));
}
DestroyFunc* destroy;
CopyFunc* copy;
};
struct SmallStorageRTTI
{
using DestroyFunc = void(void*);
using CopyFunc = void*(void*, const void*);
using MoveFunc = void*(void*, void*);
SmallStorageRTTI()
{
destroy = nullptr;
copy = nullptr;
move = nullptr;
}
template <typename _Ty>
static inline SmallStorageRTTI make()
{
SmallStorageRTTI rtti;
rtti.destroy = &SmallStorageRTTI::Destroy<_Ty>;
rtti.copy = &SmallStorageRTTI::Copy<_Ty>;
rtti.move = &SmallStorageRTTI::Move<_Ty>;
return rtti;
}
template <typename _Ty>
static void Destroy(void* const ptr) noexcept
{
if (ptr)
{
_Ty& obj = *(static_cast<_Ty* const>(ptr));
obj.~_Ty();
}
}
template <typename _Ty>
static void* Copy(void* const target, const void* const ptr) noexcept
{
return ::new (static_cast<_Ty*>(target)) _Ty(*static_cast<const _Ty*>(ptr));
}
template <typename _Ty>
static void* Move(void* const target, void* const ptr) noexcept
{
return ::new (static_cast<_Ty*>(target)) _Ty(std::move(*static_cast<_Ty*>(ptr)));
}
DestroyFunc* destroy;
CopyFunc* copy;
MoveFunc* move;
};
private:
inline SmallStorageRTTI& GetSmallRTTI()
{
return storage_.small_.rtti_;
}
inline const SmallStorageRTTI& GetSmallRTTI() const
{
return storage_.small_.rtti_;
}
inline BigStorageRTTI& GetBigRTTI()
{
return storage_.big_.rtti_;
}
inline const BigStorageRTTI& GetBigRTTI() const
{
return storage_.big_.rtti_;
}
private:
struct SmallStorage
{
const type_info* info_;
SmallStorageRTTI rtti_;
char buffer_[ANY_SMALL_SPACE_SIZE];
};
struct BigStorage
{
const type_info* info_;
BigStorageRTTI rtti_;
void* ptr_;
};
struct Storage
{
bool is_small_;
union
{
SmallStorage small_;
BigStorage big_;
};
Storage()
: is_small_(false)
, small_()
{
} // fix error C2280 for VisualStudio 2015
};
Storage storage_;
};
} // namespace kiwano