// 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 #include #include namespace kiwano { /// \~chinese /// @brief 可储存单个任意对象的容器 class Any { public: Any() : storage_{} { } template ::type, typename std::enable_if::value, int>::type = 0> Any(_Ty&& val) : storage_{} { Emplace<_Decayed>(std::forward<_Ty>(val)); } template 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 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 _Ty* CastPtr() noexcept { return const_cast<_Ty*>(const_cast(this)->CastPtr<_Ty>()); } /// \~chinese /// @brief 转换为指定类型的指针 template 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(GetSmallData()); } else { return static_cast(GetBigData()); } } return nullptr; } /// \~chinese /// @brief 转换为指定类型 /// @throw std::bad_cast 转换失败时抛出 template _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 _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 inline void EmplaceDecayed(_Args&&... args) { Store<_Decayed>(IsSmallSize<_Decayed>{}, std::forward<_Args>(args)...); } template 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 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 struct IsSmallSize : public std::bool_constant { }; struct BigStorageRTTI { using DestroyFunc = void(void*); using CopyFunc = void*(const void*); BigStorageRTTI() { destroy = nullptr; copy = nullptr; } template static inline BigStorageRTTI make() { BigStorageRTTI rtti; rtti.destroy = &BigStorageRTTI::Destroy<_Ty>; rtti.copy = &BigStorageRTTI::Copy<_Ty>; return rtti; } template static void Destroy(void* const ptr) noexcept { ::delete static_cast<_Ty*>(ptr); } template static void* Copy(const void* const ptr) noexcept { return ::new _Ty(*static_cast(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 static inline SmallStorageRTTI make() { SmallStorageRTTI rtti; rtti.destroy = &SmallStorageRTTI::Destroy<_Ty>; rtti.copy = &SmallStorageRTTI::Copy<_Ty>; rtti.move = &SmallStorageRTTI::Move<_Ty>; return rtti; } template static void Destroy(void* const ptr) noexcept { if (ptr) { _Ty& obj = *(static_cast<_Ty* const>(ptr)); obj.~_Ty(); } } template static void* Copy(void* const target, const void* const ptr) noexcept { return ::new (static_cast<_Ty*>(target)) _Ty(*static_cast(ptr)); } template 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