Add Python support for std::unique_ptr inputs

Equivalent to Java/C# implementation.
This commit is contained in:
William S Fulton 2022-07-16 13:14:40 +01:00
commit c3c061cac8
8 changed files with 103 additions and 9 deletions

View file

@ -53,7 +53,7 @@ struct KlassInheritance : virtual Klass {
} }
}; };
#if defined(SWIGJAVA) || defined (SWIGCSHARP) #if defined(SWIGJAVA) || defined (SWIGCSHARP) || defined(SWIGPYTHON)
std::string takeKlassUniquePtr(std::unique_ptr<Klass> k) { std::string takeKlassUniquePtr(std::unique_ptr<Klass> k) {
return std::string(k->getLabel()); return std::string(k->getLabel());
} }

View file

@ -1,5 +1,70 @@
from cpp11_std_unique_ptr import * from cpp11_std_unique_ptr import *
def checkCount(expected_count):
actual_count = Klass.getTotal_count()
if (actual_count != expected_count):
raise RuntimeError("Counts incorrect, expected:" + expected_count + " actual:" + actual_count)
# unique_ptr as input
kin = Klass("KlassInput")
checkCount(1)
s = takeKlassUniquePtr(kin)
checkCount(0)
if kin.thisown:
raise RuntimeError("thisown should be false")
if s != "KlassInput":
raise RuntimeError("Incorrect string: " + s)
if not is_nullptr(kin):
raise RuntimeError("is_nullptr failed")
del kin # Should not fail, even though already deleted
checkCount(0)
kin = Klass("KlassInput")
checkCount(1)
s = takeKlassUniquePtr(kin)
checkCount(0)
if kin.thisown:
raise RuntimeError("thisown should be false")
if s != "KlassInput":
raise RuntimeError("Incorrect string: " + s)
if not is_nullptr(kin):
raise RuntimeError("is_nullptr failed")
exception_thrown = False
try:
s = takeKlassUniquePtr(kin)
except RuntimeError as e:
exception_thrown = True
if not exception_thrown:
raise RuntimeError("double usage of takeKlassUniquePtr should have been an error")
del 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)
except RuntimeError as e:
exception_thrown = True
if not exception_thrown:
raise RuntimeError("Should have thrown 'Cannot release ownership as memory is not owned' error")
del kin
checkCount(0)
kini = KlassInheritance("KlassInheritanceInput")
checkCount(1)
s = takeKlassUniquePtr(kini)
checkCount(0)
if kini.thisown:
raise RuntimeError("thisown should be false")
if s != "KlassInheritanceInput":
raise RuntimeError("Incorrect string: " + s)
if not is_nullptr(kini):
raise RuntimeError("is_nullptr failed")
del kini # Should not fail, even though already deleted
checkCount(0)
# unique_ptr as output
k1 = makeKlassUniquePtr("first") k1 = makeKlassUniquePtr("first")
k2 = makeKlassUniquePtr("second") k2 = makeKlassUniquePtr("second")
if Klass.getTotal_count() != 2: if Klass.getTotal_count() != 2:

View file

