From 328aef10d767872be1fc9a8773ee295ee4699582 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 27 Mar 2016 18:24:38 -0600 Subject: [PATCH 1/5] Add failing test for non-const shared_ptr & --- src/test_module.cpp | 14 ++++++++++++++ unittests/shared_ptr_update.chai | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 unittests/shared_ptr_update.chai diff --git a/src/test_module.cpp b/src/test_module.cpp index ebccf73..5109baa 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -114,6 +114,16 @@ std::shared_ptr null_factory() return std::shared_ptr(); } +void update_shared_ptr(std::shared_ptr &ptr) +{ + ptr = std::make_shared(); +} + +void nullify_shared_ptr(std::shared_ptr &ptr) +{ + ptr = nullptr; +} + std::string hello_world() { return "Hello World"; @@ -209,6 +219,10 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::type_conversion()); m->add(chaiscript::constructor(), "Type2"); + m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr"); + m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr"); + + return m; } diff --git a/unittests/shared_ptr_update.chai b/unittests/shared_ptr_update.chai new file mode 100644 index 0000000..6378be6 --- /dev/null +++ b/unittests/shared_ptr_update.chai @@ -0,0 +1,24 @@ +load_module("test_module") + +auto o := null_factory(); + +assert_true(o.is_var_null()); + +update_shared_ptr(o); + +assert_false(o.is_var_null()); +assert_true(o.base_only_func() == -9); + +nullify_shared_ptr(o); + +assert_true(o.is_var_null()); + +try { + o.func(); +} catch (e) { + exit(0); +} + +assert_true(false); + + From 91a3ae1f14c9aca383d6f8f257d46d4007c29902 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 27 Mar 2016 20:02:27 -0600 Subject: [PATCH 2/5] Add ability to take non-const & shared_ptr params --- cheatsheet.md | 22 ++++++++++ .../dispatchkit/boxed_cast_helper.hpp | 12 +++++ .../chaiscript/dispatchkit/boxed_value.hpp | 44 +++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/cheatsheet.md b/cheatsheet.md index ce8e04a..c37045f 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -163,6 +163,28 @@ chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as(); // works with an static_cast(chai.eval("5.3+2.1")); // this version only works if we know that it's a double ``` +### Conversion Caveats + +Conversion to `std::shared_ptr &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior + +```cpp +// ok this is supported, you can register it with chaiscript engine +void nullify_shared_ptr(std::shared_ptr &t) { + t == nullptr +} +``` + +```cpp +int main() +{ + // do some stuff and create a chaiscript instance + std::shared_ptr &ptr = chai.eval &>(somevalue); + // DO NOT do this. Taking a non-const reference to a shared_ptr is not + // supported and causes undefined behavior in the chaiscript engine +} +``` + + ## Sharing Values ``` diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 505b1e1..b4e1826 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -173,6 +173,18 @@ namespace chaiscript { }; + template + struct Cast_Helper_Inner &> + { + typedef Boxed_Value::Sentinel Result_Type; + + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) + { + std::shared_ptr &res = ob.get().cast >(); + return ob.pointer_sentinel(res); + } + }; + /// Cast_Helper_Inner for casting to a const std::shared_ptr & type template struct Cast_Helper_Inner > : Cast_Helper_Inner > diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 5a49119..ff09cc1 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -231,6 +231,50 @@ namespace chaiscript return m_data->m_type_info.bare_equal(ti); } + template + struct Sentinel { + Sentinel(std::shared_ptr &ptr, Data &data) + : m_ptr(ptr), m_data(data) + { + } + + ~Sentinel() + { + // save new pointer data + m_data.get().m_data_ptr = m_ptr.get().get(); + m_data.get().m_const_data_ptr = m_ptr.get().get(); + } + + Sentinel& operator=(Sentinel&&s) { + m_ptr = std::move(s.m_ptr); + m_data = std::move(s.m_data); + } + + Sentinel(Sentinel &&s) + : m_ptr(std::move(s.m_ptr)), + m_data(std::move(s.m_data)) + { + } + + operator std::shared_ptr&() const + { + return m_ptr.get(); + } + + Sentinel &operator=(const Sentinel &) = delete; + Sentinel(Sentinel&) = delete; + + std::reference_wrapper> m_ptr; + std::reference_wrapper m_data; + }; + + + template + Sentinel pointer_sentinel(std::shared_ptr &ptr) const + { + return Sentinel(ptr, *(m_data.get())); + } + bool is_null() const CHAISCRIPT_NOEXCEPT { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); From 46c45e8fc786c867c898e1fa217fc01c35952cb5 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 27 Mar 2016 20:50:15 -0600 Subject: [PATCH 3/5] Update boxed_cast_tests to account for new features --- .../dispatchkit/boxed_cast_helper.hpp | 3 ++ unittests/boxed_cast_test.cpp | 51 ++++++++++--------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index b4e1826..da1e222 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -176,6 +176,8 @@ namespace chaiscript template struct Cast_Helper_Inner &> { + static_assert(!std::is_const::value, "Non-const reference to std::shared_ptr is not supported"); + typedef Boxed_Value::Sentinel Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *) @@ -185,6 +187,7 @@ namespace chaiscript } }; + /// Cast_Helper_Inner for casting to a const std::shared_ptr & type template struct Cast_Helper_Inner > : Cast_Helper_Inner > diff --git a/unittests/boxed_cast_test.cpp b/unittests/boxed_cast_test.cpp index 1e92874..11978ef 100644 --- a/unittests/boxed_cast_test.cpp +++ b/unittests/boxed_cast_test.cpp @@ -54,12 +54,13 @@ bool test_type_conversion(const Boxed_Value &bv, bool expectedpass) } template -bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, bool ConstTPtr, bool TPtrConst, - bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT, - bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef, - bool WrappedRef, bool WrappedConstRef, bool ConstWrappedRef, bool ConstWrappedConstRef, - bool ConstWrappedRefRef, bool ConstWrappedConstRefRef, bool Number, - bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef, bool ConstTPtrConstRef) +bool do_test(const Boxed_Value &bv, + bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, + bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT, + bool SharedPtrTRef, bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef, + bool WrappedRef, bool WrappedConstRef, bool ConstWrappedRef, bool ConstWrappedConstRef, bool ConstWrappedRefRef, + bool ConstWrappedConstRefRef, bool Number, bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef, + bool ConstTPtrConstRef) { bool passed = true; passed &= test_type_conversion(bv, T); @@ -72,8 +73,8 @@ bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTR passed &= test_type_conversion(bv, ConstTPtrConst); passed &= test_type_conversion >(bv, SharedPtrT); passed &= test_type_conversion >(bv, SharedConstPtrT); - passed &= test_type_conversion &>(bv, false); - passed &= test_type_conversion &>(bv, false); + passed &= test_type_conversion &>(bv, SharedPtrTRef); + //passed &= test_type_conversion &>(bv, false); passed &= test_type_conversion >(bv, ConstSharedPtrT); passed &= test_type_conversion >(bv, ConstSharedConstPtrT); passed &= test_type_conversion &>(bv, ConstSharedPtrTRef); @@ -115,37 +116,37 @@ bool built_in_type_test(const T &initial, bool ispod) T i = T(initial); passed &= do_test(var(i), true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, ispod, ispod, ispod, true, true); passed &= do_test(const_var(i), true, true, false, true, false, true, false, true, false, true, - false, true, false, true, false, + false, false, true, false, true, false, true, false, true, false, true, ispod, ispod, ispod, false, true); passed &= do_test(var(&i), true, true, true, true, true, true, true, true, false, false, - false, false, false, false, true, + false, false, false, false, false, true, true, true, true, true, true, ispod, ispod, ispod, true, true); passed &= do_test(const_var(&i), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); passed &= do_test(var(std::ref(i)), true, true, true, true, true, true, true, true, false, false, - false, false, false, false, true, + false, false, false, false, false, true, true, true, true, true, true, ispod, ispod, ispod, true, true); passed &= do_test(var(std::cref(i)), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); @@ -156,33 +157,33 @@ bool built_in_type_test(const T &initial, bool ispod) passed &= do_test(var(i), true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, ispod, ispod, ispod, true, true); // But a pointer or reference to it should be necessarily const passed &= do_test(var(&ir), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); passed &= do_test(var(std::ref(ir)), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); // Make sure const of const works too passed &= do_test(const_var(&ir), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); passed &= do_test(const_var(std::ref(ir)), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); @@ -192,14 +193,14 @@ bool built_in_type_test(const T &initial, bool ispod) const T*cip = &i; passed &= do_test(var(cip), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); // make sure const of const works passed &= do_test(const_var(cip), true, true, false, true, false, true, false, true, false, false, - false, false, false, false, false, + false, false, false, false, false, false, true, false, true, false, true, ispod, ispod, ispod, false, true); @@ -209,13 +210,13 @@ bool built_in_type_test(const T &initial, bool ispod) passed &= do_test(var(ip), true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, ispod, ispod, ispod, true, true); passed &= do_test(const_var(ip), true, true, false, true, false, true, false, true, false, true, - false, true, false, true, false, + false, false, true, false, true, false, true, false, true, false, true, ispod, ispod, ispod, false, true); @@ -224,14 +225,14 @@ bool built_in_type_test(const T &initial, bool ispod) passed &= do_test(var(ipc), true, true, false, true, false, true, false, true, false, true, - false, true, false, true, false, + false, false, true, false, true, false, true, false, true, false, true, ispod, ispod, ispod, false, true); // const of this should be the same, making sure it compiles passed &= do_test(const_var(ipc), true, true, false, true, false, true, false, true, false, true, - false, true, false, true, false, + false, false, true, false, true, false, true, false, true, false, true, ispod, ispod, ispod, false, true); From c07c2a9cc2e6e05290c33810cb601912748f96b6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 28 Mar 2016 15:57:26 -0600 Subject: [PATCH 4/5] Make sure type_info works with shared_ptr & --- include/chaiscript/dispatchkit/type_info.hpp | 5 +++++ unittests/shared_ptr_update.chai | 1 + 2 files changed, 6 insertions(+) diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index c91a444..c43767a 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -162,6 +162,11 @@ namespace chaiscript } }; + template + struct Get_Type_Info &> : Get_Type_Info> + { + }; + template struct Get_Type_Info &> { diff --git a/unittests/shared_ptr_update.chai b/unittests/shared_ptr_update.chai index 6378be6..cf7432a 100644 --- a/unittests/shared_ptr_update.chai +++ b/unittests/shared_ptr_update.chai @@ -10,6 +10,7 @@ assert_false(o.is_var_null()); assert_true(o.base_only_func() == -9); nullify_shared_ptr(o); +o.nullify_shared_ptr(); assert_true(o.is_var_null()); From 1e62eb4e12c9726ccd84e2df4c6d3e9ca2fb84df Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 30 Mar 2016 12:52:53 -0600 Subject: [PATCH 5/5] Update to 5.8.2 release notes --- CMakeLists.txt | 2 +- include/chaiscript/chaiscript_defines.hpp | 2 +- releasenotes.md | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b00ce4e..e3fde8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,7 @@ set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt" set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MINOR 8) -set(CPACK_PACKAGE_VERSION_PATCH 1) +set(CPACK_PACKAGE_VERSION_PATCH 2) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_VENDOR "ChaiScript.com") diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 724185f..9184f50 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -99,7 +99,7 @@ namespace chaiscript { static const int version_major = 5; static const int version_minor = 8; - static const int version_patch = 1; + static const int version_patch = 2; static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION; static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; diff --git a/releasenotes.md b/releasenotes.md index ea83197..d448be4 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,10 @@ Notes: ======= -Current Version: 5.8.1 +Current Version: 5.8.2 + +### Changes since 5.8.1 +* Allow casting to non-const & std::shared_ptr + ### Changes since 5.8.0 * Fix parsing of floats to be locale independent #250