// Copyright 2010-2021 Google LLC // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This file provides swig wrapping for some specialization of std::function // parameters. Currently, swig does not support much of C++11 features, and // especially not the std::function. // // Java callers will need to use a specific "type" of callbacks: they must // specialize one of the existing generic callback classes defined in // ../functions_swig_helpers.h (which are SWIG-wrapped to Java in a // straightforward way). See the examples. %include "ortools/base/base.i" %include "std_common.i" %include "std_string.i" %{ #include #include "ortools/base/integral_types.h" #include "ortools/util/functions_swig_helpers.h" %} #define PARENTHIZE(ReturnType, Args...) ReturnType(Args) #define CAT3(a, b, c) a ## b ## c // The C preprocessor macros below use some tricks that make them work only if // the actual C preprocessor expands them (not the SWIG preprocessor). %{ // NAMES(int64_t, bool, int) expands to: , i0, i1, i2 #define NAMES_0 #define NAMES_1 i0 #define NAMES_2 i0, i1 #define NAMES_3 i0, i1, i2 #define NAMES(num) NAMES_ ## num // INSERT_NAMES(int64_t, bool, int) expands to: int64_t i0, bool i1, int i2 #define INSERT_NAMES_0() #define INSERT_NAMES_1(arg0) arg0 i0 #define INSERT_NAMES_2(arg0, arg1) arg0 i0, arg1 i1 #define INSERT_NAMES_3(arg0, arg1, arg2) arg0 i0, arg1 i1, arg2 i2 #define INSERT_NAMES(num) INSERT_NAMES_ ## num // Abbreviation of the java type corresponding to the given CType. // Eg. JAVA_ABBREV(int64_t) expands to "J". #define JAVA_ABBREV_int64 "J" #define JAVA_ABBREV_int "I" #define JAVA_ABBREV_bool "Z" #define JAVA_ABBREV(x) JAVA_ABBREV_ ## x // ABBREV(int64_t, bool, int64_t) expands to: JZJ #define ABBREV_0() #define ABBREV_1(arg1) JAVA_ABBREV(arg1) #define ABBREV_2(arg1, arg2) JAVA_ABBREV(arg1) JAVA_ABBREV(arg2) #define ABBREV_3(arg1, arg2, arg3) ABBREV_2(arg1, arg2) JAVA_ABBREV(arg3) #define ABBREV(num) ABBREV_ ## num %} // See WRAP_STD_FUNCTION_JAVA below to understand why we need the __Unused__ // argument. %define WRAP_STD_FUNCTION_JAVA_AUX(ClassPath, ClassName, CppClass, ReturnType, JavaReturnType, NumArgs, __Unused__, Args...) // The macro expansions can be hard to follow, so we show an example of the // expected macro expansion with: ReturnType=int64_t, Args=int64_t, bool. // EXPANSION EXAMPLE: "int64_t(int64_t, bool)". %typemap(in) std::function { jclass object_class = jenv->FindClass(ClassPath ClassName); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID( object_class, "getCPtr", "(L" ClassPath ClassName ";)J"); assert(method_id != nullptr); operations_research::swig_util::CppClass* const fun = reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); // EXPANSION EXAMPLE: "int64_t i0, bool i1". $1 = [fun](INSERT_NAMES(NumArgs)(Args)) { // EXPANSION EXAMPLE: "i0, i1". return fun->Run(NAMES(NumArgs)); }; } // These 3 typemaps tell SWIG what JNI and Java types to use %typemap(jni) std::function "jobject" %typemap(jtype) std::function ClassName %typemap(jstype) std::function ClassName // This typemap handles the conversion of the jtype to jstype typemap type // and vice versa %typemap(javain) std::function "$javainput" %enddef // NUM_ARGS_MINUS_1(Guard, 4, "Hello", -1) = 3; etc. This generic macro works // with 1 to 4 args (variadic macros with a total of zero arguments don't work). #define NUM_ARGS_MINUS_1(Args...) NUM_ARGS_AUX(Args, 3, 2, 1, 0) #define NUM_ARGS_AUX(_1, _2, _3, _4, N, Args...) N #define FIRST_ARG(x, Args...) x // We make the wrapper even more convenient to use. See usage below. // // Note: the variadic 'Args...' actually contains the 'JavaReturnType' argument, // then the (possibly empty) list of argument types of the function. We do this // because despite what the SWIG documentation claims, variadic macros don't // work well when their number of arguments is zero. %define WRAP_STD_FUNCTION_JAVA(CppClass, Package, ReturnType, Args...) WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, FIRST_ARG(Args), NUM_ARGS_MINUS_1(Args), Args) %enddef // For std::function<> involving void either as input or output type, // the WRAP_STD_FUNCTION_JAVA macro doesn't work. So we use some // custom code here. // TODO(user): explain why. // --------- VoidToString --------- %define WRAP_STD_FUNCTIONS_WITH_VOID_JAVA(ClassPath) %typemap(in) std::function { jclass object_class = jenv->FindClass(ClassPath "VoidToString"); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID(object_class, "getCPtr", "(L" ClassPath "VoidToString;)J"); assert(method_id != nullptr); operations_research::swig_util::VoidToString* const fun = reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); $1 = [fun]() { return fun->Run(); }; } // These 3 typemaps tell SWIG what JNI and Java types to use %typemap(jni) std::function "jobject" %typemap(jtype) std::function "VoidToString" %typemap(jstype) std::function "VoidToString" // This typemap handles the conversion of the jstype to jtype typemap types %typemap(javain) std::function "$javainput" // --------- VoidToVoid --------- %typemap(in) std::function { jclass object_class = jenv->FindClass(ClassPath "VoidToVoid"); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID(object_class, "getCPtr", "(L" ClassPath "VoidToVoid;)J"); assert(method_id != nullptr); operations_research::swig_util::VoidToVoid* const fun = reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); $1 = [fun]() { fun->Run(); }; } // These 3 typemaps tell SWIG what JNI and Java types to use %typemap(jni) std::function "jobject" %typemap(jtype) std::function "VoidToVoid" %typemap(jstype) std::function "VoidToVoid" // This typemap handles the conversion of the jstype to jtype typemap types %typemap(javain) std::function "$javainput" // --------- LongToVoid --------- %typemap(in) std::function { jclass object_class = jenv->FindClass(ClassPath "LongToVoid"); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID(object_class, "getCPtr", "(L" ClassPath "LongToVoid;)J"); assert(method_id != nullptr); operations_research::swig_util::LongToVoid* const fun = reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); $1 = [fun](int64_t i) { fun->Run(i); }; } // These 3 typemaps tell SWIG what JNI and Java types to use %typemap(jni) std::function "jobject" %typemap(jtype) std::function "LongToVoid" %typemap(jstype) std::function "LongToVoid" // This typemap handles the conversion of the jstype to jtype typemap types %typemap(javain) std::function "$javainput" %enddef // WRAP_STD_FUNCTIONS_WITH_VOID_JAVA %define WRAP_STD_FUNCTION_JAVA_CLASS_TO_VOID(CppClass, ClassPath, Parameter) %typemap(in) std::function { jclass object_class = jenv->FindClass(ClassPath "CppClass"); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID( object_class, "getCPtr", "(L" ClassPath "CppClass;)J"); assert(method_id != nullptr); operations_research::swig_util::CppClass* const fun = reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); $1 = [fun](operations_research::Parameter* param) { fun->Run(param); }; } // These 3 typemaps tell SWIG what JNI and Java types to use %typemap(jni) std::function "jobject" %typemap(jtype) std::function "CppClass" %typemap(jstype) std::function "CppClass" // This typemap handles the conversion of the jstype to jtype typemap types %typemap(javain) std::function "$javainput" %feature("director") operations_research::swig_util::CppClass; %rename (run) operations_research::swig_util::CppClass::Run; %enddef // WRAP_STD_FUNCTION_JAVA_CLASS_TO_VOID // directors %module(directors="1") operations_research_swig_util // --------- Include the swig helpers file to create the director classes ------ // We cannot use %ignoreall/%unignoreall as this is not compatible with nested // swig files. %feature("director") operations_research::swig_util::LongToLong; %rename (run) operations_research::swig_util::LongToLong::Run; %feature("director") operations_research::swig_util::LongLongToLong; %rename (run) operations_research::swig_util::LongLongToLong::Run; %feature("director") operations_research::swig_util::IntToLong; %rename (run) operations_research::swig_util::IntToLong::Run; %feature("director") operations_research::swig_util::IntIntToLong; %rename (run) operations_research::swig_util::IntIntToLong::Run; %feature("director") operations_research::swig_util::LongLongLongToLong; %rename (run) operations_research::swig_util::LongLongLongToLong::Run; %feature("director") operations_research::swig_util::LongToBoolean; %rename (run) operations_research::swig_util::LongToBoolean::Run; %feature("director") operations_research::swig_util::VoidToString; %rename (run) operations_research::swig_util::VoidToString::Run; %feature("director") operations_research::swig_util::VoidToBoolean; %rename (run) operations_research::swig_util::VoidToBoolean::Run; %feature("director") operations_research::swig_util::LongLongLongToBoolean; %rename (run) operations_research::swig_util::LongLongLongToBoolean::Run; %feature("director") operations_research::swig_util::LongToVoid; %rename (run) operations_research::swig_util::LongToVoid::Run; %feature("director") operations_research::swig_util::VoidToVoid; %rename (run) operations_research::swig_util::VoidToVoid::Run; %include "ortools/util/functions_swig_helpers.h"