From c7077e9fe5b14cabf1d7ae187aa3852f41329012 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Mon, 2 Nov 2015 15:27:08 +0100 Subject: [PATCH] continue rewriting swig layer, better code to expose XToY methods in java/c# --- makefiles/Makefile.csharp.mk | 10 +- src/base/file.cc | 65 ++++-- src/constraint_solver/constraint_solver.h | 2 +- .../csharp/constraint_solver.swig | 208 ++++++++---------- src/constraint_solver/csharp/routing.swig | 69 +++++- .../java/constraint_solver.swig | 4 +- src/constraint_solver/java/routing.swig | 29 +-- .../python/constraint_solver.swig | 59 +---- .../python/constraint_solver_helpers.swig | 72 ++++++ src/constraint_solver/python/routing.swig | 21 +- src/linear_solver/java/linear_solver.swig | 1 + src/linear_solver/python/linear_solver.swig | 29 ++- src/util/csharp/data.swig | 102 --------- src/util/csharp/functions.swig | 9 - src/util/functions_swig_helpers.h | 70 +----- src/util/functions_swig_test_helpers.h | 10 + src/util/java/functions.swig | 43 ++-- src/util/python/functions.swig | 7 +- 18 files changed, 392 insertions(+), 418 deletions(-) create mode 100644 src/constraint_solver/python/constraint_solver_helpers.swig delete mode 100644 src/util/csharp/data.swig diff --git a/makefiles/Makefile.csharp.mk b/makefiles/Makefile.csharp.mk index 131f220156..7058d9be46 100644 --- a/makefiles/Makefile.csharp.mk +++ b/makefiles/Makefile.csharp.mk @@ -139,7 +139,7 @@ csharportools: $(BIN_DIR)/$(CLR_DLL_NAME).dll $(GEN_DIR)/linear_solver/linear_solver_csharp_wrap.cc: \ $(SRC_DIR)/linear_solver/csharp/linear_solver.swig \ - $(SRC_DIR)/base/base.swig $(SRC_DIR)/util/csharp/data.swig \ + $(SRC_DIR)/base/base.swig $(SRC_DIR)/util/csharp/proto.swig \ $(SRC_DIR)/linear_solver/linear_solver.h \ $(GEN_DIR)/linear_solver/linear_solver.pb.h $(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Slinear_solver$Slinear_solver_csharp_wrap.cc -module operations_research_linear_solver -namespace $(BASE_CLR_DLL_NAME).LinearSolver -dllimport "$(CLR_DLL_NAME).$(DYNAMIC_SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Slinearsolver $(SRC_DIR)/linear_solver$Scsharp$Slinear_solver.swig @@ -151,7 +151,7 @@ $(GEN_DIR)/constraint_solver/constraint_solver_csharp_wrap.cc: \ $(SRC_DIR)/constraint_solver/csharp/routing.swig \ $(SRC_DIR)/constraint_solver/csharp/constraint_solver.swig \ $(SRC_DIR)/base/base.swig \ - $(SRC_DIR)/util/csharp/data.swig \ + $(SRC_DIR)/util/csharp/proto.swig \ $(SRC_DIR)/util/csharp/functions.swig \ $(SRC_DIR)/constraint_solver/constraint_solver.h $(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sconstraint_solver$Sconstraint_solver_csharp_wrap.cc -module operations_research_constraint_solver -namespace $(BASE_CLR_DLL_NAME).ConstraintSolver -dllimport "$(CLR_DLL_NAME).$(DYNAMIC_SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Sconstraintsolver $(SRC_DIR)$Sconstraint_solver$Scsharp$Srouting.swig @@ -169,7 +169,7 @@ $(OBJ_DIR)/swig/constraint_solver_csharp_wrap.$O: \ $(GEN_DIR)/algorithms/knapsack_solver_csharp_wrap.cc: \ $(SRC_DIR)/algorithms/csharp/knapsack_solver.swig \ $(SRC_DIR)/base/base.swig \ - $(SRC_DIR)/util/csharp/data.swig \ + $(SRC_DIR)/util/csharp/proto.swig \ $(SRC_DIR)/algorithms/knapsack_solver.h $(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Salgorithms$Sknapsack_solver_csharp_wrap.cc -module operations_research_algorithms -namespace $(BASE_CLR_DLL_NAME).Algorithms -dllimport "$(CLR_DLL_NAME).$(DYNAMIC_SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Salgorithms $(SRC_DIR)$Salgorithms$Scsharp$Sknapsack_solver.swig @@ -179,7 +179,7 @@ $(OBJ_DIR)/swig/knapsack_solver_csharp_wrap.$O: $(GEN_DIR)/algorithms/knapsack_s $(GEN_DIR)/graph/graph_csharp_wrap.cc: \ $(SRC_DIR)/graph/csharp/graph.swig \ $(SRC_DIR)/base/base.swig \ - $(SRC_DIR)/util/csharp/data.swig \ + $(SRC_DIR)/util/csharp/proto.swig \ $(SRC_DIR)/graph/max_flow.h \ $(SRC_DIR)/graph/min_cost_flow.h $(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sgraph$Sgraph_csharp_wrap.cc -module operations_research_graph -namespace $(BASE_CLR_DLL_NAME).Graph -dllimport "$(CLR_DLL_NAME).$(DYNAMIC_SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Sgraph $(SRC_DIR)$Sgraph$Scsharp$Sgraph.swig @@ -320,7 +320,7 @@ csharpfz: \ $(GEN_DIR)/flatzinc/flatzinc_csharp_wrap.cc: \ $(SRC_DIR)/flatzinc/csharp/flatzinc.swig \ - $(SRC_DIR)/base/base.swig $(SRC_DIR)/util/csharp/data.swig + $(SRC_DIR)/base/base.swig $(SRC_DIR)/util/csharp/proto.swig $(SWIG_BINARY) $(SWIG_INC) -I$(INC_DIR) -c++ -csharp -o $(GEN_DIR)$Sflatzinc$Sflatzinc_csharp_wrap.cc -module operations_research_flatzinc -namespace $(BASE_CLR_DLL_NAME).Flatzinc -dllimport "Google.OrTools.Flatzinc.$(DYNAMIC_SWIG_LIB_SUFFIX)" -outdir $(GEN_DIR)$Scom$Sgoogle$Sortools$Sflatzinc $(SRC_DIR)/flatzinc$Scsharp$Sflatzinc.swig $(OBJ_DIR)/swig/flatzinc_csharp_wrap.$O: $(GEN_DIR)/flatzinc/flatzinc_csharp_wrap.cc diff --git a/src/base/file.cc b/src/base/file.cc index 9612b6be52..7e5fbddfc9 100644 --- a/src/base/file.cc +++ b/src/base/file.cc @@ -130,20 +130,31 @@ bool File::Open() const { return f_ != NULL; } void File::Init() {} namespace file { -util::Status GetContents(const std::string& filename, std::string* output, int flags) { - if (flags == Defaults()) { - File* file = File::Open(filename, "r"); - if (file != NULL) { - const int64 size = file->Size(); - if (file->ReadToString(output, size) == size) return util::Status::OK; - } +util::Status GetContents( + const std::string& filename, std::string* output, int flags) { + if (flags != Defaults()) { + return util::Status( + util::error::INVALID_ARGUMENT, + "The file::GetContents() APIs only support the file::Defaults() " + "options!"); + } + File* file = File::Open(filename, "r"); + if (file != NULL) { + const int64 size = file->Size(); + if (file->ReadToString(output, size) == size) return util::Status::OK; } return util::Status(util::error::INVALID_ARGUMENT, StrCat("Could not read '", filename, "'")); } util::Status WriteString(File* file, const std::string& contents, int flags) { - if (flags == Defaults() && file != NULL && + if (flags != Defaults()) { + return util::Status( + util::error::INVALID_ARGUMENT, + "The file::WriteString() APIs only support the file::Defaults() " + "options!"); + } + if (file != NULL && file->Write(contents.c_str(), contents.size()) == contents.size() && file->Close()) { return util::Status::OK; @@ -152,8 +163,14 @@ util::Status WriteString(File* file, const std::string& contents, int flags) { StrCat("Could not write ", contents.size(), " bytes")); } -util::Status SetContents(const std::string& filename, const std::string& contents, - int flags) { +util::Status SetContents( + const std::string& filename, const std::string& contents, int flags) { + if (flags != Defaults()) { + return util::Status( + util::error::INVALID_ARGUMENT, + "The file::SetContents() APIs only support the file::Defaults() " + "options!"); + } return WriteString(File::Open(filename, "w"), contents, flags); } @@ -227,28 +244,40 @@ void WriteProtoToFileOrDie(const google::protobuf::Message& proto, CHECK(WriteProtoToFile(proto, file_name)) << "file_name: " << file_name; } -util::Status SetTextProto(const std::string& filename, const google::protobuf::Message& proto, - int flags) { - if (flags == Defaults()) { - if (WriteProtoToASCIIFile(proto, filename)) return util::Status::OK; +util::Status SetTextProto( + const std::string& filename, const google::protobuf::Message& proto, + int flags) { + if (flags != Defaults()) { + return util::Status( + util::error::INVALID_ARGUMENT, + "The file::SetTextProto() APIs only support the file::Defaults() " + "options!"); } + if (WriteProtoToASCIIFile(proto, filename)) return util::Status::OK; return util::Status(util::error::INVALID_ARGUMENT, StrCat("Could not write proto to '", filename, "'.")); } util::Status SetBinaryProto(const std::string& filename, const google::protobuf::Message& proto, int flags) { - if (flags == Defaults()) { - if (WriteProtoToFile(proto, filename)) return util::Status::OK; + if (flags != Defaults()) { + return util::Status( + util::error::INVALID_ARGUMENT, + "The file::SetBinaryProto() APIs only support the file::Defaults() " + "options!"); } + if (WriteProtoToFile(proto, filename)) return util::Status::OK; return util::Status(util::error::INVALID_ARGUMENT, StrCat("Could not write proto to '", filename, "'.")); } util::Status Delete(const std::string& path, int flags) { - if (flags == Defaults()) { - if (remove(path.c_str())) return util::Status::OK; + if (flags != Defaults()) { + return util::Status( + util::error::INVALID_ARGUMENT, + "The file::Delete() APIs only support the file::Defaults() options!"); } + if (remove(path.c_str())) return util::Status::OK; return util::Status(util::error::INVALID_ARGUMENT, StrCat("Could not delete '", path, "'.")); } diff --git a/src/constraint_solver/constraint_solver.h b/src/constraint_solver/constraint_solver.h index d0bc703839..c9bea4c6e0 100644 --- a/src/constraint_solver/constraint_solver.h +++ b/src/constraint_solver/constraint_solver.h @@ -3882,7 +3882,7 @@ class IntVarIterator : public BaseObject { // This method indicates if we can call Value() or not. virtual bool Ok() const = 0; - // This method returns the value of the hole. + // This method returns the current value of the iterator. virtual int64 Value() const = 0; // This method moves the iterator to the next value. diff --git a/src/constraint_solver/csharp/constraint_solver.swig b/src/constraint_solver/csharp/constraint_solver.swig index a50b5baeaa..66e8d3f15a 100644 --- a/src/constraint_solver/csharp/constraint_solver.swig +++ b/src/constraint_solver/csharp/constraint_solver.swig @@ -34,9 +34,6 @@ using System.Collections; %feature("director") IntVarLocalSearchFilter; %feature("director") IntVarLocalSearchOperator; %feature("director") LocalSearchOperator; -%feature("director") LongResultCallback1; -%feature("director") LongResultCallback2; -%feature("director") LongResultCallback3; %feature("director") OptimizeVar; %feature("director") SearchLimit; %feature("director") SearchMonitor; @@ -125,70 +122,6 @@ PROTECT_FROM_FAILURE(Solver::Fail(), arg1); // ############ END DUPLICATED CODE BLOCK ############ -// Callback wrapping. -// TODO(user): split out the callback code; it creates another file since -// it uses a different module. -%{ -class LongResultCallback1 { - public: - virtual int64 Run(int64) = 0; - ResultCallback1* GetPermanentCallback() { - return NewPermanentCallback(this, &LongResultCallback1::Run); - } - virtual ~LongResultCallback1() {} -}; -class LongResultCallback2 { - public: - virtual int64 Run(int64, int64) = 0; - ResultCallback2* GetPermanentCallback() { - return NewPermanentCallback(this, &LongResultCallback2::Run); - } - virtual ~LongResultCallback2() {} -}; -class LongResultCallback3 { - public: - virtual int64 Run(int64, int64, int64) = 0; - ResultCallback3* GetPermanentCallback() { - return NewPermanentCallback(this, &LongResultCallback3::Run); - } - virtual ~LongResultCallback3() {} -}; -%} - -class LongResultCallback1 { - public: - virtual int64 Run(int64) = 0; - ResultCallback1* GetPermanentCallback(); - virtual ~LongResultCallback1(); -}; -class LongResultCallback2 { - public: - virtual int64 Run(int64, int64) = 0; - ResultCallback2* GetPermanentCallback(); - virtual ~LongResultCallback2(); -}; -class LongResultCallback3 { - public: - virtual int64 Run(int64, int64, int64) = 0; - ResultCallback3* GetPermanentCallback(); - virtual ~LongResultCallback3(); -}; - -// Typemaps for callbacks in csharp. -%typemap(cstype) ResultCallback1* "LongResultCallback1"; -%typemap(csin) ResultCallback1* - "$descriptor(ResultCallback1*) - .getCPtr($csinput.GetPermanentCallback())"; -%typemap(cstype) ResultCallback2* "LongResultCallback2"; -%typemap(csin) ResultCallback2* - "$descriptor(ResultCallback2*) - .getCPtr($csinput.GetPermanentCallback())"; -%typemap(cstype) ResultCallback3* - "LongResultCallback3"; -%typemap(csin) ResultCallback3* - "$descriptor(ResultCallback3*) - .getCPtr($csinput.GetPermanentCallback())"; - // Since knapsack_solver.swig and constraint_solver.swig both need to // instantiate the vector template, but their csharp_wrap.cc // files end up being compiled into the same .dll, we must name the @@ -280,7 +213,12 @@ CS_TYPEMAP_STDVECTOR_OBJECT(operations_research::SymmetryBreaker, SymmetryBreake %typemap(csinterfaces_derived) operations_research::Constraint "IConstraintWithStatus"; namespace operations_research { -// Take care of API with function +// Take care of API with function. SWIG doesn't wrap std::function<> +// properly, so we write our custom wrappers for all methods involving +// std::function<>. +%ignore Solver::MakeSearchLog( + int branch_count, + std::function display_callback); %ignore Solver::MakeSearchLog( int branch_count, IntVar* objective, @@ -289,9 +227,7 @@ namespace operations_research { int branch_count, OptimizeVar* const objective, std::function display_callback); -%ignore Solver::MakeSearchLog( - int branch_count, - std::function display_callback); + %ignore Solver::MakeCustomLimit(std::function limiter); %ignore Solver::MakeElement(IndexEvaluator1 values, IntVar* const index); %ignore Solver::MakeMonotonicElement(IndexEvaluator1 values, bool increasing, @@ -384,28 +320,37 @@ namespace operations_research { %extend Solver { IntExpr* MakeElement(swig_util::LongToLong* values, IntVar* const index) { - return $self->MakeElement(values->GetFunction(), index); + return $self->MakeElement( + [values](int64 i) { return values->Run(i); }, index); } IntExpr* MakeMonotonicElement(swig_util::LongToLong* values, bool increasing, IntVar* const index) { - return $self->MakeMonotonicElement(values->GetFunction(), increasing, index); + return $self->MakeMonotonicElement( + [values](int64 i) { return values->Run(i); }, increasing, index); } IntExpr* MakeElement(swig_util::LongLongToLong* values, IntVar* const index1, IntVar* const index2) { - return $self->MakeElement(values->GetFunction(), index1, index2); + return $self->MakeElement( + [values](int64 i, int64 j) { return values->Run(i, j); }, index1, + index2); } Constraint* MakePathCumul(const std::vector& nexts, const std::vector& active, const std::vector& cumuls, swig_util::LongLongToLong* transit_evaluator) { - return $self->MakePathCumul(nexts, active, cumuls, transit_evaluator->GetFunction()); + return $self->MakePathCumul( + nexts, active, cumuls, + [transit_evaluator](int64 i, int64 j) { + return transit_evaluator->Run(i, j); }); } Constraint* MakePathCumul(const std::vector& nexts, const std::vector& active, const std::vector& cumuls, const std::vector& slacks, swig_util::LongLongToLong* transit_evaluator) { - return $self->MakePathCumul(nexts, active, cumuls, slacks, transit_evaluator->GetFunction()); + return $self->MakePathCumul(nexts, active, cumuls, slacks, + [transit_evaluator](int64 i, int64 j) { + return transit_evaluator->Run(i, j); }); } Constraint* MakeNoCycle(const std::vector& nexts, const std::vector& active, @@ -413,20 +358,27 @@ namespace operations_research { if (sink_handler == nullptr) { return $self->MakeNoCycle(nexts, active, nullptr); } else { - return $self->MakeNoCycle(nexts, active, sink_handler->GetFunction()); + return $self->MakeNoCycle(nexts, active, + [sink_handler](int64 i) { + return sink_handler->Run(i); }); } } Constraint* MakeNoCycle(const std::vector& nexts, const std::vector& active, swig_util::LongToBoolean* sink_handler, bool assume_paths) { - return $self->MakeNoCycle(nexts, active, sink_handler->GetFunction()); + return $self->MakeNoCycle(nexts, active, + [sink_handler](int64 i) { + return sink_handler->Run(i); }); } SearchMonitor* MakeGuidedLocalSearch(bool maximize, IntVar* const objective, swig_util::LongLongToLong* objective_function, int64 step, const std::vector& vars, double penalty_factor) { return $self->MakeGuidedLocalSearch( - maximize, objective, objective_function->GetFunction(), step, vars, penalty_factor); + maximize, objective, + [objective_function](int64 i, int64 j) { + return objective_function->Run(i, j); }, + step, vars, penalty_factor); } SearchMonitor* MakeGuidedLocalSearch(bool maximize, IntVar* const objective, swig_util::LongLongLongToLong* objective_function, @@ -434,72 +386,95 @@ namespace operations_research { const std::vector& secondary_vars, double penalty_factor) { return $self->MakeGuidedLocalSearch( - maximize, objective, objective_function->GetFunction(), + maximize, objective, + [objective_function](int64 i, int64 j, int64 k) { + return objective_function->Run(i, j, k); }, step, vars, secondary_vars, penalty_factor); } DecisionBuilder* MakePhase(const std::vector& vars, swig_util::LongToLong* var_evaluator, IntValueStrategy val_str) { - return $self->MakePhase(vars, var_evaluator->GetFunction(), val_str); + return $self->MakePhase(vars, [var_evaluator](int64 i) { + return var_evaluator->Run(i); }, val_str); } DecisionBuilder* MakePhase(const std::vector& vars, - IntVarStrategy var_str, swig_util::LongLongToLong* val_eval) { - return $self->MakePhase(vars, var_str, val_eval->GetFunction()); + IntVarStrategy var_str, + swig_util::LongLongToLong* val_eval) { + return $self->MakePhase(vars, var_str, [val_eval](int64 i, int64 j) { + return val_eval->Run(i, j); }); } DecisionBuilder* MakePhase( const std::vector& vars, IntVarStrategy var_str, swig_util::LongLongLongToBoolean* var_val1_val2_comparator) { return $self->MakePhase( - vars, var_str, var_val1_val2_comparator->GetFunction()); + vars, var_str, [var_val1_val2_comparator](int64 i, int64 j, int64 k) { + return var_val1_val2_comparator->Run(i, j, k); }); } DecisionBuilder* MakePhase(const std::vector& vars, swig_util::LongToLong* var_evaluator, swig_util::LongLongToLong* val_eval) { - return $self->MakePhase(vars, var_evaluator->GetFunction(), val_eval->GetFunction()); + return $self->MakePhase(vars, [var_evaluator](int64 i) { return var_evaluator->Run(i); }, [val_eval](int64 i, int64 j) { return val_eval->Run(i, j); }); } DecisionBuilder* MakePhase(const std::vector& vars, IntVarStrategy var_str, swig_util::LongLongToLong* val_eval, swig_util::LongToLong* tie_breaker) { - return $self->MakePhase(vars, var_str, val_eval->GetFunction(), tie_breaker->GetFunction()); + return $self->MakePhase( + vars, var_str, + [val_eval](int64 i, int64 j) { return val_eval->Run(i, j); }, + [tie_breaker](int64 i) { return tie_breaker->Run(i); }); } DecisionBuilder* MakePhase(const std::vector& vars, swig_util::LongToLong* var_evaluator, swig_util::LongLongToLong* val_eval, swig_util::LongToLong* tie_breaker) { - return $self->MakePhase(vars, - var_evaluator->GetFunction(), - val_eval->GetFunction(), - tie_breaker->GetFunction()); + return $self->MakePhase( + vars, + [var_evaluator](int64 i) { return var_evaluator->Run(i); }, + [val_eval](int64 i, int64 j) { return val_eval->Run(i, j); }, + [tie_breaker](int64 i) { return tie_breaker->Run(i); }); } DecisionBuilder* MakePhase(const std::vector& vars, - swig_util::LongLongToLong* evaluator, EvaluatorStrategy str) { - return $self->MakePhase(vars, evaluator->GetFunction(), str); + swig_util::LongLongToLong* evaluator, + EvaluatorStrategy str) { + return $self->MakePhase( + vars, + [evaluator](int64 i, int64 j) { return evaluator->Run(i, j); }, + str); } DecisionBuilder* MakePhase(const std::vector& vars, swig_util::LongLongToLong* evaluator, swig_util::LongToLong* tie_breaker, EvaluatorStrategy str) { return $self->MakePhase( - vars, evaluator->GetFunction(), tie_breaker->GetFunction(), str); + vars, + [evaluator](int64 i, int64 j) { return evaluator->Run(i, j); }, + [tie_breaker](int64 i) { return tie_breaker->Run(i); }, str); } LocalSearchOperator* MakeOperator(const std::vector& vars, swig_util::LongLongLongToLong* evaluator, EvaluatorLocalSearchOperators op) { - return $self->MakeOperator(vars, evaluator->GetFunction(), op); + return $self->MakeOperator( + vars, + [evaluator](int64 i, int64 j, int64 k) { + return evaluator->Run(i, j, k); }, op); } LocalSearchOperator* MakeOperator(const std::vector& vars, const std::vector& secondary_vars, swig_util::LongLongLongToLong* evaluator, EvaluatorLocalSearchOperators op) { - return $self->MakeOperator(vars, secondary_vars, evaluator->GetFunction(), op); + return $self->MakeOperator( + vars, secondary_vars, + [evaluator](int64 i, int64 j, int64 k) { + return evaluator->Run(i, j, k); }, op); } LocalSearchFilter* MakeLocalSearchObjectiveFilter( const std::vector& vars, swig_util::LongLongToLong* values, IntVar* const objective, Solver::LocalSearchFilterBound filter_enum, Solver::LocalSearchOperation op_enum) { - return $self->MakeLocalSearchObjectiveFilter(vars, values->GetFunction(), - objective, filter_enum, op_enum); + return $self->MakeLocalSearchObjectiveFilter( + vars, [values](int64 i, int64 j) { return values->Run(i, j); }, + objective, filter_enum, op_enum); } LocalSearchFilter* MakeLocalSearchObjectiveFilter( const std::vector& vars, swig_util::LongLongToLong* values, @@ -507,7 +482,9 @@ namespace operations_research { Solver::LocalSearchFilterBound filter_enum, Solver::LocalSearchOperation op_enum) { return $self->MakeLocalSearchObjectiveFilter( - vars, values->GetFunction(), delta_objective_callback->GetFunction(), + vars, [values](int64 i, int64 j) { return values->Run(i, j); }, + [delta_objective_callback](int64 i) { + return delta_objective_callback->Run(i); }, objective, filter_enum, op_enum); } LocalSearchFilter* MakeLocalSearchObjectiveFilter( @@ -516,31 +493,36 @@ namespace operations_research { Solver::LocalSearchFilterBound filter_enum, Solver::LocalSearchOperation op_enum) { return $self->MakeLocalSearchObjectiveFilter( - vars, secondary_vars, values->GetFunction(), + vars, secondary_vars, + [values](int64 i, int64 j, int64 k) { return values->Run(i, j, k); }, objective, filter_enum, op_enum); } LocalSearchFilter* MakeLocalSearchObjectiveFilter( - const std::vector& vars, const std::vector& secondary_vars, + const std::vector& vars, + const std::vector& secondary_vars, swig_util::LongLongLongToLong* values, swig_util::LongToVoid* delta_objective_callback, IntVar* const objective, Solver::LocalSearchFilterBound filter_enum, Solver::LocalSearchOperation op_enum) { return $self->MakeLocalSearchObjectiveFilter( - vars, secondary_vars, values->GetFunction(), - delta_objective_callback->GetFunction(), + vars, secondary_vars, + [values](int64 i, int64 j, int64 k) { return values->Run(i, j, k); }, + [delta_objective_callback](int64 i) { + return delta_objective_callback->Run(i); }, objective, filter_enum, op_enum); } LocalSearchOperator* ConcatenateOperators( const std::vector& ops, swig_util::IntIntToLong* evaluator) { - return $self->ConcatenateOperators(ops, evaluator->GetFunction()); + return $self->ConcatenateOperators(ops, [evaluator](int i, int64 j) { + return evaluator->Run(i, j); }); } SearchMonitor* MakeSearchLog( int branch_count, OptimizeVar* const objective, swig_util::VoidToString* display_callback) { return $self->MakeSearchLog(branch_count, objective, [display_callback]() { - return display_callback->run(); + return display_callback->Run(); }); } SearchMonitor* MakeSearchLog( @@ -548,28 +530,28 @@ namespace operations_research { IntVar* const obj_var, swig_util::VoidToString* display_callback) { return $self->MakeSearchLog(branch_count, obj_var, [display_callback]() { - return display_callback->run(); + return display_callback->Run(); }); } SearchMonitor* MakeSearchLog( int branch_count, swig_util::VoidToString* display_callback) { return $self->MakeSearchLog(branch_count, [display_callback]() { - return display_callback->run(); + return display_callback->Run(); }); } SearchLimit* MakeCustomLimit(swig_util::VoidToBoolean* limiter) { - return $self->MakeCustomLimit([limiter]() { return limiter->run(); }); + return $self->MakeCustomLimit([limiter]() { return limiter->Run(); }); } Demon* MakeClosureDemon(swig_util::VoidToVoid* closure) { - return $self->MakeClosureDemon(closure->GetFunction()); + return $self->MakeClosureDemon([closure]() { return closure->Run(); }); } } // extend Solver %ignore DisjunctiveConstraint::SetTransitionTime(Solver::IndexEvaluator2 transit_evaluator); %extend DisjunctiveConstraint { void SetTransitionTime(swig_util::LongLongToLong* transit_evaluator) { - $self->SetTransitionTime([transit_evaluator](int64 i, int64 j) { return transit_evaluator->run(i, j); }); + $self->SetTransitionTime([transit_evaluator](int64 i, int64 j) { return transit_evaluator->Run(i, j); }); } } // extend DisjunctiveConstraint @@ -582,22 +564,24 @@ namespace operations_research { %extend Pack { void Pack::AddWeightedSumLessOrEqualConstantDimension( swig_util::LongToLong* weights, const std::vector& bounds) { - return $self->AddWeightedSumLessOrEqualConstantDimension(weights->GetFunction(), bounds); + return [$self->AddWeightedSumLessOrEqualConstantDimension([weights](int64 i) { return weights->Run(i); }, bounds); } void Pack::AddWeightedSumLessOrEqualConstantDimension( swig_util::LongLongToLong* weights, const std::vector& bounds) { - return $self->AddWeightedSumLessOrEqualConstantDimension(weights->GetFunction(), bounds); + return $self->AddWeightedSumLessOrEqualConstantDimension([weights](int64 i) { return weights->Run(i); }, bounds); } void Pack::AddWeightedSumEqualVarDimension( swig_util::LongLongToLong* weights, const std::vector& loads) { - return $self->AddWeightedSumEqualVarDimension(weights->GetFunction(), loads); + return $self->AddWeightedSumEqualVarDimension([weights](int64 i) { return weights->Run(i); }, loads); } } // extend Pack +// No custom wrapping for this method, we simply ignore it. %ignore SearchLog::SearchLog( Solver* const s, OptimizeVar* const obj, IntVar* const var, std::function display_callback, int period); +// Extend IntervalVar with an intuitive API to create precedence constraints. %extend IntervalVar { Constraint* EndsAfterEnd(IntervalVar* other) { return $self->solver()->MakeIntervalVarRelation($self, operations_research::Solver::ENDS_AFTER_END, other); diff --git a/src/constraint_solver/csharp/routing.swig b/src/constraint_solver/csharp/routing.swig index be1b744d7d..f28c8d35ec 100644 --- a/src/constraint_solver/csharp/routing.swig +++ b/src/constraint_solver/csharp/routing.swig @@ -21,6 +21,10 @@ %} %module(directors="1") operations_research; +%feature("director") LongResultCallback1; +%feature("director") LongResultCallback2; +%feature("director") LongResultCallback3; +%feature("director") NodeEvaluator2; // Convert RoutingModel::NodeIndex to (32-bit signed) integers. %typemap(ctype) operations_research::RoutingModel::NodeIndex "int" @@ -105,9 +109,36 @@ CS_TYPEMAP_STDVECTOR(operations_research::RoutingModel::NodeIndex, int, int); CS_TYPEMAP_STDVECTOR_IN1(operations_research::RoutingModel::NodeIndex, int, int); -// Create input mapping for NodeEvaluator2 -%feature("director") NodeEvaluator2; +// Create input mapping for NodeEvaluator2 and LongResultCallbackN +// Callback wrapping. +// TODO(viger): split out the callback code; it creates another file since +// it uses a different module. %{ +class LongResultCallback1 { + public: + virtual int64 Run(int64) = 0; + ResultCallback1* GetPermanentCallback() { + return NewPermanentCallback(this, &LongResultCallback1::Run); + } + virtual ~LongResultCallback1() {} +}; +class LongResultCallback2 { + public: + virtual int64 Run(int64, int64) = 0; + ResultCallback2* GetPermanentCallback() { + return NewPermanentCallback(this, &LongResultCallback2::Run); + } + virtual ~LongResultCallback2() {} +}; +class LongResultCallback3 { + public: + virtual int64 Run(int64, int64, int64) = 0; + ResultCallback3* GetPermanentCallback() { + return NewPermanentCallback(this, &LongResultCallback3::Run); + } + virtual ~LongResultCallback3() {} +}; + class NodeEvaluator2 : private operations_research::RoutingModel::NodeEvaluator2 { public: NodeEvaluator2() : used_as_permanent_handler_(false) {} @@ -143,6 +174,25 @@ class NodeEvaluator2 : private operations_research::RoutingModel::NodeEvaluator2 } %} +class LongResultCallback1 { + public: + virtual int64 Run(int64) = 0; + ResultCallback1* GetPermanentCallback(); + virtual ~LongResultCallback1(); +}; +class LongResultCallback2 { + public: + virtual int64 Run(int64, int64) = 0; + ResultCallback2* GetPermanentCallback(); + virtual ~LongResultCallback2(); +}; +class LongResultCallback3 { + public: + virtual int64 Run(int64, int64, int64) = 0; + ResultCallback3* GetPermanentCallback(); + virtual ~LongResultCallback3(); +}; + class NodeEvaluator2 : private operations_research::RoutingModel::NodeEvaluator2 { public: NodeEvaluator2(); @@ -157,6 +207,21 @@ class NodeEvaluator2 : private operations_research::RoutingModel::NodeEvaluator2 bool used_as_permanent_handler_; }; +// Typemaps for callbacks in csharp. +%typemap(cstype) ResultCallback1* "LongResultCallback1"; +%typemap(csin) ResultCallback1* + "$descriptor(ResultCallback1*) + .getCPtr($csinput.GetPermanentCallback())"; +%typemap(cstype) ResultCallback2* "LongResultCallback2"; +%typemap(csin) ResultCallback2* + "$descriptor(ResultCallback2*) + .getCPtr($csinput.GetPermanentCallback())"; +%typemap(cstype) ResultCallback3* + "LongResultCallback3"; +%typemap(csin) ResultCallback3* + "$descriptor(ResultCallback3*) + .getCPtr($csinput.GetPermanentCallback())"; + %typemap(cstype) operations_research::RoutingModel::NodeEvaluator2* "NodeEvaluator2"; %typemap(csin) operations_research::RoutingModel::NodeEvaluator2* "$descriptor(ResultCallback2*).getCPtr($csinput.DisownAndGetPermanentCallback())"; diff --git a/src/constraint_solver/java/constraint_solver.swig b/src/constraint_solver/java/constraint_solver.swig index ec3c716886..f2dbaf4ece 100644 --- a/src/constraint_solver/java/constraint_solver.swig +++ b/src/constraint_solver/java/constraint_solver.swig @@ -24,7 +24,8 @@ %include "util/java/functions.swig" // Remove swig warnings -#pragma SWIG nowarn=473 +%warnfilter(473) operations_research::DecisionBuilder; +// TODO(user): Remove this warnfilter. // ############ BEGIN DUPLICATED CODE BLOCK ############ // IMPORTANT: keep this code block in sync with the .swig @@ -83,7 +84,6 @@ PROTECT_FROM_FAILURE(Solver::Fail(), arg1); %feature("director") DecisionBuilder; %feature("director") Decision; %feature("director") SearchMonitor; -%feature("director") Action; %feature("director") LocalSearchOperator; %feature("director") PathOperator; %feature("director") BaseLns; diff --git a/src/constraint_solver/java/routing.swig b/src/constraint_solver/java/routing.swig index 647795e0ba..bf2e973997 100644 --- a/src/constraint_solver/java/routing.swig +++ b/src/constraint_solver/java/routing.swig @@ -162,53 +162,26 @@ class LongResultCallback1 : private ResultCallback1 { virtual int64 run(int64) = 0; ResultCallback1* getPermanentCallback(); virtual ~LongResultCallback1(); - - private: - virtual bool IsRepeatable() const; - virtual int64 Run(int64 i); - bool used_as_permanent_handler_; }; class LongResultCallback2 : private ResultCallback2 { public: virtual int64 run(int64, int64) = 0; ResultCallback2* getPermanentCallback(); virtual ~LongResultCallback2(); - - private: - virtual bool IsRepeatable() const; - virtual int64 Run(int64 i, int64 j); - bool used_as_permanent_handler_; }; class LongResultCallback3 : private ResultCallback3 { public: virtual int64 run(int64, int64, int64) = 0; ResultCallback3* getPermanentCallback(); virtual ~LongResultCallback3(); - - private: - virtual bool IsRepeatable() const; - virtual int64 Run(int64 i, int64 j, int64 k); - bool used_as_permanent_handler_; }; class NodeEvaluator2 : private operations_research::RoutingModel::NodeEvaluator2 { public: NodeEvaluator2() : used_as_permanent_handler_(false) {} virtual int64 run(int i, int j) = 0; - operations_research::RoutingModel::NodeEvaluator2* getPermanentCallback() { - CHECK(!used_as_permanent_handler_); - used_as_permanent_handler_ = true; - return this; - } + operations_research::RoutingModel::NodeEvaluator2* getPermanentCallback(); virtual ~NodeEvaluator2() {} - - private: - virtual bool IsRepeatable() const { return true; } - virtual int64 Run(operations_research::RoutingModel::NodeIndex i, - operations_research::RoutingModel::NodeIndex j) { - return run(i.value(), j.value()); - } - bool used_as_permanent_handler_; }; // Typemaps for callbacks in java. diff --git a/src/constraint_solver/python/constraint_solver.swig b/src/constraint_solver/python/constraint_solver.swig index 13bf357d93..5a133a154e 100644 --- a/src/constraint_solver/python/constraint_solver.swig +++ b/src/constraint_solver/python/constraint_solver.swig @@ -32,13 +32,18 @@ %include "base/base.swig" -%import "util/python/data.swig" -%include "util/python/functions.swig" +// PY_CONVERT_HELPER_* macros. +%include "constraint_solver/python/constraint_solver_helpers.swig" // Callback wrapping. See base/python/callbacks.swig. #define FATAL_CALLBACK_EXCEPTION %include "base/python/callbacks.swig" +// std::function utilities. +%include "util/python/functions.swig" + +%import "util/python/data.swig" + // We *do* need to use SWIGTYPE_... type names directly, because the // (recommended replacement) $descriptor macro fails, as of 2014-06, with // types such as operations_research::Solver. @@ -83,59 +88,16 @@ // ============= Type conversions ============== -// Conversion utilities, to be able to expose APIs that return a C++ object -// pointer. The PyObjAs template must be able to deal with all such types. -%define PY_CONVERT_HELPER_PTR(CType) -%{ -template<> -bool PyObjAs(PyObject *py_obj, operations_research::CType** b) { - return SWIG_ConvertPtr(py_obj, reinterpret_cast(b), - SWIGTYPE_p_operations_research__ ## CType, - SWIG_POINTER_EXCEPTION) >= 0; -} -%} -%enddef +// See ./constraint_solver_helpers.swig PY_CONVERT_HELPER_PTR(SearchMonitor); PY_CONVERT_HELPER_PTR(IntervalVar); PY_CONVERT_HELPER_PTR(SequenceVar); PY_CONVERT_HELPER_PTR(LocalSearchOperator); PY_CONVERT_HELPER_PTR(LocalSearchFilter); -#undef PY_CONVERT_HELPER_PTR - -// Conversion of IntExpr* and IntVar* are a bit special because of the two -// possible casts from IntExpr and Constraint. -%define PY_CONVERT_HELPER_INTEXPR_OR_INTVAR(Class) -%{ -template<> -bool PyObjAs(PyObject *py_obj, operations_research::Class** var) { - // First, try to interpret the python object as an IntExpr. - operations_research::IntExpr* t; - if (SWIG_ConvertPtr(py_obj, reinterpret_cast(&t), - SWIGTYPE_p_operations_research__IntExpr, - SWIG_POINTER_EXCEPTION) >= 0) { - if (t == nullptr) return false; - *var = t->Var(); - return true; - } - // Then, try to interpret it as a Constraint. - operations_research::Constraint* c; - if (SWIG_ConvertPtr(py_obj, reinterpret_cast(&c), - SWIGTYPE_p_operations_research__Constraint, - SWIG_POINTER_EXCEPTION) >= 0) { - if (c == nullptr || c->Var() == nullptr) return false; - *var = c->Var(); - return true; - } - // Give up. - return false; -} -%} -%enddef PY_CONVERT_HELPER_INTEXPR_OR_INTVAR(IntVar); PY_CONVERT_HELPER_INTEXPR_OR_INTVAR(IntExpr); -#undef PY_CONVERT_HELPER_INTEXPR_OR_INTVAR -// Conversions of DecisionBuilder* are also special because we redefine +// Conversions of DecisionBuilder* are special because we redefine // our own python PyDecisionBuilder object. // TODO(user): for or-tools, remove this code and use directors instead. %pythoncode { @@ -1184,7 +1146,6 @@ namespace operations_research { // - SaveAndSetValue() // - SaveAndAdd() // -// - AddFailHook() // - ExportProfilingOverview() // - CurrentlyInSolve() // - balancing_decision() @@ -1230,7 +1191,6 @@ namespace operations_research { // - Zero() // - BaseObject // - DecisionVisitor -// - Action // - ModelVisitor // - CastConstraint // - NumericalRev<> @@ -2221,3 +2181,4 @@ class PyLns(BaseLNS): PushBackIntVector(x, output_cpp_vector_fragments); return True } // %pythoncode + diff --git a/src/constraint_solver/python/constraint_solver_helpers.swig b/src/constraint_solver/python/constraint_solver_helpers.swig new file mode 100644 index 0000000000..225c2ad339 --- /dev/null +++ b/src/constraint_solver/python/constraint_solver_helpers.swig @@ -0,0 +1,72 @@ +// Copyright 2010-2014 Google +// 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 contains SWIG macros, so you must %include it and not %import it. +// These macros are put here because they're used in several files. + +// We *do* need to use SWIGTYPE_... type names directly, because the +// (recommended replacement) $descriptor macro fails, as of 2014-06, with +// types such as operations_research::Solver. +// The absence of whitespace before 'swiglint' is mandatory. +//swiglint: disable swigtype-name + +// Needed by the callback wrapping. +// TODO(user): remove this when we no longer use callbacks in the constraint +// solver and the routing library. +%{ +template<> +PyObject* PyObjFrom(const int64& c) { return PyLong_FromLongLong(c); } +%} + +// Conversion utilities, to be able to expose APIs that return a C++ object +// pointer. The PyObjAs template must be able to deal with all such types. +%define PY_CONVERT_HELPER_PTR(CType) +%{ +template<> +bool PyObjAs(PyObject *py_obj, operations_research::CType** b) { + return SWIG_ConvertPtr(py_obj, reinterpret_cast(b), + SWIGTYPE_p_operations_research__ ## CType, + SWIG_POINTER_EXCEPTION) >= 0; +} +%} +%enddef + +// Conversion of IntExpr* and IntVar* are a bit special because of the two +// possible casts from IntExpr and Constraint. +%define PY_CONVERT_HELPER_INTEXPR_OR_INTVAR(Class) +%{ +template<> +bool PyObjAs(PyObject *py_obj, operations_research::Class** var) { + // First, try to interpret the python object as an IntExpr. + operations_research::IntExpr* t; + if (SWIG_ConvertPtr(py_obj, reinterpret_cast(&t), + SWIGTYPE_p_operations_research__IntExpr, + SWIG_POINTER_EXCEPTION) >= 0) { + if (t == nullptr) return false; + *var = t->Var(); + return true; + } + // Then, try to interpret it as a Constraint. + operations_research::Constraint* c; + if (SWIG_ConvertPtr(py_obj, reinterpret_cast(&c), + SWIGTYPE_p_operations_research__Constraint, + SWIG_POINTER_EXCEPTION) >= 0) { + if (c == nullptr || c->Var() == nullptr) return false; + *var = c->Var(); + return true; + } + // Give up. + return false; +} +%} +%enddef diff --git a/src/constraint_solver/python/routing.swig b/src/constraint_solver/python/routing.swig index 07c034d053..d0170ab923 100644 --- a/src/constraint_solver/python/routing.swig +++ b/src/constraint_solver/python/routing.swig @@ -13,7 +13,21 @@ // TODO(user): Refactor this file to adhere to the SWIG style guide. -%include "constraint_solver/python/constraint_solver.swig" +%include "base/base.swig" + +// TODO(user): remove this when we no longer use callbacks in the routing. +#define FATAL_CALLBACK_EXCEPTION +%include "base/python/callbacks.swig" + +// std::function utilities. +%include "util/python/functions.swig" + +// PY_CONVERT_HELPER_* macros. +%include "constraint_solver/python/constraint_solver_helpers.swig" + +%import "util/python/data.swig" +%import "util/python/functions.swig" +%import(module="google3.util.operations_research.constraint_solver.python.pywrapcp") "constraint_solver/python/constraint_solver.swig" // Include the file we want to wrap a first time. %{ @@ -41,6 +55,11 @@ %} +// See ./constraint_solver_helpers.swig. +PY_CONVERT_HELPER_PTR(SearchMonitor); +PY_CONVERT_HELPER_PTR(IntervalVar); +PY_CONVERT_HELPER_INTEXPR_OR_INTVAR(IntVar); + // Convert RoutingModel::NodeIndex to (32-bit signed) integers. %typemap(in) operations_research::RoutingModel::NodeIndex { $1 = operations_research::RoutingModel::NodeIndex(PyInt_AsLong($input)); diff --git a/src/linear_solver/java/linear_solver.swig b/src/linear_solver/java/linear_solver.swig index c028c11502..c14d862a0b 100644 --- a/src/linear_solver/java/linear_solver.swig +++ b/src/linear_solver/java/linear_solver.swig @@ -112,6 +112,7 @@ import java.lang.reflect.*; // List of the classes exposed. %unignore operations_research::MPSolver; %unignore operations_research::MPSolver::MPSolver; +%unignore operations_research::MPSolver::~MPSolver; %unignore operations_research::MPConstraint; %unignore operations_research::MPVariable; %unignore operations_research::MPObjective; diff --git a/src/linear_solver/python/linear_solver.swig b/src/linear_solver/python/linear_solver.swig index 995ff59ed9..7caacbebf1 100644 --- a/src/linear_solver/python/linear_solver.swig +++ b/src/linear_solver/python/linear_solver.swig @@ -38,6 +38,7 @@ namespace operations_research { %pythoncode { +import numbers from ortools.linear_solver.linear_solver_natural_api import LinearExpr from ortools.linear_solver.linear_solver_natural_api import ProductCst from ortools.linear_solver.linear_solver_natural_api import Sum @@ -190,21 +191,27 @@ from ortools.linear_solver.linear_solver_natural_api import LinearConstraint objective = self.Objective() objective.Clear() objective.SetMinimization() - coeffs = {} - offset = expr.Visit(coeffs) - objective.AddOffset(offset) - for v, c, in coeffs.iteritems(): - objective.SetCoefficient(v, float(c)) + if isinstance(expr, numbers.Number): + objective.AddOffset(expr) + else: + coeffs = {} + offset = expr.Visit(coeffs) + objective.AddOffset(offset) + for v, c, in coeffs.iteritems(): + objective.SetCoefficient(v, float(c)) def Maximize(self, expr): objective = self.Objective() objective.Clear() objective.SetMaximization() - coeffs = {} - offset = expr.Visit(coeffs) - objective.AddOffset(offset) - for v, c, in coeffs.iteritems(): - objective.SetCoefficient(v, float(c)) + if isinstance(expr, numbers.Number): + objective.AddOffset(expr) + else: + coeffs = {} + offset = expr.Visit(coeffs) + objective.AddOffset(offset) + for v, c, in coeffs.iteritems(): + objective.SetCoefficient(v, float(c)) } // %pythoncode } @@ -289,6 +296,7 @@ from ortools.linear_solver.linear_solver_natural_api import LinearConstraint // Expose some of the more advanced MPSolver API. +%unignore operations_research::MPSolver::InterruptSolve; %unignore operations_research::MPSolver::SupportsProblemType; // No unit test %unignore operations_research::MPSolver::wall_time; // No unit test %unignore operations_research::MPSolver::Clear; // No unit test @@ -358,7 +366,6 @@ from ortools.linear_solver.linear_solver_natural_api import LinearConstraint // MPSolverParameters API. For expert users only. // TODO(user): also strip "MP" from the class name. -// TODO(user): unit test all of it. %unignore operations_research::MPSolverParameters; %unignore operations_research::MPSolverParameters::MPSolverParameters; %unignore operations_research::MPSolverParameters::DoubleParam; diff --git a/src/util/csharp/data.swig b/src/util/csharp/data.swig deleted file mode 100644 index 7fe8b145d7..0000000000 --- a/src/util/csharp/data.swig +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2010-2014 Google -// 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. - -// TODO(user): make this SWIG file comply with the SWIG style guide. -%include base/base.swig - -%{ -#include -#include "base/integral_types.h" -%} - -// SWIG macros to be used in generating C# wrappers for C++ protocol -// message parameters. Each protocol message is serialized into -// byte[] before passing into (or returning from) C++ code. - -// If the C++ function expects an input protocol message, transferring -// ownership to the caller (in C++): -// foo(const MyProto* message,...) -// Use PROTO_INPUT macro: -// PROTO_INPUT(MyProto, Google.Proto.Protos.Test.MyProto, message) -// -// if the C++ function returns a protocol message: -// MyProto* foo(); -// Use PROTO2_RETURN macro: -// PROTO2_RETURN(MyProto, Google.Proto.Protos.Test.MyProto, true) -// -// Replace true by false if the C++ function returns a pointer to a -// protocol message object whose ownership is not transferred to the -// (C++) caller. -// -// Passing each protocol message from C# to C++ by value. Each ProtocolMessage -// is serialized into byte[] when it is passed from C# to C++, the C++ code -// deserializes into C++ native protocol message. -// -// @param CppProtoType the fully qualified C++ protocol message type -// @param CSharpProtoType the corresponding fully qualified C# protocol message -// type -// @param param_name the parameter name -// @param deleteCppReturn indicates that the resulting object is a native -// (java, c#, python) object, and thus the C++ proto can be safely deleted -// after the conversion. -%define PROTO_INPUT(CppProtoType, CSharpProtoType, param_name) -%typemap(ctype) PROTO_TYPE* INPUT, PROTO_TYPE& INPUT "int proto_size, char*" -%typemap(imtype) PROTO_TYPE* INPUT, PROTO_TYPE& INPUT "int proto_size, byte[]" -%typemap(cstype) PROTO_TYPE* INPUT, PROTO_TYPE& INPUT "CSharpProtoType" -%typemap(csin) PROTO_TYPE* INPUT, PROTO_TYPE& INPUT "$csinput.GetByteArrayLength(), $csinput.ToByteArray()" -%typemap(in) PROTO_TYPE* INPUT (CppProtoType temp), PROTO_TYPE& INPUT (CppProtoType temp) { - int proto_size = 0; - std::unique_ptr proto_buffer($input); - bool parsed_ok = temp.ParseFromArray(proto_buffer.get(), proto_size); - if (!parsed_ok) { - SWIG_CSharpSetPendingException( - SWIG_CSharpSystemException, - "Unable to parse CppProtoType protocol message."); - } - $1 = &temp; -} - -%apply PROTO_TYPE& INPUT { const CppProtoType& param_name } -%apply PROTO_TYPE& INPUT { CppProtoType& param_name } -%apply PROTO_TYPE* INPUT { const CppProtoType* param_name } -%apply PROTO_TYPE* INPUT { CppProtoType* param_name } - -%enddef // end PROTO_INPUT - -%define PROTO2_RETURN(CppProtoType, CSharpProtoType, deleteCppReturn) -%typemap(ctype) CppProtoType* "char*" -%typemap(imtype) CppProtoType* "byte[]" -%typemap(cstype) CppProtoType* "CSharpProtoType" -%typemap(csout) CppProtoType* { - byte[] buf = $imcall; - if (buf == null || buf.Length == 0) { - return null; - } - try { - return CSharpProtoType.ParseFrom(buf); - } catch (Google.Protobuf.InvalidProtocolBufferException e) { - throw new SystemException( - "Unable to parse CSharpProtoType protocol message."); - } -} -%typemap(out) CppProtoType* { - std::unique_ptr buf(new char[$1->ByteSize()]); - $1->SerializeWithCachedSizesToArray(reinterpret_cast(buf.get())); - $result = buf.get(); - if (deleteCppReturn) { - // To prevent a memory leak. - delete $1; - $1 = NULL; - } -} -%enddef // end PROTO2_RETURN_AND_DELETE diff --git a/src/util/csharp/functions.swig b/src/util/csharp/functions.swig index 316461e684..0ce40e65d7 100644 --- a/src/util/csharp/functions.swig +++ b/src/util/csharp/functions.swig @@ -38,22 +38,13 @@ // 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::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; %include "util/functions_swig_helpers.h" diff --git a/src/util/functions_swig_helpers.h b/src/util/functions_swig_helpers.h index 4683c562c4..6b82c0cb56 100644 --- a/src/util/functions_swig_helpers.h +++ b/src/util/functions_swig_helpers.h @@ -28,111 +28,61 @@ namespace swig_util { class LongToLong { public: virtual ~LongToLong() {} - virtual int64 run(int64) = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this](int64 i) { return run(i); }; - } -#endif + virtual int64 Run(int64) = 0; }; class LongLongToLong { public: virtual ~LongLongToLong() {} - virtual int64 run(int64, int64) = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this](int64 i, int64 j) { return run(i, j); }; - } -#endif + virtual int64 Run(int64, int64) = 0; }; class IntIntToLong { public: virtual ~IntIntToLong() {} - virtual int64 run(int, int) = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this](int i, int j) { return run(i, j); }; - } -#endif + virtual int64 Run(int, int) = 0; }; class LongLongLongToLong { public: virtual ~LongLongLongToLong() {} - virtual int64 run(int64, int64, int64) = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this](int64 i, int64 j, int64 k) { return run(i, j, k); }; - } -#endif + virtual int64 Run(int64, int64, int64) = 0; }; class LongToBoolean { public: virtual ~LongToBoolean() {} - virtual bool run(int64) = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this](int64 i) { return run(i); }; - } -#endif + virtual bool Run(int64) = 0; }; class VoidToString { public: virtual ~VoidToString() {} - virtual std::string run() = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this]() { return run(); }; - } -#endif + virtual std::string Run() = 0; }; class VoidToBoolean { public: virtual ~VoidToBoolean() {} - virtual bool run() = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this]() { return run(); }; - } -#endif + virtual bool Run() = 0; }; class LongLongLongToBoolean { public: virtual ~LongLongLongToBoolean() {} - virtual bool run(int64 i, int64 j, int64 k) = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this](int64 i, int64 j, int64 k) { return run(i, j, k); }; - } -#endif + virtual bool Run(int64 i, int64 j, int64 k) = 0; }; class LongToVoid { public: virtual ~LongToVoid() {} - virtual void run(int64 i) = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this](int64 i) { run(i); }; - } -#endif + virtual void Run(int64 i) = 0; }; class VoidToVoid { public: virtual ~VoidToVoid() {} - virtual void run() = 0; -#if !defined(SWIG) - std::function GetFunction() { - return [this]() { run(); }; - } -#endif + virtual void Run() = 0; }; } // namespace swig_util } // namespace operations_research diff --git a/src/util/functions_swig_test_helpers.h b/src/util/functions_swig_test_helpers.h index 7b1e86f4fb..cb37d25277 100644 --- a/src/util/functions_swig_test_helpers.h +++ b/src/util/functions_swig_test_helpers.h @@ -38,12 +38,22 @@ class FunctionSwigTestHelpers { return fun(x, y); } + static int64 NoOpIntPairToInt64(std::function fun, int x, + int y) { + return fun(x, y); + } + static int64 NoOpInt64TripleToInt64( std::function fun, int64 x, int64 y, int64 z) { return fun(x, y, z); } + static bool NoOpInt64TripleToBool( + std::function fun, int64 x, int64 y, int64 z) { + return fun(x, y, z); + } + static bool NoOpInt64ToBool(std::function fun, int64 x) { return fun(x); } diff --git a/src/util/java/functions.swig b/src/util/java/functions.swig index 88339b556c..34410bedb3 100644 --- a/src/util/java/functions.swig +++ b/src/util/java/functions.swig @@ -15,6 +15,7 @@ // 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 @@ -87,7 +88,7 @@ // EXPANSION EXAMPLE: "int64 i0, bool i1". $1 = [fun](INSERT_NAMES(NumArgs)(Args)) { // EXPANSION EXAMPLE: "i0, i1". - return fun->run(NAMES(NumArgs)); + return fun->Run(NAMES(NumArgs)); }; } @@ -123,7 +124,8 @@ WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, %typemap(in) std::function { jclass object_class = - jenv->FindClass("com/google/ortools/util/VoidToString"); + jenv->FindClass("com/google/ortools/" + "util/VoidToString"); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID(object_class, "getCPtr", @@ -133,7 +135,7 @@ WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); $1 = [fun]() { - return fun->run(); + return fun->Run(); }; } @@ -145,12 +147,12 @@ WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, // 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("com/google/ortools/util/VoidToVoid"); + jenv->FindClass("com/google/ortools/" + "util/VoidToVoid"); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID(object_class, "getCPtr", @@ -159,7 +161,7 @@ WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, operations_research::swig_util::VoidToVoid* const fun = reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); - $1 = [fun]() { fun->run(); }; + $1 = [fun]() { fun->Run(); }; } // These 3 typemaps tell SWIG what JNI and Java types to use @@ -174,7 +176,8 @@ WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, %typemap(in) std::function { jclass object_class = - jenv->FindClass("com/google/ortools/util/LongToVoid"); + jenv->FindClass("com/google/ortools/" + "util/LongToVoid"); if (nullptr == object_class) return $null; jmethodID method_id = jenv->GetStaticMethodID(object_class, "getCPtr", @@ -183,7 +186,7 @@ WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, operations_research::swig_util::LongToVoid* const fun = reinterpret_cast( jenv->CallStaticLongMethod(object_class, method_id, $input)); - $1 = [fun](int64 i) { fun->run(i); }; + $1 = [fun](int64 i) { fun->Run(i); }; } // These 3 typemaps tell SWIG what JNI and Java types to use @@ -202,15 +205,23 @@ WRAP_STD_FUNCTION_JAVA_AUX(Package, "CppClass", CppClass, ReturnType, // We cannot use %ignoreall/%unignoreall as this is not compatible with nested // swig files. -%feature("director") operations_research::swig_util::IntIntToLong; -%feature("director") operations_research::swig_util::LongLongLongToBoolean; -%feature("director") operations_research::swig_util::LongLongLongToLong; -%feature("director") operations_research::swig_util::LongLongToLong; -%feature("director") operations_research::swig_util::LongToBoolean; %feature("director") operations_research::swig_util::LongToLong; -%feature("director") operations_research::swig_util::LongToVoid; -%feature("director") operations_research::swig_util::VoidToBoolean; +%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::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; -%feature("director") operations_research::swig_util::VoidToVoid; +%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; %include "util/functions_swig_helpers.h" diff --git a/src/util/python/functions.swig b/src/util/python/functions.swig index 3f1c2b531b..7c777721e9 100644 --- a/src/util/python/functions.swig +++ b/src/util/python/functions.swig @@ -14,13 +14,16 @@ // 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. - +// +// For now, clients must %include this. +// TODO(user): move the C++ code to a separate file, so that clients can +// simply %import this (and %{ #include %} the C++ file). +// // Usage and tests in pywrapfunctions_test.py %include "base/base.swig" %{ - #include // Wrap std::function