465 lines
11 KiB
C
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
|