diff --git a/CHANGES.current b/CHANGES.current index 616d973c9..d05cf04ca 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-08-02: wsfulton + [Octave] Add support for std::unique_ptr in std_unique_ptr.i. + Add support for std::auto_ptr in std_auto_ptr.i. + 2022-08-01: wsfulton [Python] Add initialisers for additional members in PyHeapTypeObject (builtin mode) for Python-3.11 - _ht_tpname, _spec_cache. diff --git a/Examples/test-suite/cpp11_std_unique_ptr.i b/Examples/test-suite/cpp11_std_unique_ptr.i index 2dcdbca45..745c7e918 100644 --- a/Examples/test-suite/cpp11_std_unique_ptr.i +++ b/Examples/test-suite/cpp11_std_unique_ptr.i @@ -1,6 +1,6 @@ %module cpp11_std_unique_ptr -#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) +#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) %include "std_string.i" %include "std_unique_ptr.i" diff --git a/Examples/test-suite/li_std_auto_ptr.i b/Examples/test-suite/li_std_auto_ptr.i index 68dbf0ffa..e2a908423 100644 --- a/Examples/test-suite/li_std_auto_ptr.i +++ b/Examples/test-suite/li_std_auto_ptr.i @@ -12,17 +12,28 @@ #endif %} -#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) +#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) %include "std_string.i" %include "std_auto_ptr.i" %auto_ptr(Klass) +%inline %{ +void show_cplusplus_version() { + printf("__cplusplus %d\n", (int)__cplusplus); +} +%} + %{ #if __cplusplus < 201703L #include #else + +// If has already been include (Octave does) then unfortunately gcc incorrectly still provides +// std::auto_ptr when _GLIBCXX_USE_DEPRECATED is defined by the compiler configuration/OS/who knows what!! +#include // Now need to include it in case _GLIBCXX_USE_DEPRECATED is defined and has not been included, argh +#if !defined(_GLIBCXX_USE_DEPRECATED) // Simple std::auto_ptr implementation for testing after its removal in C++17 namespace std { template class auto_ptr { @@ -40,6 +51,8 @@ namespace std { } #endif +#endif + #include #include "swig_examples_lock.h" %} diff --git a/Examples/test-suite/octave/cpp11_std_unique_ptr_runme.m b/Examples/test-suite/octave/cpp11_std_unique_ptr_runme.m new file mode 100644 index 000000000..3da93e338 --- /dev/null +++ b/Examples/test-suite/octave/cpp11_std_unique_ptr_runme.m @@ -0,0 +1,109 @@ +# do not dump Octave core +if exist("crash_dumps_octave_core", "builtin") + crash_dumps_octave_core(0); +endif + +cpp11_std_unique_ptr + +function checkCount(expected_count) + actual_count = Klass_getTotal_count(); + if (actual_count != expected_count) + error("Counts incorrect, expected:%d actual:%d", expected_count, actual_count); + endif +end + + +# unique_ptr as input +kin = Klass("KlassInput"); +checkCount(1); +s = takeKlassUniquePtr(kin); +checkCount(0); +if (!strcmp(s, "KlassInput")) + error("Incorrect string: %s", s); +endif +if (!is_nullptr(kin)) + error("is_nullptr failed"); +endif +clear kin; # Should not fail, even though already deleted +checkCount(0); + +kin = Klass("KlassInput"); +checkCount(1); +s = takeKlassUniquePtr(kin); +checkCount(0); +if (!strcmp(s, "KlassInput")) + error("Incorrect string: %s", s); +endif +if (!is_nullptr(kin)) + error("is_nullptr failed"); +endif +exception_thrown = false; +try + takeKlassUniquePtr(kin); +catch e + if (isempty(strfind(e.message, "cannot release ownership as memory is not owned"))) + error("incorrect exception message %s", e.message); + endif + exception_thrown = true; +end_try_catch +if (!exception_thrown) + error("double usage of takeKlassUniquePtr should have been an error"); +endif +clear kin; # Should not fail, even though already deleted +checkCount(0); + +kin = Klass("KlassInput"); +exception_thrown = false; +try + notowned = get_not_owned_ptr(kin); + takeKlassUniquePtr(notowned); +catch e + if (isempty(strfind(e.message, "cannot release ownership as memory is not owned"))) + error("incorrect exception message %s", e.message); + endif + exception_thrown = true; +end_try_catch +if (!exception_thrown) + error("Should have thrown 'Cannot release ownership as memory is not owned' error"); +endif +clear kin; +checkCount(0); + +kini = KlassInheritance("KlassInheritanceInput"); +checkCount(1); +s = takeKlassUniquePtr(kini); +checkCount(0); +if (!strcmp(s, "KlassInheritanceInput")) + error("Incorrect string: %s", s); +endif +if (!is_nullptr(kini)) + error("is_nullptr failed"); +endif +clear kini; # Should not fail, even though already deleted +checkCount(0); + + +# unique_ptr as output +k1 = makeKlassUniquePtr("first"); +if (!strcmp(k1.getLabel(), "first")) + error("wrong object label"); +endif + +k2 = makeKlassUniquePtr("second"); +if (Klass_getTotal_count() != 2) + error("number of objects should be 2"); +endif + +clear k1; +if (Klass.getTotal_count() != 1) + error("number of objects should be 1"); +endif + +if (!strcmp(k2.getLabel(), "second")) + error("wrong object label"); +endif + +clear k2; +if (Klass.getTotal_count() != 0) + error("no objects should be left"); +endif diff --git a/Examples/test-suite/octave/li_std_auto_ptr_runme.m b/Examples/test-suite/octave/li_std_auto_ptr_runme.m new file mode 100644 index 000000000..c1e655db5 --- /dev/null +++ b/Examples/test-suite/octave/li_std_auto_ptr_runme.m @@ -0,0 +1,108 @@ +# do not dump Octave core +if exist("crash_dumps_octave_core", "builtin") + crash_dumps_octave_core(0); +endif + +li_std_auto_ptr + +function checkCount(expected_count) + actual_count = Klass_getTotal_count(); + if (actual_count != expected_count) + error("Counts incorrect, expected:%d actual:%d", expected_count, actual_count); + endif +end + +# auto_ptr as input +kin = Klass("KlassInput"); +checkCount(1); +s = takeKlassAutoPtr(kin); +checkCount(0); +if (!strcmp(s, "KlassInput")) + error("Incorrect string: %s", s); +endif +if (!is_nullptr(kin)) + error("is_nullptr failed"); +endif +clear kin; # Should not fail, even though already deleted +checkCount(0); + +kin = Klass("KlassInput"); +checkCount(1); +s = takeKlassAutoPtr(kin); +checkCount(0); +if (!strcmp(s, "KlassInput")) + error("Incorrect string: %s", s); +endif +if (!is_nullptr(kin)) + error("is_nullptr failed"); +endif +exception_thrown = false; +try + takeKlassAutoPtr(kin); +catch e + if (isempty(strfind(e.message, "cannot release ownership as memory is not owned"))) + error("incorrect exception message %s", e.message); + endif + exception_thrown = true; +end_try_catch +if (!exception_thrown) + error("double usage of takeKlassAutoPtr should have been an error"); +endif +clear kin; # Should not fail, even though already deleted +checkCount(0); + +kin = Klass("KlassInput"); +exception_thrown = false; +try + notowned = get_not_owned_ptr(kin); + takeKlassAutoPtr(notowned); +catch e + if (isempty(strfind(e.message, "cannot release ownership as memory is not owned"))) + error("incorrect exception message %s", e.message); + endif + exception_thrown = true; +end_try_catch +if (!exception_thrown) + error("Should have thrown 'Cannot release ownership as memory is not owned' error"); +endif +clear kin; +checkCount(0); + +kini = KlassInheritance("KlassInheritanceInput"); +checkCount(1); +s = takeKlassAutoPtr(kini); +checkCount(0); +if (!strcmp(s, "KlassInheritanceInput")) + error("Incorrect string: %s", s); +endif +if (!is_nullptr(kini)) + error("is_nullptr failed"); +endif +clear kini; # Should not fail, even though already deleted +checkCount(0); + + +# auto_ptr as output +k1 = makeKlassAutoPtr("first"); +if (!strcmp(k1.getLabel(), "first")) + error("wrong object label"); +endif + +k2 = makeKlassAutoPtr("second"); +if (Klass_getTotal_count() != 2) + error("number of objects should be 2"); +endif + +clear k1; +if (Klass.getTotal_count() != 1) + error("number of objects should be 1"); +endif + +if (!strcmp(k2.getLabel(), "second")) + error("wrong object label"); +endif + +clear k2; +if (Klass.getTotal_count() != 0) + error("no objects should be left"); +endif diff --git a/Lib/octave/octrun.swg b/Lib/octave/octrun.swg index d94056c8c..71a907f9b 100644 --- a/Lib/octave/octrun.swg +++ b/Lib/octave/octrun.swg @@ -232,7 +232,7 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); const swig_type_info *construct_type; // type of special type object std::vector < type_ptr_pair > types; // our c++ base classes - int own; // whether we call c++ destructors when we die + int thisown; // whether we call c++ destructors when we die typedef std::pair < const swig_octave_member *, octave_value > member_value_pair; typedef std::map < std::string, member_value_pair > member_map; @@ -412,7 +412,7 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); octave_swig_type(void *_ptr = 0, const swig_type_info *_type = 0, int _own = 0, bool _always_static = false) - : module(0), construct_type(_ptr ? 0 : _type), own(_own), + : module(0), construct_type(_ptr ? 0 : _type), thisown(_own), always_static(_always_static) { if (_type || _ptr) types.push_back(std::make_pair(_type, _ptr)); @@ -426,7 +426,7 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); } ~octave_swig_type() { - if (own) { + if (thisown) { ++count; for (unsigned int j = 0; j < types.size(); ++j) { if (!types[j].first || !types[j].first->clientdata) @@ -559,7 +559,7 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); } void merge(octave_swig_type &rhs) { - rhs.own = 0; + rhs.thisown = 0; for (unsigned int j = 0; j < rhs.types.size(); ++j) { assert(!rhs.types[j].second.destroyed); #ifdef SWIG_DIRECTORS @@ -582,35 +582,56 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); swig_member_const_iterator swig_members_begin() { return members.begin(); } swig_member_const_iterator swig_members_end() { return members.end(); } - int cast(void **vptr, swig_type_info *type, int *_own, int flags) { + int cast(void **vptr, swig_type_info *type, int *own, int flags) { int res = SWIG_ERROR; - if (_own) - *_own = own; - if (flags &SWIG_POINTER_DISOWN) - own = 0; + int clear_pointer = 0; + + if (own) + *own = 0; + if (((flags & SWIG_POINTER_RELEASE) == SWIG_POINTER_RELEASE) && !thisown) { + return SWIG_ERROR_RELEASE_NOT_OWNED; + } else { + if (own) + *own = *own | thisown; + if (flags & SWIG_POINTER_DISOWN) { + thisown = 0; + } + if (flags & SWIG_POINTER_CLEAR) { + clear_pointer = 1; + } + } + if (!type && types.size()) { - if(vptr) + if (vptr) { *vptr = types[0].second.ptr; + if (clear_pointer) + types[0].second.ptr = 0; + } return SWIG_OK; } for (unsigned int j = 0; j < types.size(); ++j) if (type == types[j].first) { - if(vptr) + if (vptr) { *vptr = types[j].second.ptr; + if (clear_pointer) + types[j].second.ptr = 0; + } return SWIG_OK; } for (unsigned int j = 0; j < types.size(); ++j) { swig_cast_info *tc = SWIG_TypeCheck(types[j].first->name, type); if (!tc) continue; - if(vptr) { + if (vptr) { int newmemory = 0; *vptr = SWIG_TypeCast(tc, types[j].second.ptr, &newmemory); - if (newmemory == SWIG_CAST_NEW_MEMORY) { - assert(_own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */ - if (_own) - *_own = *_own | SWIG_CAST_NEW_MEMORY; - } + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */ + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + if (clear_pointer) + types[j].second.ptr = 0; } res = SWIG_OK; break; @@ -619,7 +640,7 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); } bool is_owned() const { - return own; + return thisown; } #ifdef SWIG_DIRECTORS diff --git a/Lib/octave/std_auto_ptr.i b/Lib/octave/std_auto_ptr.i new file mode 100644 index 000000000..d062886e4 --- /dev/null +++ b/Lib/octave/std_auto_ptr.i @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------------- + * std_auto_ptr.i + * + * SWIG library file for handling std::auto_ptr. + * Memory ownership is passed from the std::auto_ptr C++ layer to the proxy + * class when returning a std::auto_ptr from a function. + * Memory ownership is passed from the proxy class to the std::auto_ptr in the + * C++ layer when passed as a parameter to a wrapped function. + * ----------------------------------------------------------------------------- */ + +%define %auto_ptr(TYPE) +%typemap(in, noblock=1) std::auto_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + +%typemap (out) std::auto_ptr< TYPE > %{ + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); +%} + +%template() std::auto_ptr< TYPE >; +%enddef + +namespace std { + template class auto_ptr {}; +} diff --git a/Lib/octave/std_unique_ptr.i b/Lib/octave/std_unique_ptr.i new file mode 100644 index 000000000..1a7ec06fa --- /dev/null +++ b/Lib/octave/std_unique_ptr.i @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------------- + * std_unique_ptr.i + * + * SWIG library file for handling std::unique_ptr. + * Memory ownership is passed from the std::unique_ptr C++ layer to the proxy + * class when returning a std::unique_ptr from a function. + * Memory ownership is passed from the proxy class to the std::unique_ptr in the + * C++ layer when passed as a parameter to a wrapped function. + * ----------------------------------------------------------------------------- */ + +%define %unique_ptr(TYPE) +%typemap(in, noblock=1) std::unique_ptr< TYPE > (void *argp = 0, int res = 0) { + res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags); + if (!SWIG_IsOK(res)) { + if (res == SWIG_ERROR_RELEASE_NOT_OWNED) { + %releasenotowned_fail(res, "TYPE *", $symname, $argnum); + } else { + %argument_fail(res, "TYPE *", $symname, $argnum); + } + } + $1.reset((TYPE *)argp); +} + +%typemap (out) std::unique_ptr< TYPE > %{ + %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); +%} + +%template() std::unique_ptr< TYPE >; +%enddef + +namespace std { + template class unique_ptr {}; +}