reduce swig complexity

This commit is contained in:
Laurent Perron
2018-12-11 11:52:50 +01:00
parent aa86dbd25a
commit 1e59a36509
4 changed files with 13 additions and 270 deletions

View File

@@ -48,112 +48,6 @@
// type names. Google typedefs are placed at the very end along with
// the necessary %apply macros. See COPY_TYPEMAPS below for details.
// Support for those popular buffer-pointer/length input pairs
%typemap(in) (void *INPUT, unsigned int LENGTH) (Py_ssize_t len) {
if (PyObject_AsReadBuffer($input, (const void**) &$1, &len) != 0)
return NULL;
if (((Py_ssize_t)($2_type)len) != len) {
SWIG_exception(SWIG_ValueError, "input data too large");
}
$2 = ($2_type)len;
}
%typemap(in) (void *INPUT, uint64 LENGTH) (Py_ssize_t len) {
if (PyObject_AsReadBuffer($input, (const void**) &$1, &len) != 0)
return NULL;
$2 = len;
}
// char **
%typemap(in, numinputs=0) char ** OUTPUT {
}
%typemap(argout, fragment="t_output_helper") char ** OUTPUT {
char* tmpstr = NULL;
if ($1 != NULL) tmpstr = *$1;
$result = t_output_helper($result, PyString_FromString(tmpstr));
}
// STL std::vector<T> for common types
// Get const std::vector<std::string>& "in" typemap.
%include "python/std_vector.i"
%include "python/std_map.i"
%include "python/std_set.i"
%include "python/std_list.i"
%define LIST_OUTPUT_TYPEMAP(type, py_converter)
%typemap(in) std::vector<type>(std::vector<type> temp) {
if (!vector_input_helper($input, &temp, PyObjAs<type>)) {
if (!PyErr_Occurred())
SWIG_Error(SWIG_TypeError, "sequence(type) expected");
return NULL;
}
$1 = temp;
}
%typemap(in) const std::vector<type>& (std::vector<type> temp),
const std::vector<type>* (std::vector<type> temp) {
if (!vector_input_helper($input, &temp, PyObjAs<type>)) {
if (!PyErr_Occurred())
SWIG_Error(SWIG_TypeError, "sequence(type) expected");
return NULL;
}
$1 = &temp;
}
%typemap(in,numinputs=0)
std::vector<type>* OUTPUT (std::vector<type> temp),
std::unordered_set<type>* OUTPUT (std::unordered_set<type> temp),
std::set<type>* OUTPUT (std::set<type> temp) {
$1 = &temp;
}
%typemap(argout)
std::vector<type>* OUTPUT,
std::set<type>* OUTPUT,
std::unordered_set<type>* OUTPUT {
%append_output(list_output_helper($1, &py_converter));
}
%typemap(out) std::vector<type> {
$result = vector_output_helper(&$1, &py_converter);
}
%typemap(out) std::vector<type>*, const std::vector<type>& {
$result = vector_output_helper($1, &py_converter);
}
%enddef
LIST_OUTPUT_TYPEMAP(bool, PyBool_FromLong);
LIST_OUTPUT_TYPEMAP(signed char, PyInt_FromLong);
LIST_OUTPUT_TYPEMAP(short, PyInt_FromLong);
LIST_OUTPUT_TYPEMAP(unsigned short, PyInt_FromLong);
LIST_OUTPUT_TYPEMAP(int, PyInt_FromLong);
LIST_OUTPUT_TYPEMAP(unsigned int, PyLong_FromUnsignedLong);
LIST_OUTPUT_TYPEMAP(long, PyInt_FromLong);
LIST_OUTPUT_TYPEMAP(unsigned long, PyLong_FromUnsignedLong);
LIST_OUTPUT_TYPEMAP(int64, PyLong_FromLongLong);
LIST_OUTPUT_TYPEMAP(uint64, PyLong_FromUnsignedLongLong);
LIST_OUTPUT_TYPEMAP(std::string, SwigString_FromString);
LIST_OUTPUT_TYPEMAP(char *, PyBytes_FromString);
LIST_OUTPUT_TYPEMAP(double, PyFloat_FromDouble);
LIST_OUTPUT_TYPEMAP(float, PyFloat_FromDouble);
#undef LIST_OUTPUT_TYPEMAP
%apply bool * OUTPUT { bool * OUTPUT2 };
%apply int * OUTPUT { int * OUTPUT2 };
%apply short * OUTPUT { short * OUTPUT2 };
%apply long * OUTPUT { long * OUTPUT2 };
%apply unsigned * OUTPUT { unsigned * OUTPUT2 };
%apply unsigned short * OUTPUT { unsigned short * OUTPUT2 };
%apply unsigned long * OUTPUT { unsigned long * OUTPUT2 };
%apply unsigned char * OUTPUT { unsigned char * OUTPUT2 };
%apply signed char * OUTPUT { signed char * OUTPUT2 };
%apply double * OUTPUT { double * OUTPUT2 };
%apply float * OUTPUT { float * OUTPUT2 };
%apply char ** OUTPUT { char ** OUTPUT2 };
// these are copied from basictypes.h
%define COPY_TYPEMAPS(oldtype, newtype)
typedef oldtype newtype;
%apply oldtype * OUTPUT { newtype * OUTPUT };
@@ -169,59 +63,11 @@ COPY_TYPEMAPS(int, int32);
COPY_TYPEMAPS(unsigned int, uint32);
COPY_TYPEMAPS(int64_t, int64);
COPY_TYPEMAPS(uint64_t, uint64);
COPY_TYPEMAPS(unsigned int, size_t);
#undef COPY_TYPEMAPS
%apply (void * INPUT, unsigned int LENGTH)
{ (void * INPUT, uint32 LENGTH) }
%apply (void * INPUT, uint64 LENGTH)
{ (void * INPUT, size_t LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const void * INPUT, unsigned int LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const void * INPUT, uint32 LENGTH) };
%apply (void * INPUT, uint64 LENGTH)
{ (const void * INPUT, size_t LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const char * INPUT, unsigned int LENGTH) };
%apply (void * INPUT, unsigned int LENGTH)
{ (const char * INPUT, uint32 LENGTH) };
%apply (void * INPUT, uint64 LENGTH)
{ (const char * INPUT, size_t LENGTH) };
// We accept either python ints or longs for uint64 arguments.
%typemap(in) uint64 {
if (PyInt_Check($input)) {
$1 = static_cast<uint64>(PyInt_AsLong($input));
} else if (PyLong_Check($input)) {
$1 = static_cast<uint64>(PyLong_AsUnsignedLongLong($input));
} else {
SWIG_exception(SWIG_TypeError,
"int or long value expected for argument \"$1_name\"")
}
}
// When a method returns a pointer or reference to a subobject of the
// receiver, it should be marked with SWIG_RETURN_POINTER_TO_SUBOBJECT.
// This ensures that the wrapper of the subobject keeps the wrapper of
// the parent object alive, which indirectly keeps the subobject alive.
%define SWIG_RETURN_POINTER_TO_SUBOBJECT(cpp_method, py_method)
%feature("shadow") cpp_method %{
def py_method(*args):
result = $action(*args)
if result is not None:
result.keepalive = args[0]
return result
%}
%enddef
#endif // SWIGPYTHON
#ifdef SWIGJAVA
// Add a char* cast to the SWIG 1.3.21 typemaps to remove a compiler warning.
%{
#include <cstdint>
#include <map>
@@ -236,114 +82,11 @@ COPY_TYPEMAPS(unsigned int, size_t);
%include <stdint.i>
%include <std_string.i>
%apply const std::string & {std::string &};
%apply const std::string & {std::string *};
// std::string
%typemap(jni) std::string "jstring"
%typemap(jtype) std::string "String"
%typemap(jstype) std::string "String"
%typemap(javadirectorin) std::string "$jniinput"
%typemap(javadirectorout) std::string "$javacall"
%typemap(in) std::string
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
$1.assign($1_pstr);
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorout) std::string
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
$result.assign($1_pstr);
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorin,descriptor="Ljava/lang/String;") std::string
%{ $input = jenv->NewStringUTF($1.c_str()); %}
%typemap(out) std::string
%{ $result = jenv->NewStringUTF($1.c_str()); %}
%typemap(javain) std::string "$javainput"
%typemap(javaout) std::string {
return $jnicall;
}
%typemap(typecheck) std::string = char *;
%typemap(throws) std::string
%{ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, $1.c_str());
return $null; %}
// const std::string &
%typemap(jni) const std::string & "jstring"
%typemap(jtype) const std::string & "String"
%typemap(jstype) const std::string & "String"
%typemap(javadirectorin) const std::string & "$jniinput"
%typemap(javadirectorout) const std::string & "$javacall"
%typemap(in) const std::string &
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
std::string $1_str($1_pstr);
$1 = &$1_str;
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const std::string &
%{ if(!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null std::string");
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
if (!$1_pstr) return $null;
/* possible thread - reentrant code problem */
static std::string $1_str;
$1_str = $1_pstr;
$result = &$1_str;
jenv->ReleaseStringUTFChars($input, $1_pstr); %}
%typemap(directorin,descriptor="Ljava/lang/String;") const std::string &
%{ $input = jenv->NewStringUTF($1.c_str()); %}
%typemap(out) const std::string &
%{ $result = jenv->NewStringUTF($1->c_str()); %}
%typemap(javain) const std::string & "$javainput"
%typemap(javaout) const std::string & {
return $jnicall;
}
%typemap(typecheck) const std::string & = char *;
%typemap(throws) const std::string &
%{ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, $1.c_str());
return $null;
%}
%define COPY_TYPEMAPS(oldtype, newtype)
typedef oldtype newtype;
%enddef
typedef int int32;
typedef unsigned int uint32;
typedef int64_t int64;
typedef uint64_t uint64;
#undef COPY_TYPEMAPS
#endif // SWIGJAVA
#ifdef SWIGCSHARP
@@ -362,15 +105,11 @@ typedef uint64_t uint64;
%include <std_string.i>
%include <stdint.i>
%apply const std::string & {std::string &};
%apply const std::string & {std::string *};
typedef int int32;
typedef unsigned int uint32;
typedef int64_t int64;
typedef uint64_t uint64;
#undef COPY_TYPEMAPS
#endif // SWIGCSHARP
// SWIG macros for explicit API declaration.

