diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index 8a624b1..9735016 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -8,6 +8,7 @@ #define CHAISCRIPT_ANY_HPP_ #include +#include namespace chaiscript { namespace detail { @@ -44,6 +45,15 @@ namespace chaiscript { class Any { private: + + + template + struct destruct { + void operator()(T *t) const { + t->~T(); + } + }; + struct Data { Data(const std::type_info &t_type) @@ -61,7 +71,7 @@ namespace chaiscript { return m_type; } - virtual std::unique_ptr clone() const = 0; + virtual void clone(void *t_ptr) const = 0; const std::type_info &m_type; }; @@ -81,9 +91,9 @@ namespace chaiscript { return &m_data; } - std::unique_ptr clone() const CHAISCRIPT_OVERRIDE + void clone(void *t_ptr) const CHAISCRIPT_OVERRIDE { - return std::unique_ptr(new Data_Impl(m_data)); + new (t_ptr) Data_Impl(m_data); } Data_Impl &operator=(const Data_Impl&) = delete; @@ -91,32 +101,70 @@ namespace chaiscript { T m_data; }; - std::unique_ptr m_data; + static const size_t buffersize = sizeof(Data_Impl>)>sizeof(Data_Impl>)?sizeof(Data_Impl>):sizeof(Data_Impl>); + bool m_constructed; + mutable std::array m_data_holder; - public: - // construct/copy/destruct - Any() = default; + inline Data *data() const + { + return reinterpret_cast(m_data_holder.data()); + } - Any(const Any &t_any) - { - if (!t_any.empty()) + + void call_destructor() + { + if (m_constructed) { - m_data = t_any.m_data->clone(); - } else { - m_data.reset(); + m_constructed = false; + data()->~Data(); } } -#if !defined(_MSC_VER) || _MSC_VER != 1800 - Any(Any &&) = default; - Any &operator=(Any &&t_any) = default; -#endif + public: + Any() + : m_constructed(false) + { + } + + // construct/copy/destruct + Any(const Any &t_any) + : m_constructed(false) + { + if (t_any.m_constructed) { + t_any.data()->clone(m_data_holder.data()); + m_constructed = true; + } + } + + Any(Any &&t_any) + : m_constructed(false) + { + if (t_any.m_constructed) { + t_any.m_constructed = false; + m_constructed = true; + m_data_holder = std::move(t_any.m_data_holder); + } + } + + Any &operator=(Any &&t_any) + { + call_destructor(); + if (t_any.m_constructed) { + t_any.m_constructed = false; + m_constructed = true; + m_data_holder = std::move(t_any.m_data_holder); + } + return *this; + } + template::type>::value>::type> explicit Any(ValueType &&t_value) - : m_data(std::unique_ptr(new Data_Impl::type>(std::forward(t_value)))) + : m_constructed(true) { + static_assert(sizeof(Data_Impl::type>) <= buffersize, "Buffer too small"); + (void)(new (m_data_holder.data()) Data_Impl::type>(std::forward(t_value))); } @@ -130,9 +178,9 @@ namespace chaiscript { template ToType &cast() const { - if (m_data && typeid(ToType) == m_data->type()) + if (m_constructed && typeid(ToType) == data()->type()) { - return *static_cast(m_data->data()); + return *static_cast(data()->data()); } else { throw chaiscript::detail::exception::bad_any_cast(); } @@ -141,26 +189,22 @@ namespace chaiscript { ~Any() { + call_destructor(); } // modifiers Any & swap(Any &t_other) { - std::swap(t_other.m_data, m_data); + std::swap(t_other.m_data_holder, m_data_holder); + std::swap(t_other.m_constructed, m_constructed); return *this; } - // queries - bool empty() const - { - return !bool(m_data); - } const std::type_info & type() const { - if (m_data) - { - return m_data->type(); + if (m_constructed) { + return data()->type(); } else { return typeid(void); }