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<C_P, const CopyDetector &, const CopyDetector &, gsi::arg_make_reference> ("pass_cd_cref_as_ref", &C_P::pass_cd_cref)
This commit is contained in:
Matthias Koefferlein 2019-01-31 00:36:44 +01:00
parent 4068478887
commit 30e26c4f96
10 changed files with 539 additions and 76 deletions

View File

@ -334,11 +334,23 @@ public:
/**
* @brief Adds an argument to the argument list (of type X)
*/
template <class X>
template <class X>
void add_arg ()
{
ArgType a;
a.template init<X> ();
a.template init<X, arg_make_reference> ();
m_arg_types.push_back (a);
m_argsize += a.size ();
}
/**
* @brief Adds an argument to the argument list (of type X)
*/
template <class X, class Transfer>
void add_arg ()
{
ArgType a;
a.template init<X, Transfer> ();
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 <class X>
template <class X>
void add_arg (const ArgSpecBase &spec)
{
ArgType a;
a.template init<X> (spec);
a.template init<X, arg_make_reference> (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 <class X, class Transfer>
void add_arg (const ArgSpecBase &spec)
{
ArgType a;
a.template init<X, Transfer> (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 <class X>
template <class X>
void add_arg (ArgSpecBase *spec)
{
ArgType a;
a.template init<X> (spec);
a.template init<X, arg_make_reference> (spec);
m_arg_types.push_back (a);
m_argsize += a.size ();
}
/**
* @brief This version will take the ownership of the ArgSpecBase object
*/
template <class X, class Transfer>
void add_arg (ArgSpecBase *spec)
{
ArgType a;
a.template init<X, Transfer> (spec);
m_arg_types.push_back (a);
m_argsize += a.size ();
}
@ -379,10 +415,19 @@ public:
/**
* @brief Sets the return type to "X"
*/
template <class X>
template <class X>
void set_return ()
{
m_ret_type.template init<X> ();
m_ret_type.template init<X, arg_default_return_value_preference> ();
}
/**
* @brief Sets the return type to "X"
*/
template <class X, class Transfer>
void set_return ()
{
m_ret_type.template init<X, Transfer> ();
}
/**
@ -391,7 +436,7 @@ public:
template <class X>
void set_return_new ()
{
m_ret_type.template init<X> (true);
m_ret_type.template init<X, arg_pass_ownership> ();
}
/**
@ -853,16 +898,6 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
return Methods (new ConstantValueGetter <R> (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

View File

@ -220,7 +220,7 @@ private:
_ARGSPECMEM
};
template <class X, class R _COMMA _TMPLARG, class F = gsi::return_by_value>
template <class X, class R _COMMA _TMPLARG, class Transfer = gsi::arg_default_return_value_preference>
class _NAME(Method)
: public MethodSpecificBase <X>
{
@ -240,11 +240,7 @@ public:
{
this->clear ();
_ADDARGS
if (tl::value_from_type (typename F::is_factory ())) {
this->template set_return_new<R> ();
} else {
this->template set_return<R> ();
}
this->template set_return<R, Transfer> ();
}
virtual MethodBase *clone () const
@ -268,7 +264,7 @@ private:
_ARGSPECMEM
};
template <class X, class R _COMMA _TMPLARG, class F = gsi::return_by_value>
template <class X, class R _COMMA _TMPLARG, class Transfer = gsi::arg_default_return_value_preference>
class _NAME(ConstMethod)
: public MethodSpecificBase <X>
{
@ -288,11 +284,7 @@ public:
{
this->clear ();
_ADDARGS
if (tl::value_from_type (typename F::is_factory ())) {
this->template set_return_new<R> ();
} else {
this->template set_return<R> ();
}
this->template set_return<R, Transfer> ();
}
virtual MethodBase *clone () const
@ -316,7 +308,7 @@ private:
_ARGSPECMEM
};
template <class X, class R _COMMA _TMPLARG, class F = gsi::return_by_value>
template <class X, class R _COMMA _TMPLARG, class Transfer = gsi::arg_default_return_value_preference>
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<R> ();
} else {
this->template set_return<R> ();
}
this->template set_return<R, Transfer> ();
}
virtual MethodBase *clone () const
@ -364,7 +352,7 @@ private:
_ARGSPECMEM
};
template <class R _COMMA _TMPLARG, class F = gsi::return_by_value>
template <class R _COMMA _TMPLARG, class Transfer = gsi::arg_default_return_value_preference>
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<R> ();
} else {
this->template set_return<R> ();
}
this->template set_return<R, Transfer> ();
}
virtual MethodBase *clone () const
@ -1300,7 +1284,14 @@ template <class X, class R _COMMA _TMPLARG>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(Method) <X, R _COMMA _FUNCARGLIST> (name, m, doc));
return Methods (new _NAME(Method) <X, R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, m, doc));
}
template <class X, class R _COMMA _TMPLARG, class Transfer>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(Method) <X, R _COMMA _FUNCARGLIST, Transfer> (name, m, doc));
}
#if _COUNT != 0
@ -1308,7 +1299,14 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(Method) <X, R _COMMA _FUNCARGLIST> (name, m, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(Method) <X, R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, m, doc))->add_args (_ARGSPECARGS));
}
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS, class Transfer>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(Method) <X, R _COMMA _FUNCARGLIST, Transfer> (name, m, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1316,7 +1314,7 @@ template <class X, class R _COMMA _TMPLARG>
Methods
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(Method) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
return Methods (new _NAME(Method) <X, R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc));
}
#if _COUNT != 0
@ -1324,7 +1322,7 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
Methods
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(Method) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(Method) <X, R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1332,7 +1330,14 @@ template <class X, class R _COMMA _TMPLARG>
Methods
method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(ExtMethod) <X, R _COMMA _FUNCARGLIST> (name, xm, doc));
return Methods (new _NAME(ExtMethod) <X, R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, xm, doc));
}
template <class X, class R _COMMA _TMPLARG, class Transfer>
Methods
method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(ExtMethod) <X, R _COMMA _FUNCARGLIST, Transfer> (name, xm, doc));
}
#if _COUNT != 0
@ -1340,7 +1345,14 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
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) <X, R _COMMA _FUNCARGLIST> (name, xm, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(ExtMethod) <X, R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, xm, doc))->add_args (_ARGSPECARGS));
}
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS, class Transfer>
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) <X, R _COMMA _FUNCARGLIST, Transfer> (name, xm, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1348,7 +1360,7 @@ template <class X, class R _COMMA _TMPLARG>
Methods
factory_ext (const std::string &name, R *(*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(ExtMethod) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, xm, doc));
return Methods (new _NAME(ExtMethod) <X, R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, xm, doc));
}
#if _COUNT != 0
@ -1356,7 +1368,7 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
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) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, xm, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(ExtMethod) <X, R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, xm, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1364,7 +1376,7 @@ template <class X _COMMA _TMPLARG>
Methods
constructor (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(StaticMethod) <X * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
return Methods (new _NAME(StaticMethod) <X * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc));
}
#if _COUNT != 0
@ -1372,7 +1384,7 @@ template <class X _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
Methods
constructor (const std::string &name, X *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(StaticMethod) <X * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(StaticMethod) <X * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1380,7 +1392,14 @@ template <class R _COMMA _TMPLARG>
Methods
method (const std::string &name, R (*m) (_FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(StaticMethod) <R _COMMA _FUNCARGLIST> (name, m, doc));
return Methods (new _NAME(StaticMethod) <R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, m, doc));
}
template <class R _COMMA _TMPLARG, class Transfer>
Methods
method (const std::string &name, R (*m) (_FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(StaticMethod) <R _COMMA _FUNCARGLIST, Transfer> (name, m, doc));
}
#if _COUNT != 0
@ -1388,7 +1407,14 @@ template <class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
Methods
method (const std::string &name, R (*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(StaticMethod) <R _COMMA _FUNCARGLIST> (name, m, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(StaticMethod) <R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, m, doc))->add_args (_ARGSPECARGS));
}
template <class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS, class Transfer>
Methods
method (const std::string &name, R (*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(StaticMethod) <R _COMMA _FUNCARGLIST, Transfer> (name, m, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1396,7 +1422,7 @@ template <class R _COMMA _TMPLARG>
Methods
factory (const std::string &name, R *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
{
return Methods (new _NAME(StaticMethod) <R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
return Methods (new _NAME(StaticMethod) <R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc));
}
#if _COUNT != 0
@ -1404,7 +1430,7 @@ template <class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
Methods
factory (const std::string &name, R *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(StaticMethod) <R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(StaticMethod) <R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1428,7 +1454,7 @@ template <class X, class R _COMMA _TMPLARG>
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) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb));
return Methods (new _NAME(Method) <X, R _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc, cb));
}
#if _COUNT != 0
@ -1436,7 +1462,7 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
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) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(Method) <X, R _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc, cb))->add_args (_ARGSPECARGS));
}
#endif
@ -1444,7 +1470,14 @@ template <class X, class R _COMMA _TMPLARG>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ())
{
return Methods (new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST> (name, m, doc));
return Methods (new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, m, doc));
}
template <class X, class R _COMMA _TMPLARG, class Transfer>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ())
{
return Methods (new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, Transfer> (name, m, doc));
}
#if _COUNT != 0
@ -1452,7 +1485,14 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST> (name, m, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, arg_default_return_value_preference> (name, m, doc))->add_args (_ARGSPECARGS));
}
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS, class Transfer>
Methods
method (const std::string &name, R (X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, Transfer> (name, m, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1460,7 +1500,7 @@ template <class X, class R _COMMA _TMPLARG>
Methods
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ())
{
return Methods (new _NAME(ConstMethod) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
return Methods (new _NAME(ConstMethod) <X, R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc));
}
#if _COUNT != 0
@ -1468,7 +1508,7 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
Methods
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) const _COMMA _ARGSPECS, const std::string &doc = std::string ())
{
return Methods ((new _NAME(ConstMethod) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(ConstMethod) <X, R * _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc))->add_args (_ARGSPECARGS));
}
#endif
@ -1492,7 +1532,7 @@ template <class X, class R _COMMA _TMPLARG>
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) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb));
return Methods (new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc, cb));
}
#if _COUNT != 0
@ -1500,7 +1540,7 @@ template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
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) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb))->add_args (_ARGSPECARGS));
return Methods ((new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, gsi::arg_pass_ownership> (name, m, doc, cb))->add_args (_ARGSPECARGS));
}
#endif

View File

@ -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

View File

@ -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 <class Transfer, class X>
struct compute_prefer_copy
{
static bool value () { return false; }
};
template <class X>
struct compute_prefer_copy<arg_default_return_value_preference, X>
{
static bool value () { return type_traits<X>::is_cref (); }
};
template <class X>
struct compute_prefer_copy<arg_make_copy, X>
{
static bool value () { return true; }
};
/**
* @brief A function computing the "pass_obj" value
*/
template <class Transfer, class X>
struct compute_pass_obj
{
static bool value () { return false; }
};
template <class X>
struct compute_pass_obj<arg_pass_ownership, X>
{
static bool value () { return true; }
};
/**
* @brief Generic argument type declaration
*
@ -1427,7 +1488,22 @@ public:
template <class X>
void init (const ArgSpecBase &spec)
{
init<X> ();
init<X, arg_default_return_value_preference> ();
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 <class X, class Transfer>
void init (const ArgSpecBase &spec)
{
init<X, Transfer> ();
mp_spec = &spec;
m_owns_spec = false;
}
@ -1442,7 +1518,22 @@ public:
template <class X>
void init (ArgSpecBase *spec)
{
init<X> ();
init<X, arg_default_return_value_preference> ();
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 <class X, class Transfer>
void init (ArgSpecBase *spec)
{
init<X, Transfer> ();
mp_spec = spec;
m_owns_spec = true;
}
@ -1454,7 +1545,7 @@ public:
* to the case of object pointers mainly.
*/
template <class X>
void init (bool pass_obj = false)
void init ()
{
release_spec ();
@ -1462,7 +1553,8 @@ public:
m_is_iter = type_traits<X>::is_iter ();
mp_cls = type_traits<X>::cls_decl ();
m_pass_obj = pass_obj;
m_pass_obj = compute_pass_obj<arg_default_return_value_preference, X>::value ();
m_prefer_copy = compute_prefer_copy<arg_default_return_value_preference, X>::value ();
m_is_ref = type_traits<X>::is_ref ();
m_is_ptr = type_traits<X>::is_ptr ();
m_is_cref = type_traits<X>::is_cref ();
@ -1481,12 +1573,56 @@ public:
if (type_traits<typename type_traits<X>::inner_type>::code () != T_void) {
mp_inner = new ArgType;
mp_inner->init<typename type_traits<X>::inner_type> ();
mp_inner->init<typename type_traits<X>::inner_type, arg_make_reference> ();
}
if (type_traits<typename type_traits<X>::inner_k_type>::code () != T_void) {
mp_inner_k = new ArgType;
mp_inner_k->init<typename type_traits<X>::inner_k_type> ();
mp_inner_k->init<typename type_traits<X>::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 <class X, class Transfer>
void init ()
{
release_spec ();
m_type = type_traits<X>::code ();
m_is_iter = type_traits<X>::is_iter ();
mp_cls = type_traits<X>::cls_decl ();
m_pass_obj = compute_pass_obj<Transfer, X>::value ();
m_prefer_copy = compute_prefer_copy<Transfer, X>::value ();
m_is_ref = type_traits<X>::is_ref ();
m_is_ptr = type_traits<X>::is_ptr ();
m_is_cref = type_traits<X>::is_cref ();
m_is_cptr = type_traits<X>::is_cptr ();
m_size = (unsigned int) type_traits<X>::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<typename type_traits<X>::inner_type>::code () != T_void) {
mp_inner = new ArgType;
mp_inner->init<typename type_traits<X>::inner_type, arg_make_reference> ();
}
if (type_traits<typename type_traits<X>::inner_k_type>::code () != T_void) {
mp_inner_k = new ArgType;
mp_inner_k->init<typename type_traits<X>::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;

View File

@ -1057,9 +1057,34 @@ static gsi::ClassExt<B> b_ext (
gsi::iterator_ext ("b10p", &b10bp_ext, &b10ep_ext)
);
CopyDetector *new_cd (int x)
{
return new CopyDetector (x);
}
static gsi::Class<CopyDetector> decl_copy_detector ("", "CopyDetector",
gsi::constructor ("new", &new_cd) +
gsi::method ("x", &CopyDetector::x) +
gsi::method ("xx", &CopyDetector::xx)
);
static gsi::Class<C_P> 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<C_P, const CopyDetector &, const CopyDetector &, gsi::arg_make_copy> ("pass_cd_cref_as_copy", &C_P::pass_cd_cref) +
gsi::method<C_P, const CopyDetector &, const CopyDetector &, gsi::arg_make_reference> ("pass_cd_cref_as_ref", &C_P::pass_cd_cref) +
gsi::method ("pass_cd_cptr", &C_P::pass_cd_cptr) +
gsi::method<C_P, const CopyDetector *, const CopyDetector &, gsi::arg_make_copy> ("pass_cd_cptr_as_copy", &C_P::pass_cd_cptr) +
gsi::method<C_P, const CopyDetector *, const CopyDetector &, gsi::arg_make_reference> ("pass_cd_cptr_as_ref", &C_P::pass_cd_cptr) +
gsi::method ("pass_cd_ref", &C_P::pass_cd_ref) +
gsi::method<C_P, CopyDetector &, const CopyDetector &, gsi::arg_make_copy> ("pass_cd_ref_as_copy", &C_P::pass_cd_ref) +
gsi::method<C_P, CopyDetector &, const CopyDetector &, gsi::arg_make_reference> ("pass_cd_ref_as_ref", &C_P::pass_cd_ref) +
gsi::method ("pass_cd_ptr", &C_P::pass_cd_ptr) +
gsi::method<C_P, CopyDetector *, const CopyDetector &, gsi::arg_make_copy> ("pass_cd_ptr_as_copy", &C_P::pass_cd_ptr) +
gsi::method<C_P, CopyDetector *, const CopyDetector &, gsi::arg_make_reference> ("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) +

View File

@ -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<CopyDetector *> (&cd); }
CopyDetector &pass_cd_ref (const CopyDetector &cd) { return const_cast<CopyDetector &> (cd); }
static int s1 ();
static std::vector<int>::const_iterator s1a ();
static std::vector<int>::const_iterator s1b ();
@ -880,7 +925,13 @@ public:
return f_cb.can_issue () ? f_cb.issue<C, unsigned int, const std::string &> (&C::f, s) : C::f (s);
}
virtual void vfunc (const CopyDetector &cd)
{
return vfunc_cb.can_issue () ? vfunc_cb.issue<C, const CopyDetector &> (&C::vfunc, cd) : C::vfunc (cd);
}
gsi::Callback f_cb;
gsi::Callback vfunc_cb;
};
struct E

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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