View File

@@ -30,6 +30,8 @@
%include "ortools/base/base.i"
%include "ortools/util/python/vector.i"
%import "ortools/graph/ebert_graph.h"
// Convert the "std::vector<int>* result" parameters to python outputs.

View File

@@ -31,6 +31,7 @@
%include <stdint.i>
%include "ortools/base/base.i"
%include "ortools/util/python/vector.i"
// We need to forward-declare the proto here, so that the PROTO_* macros
// involving them work correctly. The order matters very much: this declaration

View File

@@ -16,7 +16,6 @@
%import "ortools/base/integral_types.h"
namespace operations_research {
// --------- std::vector<data> wrapping ----------
// We can't just reuse the google.i code (see LIST_OUTPUT_TYPEMAP in that
@@ -30,6 +29,12 @@ namespace operations_research {
// Note(user): for an unknown reason, using the (handy) method PyObjAs()
// defined in base/swig/python-swig.cc seems to cause issues, so we can't
// use a generic, templated type checker.
// Get const std::vector<string>& "in" typemap.
%include "python/std_vector.i"
%include "python/std_map.i"
%include "python/std_set.i"
%include "python/std_list.i"
%define PY_LIST_OUTPUT_TYPEMAP(type, checker, py_converter)
%typecheck(SWIG_TYPECHECK_POINTER) const std::vector<type>&,
std::vector<type>,
@@ -70,7 +75,10 @@ namespace operations_research {
std::set<type>* OUTPUT (std::set<type> temp) {
$1 = &temp;
}
%typemap(argout) std::vector<type>* OUTPUT, std::set<type>* OUTPUT, std::unordered_set<type>* OUTPUT {
%typemap(argout)
std::vector<type>* OUTPUT,
std::set<type>* OUTPUT,
std::unordered_set<type>* OUTPUT {
%append_output(list_output_helper($1, &py_converter));
}
%typemap(out) std::vector<type> {
@@ -80,12 +88,6 @@ namespace operations_research {
$result = vector_output_helper($1, &py_converter);
}
%apply const std::vector<type>& { const std::vector<type>& }
%apply const std::vector<type>* { const std::vector<type>* }
%apply std::vector<type>* { std::vector<type>* }
%apply std::vector<type> { std::vector<type> }
%apply std::vector<type>* OUTPUT { std::vector<type>* OUTPUT }
%apply std::set<type>* OUTPUT { std::set<type>* OUTPUT }
@@ -168,4 +170,3 @@ PY_LIST_OUTPUT_TYPEMAP(double, PyFloat_Check, PyFloat_FromDouble);
%enddef // PY_LIST_LIST_INPUT_TYPEMAP
PY_LIST_LIST_INPUT_TYPEMAP(int64, SwigPyIntOrLong_Check);
} // namespace operations_research