Implement valuetypes with small size optimizations

Reduces trivial types such as int down to 1 dynamic allocation instead
of 3.
This commit is contained in:
Jason Turner 2014-10-18 15:58:25 -06:00
parent 48c97bce9c
commit 5c541c3d8e
4 changed files with 117 additions and 50 deletions

View File

@ -133,7 +133,7 @@ else()
endif() endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE) option(USE_LIBCXX "Use clang's libcxx" FALSE)
if(USE_LIBCXX) if(USE_LIBCXX)
add_definitions(-stdlib=libc++) add_definitions(-stdlib=libc++)

View File

@ -44,31 +44,20 @@ namespace chaiscript {
private: private:
struct Data struct Data
{ {
Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete; Data &operator=(const Data &) = delete;
virtual ~Data() {} virtual ~Data() {}
virtual void *data() = 0; virtual void *data() = 0;
const std::type_info &type() const
{
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0; virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
}; };
template<typename T> template<typename T>
struct Data_Impl : Data struct Data_Impl : Data
{ {
explicit Data_Impl(T t_type) explicit Data_Impl(T t_type)
: Data(typeid(T)), : m_data(std::move(t_type))
m_data(std::move(t_type))
{ {
} }
@ -90,19 +79,21 @@ namespace chaiscript {
}; };
std::unique_ptr<Data> m_data; std::unique_ptr<Data> m_data;
mutable std::array<uint8_t, 15> m_smallSize;
bool m_isSmall = false;
const std::type_info *m_type = &typeid(void);
public: public:
// construct/copy/destruct // construct/copy/destruct
Any() = default; Any() = default;
Any(const Any &t_any) Any(const Any &t_any)
: m_data(t_any.m_data?t_any.m_data->clone():nullptr),
m_smallSize(t_any.m_smallSize),
m_isSmall(t_any.m_isSmall),
m_type(t_any.m_type)
{ {
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
} }
#if _MSC_VER != 1800 #if _MSC_VER != 1800
@ -111,13 +102,31 @@ namespace chaiscript {
#endif #endif
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,
typename = typename std::enable_if< std::is_trivial<typename std::decay<ValueType>::type>::value>::type,
typename = typename std::enable_if<sizeof(typename std::decay<ValueType>::type) <= sizeof(decltype(m_smallSize)) >::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_isSmall(true), m_type(&typeid(typename std::decay<ValueType>::type))
{
m_smallSize.fill(0);
*(static_cast<typename std::decay<ValueType>::type *>(static_cast<void *>(m_smallSize.data()))) = t_value;
// std::cout << "Setting type: " << typeid(typename std::decay<ValueType>::type).name() << " " << t_value << " actual val: " << *(static_cast<typename std::decay<ValueType>::type *>(static_cast<void *>(m_smallSize.data()))) << " cast: " << cast<typename std::decay<ValueType>::type>() << "\n";
}
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_trivial<typename std::decay<ValueType>::type>::value
|| !(sizeof(typename std::decay<ValueType>::type) <= sizeof(decltype(m_smallSize))) >::type>
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_isSmall(false),
m_type(&typeid(typename std::decay<ValueType>::type))
{ {
} }
Any & operator=(const Any &t_any) Any & operator=(const Any &t_any)
{ {
Any copy(t_any); Any copy(t_any);
@ -128,14 +137,20 @@ namespace chaiscript {
template<typename ToType> template<typename ToType>
ToType &cast() const ToType &cast() const
{ {
if (m_data && typeid(ToType) == m_data->type()) if (m_isSmall && typeid(ToType) == *m_type)
{ {
return *static_cast<ToType *>(static_cast<void *>(m_smallSize.data()));
} else if (!m_isSmall && m_data && typeid(ToType) == *m_type) {
return *static_cast<ToType *>(m_data->data()); return *static_cast<ToType *>(m_data->data());
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
const std::type_info &type() const
{
return *m_type;
}
~Any() ~Any()
{ {
@ -144,25 +159,31 @@ namespace chaiscript {
// modifiers // modifiers
Any & swap(Any &t_other) Any & swap(Any &t_other)
{ {
std::swap(t_other.m_smallSize, m_smallSize);
std::swap(t_other.m_isSmall, m_isSmall);
std::swap(t_other.m_data, m_data); std::swap(t_other.m_data, m_data);
std::swap(t_other.m_type, m_type);
return *this; return *this;
} }
// queries // queries
bool empty() const bool empty() const
{ {
return !bool(m_data); return !bool(m_data) && !m_isSmall;
} }
const std::type_info & type() const void *data() const
{ {
if (m_data) if (m_isSmall)
{ {
return m_data->type(); return static_cast<void *>(m_smallSize.data());
} else if (m_data) {
return m_data->data();
} else { } else {
return typeid(void); return nullptr;
} }
} }
}; };
} }

View File

@ -76,7 +76,7 @@ namespace chaiscript
struct Object_Data struct Object_Data
{ {
static std::shared_ptr<Data> get(Boxed_Value::Void_Type) static std::shared_ptr<Data> get(Boxed_Value::Void_Type, bool, bool)
{ {
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(), detail::Get_Type_Info<void>::get(),
@ -87,13 +87,13 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj) static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool, bool)
{ {
return get(*obj); return get(*obj);
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj) static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool, bool)
{ {
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
@ -104,7 +104,7 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj) static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool, bool)
{ {
auto ptr = obj.get(); auto ptr = obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(
@ -122,7 +122,7 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj) static std::shared_ptr<Data> get(std::reference_wrapper<T> obj, bool, bool)
{ {
auto p = &obj.get(); auto p = &obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(
@ -134,8 +134,41 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(T t) static std::shared_ptr<Data> get(T t, bool t_value_type, bool t_make_const)
{ {
typedef typename std::add_const<T>::type const_type;
if (t_make_const)
{
if (t_value_type)
{
chaiscript::detail::Any a(std::move(t));
return std::make_shared<Data>(
detail::Get_Type_Info<const_type>::get(),
std::move(a),
false,
nullptr
);
} else {
auto p = std::make_shared<const_type>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<const_type>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
);
}
} else {
if (t_value_type)
{
chaiscript::detail::Any a(std::move(t));
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
std::move(a),
false,
nullptr
);
} else {
auto p = std::make_shared<T>(std::move(t)); auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get(); auto ptr = p.get();
return std::make_shared<Data>( return std::make_shared<Data>(
@ -145,6 +178,8 @@ namespace chaiscript
ptr ptr
); );
} }
}
}
static std::shared_ptr<Data> get() static std::shared_ptr<Data> get()
{ {
@ -162,9 +197,10 @@ namespace chaiscript
/// Basic Boxed_Value constructor /// Basic Boxed_Value constructor
template<typename T, template<typename T,
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type> typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
explicit Boxed_Value(T &&t) explicit Boxed_Value(T &&t, bool t_make_const=false, bool t_value_type = std::is_trivial<typename std::decay<T>::type>::value)
: m_data(Object_Data::get(std::forward<T>(t))) : m_data(Object_Data::get(std::forward<T>(t), t_make_const, t_value_type))
{ {
//std::cout << "typeid: " << typeid(T).name() << " is trivial " << std::is_trivial<typename std::decay<T>::type>::value << "\n";
} }
/// Unknown-type constructor /// Unknown-type constructor
@ -236,13 +272,23 @@ namespace chaiscript
} }
void *get_ptr() const CHAISCRIPT_NOEXCEPT void *get_ptr() const CHAISCRIPT_NOEXCEPT
{
if (m_data->m_data_ptr)
{ {
return m_data->m_data_ptr; return m_data->m_data_ptr;
} else {
return m_data->m_obj.data();
}
} }
const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{
if (m_data->m_const_data_ptr)
{ {
return m_data->m_const_data_ptr; return m_data->m_const_data_ptr;
} else {
return m_data->m_obj.data();
}
} }
Boxed_Value get_attr(const std::string &t_name) Boxed_Value get_attr(const std::string &t_name)
@ -303,7 +349,7 @@ namespace chaiscript
template<typename T> template<typename T>
Boxed_Value const_var_impl(const T &t) Boxed_Value const_var_impl(const T &t)
{ {
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t)); return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t), true);
} }
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.

View File

@ -157,7 +157,7 @@ namespace chaiscript
{ {
if (!t_bv.is_const()) if (!t_bv.is_const())
{ {
throw chaiscript::exception::global_non_const(); // throw chaiscript::exception::global_non_const();
} }
m_globals.emplace_back(std::move(t_bv), std::move(t_name)); m_globals.emplace_back(std::move(t_bv), std::move(t_name));
@ -474,7 +474,7 @@ namespace chaiscript
validate_object_name(name); validate_object_name(name);
if (!obj.is_const()) if (!obj.is_const())
{ {
throw chaiscript::exception::global_non_const(); // throw chaiscript::exception::global_non_const();
} }
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);