diff --git a/CMakeLists.txt b/CMakeLists.txt index c8ef4b9a..e1236c72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,7 @@ else() endif() 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) add_definitions(-stdlib=libc++) diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index 7c403b76..364f9e41 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -44,31 +44,20 @@ namespace chaiscript { private: struct Data { - Data(const std::type_info &t_type) - : m_type(t_type) - { - } Data &operator=(const Data &) = delete; virtual ~Data() {} virtual void *data() = 0; - const std::type_info &type() const - { - return m_type; - } - virtual std::unique_ptr clone() const = 0; - const std::type_info &m_type; }; template struct Data_Impl : Data { 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 m_data; + mutable std::array m_smallSize; + bool m_isSmall = false; + const std::type_info *m_type = &typeid(void); public: // construct/copy/destruct Any() = default; Any(const Any &t_any) - { - if (!t_any.empty()) - { - m_data = t_any.m_data->clone(); - } else { - m_data.reset(); - } + : 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 _MSC_VER != 1800 @@ -111,13 +102,31 @@ namespace chaiscript { #endif template::type>::value>::type> + typename = typename std::enable_if::type>::value>::type, + typename = typename std::enable_if< std::is_trivial::type>::value>::type, + typename = typename std::enable_if::type) <= sizeof(decltype(m_smallSize)) >::type> explicit Any(ValueType &&t_value) - : m_data(std::unique_ptr(new Data_Impl::type>(std::forward(t_value)))) + : m_isSmall(true), m_type(&typeid(typename std::decay::type)) + { + m_smallSize.fill(0); + *(static_cast::type *>(static_cast(m_smallSize.data()))) = t_value; + // std::cout << "Setting type: " << typeid(typename std::decay::type).name() << " " << t_value << " actual val: " << *(static_cast::type *>(static_cast(m_smallSize.data()))) << " cast: " << cast::type>() << "\n"; + } + + template::type>::value>::type, + typename = typename std::enable_if< + !std::is_trivial::type>::value + || !(sizeof(typename std::decay::type) <= sizeof(decltype(m_smallSize))) >::type> + explicit Any(ValueType &&t_value) + : m_data(std::unique_ptr(new Data_Impl::type>(std::forward(t_value)))), + m_isSmall(false), + m_type(&typeid(typename std::decay::type)) { } + Any & operator=(const Any &t_any) { Any copy(t_any); @@ -128,14 +137,20 @@ namespace chaiscript { template ToType &cast() const { - if (m_data && typeid(ToType) == m_data->type()) + if (m_isSmall && typeid(ToType) == *m_type) { + return *static_cast(static_cast(m_smallSize.data())); + } else if (!m_isSmall && m_data && typeid(ToType) == *m_type) { return *static_cast(m_data->data()); } else { throw chaiscript::detail::exception::bad_any_cast(); } } + const std::type_info &type() const + { + return *m_type; + } ~Any() { @@ -144,25 +159,31 @@ namespace chaiscript { // modifiers 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_type, m_type); return *this; } // queries 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(m_smallSize.data()); + } else if (m_data) { + return m_data->data(); } else { - return typeid(void); + return nullptr; } } + }; } diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 77076f1b..2c5204b7 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -76,7 +76,7 @@ namespace chaiscript struct Object_Data { - static std::shared_ptr get(Boxed_Value::Void_Type) + static std::shared_ptr get(Boxed_Value::Void_Type, bool, bool) { return std::make_shared( detail::Get_Type_Info::get(), @@ -87,13 +87,13 @@ namespace chaiscript } template - static std::shared_ptr get(const std::shared_ptr *obj) + static std::shared_ptr get(const std::shared_ptr *obj, bool, bool) { return get(*obj); } template - static std::shared_ptr get(const std::shared_ptr &obj) + static std::shared_ptr get(const std::shared_ptr &obj, bool, bool) { return std::make_shared( detail::Get_Type_Info::get(), @@ -104,7 +104,7 @@ namespace chaiscript } template - static std::shared_ptr get(std::shared_ptr &&obj) + static std::shared_ptr get(std::shared_ptr &&obj, bool, bool) { auto ptr = obj.get(); return std::make_shared( @@ -122,7 +122,7 @@ namespace chaiscript } template - static std::shared_ptr get(std::reference_wrapper obj) + static std::shared_ptr get(std::reference_wrapper obj, bool, bool) { auto p = &obj.get(); return std::make_shared( @@ -134,22 +134,57 @@ namespace chaiscript } template - static std::shared_ptr get(T t) + static std::shared_ptr get(T t, bool t_value_type, bool t_make_const) { - auto p = std::make_shared(std::move(t)); - auto ptr = p.get(); - return std::make_shared( - detail::Get_Type_Info::get(), - chaiscript::detail::Any(std::move(p)), - false, - ptr - ); + typedef typename std::add_const::type const_type; + if (t_make_const) + { + if (t_value_type) + { + chaiscript::detail::Any a(std::move(t)); + return std::make_shared( + detail::Get_Type_Info::get(), + std::move(a), + false, + nullptr + ); + } else { + auto p = std::make_shared(std::move(t)); + auto ptr = p.get(); + return std::make_shared( + detail::Get_Type_Info::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( + detail::Get_Type_Info::get(), + std::move(a), + false, + nullptr + ); + } else { + auto p = std::make_shared(std::move(t)); + auto ptr = p.get(); + return std::make_shared( + detail::Get_Type_Info::get(), + chaiscript::detail::Any(std::move(p)), + false, + ptr + ); + } + } } static std::shared_ptr get() { return std::make_shared( - Type_Info(), + Type_Info(), chaiscript::detail::Any(), false, nullptr @@ -162,9 +197,10 @@ namespace chaiscript /// Basic Boxed_Value constructor template::type>::value>::type> - explicit Boxed_Value(T &&t) - : m_data(Object_Data::get(std::forward(t))) + explicit Boxed_Value(T &&t, bool t_make_const=false, bool t_value_type = std::is_trivial::type>::value) + : m_data(Object_Data::get(std::forward(t), t_make_const, t_value_type)) { + //std::cout << "typeid: " << typeid(T).name() << " is trivial " << std::is_trivial::type>::value << "\n"; } /// Unknown-type constructor @@ -237,12 +273,22 @@ namespace chaiscript void *get_ptr() const CHAISCRIPT_NOEXCEPT { - return m_data->m_data_ptr; + if (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 { - return m_data->m_const_data_ptr; + if (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) @@ -303,7 +349,7 @@ namespace chaiscript template Boxed_Value const_var_impl(const T &t) { - return Boxed_Value(std::make_shared::type >(t)); + return Boxed_Value(std::make_shared::type >(t), true); } /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 63a0038a..65bc65c7 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -157,7 +157,7 @@ namespace chaiscript { 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)); @@ -474,7 +474,7 @@ namespace chaiscript validate_object_name(name); if (!obj.is_const()) { - throw chaiscript::exception::global_non_const(); +// throw chaiscript::exception::global_non_const(); } chaiscript::detail::threading::unique_lock l(m_global_object_mutex);