Use placement new to avoid unique_ptr allocations
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
#define CHAISCRIPT_ANY_HPP_
|
#define CHAISCRIPT_ANY_HPP_
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -44,6 +45,15 @@ namespace chaiscript {
|
|||||||
|
|
||||||
class Any {
|
class Any {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct destruct {
|
||||||
|
void operator()(T *t) const {
|
||||||
|
t->~T();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Data
|
struct Data
|
||||||
{
|
{
|
||||||
Data(const std::type_info &t_type)
|
Data(const std::type_info &t_type)
|
||||||
@@ -61,7 +71,7 @@ namespace chaiscript {
|
|||||||
return m_type;
|
return m_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<Data> clone() const = 0;
|
virtual void clone(void *t_ptr) const = 0;
|
||||||
const std::type_info &m_type;
|
const std::type_info &m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,9 +91,9 @@ namespace chaiscript {
|
|||||||
return &m_data;
|
return &m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
|
void clone(void *t_ptr) const CHAISCRIPT_OVERRIDE
|
||||||
{
|
{
|
||||||
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
|
new (t_ptr) Data_Impl<T>(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Data_Impl &operator=(const Data_Impl&) = delete;
|
Data_Impl &operator=(const Data_Impl&) = delete;
|
||||||
@@ -91,32 +101,70 @@ namespace chaiscript {
|
|||||||
T m_data;
|
T m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Data> m_data;
|
static const size_t buffersize = sizeof(Data_Impl<std::shared_ptr<int>>)>sizeof(Data_Impl<std::reference_wrapper<int>>)?sizeof(Data_Impl<std::shared_ptr<int>>):sizeof(Data_Impl<std::reference_wrapper<int>>);
|
||||||
|
bool m_constructed;
|
||||||
|
mutable std::array<uint8_t, buffersize> m_data_holder;
|
||||||
|
|
||||||
public:
|
inline Data *data() const
|
||||||
// construct/copy/destruct
|
{
|
||||||
Any() = default;
|
return reinterpret_cast<Data*>(m_data_holder.data());
|
||||||
|
}
|
||||||
|
|
||||||
Any(const Any &t_any)
|
|
||||||
{
|
void call_destructor()
|
||||||
if (!t_any.empty())
|
{
|
||||||
|
if (m_constructed)
|
||||||
{
|
{
|
||||||
m_data = t_any.m_data->clone();
|
m_constructed = false;
|
||||||
} else {
|
data()->~Data();
|
||||||
m_data.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || _MSC_VER != 1800
|
public:
|
||||||
Any(Any &&) = default;
|
Any()
|
||||||
Any &operator=(Any &&t_any) = default;
|
: m_constructed(false)
|
||||||
#endif
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<typename ValueType,
|
template<typename ValueType,
|
||||||
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
|
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
|
||||||
explicit Any(ValueType &&t_value)
|
explicit Any(ValueType &&t_value)
|
||||||
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
|
: m_constructed(true)
|
||||||
{
|
{
|
||||||
|
static_assert(sizeof(Data_Impl<typename std::decay<ValueType>::type>) <= buffersize, "Buffer too small");
|
||||||
|
(void)(new (m_data_holder.data()) Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,9 +178,9 @@ namespace chaiscript {
|
|||||||
template<typename ToType>
|
template<typename ToType>
|
||||||
ToType &cast() const
|
ToType &cast() const
|
||||||
{
|
{
|
||||||
if (m_data && typeid(ToType) == m_data->type())
|
if (m_constructed && typeid(ToType) == data()->type())
|
||||||
{
|
{
|
||||||
return *static_cast<ToType *>(m_data->data());
|
return *static_cast<ToType *>(data()->data());
|
||||||
} else {
|
} else {
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
}
|
}
|
||||||
@@ -141,26 +189,22 @@ namespace chaiscript {
|
|||||||
|
|
||||||
~Any()
|
~Any()
|
||||||
{
|
{
|
||||||
|
call_destructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
// modifiers
|
// modifiers
|
||||||
Any & swap(Any &t_other)
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// queries
|
|
||||||
bool empty() const
|
|
||||||
{
|
|
||||||
return !bool(m_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::type_info & type() const
|
const std::type_info & type() const
|
||||||
{
|
{
|
||||||
if (m_data)
|
if (m_constructed) {
|
||||||
{
|
return data()->type();
|
||||||
return m_data->type();
|
|
||||||
} else {
|
} else {
|
||||||
return typeid(void);
|
return typeid(void);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user