diff --git a/Examples/test-suite/cpp11_shared_ptr_const.i b/Examples/test-suite/cpp11_shared_ptr_const.i new file mode 100644 index 000000000..0d1acdac0 --- /dev/null +++ b/Examples/test-suite/cpp11_shared_ptr_const.i @@ -0,0 +1,57 @@ +%module cpp11_shared_ptr_const + +%{ + +#include +#include + +class Foo +{ +public: + Foo(int i) : m(i) {} + int get_m() { return m;} + int m; +}; + +std::shared_ptr foo(Foo v) { + return std::shared_ptr(new Foo(v)); +} + +std::shared_ptr const_foo(Foo v) { + return std::shared_ptr(new Foo(v)); +} + +std::vector > foo_vec(Foo v) { + std::vector > result; + result.push_back( std::shared_ptr(new Foo(v)) ); + return result; +} + +std::vector > const_foo_vec(Foo v) { + std::vector > result; + result.push_back( std::shared_ptr(new Foo(v)) ); + return result; +} + +%} + +%include +%include + +%shared_ptr(Foo); + +%template (FooVector) std::vector >; +%template (FooConstVector) std::vector >; + +class Foo +{ +public: + Foo(int i); + int get_m(); + int m; +}; +std::shared_ptr foo(Foo v); +std::shared_ptr const_foo(Foo v); +std::vector > foo_vec(Foo v) const; +std::vector > const_foo_vec(Foo v) const; + diff --git a/Examples/test-suite/cpp11_shared_ptr_upcast.i b/Examples/test-suite/cpp11_shared_ptr_upcast.i new file mode 100644 index 000000000..3427829d9 --- /dev/null +++ b/Examples/test-suite/cpp11_shared_ptr_upcast.i @@ -0,0 +1,188 @@ +%module cpp11_shared_ptr_upcast + +%{ +#include +#include +#include +#include +#include +#include +%} + +%include +%include +%include + +%{ + +class Base { +public: + Base() : m(-1) {} + Base(int i) : m(i) {} + int get_m() { return m; } + int m; +}; + +class Derived : public Base { +public: + Derived() : n(-2) {} + Derived(int i) : n(i) {} + int get_n() { return n; } + int n; +}; + +typedef std::shared_ptr BasePtr; +typedef std::shared_ptr DerivedPtr; + +// non-overloaded +int derived_num1(DerivedPtr v) { + return v == nullptr ? 999 : (*v).get_n(); +} + +int derived_num2(std::vector v) { + return v[0] == nullptr ? 999 : (*v[0]).get_n(); +} + +int derived_num3(std::map v) { + return v[0] == nullptr ? 999 : (*v[0]).get_n(); +} + +int base_num1(BasePtr v) { + return v == nullptr ? 999 : (*v).get_m(); +} + +int base_num2(std::vector v) { + return v[0] == nullptr ? 999 : (*v[0]).get_m(); +} + +int base_num3(std::map v) { + return v[0] == nullptr ? 999 : (*v[0]).get_m(); +} + +// overloaded +int derived_num(DerivedPtr v) { + return derived_num1(v); +} + +int derived_num(std::vector v) { + return derived_num2(v); +} + +int derived_num(std::map v) { + return derived_num3(v); +} + +int base_num(BasePtr v) { + return base_num1(v); +} + +int base_num(std::vector v) { + return base_num2(v); +} + +int base_num(std::map v) { + return base_num3(v); +} +%} + + +%shared_ptr(Base); +%shared_ptr(Derived); + +%template(BaseList) std::vector >; +%template(DerivedList) std::vector >; + +%template(BaseMap) std::map >; +%template(DerivedMap) std::map >; + +class Base { +public: + Base(); + int get_m(); + int m; +}; + +class Derived : public Base { +public: + Derived(); + Derived(int i); + int get_n(); + int n; +}; + +typedef std::shared_ptr BasePtr; +typedef std::shared_ptr DerivedPtr; + +// non-overloaded +int derived_num1(DerivedPtr); +int derived_num2(std::vector > v); +int derived_num3(std::map v); +int base_num1(BasePtr); +int base_num2(std::vector > v); +int base_num3(std::map v); + +// overloaded +int derived_num(DerivedPtr); +int derived_num(std::vector > v); +int derived_num(std::map v); +int base_num(BasePtr); +int base_num(std::vector > v); +int base_num(std::map v); + +// ptr to shared_ptr +%shared_ptr(Base2); +%shared_ptr(Derived2) + +%inline %{ +class Base2 { +public: + Base2() : m(-1) {} + Base2(int i) : m(i) {} + int get_m() { return m; } + int m; +}; + + +class Derived2 : public Base2 { +public: + Derived2() : n(0) {} + Derived2(int i) : n(i) {} + int get_n_2() { return n; } + int n; +}; +%} + +%template(Base2List) std::vector * >; +%template(Base2Map) std::map * >; + +%template(Derived2List) std::vector * >; +%template(Derived2Map) std::map * >; + +%inline %{ +typedef std::shared_ptr * Derived2Ptr; +typedef std::shared_ptr * Base2Ptr; + +int base2_num1(Base2Ptr v) { + return v == nullptr ? 999 : *v == nullptr ? 888 : (*v)->get_m(); +} + +int base2_num2(std::vector v) { + return v[0] == nullptr ? 999 : *v[0] == nullptr ? 888 : (*v[0])->get_m(); +} + +int base2_num3(std::map v) { + return v[0] == nullptr ? 999 : *v[0] == nullptr ? 888 : (*v[0])->get_m(); +} + +int derived2_num1(Derived2Ptr v) { + return v == nullptr ? 999 : *v == nullptr ? 888 : (*v)->get_n_2(); +} + +int derived2_num2(std::vector v) { + return v[0] == nullptr ? 999 : *v[0] == nullptr ? 888 : (*v[0])->get_n_2(); +} + +int derived2_num3(std::map v) { + return v[0] == nullptr ? 999 : *v[0] == nullptr ? 888 : (*v[0])->get_n_2(); +} +%} diff --git a/Examples/test-suite/ruby/Makefile.in b/Examples/test-suite/ruby/Makefile.in index 47ea44037..27e9f5e18 100644 --- a/Examples/test-suite/ruby/Makefile.in +++ b/Examples/test-suite/ruby/Makefile.in @@ -32,6 +32,8 @@ CPP_TEST_CASES = \ CPP11_TEST_CASES = \ cpp11_hash_tables \ + cpp11_shared_ptr_upcast \ + cpp11_shared_ptr_const C_TEST_CASES += \ li_cstring \ diff --git a/Examples/test-suite/ruby/cpp11_shared_ptr_const_runme.rb b/Examples/test-suite/ruby/cpp11_shared_ptr_const_runme.rb new file mode 100644 index 000000000..149aa0898 --- /dev/null +++ b/Examples/test-suite/ruby/cpp11_shared_ptr_const_runme.rb @@ -0,0 +1,9 @@ +require "swig_assert" +require "cpp11_shared_ptr_const" + +include Cpp11_shared_ptr_const + +swig_assert_equal_simple(1, foo( Foo.new(1) ).get_m ) +swig_assert_equal_simple(7, const_foo( Foo.new(7) ).get_m ) +swig_assert_equal_simple(7, foo_vec( Foo.new(7) )[0].get_m ) +swig_assert_equal_simple(8, const_foo_vec( Foo.new(8) )[0].get_m ) diff --git a/Examples/test-suite/ruby/cpp11_shared_ptr_upcast_runme.rb b/Examples/test-suite/ruby/cpp11_shared_ptr_upcast_runme.rb new file mode 100644 index 000000000..000b9b6a9 --- /dev/null +++ b/Examples/test-suite/ruby/cpp11_shared_ptr_upcast_runme.rb @@ -0,0 +1,60 @@ +require 'swig_assert' +require 'cpp11_shared_ptr_upcast' + + +include Cpp11_shared_ptr_upcast + +# non-overloaded +swig_assert_equal_simple( 7, derived_num1(Derived.new(7)) ) +swig_assert_equal_simple( 7, derived_num2([Derived.new(7)]) ) +swig_assert_equal_simple( 7, derived_num3({0 => Derived.new(7)}) ) + +swig_assert_equal_simple(-1, base_num1(Derived.new(7)) ) +swig_assert_equal_simple(-1, base_num2([Derived.new(7)]) ) +swig_assert_equal_simple(-1, base_num3({0 => Derived.new(7)}) ) + +swig_assert_equal_simple( 999, derived_num1(nil) ) +swig_assert_equal_simple( 999, derived_num2([nil]) ) +swig_assert_equal_simple( 999, derived_num3({0 => nil}) ) + +swig_assert_equal_simple( 999, base_num1(nil) ) +swig_assert_equal_simple( 999, base_num2([nil]) ) +swig_assert_equal_simple( 999, base_num3({0 => nil}) ) + +# overloaded +swig_assert_equal_simple( 7, derived_num(Derived.new(7)) ) +swig_assert_equal_simple( 7, derived_num([Derived.new(7)]) ) +swig_assert_equal_simple( 7, derived_num({0 => Derived.new(7)}) ) + +swig_assert_equal_simple(-1, base_num(Derived.new(7)) ) +swig_assert_equal_simple(-1, base_num([Derived.new(7)]) ) +swig_assert_equal_simple(-1, base_num({0 => Derived.new(7)}) ) + +# ptr to shared_ptr +swig_assert_equal_simple( 7, derived2_num1(Derived2.new(7)) ) +swig_assert_equal_simple( 7, derived2_num2([Derived2.new(7)]) ) +swig_assert_equal_simple( 7, derived2_num3({0 => Derived2.new(7)}) ) + +swig_assert_equal_simple( -1, base2_num1(Derived2.new(7)) ) + +begin + # Upcast for pointers to shared_ptr in this generic framework has not been implemented + swig_assert_equal_simple( -1, base2_num2([Derived2.new(7)]) ) + raise RuntimeError, "Failed to catch TypeError" +rescue TypeError +end +begin + # Upcast for pointers to shared_ptr in this generic framework has not been implemented + swig_assert_equal_simple( -1, base2_num3({0 => Derived2.new(7)}) ) + raise RuntimeError, "Failed to catch TypeError" +rescue TypeError +end + +swig_assert_equal_simple( 888, derived2_num1(nil) ) +swig_assert_equal_simple( 999, derived2_num2([nil]) ) # although 888 would be more consistent +swig_assert_equal_simple( 999, derived2_num3({0 => nil}) ) # although 888 would be more consistent + +swig_assert_equal_simple( 888, base2_num1(nil) ) +swig_assert_equal_simple( 999, base2_num2([nil]) ) # although 888 would be more consistent +swig_assert_equal_simple( 999, base2_num3({0 => nil}) ) # although 888 would be more consistent + diff --git a/Examples/test-suite/ruby/swig_assert.rb b/Examples/test-suite/ruby/swig_assert.rb index 69a1a0207..5b3f9b5ce 100644 --- a/Examples/test-suite/ruby/swig_assert.rb +++ b/Examples/test-suite/ruby/swig_assert.rb @@ -1,12 +1,7 @@ #!/usr/bin/env ruby # -# A simple function to create useful asserts +# Useful assert functions # -# -# -# -# - # # Exception raised when some swig binding test fails @@ -15,6 +10,21 @@ class SwigRubyError < RuntimeError end +# +# Simple assertions. Strings are not needed as arguments. +# +def swig_assert_equal_simple(a, b) + unless a == b + raise SwigRubyError.new("\n#{a} expected but was \n#{b}") + end +end + +def swig_assert_simple(a) + unless a + raise SwigRubyError.new("assertion falied.") + end +end + # # Asserts whether a and b are equal. # diff --git a/Lib/ruby/rubystdcommon.swg b/Lib/ruby/rubystdcommon.swg index e32f46d1c..5cbdb430d 100644 --- a/Lib/ruby/rubystdcommon.swg +++ b/Lib/ruby/rubystdcommon.swg @@ -3,8 +3,9 @@ * The Ruby classes, for C++ * ------------------------------------------------------------ */ %include +%include -%fragment("StdTraits","header",fragment="StdTraitsCommon") +%fragment("StdTraits","header",fragment="StdTraitsCommon",fragment="StdTraitsForwardDeclaration") { namespace swig { diff --git a/Lib/ruby/rubystdcommon_forward.swg b/Lib/ruby/rubystdcommon_forward.swg new file mode 100644 index 000000000..27bcb9960 --- /dev/null +++ b/Lib/ruby/rubystdcommon_forward.swg @@ -0,0 +1,14 @@ +%fragment("StdTraitsForwardDeclaration","header") +{ +namespace swig { + template struct traits_asptr; + template struct traits_asval; + struct pointer_category; + template struct traits_as; + template struct traits_from; + template struct noconst_traits; + template swig_type_info* type_info(); + template const char* type_name(); + template VALUE from(const Type& val); +} +} diff --git a/Lib/ruby/std_shared_ptr.i b/Lib/ruby/std_shared_ptr.i index df873679c..f6c0a15ac 100644 --- a/Lib/ruby/std_shared_ptr.i +++ b/Lib/ruby/std_shared_ptr.i @@ -1,2 +1,130 @@ #define SWIG_SHARED_PTR_NAMESPACE std %include +%include + + +%fragment("StdSharedPtrTraits","header",fragment="StdTraitsForwardDeclaration") +{ +namespace swig { + /* + Template specialization for functions defined in rubystdcommon.swg. Special handling for shared_ptr + is required as, shared_ptr * is used rather than the usual T *, see shared_ptr.i. + */ + template + struct traits_asptr > { + static int asptr(VALUE obj, std::shared_ptr **val) { + std::shared_ptr *p = 0; + swig_type_info *descriptor = type_info >(); + swig_ruby_owntype newmem = {0, 0}; + int res = descriptor ? SWIG_ConvertPtrAndOwn(obj, (void **)&p, descriptor, 0, &newmem) : SWIG_ERROR; + if (SWIG_IsOK(res)) { + if (val) { + if (*val) { + **val = p ? *p : std::shared_ptr(); + } else { + *val = p; + if (newmem.own & SWIG_CAST_NEW_MEMORY) { + // Upcast for pointers to shared_ptr in this generic framework has not been implemented + res = SWIG_ERROR; + } + } + } + if (newmem.own & SWIG_CAST_NEW_MEMORY) + delete p; + } + return res; + } + }; + + template + struct traits_asval > { + static int asval(VALUE obj, std::shared_ptr *val) { + if (val) { + std::shared_ptr ret; + std::shared_ptr *p = &ret; + int res = traits_asptr >::asptr(obj, &p); + if (!SWIG_IsOK(res)) + return res; + *val = ret; + return SWIG_OK; + } else { + return traits_asptr >::asptr(obj, (std::shared_ptr **)(0)); + } + } + }; + + template + struct traits_asval *> { + static int asval(VALUE obj, std::shared_ptr **val) { + if (val) { + typedef typename noconst_traits >::noconst_type noconst_type; + if (*val) { + noconst_type ret; + noconst_type *p = &ret; + int res = traits_asptr::asptr(obj, &p); + if (SWIG_IsOK(res)) + **(const_cast(val)) = ret; + return res; + } else { + noconst_type *p = 0; + int res = traits_asptr::asptr(obj, &p); + if (SWIG_IsOK(res)) + *val = p; + return res; + } + } else { + return traits_asptr >::asptr(obj, (std::shared_ptr **)(0)); + } + } + }; + + template + struct traits_as, pointer_category> { + static std::shared_ptr as(VALUE obj, bool throw_error) { + std::shared_ptr ret; + std::shared_ptr *v = &ret; + int res = traits_asptr >::asptr(obj, &v); + if (SWIG_IsOK(res)) { + return ret; + } else { + if (throw_error) throw std::invalid_argument("bad type"); + VALUE lastErr = rb_gv_get("$!"); + if (lastErr == Qnil) + SWIG_Error(SWIG_TypeError, swig::type_name >()); + return std::shared_ptr(); + } + } + }; + + template + struct traits_as *, pointer_category> { + static std::shared_ptr * as(VALUE obj, bool throw_error) { + std::shared_ptr *p = 0; + int res = traits_asptr >::asptr(obj, &p); + if (SWIG_IsOK(res)) { + return p; + } else { + if (throw_error) throw std::invalid_argument("bad type"); + VALUE lastErr = rb_gv_get("$!"); + if (lastErr == Qnil) + SWIG_Error(SWIG_TypeError, swig::type_name *>()); + return 0; + } + } + }; + + /* + The descriptors in the shared_ptr typemaps remove the const qualifier for the SWIG type system. + Remove const likewise here, otherwise SWIG_TypeQuery("std::shared_ptr") will return NULL. + */ + template + struct traits_from > { + static VALUE from(const std::shared_ptr& val) { + std::shared_ptr p = std::const_pointer_cast(val); + return swig::from(p); + } + }; +} +} + +%fragment("StdSharedPtrTraits");