From 30e26c4f962b0b7b8e5e0909fc3a349c8ee4fa1e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 31 Jan 2019 00:36:44 +0100 Subject: [PATCH] Avoid an issue with virtual functions Reimplementing virtual functions with "const &" arguments wasn't behaving as expected because these arguments were copied. Now, "const &" for arguments (in virtual function reimplementation) is not implemented as a copy. In addition, now it's possible to declare results as references always (also if const &). See gsiTest.cc:1078 for example: // gsi::arg_make_reference makes the function's return value // always being taken as a reference gsi::method ("pass_cd_cref_as_ref", &C_P::pass_cd_cref) --- src/gsi/gsi/gsiMethods.h | 73 ++++++++++---- src/gsi/gsi/gsiMethodsVar.h | 132 ++++++++++++++++--------- src/gsi/gsi/gsiTypes.cc | 7 +- src/gsi/gsi/gsiTypes.h | 165 ++++++++++++++++++++++++++++++-- src/gsi/gsi_test/gsiTest.cc | 25 +++++ src/gsi/gsi_test/gsiTest.h | 51 ++++++++++ src/pya/pya/pyaConvert.cc | 2 +- src/rba/rba/rbaConvert.cc | 2 +- testdata/python/basic.py | 74 ++++++++++++++ testdata/ruby/basic_testcore.rb | 84 ++++++++++++++++ 10 files changed, 539 insertions(+), 76 deletions(-) diff --git a/src/gsi/gsi/gsiMethods.h b/src/gsi/gsi/gsiMethods.h index 472748710..9d214ef6f 100644 --- a/src/gsi/gsi/gsiMethods.h +++ b/src/gsi/gsi/gsiMethods.h @@ -334,11 +334,23 @@ public: /** * @brief Adds an argument to the argument list (of type X) */ - template + template void add_arg () { ArgType a; - a.template init (); + a.template init (); + m_arg_types.push_back (a); + m_argsize += a.size (); + } + + /** + * @brief Adds an argument to the argument list (of type X) + */ + template + void add_arg () + { + ArgType a; + a.template init (); m_arg_types.push_back (a); m_argsize += a.size (); } @@ -346,11 +358,23 @@ public: /** * @brief Adds an argument to the argument list (of type X plus additional specs) */ - template + template void add_arg (const ArgSpecBase &spec) { ArgType a; - a.template init (spec); + a.template init (spec); + m_arg_types.push_back (a); + m_argsize += a.size (); + } + + /** + * @brief Adds an argument to the argument list (of type X plus additional specs) + */ + template + void add_arg (const ArgSpecBase &spec) + { + ArgType a; + a.template init (spec); m_arg_types.push_back (a); m_argsize += a.size (); } @@ -358,11 +382,23 @@ public: /** * @brief This version will take the ownership of the ArgSpecBase object */ - template + template void add_arg (ArgSpecBase *spec) { ArgType a; - a.template init (spec); + a.template init (spec); + m_arg_types.push_back (a); + m_argsize += a.size (); + } + + /** + * @brief This version will take the ownership of the ArgSpecBase object + */ + template + void add_arg (ArgSpecBase *spec) + { + ArgType a; + a.template init (spec); m_arg_types.push_back (a); m_argsize += a.size (); } @@ -379,10 +415,19 @@ public: /** * @brief Sets the return type to "X" */ - template + template void set_return () { - m_ret_type.template init (); + m_ret_type.template init (); + } + + /** + * @brief Sets the return type to "X" + */ + template + void set_return () + { + m_ret_type.template init (); } /** @@ -391,7 +436,7 @@ public: template void set_return_new () { - m_ret_type.template init (true); + m_ret_type.template init (); } /** @@ -853,16 +898,6 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str return Methods (new ConstantValueGetter (name, v, doc)); } -struct return_by_value -{ - typedef tl::False is_factory; -}; - -struct return_new_object -{ - typedef tl::True is_factory; -}; - // 0 argument #define _COUNT 0 diff --git a/src/gsi/gsi/gsiMethodsVar.h b/src/gsi/gsi/gsiMethodsVar.h index db383beaf..c0511038f 100644 --- a/src/gsi/gsi/gsiMethodsVar.h +++ b/src/gsi/gsi/gsiMethodsVar.h @@ -220,7 +220,7 @@ private: _ARGSPECMEM }; -template +template class _NAME(Method) : public MethodSpecificBase { @@ -240,11 +240,7 @@ public: { this->clear (); _ADDARGS - if (tl::value_from_type (typename F::is_factory ())) { - this->template set_return_new (); - } else { - this->template set_return (); - } + this->template set_return (); } virtual MethodBase *clone () const @@ -268,7 +264,7 @@ private: _ARGSPECMEM }; -template +template class _NAME(ConstMethod) : public MethodSpecificBase { @@ -288,11 +284,7 @@ public: { this->clear (); _ADDARGS - if (tl::value_from_type (typename F::is_factory ())) { - this->template set_return_new (); - } else { - this->template set_return (); - } + this->template set_return (); } virtual MethodBase *clone () const @@ -316,7 +308,7 @@ private: _ARGSPECMEM }; -template +template class _NAME(ExtMethod) : public MethodBase { @@ -336,11 +328,7 @@ public: { this->clear (); _ADDARGS - if (tl::value_from_type (typename F::is_factory ())) { - this->template set_return_new (); - } else { - this->template set_return (); - } + this->template set_return (); } virtual MethodBase *clone () const @@ -364,7 +352,7 @@ private: _ARGSPECMEM }; -template +template class _NAME(StaticMethod) : public StaticMethodBase { @@ -384,11 +372,7 @@ public: { this->clear (); _ADDARGS - if (tl::value_from_type (typename F::is_factory ())) { - this->template set_return_new (); - } else { - this->template set_return (); - } + this->template set_return (); } virtual MethodBase *clone () const @@ -1300,7 +1284,14 @@ template Methods method (const std::string &name, R (X::*m) (_FUNCARGLIST), const std::string &doc = std::string ()) { - return Methods (new _NAME(Method) (name, m, doc)); + return Methods (new _NAME(Method) (name, m, doc)); +} + +template +Methods +method (const std::string &name, R (X::*m) (_FUNCARGLIST), const std::string &doc = std::string ()) +{ + return Methods (new _NAME(Method) (name, m, doc)); } #if _COUNT != 0 @@ -1308,7 +1299,14 @@ template Methods method (const std::string &name, R (X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(Method) (name, m, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(Method) (name, m, doc))->add_args (_ARGSPECARGS)); +} + +template +Methods +method (const std::string &name, R (X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) +{ + return Methods ((new _NAME(Method) (name, m, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1316,7 +1314,7 @@ template Methods factory (const std::string &name, R *(X::*m) (_FUNCARGLIST), const std::string &doc = std::string ()) { - return Methods (new _NAME(Method) (name, m, doc)); + return Methods (new _NAME(Method) (name, m, doc)); } #if _COUNT != 0 @@ -1324,7 +1322,7 @@ template Methods factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(Method) (name, m, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(Method) (name, m, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1332,7 +1330,14 @@ template Methods method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ()) { - return Methods (new _NAME(ExtMethod) (name, xm, doc)); + return Methods (new _NAME(ExtMethod) (name, xm, doc)); +} + +template +Methods +method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ()) +{ + return Methods (new _NAME(ExtMethod) (name, xm, doc)); } #if _COUNT != 0 @@ -1340,7 +1345,14 @@ template Methods method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(ExtMethod) (name, xm, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(ExtMethod) (name, xm, doc))->add_args (_ARGSPECARGS)); +} + +template +Methods +method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) +{ + return Methods ((new _NAME(ExtMethod) (name, xm, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1348,7 +1360,7 @@ template Methods factory_ext (const std::string &name, R *(*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ()) { - return Methods (new _NAME(ExtMethod) (name, xm, doc)); + return Methods (new _NAME(ExtMethod) (name, xm, doc)); } #if _COUNT != 0 @@ -1356,7 +1368,7 @@ template Methods factory_ext (const std::string &name, R *(*xm) (X * _COMMA _FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(ExtMethod) (name, xm, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(ExtMethod) (name, xm, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1364,7 +1376,7 @@ template Methods constructor (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc = std::string ()) { - return Methods (new _NAME(StaticMethod) (name, m, doc)); + return Methods (new _NAME(StaticMethod) (name, m, doc)); } #if _COUNT != 0 @@ -1372,7 +1384,7 @@ template Methods constructor (const std::string &name, X *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(StaticMethod) (name, m, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(StaticMethod) (name, m, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1380,7 +1392,14 @@ template Methods method (const std::string &name, R (*m) (_FUNCARGLIST), const std::string &doc = std::string ()) { - return Methods (new _NAME(StaticMethod) (name, m, doc)); + return Methods (new _NAME(StaticMethod) (name, m, doc)); +} + +template +Methods +method (const std::string &name, R (*m) (_FUNCARGLIST), const std::string &doc = std::string ()) +{ + return Methods (new _NAME(StaticMethod) (name, m, doc)); } #if _COUNT != 0 @@ -1388,7 +1407,14 @@ template Methods method (const std::string &name, R (*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(StaticMethod) (name, m, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(StaticMethod) (name, m, doc))->add_args (_ARGSPECARGS)); +} + +template +Methods +method (const std::string &name, R (*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) +{ + return Methods ((new _NAME(StaticMethod) (name, m, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1396,7 +1422,7 @@ template Methods factory (const std::string &name, R *(*m) (_FUNCARGLIST), const std::string &doc = std::string ()) { - return Methods (new _NAME(StaticMethod) (name, m, doc)); + return Methods (new _NAME(StaticMethod) (name, m, doc)); } #if _COUNT != 0 @@ -1404,7 +1430,7 @@ template Methods factory (const std::string &name, R *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(StaticMethod) (name, m, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(StaticMethod) (name, m, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1428,7 +1454,7 @@ template Methods factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST), Callback X::*cb, const std::string &doc = std::string ()) { - return Methods (new _NAME(Method) (name, m, doc, cb)); + return Methods (new _NAME(Method) (name, m, doc, cb)); } #if _COUNT != 0 @@ -1436,7 +1462,7 @@ template Methods factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST), Callback X::*cb _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(Method) (name, m, doc, cb))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(Method) (name, m, doc, cb))->add_args (_ARGSPECARGS)); } #endif @@ -1444,7 +1470,14 @@ template Methods method (const std::string &name, R (X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ()) { - return Methods (new _NAME(ConstMethod) (name, m, doc)); + return Methods (new _NAME(ConstMethod) (name, m, doc)); +} + +template +Methods +method (const std::string &name, R (X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ()) +{ + return Methods (new _NAME(ConstMethod) (name, m, doc)); } #if _COUNT != 0 @@ -1452,7 +1485,14 @@ template Methods method (const std::string &name, R (X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(ConstMethod) (name, m, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(ConstMethod) (name, m, doc))->add_args (_ARGSPECARGS)); +} + +template +Methods +method (const std::string &name, R (X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS, const std::string &doc = std::string ()) +{ + return Methods ((new _NAME(ConstMethod) (name, m, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1460,7 +1500,7 @@ template Methods factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ()) { - return Methods (new _NAME(ConstMethod) (name, m, doc)); + return Methods (new _NAME(ConstMethod) (name, m, doc)); } #if _COUNT != 0 @@ -1468,7 +1508,7 @@ template Methods factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(ConstMethod) (name, m, doc))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(ConstMethod) (name, m, doc))->add_args (_ARGSPECARGS)); } #endif @@ -1492,7 +1532,7 @@ template Methods factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST) const, Callback X::*cb, const std::string &doc = std::string ()) { - return Methods (new _NAME(ConstMethod) (name, m, doc, cb)); + return Methods (new _NAME(ConstMethod) (name, m, doc, cb)); } #if _COUNT != 0 @@ -1500,7 +1540,7 @@ template Methods factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST) const, Callback X::*cb _COMMA _ARGSPECS, const std::string &doc = std::string ()) { - return Methods ((new _NAME(ConstMethod) (name, m, doc, cb))->add_args (_ARGSPECARGS)); + return Methods ((new _NAME(ConstMethod) (name, m, doc, cb))->add_args (_ARGSPECARGS)); } #endif diff --git a/src/gsi/gsi/gsiTypes.cc b/src/gsi/gsi/gsiTypes.cc index c79711b86..237e154ac 100644 --- a/src/gsi/gsi/gsiTypes.cc +++ b/src/gsi/gsi/gsiTypes.cc @@ -112,7 +112,7 @@ ArgType::to_string () const ArgType::ArgType () : m_type (T_void), mp_spec (0), mp_inner (0), mp_inner_k (0), m_is_ref (false), m_is_ptr (false), m_is_cref (false), m_is_cptr (false), m_is_iter (false), - m_owns_spec (false), m_pass_obj (false), + m_owns_spec (false), m_pass_obj (false), m_prefer_copy (false), mp_cls (0), m_size (0) { } @@ -132,7 +132,7 @@ ArgType::~ArgType () ArgType::ArgType (const ArgType &other) : m_type (T_void), mp_spec (0), mp_inner (0), mp_inner_k (0), m_is_ref (false), m_is_ptr (false), m_is_cref (false), m_is_cptr (false), m_is_iter (false), - m_owns_spec (false), m_pass_obj (false), + m_owns_spec (false), m_pass_obj (false), m_prefer_copy (false), mp_cls (0), m_size (0) { operator= (other); @@ -156,6 +156,7 @@ ArgType::operator= (const ArgType &other) m_type = other.m_type; m_pass_obj = other.m_pass_obj; + m_prefer_copy = other.m_prefer_copy; m_is_ref = other.m_is_ref; m_is_cref = other.m_is_cref; m_is_ptr = other.m_is_ptr; @@ -204,7 +205,7 @@ ArgType::operator== (const ArgType &b) const } return m_type == b.m_type && m_is_iter == b.m_is_iter && m_is_ref == b.m_is_ref && m_is_cref == b.m_is_cref && m_is_ptr == b.m_is_ptr && m_is_cptr == b.m_is_cptr && - mp_cls == b.mp_cls && m_pass_obj == b.m_pass_obj; + mp_cls == b.mp_cls && m_pass_obj == b.m_pass_obj && m_prefer_copy == b.m_prefer_copy; } void diff --git a/src/gsi/gsi/gsiTypes.h b/src/gsi/gsi/gsiTypes.h index 3347772be..4f4065285 100644 --- a/src/gsi/gsi/gsiTypes.h +++ b/src/gsi/gsi/gsiTypes.h @@ -1385,6 +1385,67 @@ public: } }; +/** + * @brief A tag indicating ownership transfer + * This tag will transfer ownership of an object (either back- or forward). + */ +struct arg_pass_ownership { }; + +/** + * @brief A tag indicating copy preference + * By specifying this tag, making a copy of the object is the preferred transfer method + */ +struct arg_make_copy { }; + +/** + * @brief A tag indicating to take the reference of an object + * By specifying this tag, taking a reference is the preferred transfer method + */ +struct arg_make_reference { }; + +/** + * @brief A tag indicating the default return value preference + * The default return value preference is "copy" for const references and direct values + * and reference otherwise. + */ +struct arg_default_return_value_preference { }; + +/** + * @brief A function computing the "prefer_copy" value + */ +template +struct compute_prefer_copy +{ + static bool value () { return false; } +}; + +template +struct compute_prefer_copy +{ + static bool value () { return type_traits::is_cref (); } +}; + +template +struct compute_prefer_copy +{ + static bool value () { return true; } +}; + +/** + * @brief A function computing the "pass_obj" value + */ +template +struct compute_pass_obj +{ + static bool value () { return false; } +}; + +template +struct compute_pass_obj +{ + static bool value () { return true; } +}; + /** * @brief Generic argument type declaration * @@ -1427,7 +1488,22 @@ public: template void init (const ArgSpecBase &spec) { - init (); + init (); + mp_spec = &spec; + m_owns_spec = false; + } + + /** + * @brief Initializes with an external specification + * + * This method will initialize the type object referring to an external + * spec object. The spec object will specify name and default + * value for arguments + */ + template + void init (const ArgSpecBase &spec) + { + init (); mp_spec = &spec; m_owns_spec = false; } @@ -1442,7 +1518,22 @@ public: template void init (ArgSpecBase *spec) { - init (); + init (); + mp_spec = spec; + m_owns_spec = true; + } + + /** + * @brief Initializes with a specification + * + * This method will initialize the type object with a specification. + * The ownership over the specification object will be transferred to + * the type object. + */ + template + void init (ArgSpecBase *spec) + { + init (); mp_spec = spec; m_owns_spec = true; } @@ -1454,7 +1545,7 @@ public: * to the case of object pointers mainly. */ template - void init (bool pass_obj = false) + void init () { release_spec (); @@ -1462,7 +1553,8 @@ public: m_is_iter = type_traits::is_iter (); mp_cls = type_traits::cls_decl (); - m_pass_obj = pass_obj; + m_pass_obj = compute_pass_obj::value (); + m_prefer_copy = compute_prefer_copy::value (); m_is_ref = type_traits::is_ref (); m_is_ptr = type_traits::is_ptr (); m_is_cref = type_traits::is_cref (); @@ -1481,12 +1573,56 @@ public: if (type_traits::inner_type>::code () != T_void) { mp_inner = new ArgType; - mp_inner->init::inner_type> (); + mp_inner->init::inner_type, arg_make_reference> (); } if (type_traits::inner_k_type>::code () != T_void) { mp_inner_k = new ArgType; - mp_inner_k->init::inner_k_type> (); + mp_inner_k->init::inner_k_type, arg_make_reference> (); + } + } + + /** + * @brief Initialize the type from a given type X + * If "pass_obj" is true, the receiver of an object will always + * take over the ownership over the passed object. This applies + * to the case of object pointers mainly. + */ + template + void init () + { + release_spec (); + + m_type = type_traits::code (); + m_is_iter = type_traits::is_iter (); + mp_cls = type_traits::cls_decl (); + + m_pass_obj = compute_pass_obj::value (); + m_prefer_copy = compute_prefer_copy::value (); + m_is_ref = type_traits::is_ref (); + m_is_ptr = type_traits::is_ptr (); + m_is_cref = type_traits::is_cref (); + m_is_cptr = type_traits::is_cptr (); + m_size = (unsigned int) type_traits::serial_size (); + + if (mp_inner) { + delete mp_inner; + mp_inner = 0; + } + + if (mp_inner_k) { + delete mp_inner_k; + mp_inner_k = 0; + } + + if (type_traits::inner_type>::code () != T_void) { + mp_inner = new ArgType; + mp_inner->init::inner_type, arg_make_reference> (); + } + + if (type_traits::inner_k_type>::code () != T_void) { + mp_inner_k = new ArgType; + mp_inner_k->init::inner_k_type, arg_make_reference> (); } } @@ -1571,6 +1707,22 @@ public: m_pass_obj = b; } + /** + * @brief Returns a value indicating that the value prefers to be copied + */ + bool prefer_copy () const + { + return m_prefer_copy; + } + + /** + * @brief Sets a value indicating that the value prefers to be copied + */ + void set_prefer_copy (bool b) + { + m_prefer_copy = b; + } + /** * @brief Returns a value indicating whether the type is a reference */ @@ -1702,6 +1854,7 @@ private: bool m_is_iter : 1; bool m_owns_spec : 1; bool m_pass_obj : 1; + bool m_prefer_copy : 1; mutable const ClassBase *mp_cls; unsigned int m_size; diff --git a/src/gsi/gsi_test/gsiTest.cc b/src/gsi/gsi_test/gsiTest.cc index 4750e7ad3..d115a54a7 100644 --- a/src/gsi/gsi_test/gsiTest.cc +++ b/src/gsi/gsi_test/gsiTest.cc @@ -1057,9 +1057,34 @@ static gsi::ClassExt b_ext ( gsi::iterator_ext ("b10p", &b10bp_ext, &b10ep_ext) ); +CopyDetector *new_cd (int x) +{ + return new CopyDetector (x); +} + +static gsi::Class decl_copy_detector ("", "CopyDetector", + gsi::constructor ("new", &new_cd) + + gsi::method ("x", &CopyDetector::x) + + gsi::method ("xx", &CopyDetector::xx) +); static gsi::Class decl_c ("", "C", gsi::callback ("f", &C_P::f, &C_P::f_cb) + + gsi::callback ("vfunc", &C_P::vfunc, &C_P::vfunc_cb) + + gsi::method ("call_vfunc", &C_P::call_vfunc) + + gsi::method ("pass_cd_direct", &C_P::pass_cd_direct) + + gsi::method ("pass_cd_cref", &C_P::pass_cd_cref) + + gsi::method ("pass_cd_cref_as_copy", &C_P::pass_cd_cref) + + gsi::method ("pass_cd_cref_as_ref", &C_P::pass_cd_cref) + + gsi::method ("pass_cd_cptr", &C_P::pass_cd_cptr) + + gsi::method ("pass_cd_cptr_as_copy", &C_P::pass_cd_cptr) + + gsi::method ("pass_cd_cptr_as_ref", &C_P::pass_cd_cptr) + + gsi::method ("pass_cd_ref", &C_P::pass_cd_ref) + + gsi::method ("pass_cd_ref_as_copy", &C_P::pass_cd_ref) + + gsi::method ("pass_cd_ref_as_ref", &C_P::pass_cd_ref) + + gsi::method ("pass_cd_ptr", &C_P::pass_cd_ptr) + + gsi::method ("pass_cd_ptr_as_copy", &C_P::pass_cd_ptr) + + gsi::method ("pass_cd_ptr_as_ref", &C_P::pass_cd_ptr) + gsi::method ("g", &C_P::g) + gsi::method ("s1", &C::s1) + gsi::method ("s2", &C::s2) + diff --git a/src/gsi/gsi_test/gsiTest.h b/src/gsi/gsi_test/gsiTest.h index 7992a42b3..a7e6938f6 100644 --- a/src/gsi/gsi_test/gsiTest.h +++ b/src/gsi/gsi_test/gsiTest.h @@ -846,6 +846,35 @@ struct B static B *b_inst; }; +class CopyDetector +{ +public: + CopyDetector (int x) + : m_x (x), m_xx (x) + { } + + CopyDetector () + : m_x (0), m_xx (0) + { } + + CopyDetector (const CopyDetector &d) + : m_x (d.m_x), m_xx (d.m_xx + 1) // this detects the copy + { } + + CopyDetector &operator= (const CopyDetector &d) + { + m_x = d.m_x; + m_xx = d.m_xx + 1; + return *this; + } + + int x () const { return m_x; } + int xx () const { return m_xx; } + +private: + int m_x, m_xx; +}; + class C { public: @@ -861,6 +890,22 @@ public: return f(s); } + virtual void vfunc (const CopyDetector &) + { + // .. nothing yet .. + } + + void call_vfunc (const CopyDetector &cd) + { + vfunc (cd); + } + + CopyDetector pass_cd_direct (const CopyDetector &cd) { return cd; } + const CopyDetector &pass_cd_cref (const CopyDetector &cd) { return cd; } + const CopyDetector *pass_cd_cptr (const CopyDetector &cd) { return &cd; } + CopyDetector *pass_cd_ptr (const CopyDetector &cd) { return const_cast (&cd); } + CopyDetector &pass_cd_ref (const CopyDetector &cd) { return const_cast (cd); } + static int s1 (); static std::vector::const_iterator s1a (); static std::vector::const_iterator s1b (); @@ -880,7 +925,13 @@ public: return f_cb.can_issue () ? f_cb.issue (&C::f, s) : C::f (s); } + virtual void vfunc (const CopyDetector &cd) + { + return vfunc_cb.can_issue () ? vfunc_cb.issue (&C::vfunc, cd) : C::vfunc (cd); + } + gsi::Callback f_cb; + gsi::Callback vfunc_cb; }; struct E diff --git a/src/pya/pya/pyaConvert.cc b/src/pya/pya/pyaConvert.cc index 4ceff8ecd..57918f95b 100644 --- a/src/pya/pya/pyaConvert.cc +++ b/src/pya/pya/pyaConvert.cc @@ -345,7 +345,7 @@ object_to_python (void *obj, PYAObjectBase *self, const gsi::ArgType &atype) bool is_direct = !(atype.is_ptr () || atype.is_ref () || atype.is_cptr () || atype.is_cref ()); bool pass_obj = atype.pass_obj () || is_direct; bool is_const = atype.is_cptr () || atype.is_cref (); - bool prefer_copy = atype.is_cref (); + bool prefer_copy = atype.prefer_copy (); bool can_destroy = prefer_copy || atype.is_ptr (); return object_to_python (obj, self, cls, pass_obj, is_const, prefer_copy, can_destroy); diff --git a/src/rba/rba/rbaConvert.cc b/src/rba/rba/rbaConvert.cc index 1210624c5..e54bfb73b 100644 --- a/src/rba/rba/rbaConvert.cc +++ b/src/rba/rba/rbaConvert.cc @@ -133,7 +133,7 @@ VALUE object_to_ruby (void *obj, Proxy *self, const gsi::ArgType &atype) bool is_direct = !(atype.is_ptr () || atype.is_ref () || atype.is_cptr () || atype.is_cref ()); bool pass_obj = atype.pass_obj () || is_direct; bool is_const = atype.is_cptr () || atype.is_cref (); - bool prefer_copy = atype.is_cref (); + bool prefer_copy = atype.prefer_copy (); bool can_destroy = prefer_copy || atype.is_ptr (); return object_to_ruby (obj, self, cls, pass_obj, is_const, prefer_copy, can_destroy); diff --git a/testdata/python/basic.py b/testdata/python/basic.py index 568a9ee16..ec7f58ef0 100644 --- a/testdata/python/basic.py +++ b/testdata/python/basic.py @@ -73,6 +73,14 @@ class C_IMP2(pya.C): class C_IMP3(pya.C): anything = None +class C_IMP4(pya.C): + def __init__(self): + self.x = None + self.xx = None + def vfunc(self, cd): + self.x = cd.x() + self.xx = cd.xx() + class Z_IMP1(pya.Z): def f(self, x): return x.cls_name() @@ -1072,6 +1080,11 @@ class BasicTest(unittest.TestCase): arr.append(i) self.assertEqual( arr, [ 0, 1, 2, 3, 4, 5, 6, 0, 0, 1 ] ) + c4 = C_IMP4() + c4.call_vfunc(pya.CopyDetector(17)) + self.assertEqual(c4.x, 17) + self.assertEqual(c4.xx, 17) + def test_20(self): b = pya.B() @@ -1538,6 +1551,67 @@ class BasicTest(unittest.TestCase): b = None self.assertEqual(pya.B.has_inst(), False) + def test_29(self): + + # copy/ref semantics on return + + c = pya.C() + + cd = pya.CopyDetector(42) + + cd2 = c.pass_cd_direct(cd) + self.assertEqual(cd2.x(), 42) + # two copies: one for return statement and then one for the new object + self.assertEqual(cd2.xx(), 44) + + cd2 = c.pass_cd_cref(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 43) + + cd2 = c.pass_cd_cref_as_copy(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 43) + + cd2 = c.pass_cd_cref_as_ref(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 42) + + cd2 = c.pass_cd_cptr(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 42) + + cd2 = c.pass_cd_cptr_as_copy(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 43) + + cd2 = c.pass_cd_cptr_as_ref(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 42) + + cd2 = c.pass_cd_ptr(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 42) + + cd2 = c.pass_cd_ptr_as_copy(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 43) + + cd2 = c.pass_cd_ptr_as_ref(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 42) + + cd2 = c.pass_cd_ref(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 42) + + cd2 = c.pass_cd_ref_as_copy(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 43) + + cd2 = c.pass_cd_ref_as_ref(cd) + self.assertEqual(cd2.x(), 42) + self.assertEqual(cd2.xx(), 42) + def test_30(self): # some basic tests for the *Value boxing classes diff --git a/testdata/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb index 467ceaccf..8d9cd8493 100644 --- a/testdata/ruby/basic_testcore.rb +++ b/testdata/ruby/basic_testcore.rb @@ -936,6 +936,22 @@ class Basic_TestClass < TestBase class C_IMP3 < RBA::C end + class C_IMP4 < RBA::C + def initialize + @x = @xx = nil + end + def x + @x + end + def xx + @xx + end + def vfunc(cd) + @x = cd.x + @xx = cd.xx + end + end + def test_19 c0 = RBA::C.new @@ -978,6 +994,11 @@ class Basic_TestClass < TestBase C_IMP2.each { |i| arr.push i } assert_equal( arr, [ 0, 1, 2, 3, 4, 5, 6, 0, 0, 1 ] ) + c4 = C_IMP4.new + c4.call_vfunc(RBA::CopyDetector::new(17)) + assert_equal(c4.x, 17) + assert_equal(c4.xx, 17) + end def test_20 @@ -1414,6 +1435,69 @@ class Basic_TestClass < TestBase end + def test_29 + + # copy/ref semantics on return + + c = RBA::C::new + + cd = RBA::CopyDetector::new(42) + + cd2 = c.pass_cd_direct(cd) + assert_equal(cd2.x, 42) + # two copies: one for return statement and then one for the new object + assert_equal(cd2.xx, 44) + + cd2 = c.pass_cd_cref(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 43) + + cd2 = c.pass_cd_cref_as_copy(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 43) + + cd2 = c.pass_cd_cref_as_ref(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 42) + + cd2 = c.pass_cd_cptr(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 42) + + cd2 = c.pass_cd_cptr_as_copy(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 43) + + cd2 = c.pass_cd_cptr_as_ref(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 42) + + cd2 = c.pass_cd_ptr(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 42) + + cd2 = c.pass_cd_ptr_as_copy(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 43) + + cd2 = c.pass_cd_ptr_as_ref(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 42) + + cd2 = c.pass_cd_ref(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 42) + + cd2 = c.pass_cd_ref_as_copy(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 43) + + cd2 = c.pass_cd_ref_as_ref(cd) + assert_equal(cd2.x, 42) + assert_equal(cd2.xx, 42) + + end + def test_30 # some basic tests for the *Value boxing classes