@ -1357,12 +1357,19 @@ SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int
} }
} }
if (sobj) { if (sobj) {
if (own) if (((flags & SWIG_POINTER_RELEASE) == SWIG_POINTER_RELEASE) && !sobj->own) {
*own = *own | sobj->own; res = SWIG_ERROR_RELEASE_NOT_OWNED;
if (flags & SWIG_POINTER_DISOWN) { } else {
sobj->own = 0; if (own)
*own = *own | sobj->own;
if (flags & SWIG_POINTER_DISOWN) {
sobj->own = 0;
}
if (flags & SWIG_POINTER_CLEAR) {
sobj->ptr = 0;
}
res = SWIG_OK;
} }
res = SWIG_OK;
} else { } else {
if (implicit_conv) { if (implicit_conv) {
SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0;

View file

@ -8,9 +8,22 @@
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
%define %unique_ptr(TYPE) %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 > %{ %typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags)); %set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%} %}
%template() std::unique_ptr< TYPE >; %template() std::unique_ptr< TYPE >;
%enddef %enddef

View file

@ -1,4 +1,4 @@
/* Errors in SWIG */ /* SWIG Errors applicable to all language modules, values are reserved from -1 to -99 */
#define SWIG_UnknownError -1 #define SWIG_UnknownError -1
#define SWIG_IOError -2 #define SWIG_IOError -2
#define SWIG_RuntimeError -3 #define SWIG_RuntimeError -3
@ -13,4 +13,3 @@
#define SWIG_MemoryError -12 #define SWIG_MemoryError -12
#define SWIG_NullReferenceError -13 #define SWIG_NullReferenceError -13

View file

@ -44,6 +44,8 @@
#define SWIG_POINTER_DISOWN 0x1 #define SWIG_POINTER_DISOWN 0x1
#define SWIG_CAST_NEW_MEMORY 0x2 #define SWIG_CAST_NEW_MEMORY 0x2
#define SWIG_POINTER_NO_NULL 0x4 #define SWIG_POINTER_NO_NULL 0x4
#define SWIG_POINTER_CLEAR 0x8
#define SWIG_POINTER_RELEASE (SWIG_POINTER_CLEAR | SWIG_POINTER_DISOWN)
/* Flags for new pointer objects */ /* Flags for new pointer objects */
#define SWIG_POINTER_OWN 0x1 #define SWIG_POINTER_OWN 0x1
@ -129,7 +131,13 @@
*/ */
#define SWIG_OK (0) #define SWIG_OK (0)
/* Runtime errors are < 0 */
#define SWIG_ERROR (-1) #define SWIG_ERROR (-1)
/* Errors in range -1 to -99 are in swigerrors.swg (errors for all languages including those not using the runtime) */
/* Errors in range -100 to -199 are language specific errors defined in *errors.swg */
/* Errors < -200 are generic runtime specific errors */
#define SWIG_ERROR_RELEASE_NOT_OWNED (-200)
#define SWIG_IsOK(r) (r >= 0) #define SWIG_IsOK(r) (r >= 0)
#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) #define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError)
@ -144,7 +152,7 @@
#define SWIG_OLDOBJ (SWIG_OK) #define SWIG_OLDOBJ (SWIG_OK)
#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) #define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK)
#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) #define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK)
/* Check, add and del mask methods */ /* Check, add and del object mask methods */
#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) #define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) #define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) #define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))

View file

@ -19,6 +19,7 @@
#endif #endif
#define %varnullref_fmt(_type,_name) %nullref_fmt() %varfail_fmt(_type, _name) #define %varnullref_fmt(_type,_name) %nullref_fmt() %varfail_fmt(_type, _name)
#define %outnullref_fmt(_type) %nullref_fmt() %outfail_fmt(_type) #define %outnullref_fmt(_type) %nullref_fmt() %outfail_fmt(_type)
#define %releasenotownedfail_fmt(_type,_name,_argn) "in method '" `_name` "', cannot release ownership as memory is not owned for argument " `_argn`" of type '" `_type`"'"
/* setting an error */ /* setting an error */
#define %error(code,msg...) SWIG_Error(code, msg) #define %error(code,msg...) SWIG_Error(code, msg)

View file

@ -140,6 +140,7 @@
#define %argument_nullref(type, name, argn) SWIG_exception_fail(SWIG_ValueError, %argnullref_fmt(type, name, argn)) #define %argument_nullref(type, name, argn) SWIG_exception_fail(SWIG_ValueError, %argnullref_fmt(type, name, argn))
#define %variable_fail(code, type, name) SWIG_exception_fail(%default_code(code), %varfail_fmt(type, name)) #define %variable_fail(code, type, name) SWIG_exception_fail(%default_code(code), %varfail_fmt(type, name))
#define %variable_nullref(type, name) SWIG_exception_fail(SWIG_ValueError, %varnullref_fmt(type, name)) #define %variable_nullref(type, name) SWIG_exception_fail(SWIG_ValueError, %varnullref_fmt(type, name))
#define %releasenotowned_fail(code, type, name, argn) SWIG_exception_fail(%default_code(code), %releasenotownedfail_fmt(type, name, argn))
#if defined(SWIG_DIRECTOR_TYPEMAPS) #if defined(SWIG_DIRECTOR_TYPEMAPS)
#define %dirout_fail(code, type) SWIG_DirOutFail(%default_code(code), %outfail_fmt(type)) #define %dirout_fail(code, type) SWIG_DirOutFail(%default_code(code), %outfail_fmt(type))