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
 |