Merge remote-tracking branch 'upstream/master' into OCaml-INPUT-OUTPUT-INOUT-primitives

This commit is contained in:
Zackery Spytz 2019-02-18 20:41:13 -07:00
commit 5a58f9a87b
25 changed files with 354 additions and 23 deletions

View file

@ -7,6 +7,15 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.0.0 (in progress)
===========================
2019-02-18: jakecobb
[Python] #945 #1234 Elements in std::vector memory access fix.
Accessing an element in a std::vector obtains a reference to the element via an
iterator pointing to the element in the container. If the vector is garbage collected,
the SWIG wrapper containing the pointer to the element becomes invalid. The fix is
to obtain a back-reference to the container by the wrapper to the element in the Python
layer to prevent the garbage collector from destroying the underlying container.
2019-02-17: wsfulton
Fix typemap matching to expand template parameters when the name contains
template parameters. In the %typemap below the type is T and the name is X<T>::make

View file

@ -1828,7 +1828,7 @@ Consider the following C++ code:
<pre>
struct Wheel {
int size;
Wheel(int sz) : size(sz) {}
Wheel(int sz = 0) : size(sz) {}
};
class Bike {

View file

@ -3711,7 +3711,7 @@ Below are some practical steps that should help meet these requirements.
</li>
<li>
Copying an existing language module and adapting the source for it is likely to be the most efficient
approach to fully developing a new module as a numbe of corner cases are covered in the existing implementations.
approach to fully developing a new module as a number of corner cases are covered in the existing implementations.
The most advanced scripting languages are Python and Ruby.
The most advanced compiled target languages are Java and C#.
</li>

View file

@ -8295,7 +8295,7 @@ Consider the following C++ code:
<pre>
struct Wheel {
int size;
Wheel(int sz) : size(sz) {}
Wheel(int sz = 0) : size(sz) {}
};
class Bike {

View file

@ -5452,7 +5452,7 @@ Consider the following C++ code:
#include &lt;iostream&gt;
struct Wheel {
int size;
Wheel(int sz) : size(sz) {}
Wheel(int sz = 0) : size(sz) {}
~Wheel() { std::cout &lt;&lt; "~Wheel" &lt;&lt; std::endl; }
};

View file

@ -4616,7 +4616,7 @@ except Error, e:
<p>
Details of how to tailor code for handling the caught C++ exception and converting it into the target language's exception/error handling mechanism
is outlined in the <a href="Typemaps.html#throws_typemap">"throws" typemap</a> section.
is outlined in the <a href="Typemaps.html#Typemaps_throws_typemap">"throws" typemap</a> section.
</p>
<p>

View file

@ -1,13 +1,13 @@
/* File : example.i */
%module example
%typemap(argout) (int &x, int &y) {
%typemap(argout) (const int &x, const int &y) {
swig_result = caml_list_append(swig_result, caml_val_int(*$1));
swig_result = caml_list_append(swig_result, caml_val_int(*$2));
}
%{
extern "C" void factor(int &x, int &y);
extern "C" void factor(const int &x, const int &y);
%}
extern "C" void factor(int &x, int &y);
extern "C" void factor(const int &x, const int &y);

View file

@ -647,6 +647,7 @@ CPP_STD_TEST_CASES += \
li_std_pair_using \
li_std_string \
li_std_vector \
li_std_vector_back_reference \
li_std_vector_enum \
li_std_vector_member_var\
li_std_vector_ptr \

View file

@ -0,0 +1,14 @@
%module li_std_vector_back_reference
%include <std_vector.i>
%inline %{
// #include <iostream>
struct Wheel {
int size;
Wheel(int sz = 0) : size(sz) {}
// ~Wheel() { std::cout << "~Wheel" << std::endl; }
};
%}
%template(VectorWheel) std::vector<Wheel>;

View file

@ -0,0 +1,53 @@
open Swig
open Extend_placement
let _ =
let f = new_Foo '() in
assert (f -> spam () as int = 1);
assert (new_Foo '(1) -> spam () as int = 1);
let f = new_Foo '(1, 1) in
assert (f -> spam () as int = 1);
assert (f -> spam ("hello") as int = 2);
assert (f -> spam (1) as int = 1);
assert (f -> spam (1, 2) as int = 3);
assert (f -> spam (2, 4, 6) as int = 6);
assert (f -> spam (f) as int = 0);
let arg = C_double 1. in
assert (f -> spam (f, arg) as int = 0);
assert (new_Bar '() -> spam () as int = 1);
let b = new_Bar '(1) in
assert (b -> spam () as int = 1);
assert (b -> spam ("hello") as int = 2);
assert (b -> spam (1) as int = 1);
assert (b -> spam (1, 2) as int = 3);
assert (b -> spam (2, 4, 6) as int = 6);
assert (b -> spam (b) as int = 0);
let arg = C_double 1. in
assert (b -> spam (b, arg) as int = 0);
assert (new_FooTi '() -> spam () as int = 1);
assert (new_FooTi '(1) -> spam () as int = 1);
let f = new_FooTi '(1, 1) in
assert (f -> spam () as int = 1);
assert (f -> spam ("hello") as int = 2);
assert (f -> spam (1) as int = 1);
assert (f -> spam (1, 2) as int = 3);
assert (f -> spam (2, 4, 6) as int = 6);
let foo = new_Foo '() in
assert (f -> spam (foo) as int = 0);
let arg = C_double 1. in
assert (f -> spam (foo, arg) as int = 0);
assert (new_BarTi '() -> spam () as int = 1);
let b = new_BarTi '(1) in
assert (b -> spam () as int = 1);
assert (b -> spam ("hello") as int = 2);
assert (b -> spam (1) as int = 1);
assert (b -> spam (1, 2) as int = 3);
assert (b -> spam (2, 4, 6) as int = 6);
let bar = new_Bar '() in
assert (b -> spam (bar) as int = 0);
let arg = C_double 1. in
assert (b -> spam (bar, arg) as int = 0);
;;

View file

@ -0,0 +1,15 @@
open Swig
open Global_vars
_init '()
let _ =
assert (_b '() as string = "string b");
assert (_b '("a string value") as string = "a string value");
assert (_b '() as string = "a string value");
assert (_x '() as int = 1234);
assert (_x '(9876) as int = 9876);
assert (_x '() as int = 9876);
assert (_Hi '() as int = 0);
assert (_Hola '() as int = 1);
;;

View file

@ -0,0 +1,60 @@
open Swig
open Overload_template
let _ =
assert (_foo '() as int = 3);
assert (_maximum '(3, 4) as int = 4);
assert (_maximum '(3.4, 5.2) as float > 5.);
assert (_mix1 '("hi") as int = 101);
assert (_mix1 '(1.0, 1.0) as int = 102);
assert (_mix1 '(1.0) as int = 103);
assert (_mix2 '("hi") as int = 101);
assert (_mix2 '(1.0, 1.0) as int = 102);
assert (_mix2 '(1.0) as int = 103);
assert (_mix3 '("hi") as int = 101);
assert (_mix3 '(1.0, 1.0) as int = 102);
assert (_mix3 '(1.0) as int = 103);
assert (_overtparams1 '(100) as int = 10);
assert (_overtparams1 '(100.0, 100) as int = 20);
assert (_overtparams2 '(100.0, 100) as int = 40);
assert (_overloaded '() as int = 60);
assert (_overloaded '(100.0, 100) as int = 70);
assert (_overloadedagain '("hello") as int = 80);
assert (_overloadedagain '() as int = 90);
assert (_specialization '(10) as int = 202);
assert (_specialization '(10.0) as int = 203);
assert (_specialization '(10, 10) as int = 204);
assert (_specialization '(10.0, 10.0) as int = 205);
assert (_specialization '("hi", "hi") as int = 201);
assert (_xyz '() = C_void);
assert (_xyz_int '() = C_void);
assert (_xyz_double '() = C_void);
assert (_overload '("hi") as int = 0);
assert (_overload '(1) as int = 10);
assert (_overload '(1, 1) as int = 20);
assert (_overload '(1, "hello") as int = 30);
let k = new_Klass '() in
assert (_overload '(k) as int = 10);
assert (_overload '(k, k) as int = 20);
assert (_overload '(k, "hello") as int = 30);
assert (_overload '(10.0, "hi") as int = 40);
assert (_overload '() as int = 50);
assert (_nsoverload '("hi") as int = 1000);
assert (_nsoverload '(1) as int = 1010);
assert (_nsoverload '(1, 1) as int = 1020);
assert (_nsoverload '(1, "hello") as int = 1030);
assert (_nsoverload '(k) as int = 1010);
assert (_nsoverload '(k, k) as int = 1020);
assert (_nsoverload '(k, "hello") as int = 1030);
assert (_nsoverload '(10.0, "hi") as int = 1040);
assert (_nsoverload '() as int = 1050);
assert (_A_foo '(1) = C_void);
let b = new_B '() in
assert (b -> foo(1) = C_void);
;;

View file

@ -22,7 +22,7 @@ let _ =
let _ = _var_short (_createref_short (C_short 10)) in
assert (_value_short (_var_short '()) as int = 10);
let _ = _var_unsigned_short (_createref_unsigned_short (C_ushort 10)) in
assert (_value_unsigned_short (_var_unsigned_short '()) as int = 10);

View file

@ -0,0 +1,10 @@
open Swig
open Sizet
let _ =
let s = C_int64 2000L in
assert (_test1 '(s) as int = 2000);
assert (_test2 '(s) as int = 2000);
assert (_test3 '(s) as int = 2000);
assert (_test4 '(s) as int = 2000);
;;

View file

@ -0,0 +1,17 @@
open Swig
open Template_default_arg_overloaded_extend
let _ =
let rs = new_ResultSet '() and sp = new_SearchPoint '() in
assert (rs -> go_get_method (0, sp) as int = -1);
assert (rs -> go_get_method (0, sp, 100) as int = 100);
assert (rs -> go_get_template (0, sp) as int = -2);
assert (rs -> go_get_template (0, sp, 100) as int = 100);
assert (rs -> over () as string = "over(int)");
assert (rs -> over (10) as string = "over(int)");
assert (rs -> over (sp) as string = "over(giai2::SearchPoint, int)");
assert (rs -> over (sp, 10) as string = "over(giai2::SearchPoint, int)");
assert (rs -> over (true, sp) as string = "over(bool, gaia2::SearchPoint, int)");
assert (rs -> over (true, sp, 10) as string = "over(bool, gaia2::SearchPoint, int)");
;;

View file

@ -0,0 +1,52 @@
open Swig
open Template_default_arg
let _ =
let helloInt = new_Hello_int '() and enumArg = _hi '() in
assert (helloInt -> foo (enumArg) = C_void);
assert (helloInt -> foo () = C_void);
let x = new_X_int '() in
assert (x -> meth (20.0, 200) as int = 200);
assert (x -> meth (20) as int = 20);
assert (x -> meth () as int = 0);
let x = new_Y_unsigned '() in
let args = C_list [ C_double 20.0 ; C_uint 200l ] in
assert (x -> meth (args) as int = 200);
let args = C_uint 20l in
assert (x -> meth (args) as int = 20);
assert (x -> meth () as int = 0);
let x = new_X_longlong '() in
assert (x -> meth (20.0) as int = 0);
let x = new_X_longlong '(20.0) in
assert (x -> meth (20.0) as int = 0);
let args = C_list [ C_double 20.0 ; C_int64 200L ] in
let x = new_X_longlong '(args) in
assert (x -> meth (20.0) as int = 0);
let x = new_X_int '() in
assert (x -> meth (20.0) as int = 0);
let x = new_X_int '(20.0) in
assert (x -> meth (20.0) as int = 0);
let x = new_X_int '(20.0, 200) in
assert (x -> meth (20.0) as int = 0);
let arg = new_Foo_int '() in
assert (_ott '(arg) as int = 30);
assert (_ott '() as int = 10);
assert (_ott '(1) as int = 10);
assert (_ott '(1, 1) as int = 10);
assert (_ott '("hi") as int = 20);
assert (_ott '("hi", 1) as int = 20);
assert (_ott '("hi", 1, 1) as int = 20);
let arg = new_Hello_int '() in
assert (_ottstring '(arg, "hi") as int = 40);
assert (_ottstring '(arg) as int = 40);
assert (_ottint '(arg, 1) as int = 50);
assert (_ottint '(arg) as int = 50);
assert (_ott '(arg, 1.0) as int = 60);
assert (_ott '(arg) as int = 60);
;;

View file

@ -0,0 +1,11 @@
open Swig
open Typedef_reference
let _ =
let i = _copy_intp '(2) in
assert (_somefunc '(i) as int = 2);
assert (_delete_intp '(i) = C_void);
let i = _copy_intp '(3) in
assert (_otherfunc '(i) as int = 3);
assert (_delete_intp '(i) = C_void);
;;

View file

@ -0,0 +1,10 @@
open Swig
open Wrapmacro
let _ =
let args = C_list [ C_int64 2L ; C_int64 1L ] in
assert (_maximum '(args) as int = 2);
let args = C_list [ C_double (2. /. 7.) ; C_double 256. ] in
assert (_maximum '(args) as float = 256.);
assert (_GUINT16_SWAP_LE_BE_CONSTANT '(0x1234) as int = 0x3412);
;;

View file

@ -0,0 +1,10 @@
from li_std_vector_back_reference import *
def first_element():
v = VectorWheel((Wheel(11), Wheel(22)))
# v will be deleted after exit from this method
return v[0]
size = first_element().size
if size != 11:
raise RuntimeError("Back reference not working {}".format(size))

View file

@ -62,7 +62,7 @@ extern "C" {
SWIG_TypeCheckStruct(source_type, dest_type );
#ifdef TYPE_CAST_VERBOSE
fprintf( stderr, "Typecheck -> %s\n",
tc ? tc->str : "<none>" );
tc ? tc->type->str : "<none>" );
#endif
if( tc ) {
int newmemory = 0;

View file

@ -7,6 +7,7 @@
%include <std/std_except.i>
%apply size_t { std::size_t };
%apply const size_t& { const std::size_t& };
%{
#include <string>

View file

@ -86,6 +86,7 @@ class wstring;
%typemap(out) string * {
$result = caml_val_string_len((*$1).c_str(),(*$1).size());
}
%typemap(typecheck) string, const string & = char *;
}
#ifdef ENABLE_CHARPTR_ARRAY

View file

@ -72,7 +72,8 @@
long, signed long, unsigned long,
long long, signed long long, unsigned long long,
const long &, const signed long &, const unsigned long &,
const long long &, const signed long long &, const unsigned long long &
const long long &, const signed long long &, const unsigned long long &,
size_t, const size_t &
{
if( !Is_block($input) ) $1 = 0;
else {
@ -135,24 +136,42 @@
}
%typecheck(SWIG_TYPECHECK_POINTER) SWIGTYPE *, SWIGTYPE &, SWIGTYPE &&, SWIGTYPE [] {
void *ptr;
$1 = !caml_ptr_val_internal($input, &ptr,$descriptor);
if (!Is_block($input) || !(SWIG_Tag_val($input) == C_obj || SWIG_Tag_val($input) == C_ptr)) {
$1 = 0;
} else {
void *ptr;
$1 = !caml_ptr_val_internal($input, &ptr, $descriptor);
}
}
#if 0
%typecheck(SWIG_TYPECHECK_POINTER) SWIGTYPE {
void *ptr;
$1 = !caml_ptr_val_internal($input, &ptr, $&1_descriptor);
swig_type_info *typeinfo;
if (!Is_block($input)) {
$1 = 0;
} else {
switch (SWIG_Tag_val($input)) {
case C_obj: {
void *ptr;
$1 = !caml_ptr_val_internal($input, &ptr, $&1_descriptor);
break;
}
case C_ptr: {
typeinfo = (swig_type_info *)SWIG_Int64_val(SWIG_Field($input, 1));
$1 = SWIG_TypeCheck("$1_type", typeinfo) != NULL;
break;
}
default: $1 = 0; break;
}
}
}
#endif
%typecheck(SWIG_TYPECHECK_VOIDPTR) void * {
void *ptr;
$1 = !caml_ptr_val_internal($input, &ptr, 0);
}
%typecheck(SWIG_TYPECHECK_SWIGOBJECT) CAML_VALUE "$1 = 1;"
%define INPUT_OUTPUT_INOUT_TYPEMAPS(type, c_to_ocaml, ocaml_to_c)
%typemap(in) type *INPUT(type temp), type &INPUT(type temp) {
temp = (type)ocaml_to_c($input);

View file

@ -132,11 +132,11 @@
%typemap(varin) C_NAME {
$1 = OCAML_TO_C($input);
}
%typemap(in) C_NAME & ($*1_ltype temp) {
%typemap(in) const C_NAME & ($*1_ltype temp) {
temp = ($*1_ltype) OCAML_TO_C($input);
$1 = &temp;
}
%typemap(varin) C_NAME & {
%typemap(varin) const C_NAME & {
$1 = OCAML_TO_C($input);
}
%typemap(directorout) C_NAME {
@ -149,10 +149,10 @@
%typemap(varout) C_NAME {
$result = C_TO_OCAML($1);
}
%typemap(varout) C_NAME & {
%typemap(varout) const C_NAME & {
$result = C_TO_OCAML($1);
}
%typemap(out) C_NAME & {
%typemap(out) const C_NAME & {
$result = C_TO_OCAML(*$1);
}
%typemap(directorin) C_NAME {

View file

@ -36,6 +36,48 @@
%include <std_except.i>
%fragment("container_owner_attribute_init", "init") {
// thread safe initialization
swig::container_owner_attribute();
}
%fragment("reference_container_owner", "header", fragment="container_owner_attribute_init") {
namespace swig {
PyObject* container_owner_attribute() {
static PyObject* attr = SWIG_Python_str_FromChar("__swig_container");
return attr;
}
template <typename T>
struct container_owner {
// By default, do not add the back-reference (for value types)
// Specialization below will check the reference for pointer types.
static bool back_reference(PyObject* child, PyObject* owner) {
return false;
}
};
template <>
struct container_owner<swig::pointer_category> {
/*
* Call to add a back-reference to the owning object when returning a
* reference from a container. Will only set the reference if child
* is a SWIG wrapper object that does not own the pointer.
*
* returns whether the reference was set or not
*/
static bool back_reference(PyObject* child, PyObject* owner) {
SwigPyObject* swigThis = SWIG_Python_GetSwigThis(child);
if (swigThis && (swigThis->own & SWIG_POINTER_OWN) != SWIG_POINTER_OWN) {
PyObject_SetAttr(child, container_owner_attribute(), owner);
return true;
}
return false;
}
};
}
}
%fragment(SWIG_Traits_frag(swig::SwigPtr_PyObject),"header",fragment="StdTraits") {
namespace swig {
template <> struct traits<SwigPtr_PyObject > {
@ -766,6 +808,12 @@ namespace swig
size_type __len__() const {
return self->size();
}
// Although __getitem__, front, back actually use a const value_type& return type, the typemaps below
// use non-const so that they can be easily overridden by users if necessary.
%typemap(ret, fragment="reference_container_owner", noblock=1) value_type& __getitem__, value_type& front, value_type& back {
(void)swig::container_owner<swig::traits<$*1_ltype>::category>::back_reference($result, $self);
}
}
%enddef