diff --git a/include/boost/python/classes.hpp b/include/boost/python/classes.hpp index 2d69e81e..f88f1000 100644 --- a/include/boost/python/classes.hpp +++ b/include/boost/python/classes.hpp @@ -78,6 +78,19 @@ class instance PyObject* gt(PyObject* other); PyObject* ge(PyObject* other); + // Inplace operations. + PyObject* inplace_add(PyObject* other); + PyObject* inplace_subtract(PyObject* other); + PyObject* inplace_multiply(PyObject* other); + PyObject* inplace_divide(PyObject* other); + PyObject* inplace_remainder(PyObject* other); + PyObject* inplace_power(PyObject* exponent, PyObject* modulus); + PyObject* inplace_lshift(PyObject* other); + PyObject* inplace_rshift(PyObject* other); + PyObject* inplace_and(PyObject* other); + PyObject* inplace_or(PyObject* other); + PyObject* inplace_xor(PyObject* other); + private: // noncopyable, without the size bloat instance(const instance&); void operator=(const instance&); @@ -178,6 +191,18 @@ class class_t PyObject* instance_number_oct(PyObject*) const; PyObject* instance_number_hex(PyObject*) const; + PyObject* instance_number_inplace_add(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_subtract(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_multiply(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_divide(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_remainder(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_power(PyObject*, PyObject*, PyObject*) const; + PyObject* instance_number_inplace_lshift(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_rshift(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_and(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_or(PyObject*, PyObject*) const; + PyObject* instance_number_inplace_xor(PyObject*, PyObject*) const; + private: // Implement rich comparisons PyObject* instance_lt(PyObject*, PyObject*) const; PyObject* instance_le(PyObject*, PyObject*) const; @@ -493,6 +518,72 @@ PyObject* class_t::instance_number_hex(PyObject* obj) const return downcast(obj)->hex(); } +template +PyObject* class_t::instance_number_inplace_add(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_add(other); +} + +template +PyObject* class_t::instance_number_inplace_subtract(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_subtract(other); +} + +template +PyObject* class_t::instance_number_inplace_multiply(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_multiply(other); +} + +template +PyObject* class_t::instance_number_inplace_divide(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_divide(other); +} + +template +PyObject* class_t::instance_number_inplace_remainder(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_remainder(other); +} + +template +PyObject* class_t::instance_number_inplace_power(PyObject* obj, PyObject* exponent, PyObject* modulus) const +{ + return downcast(obj)->inplace_power(exponent, modulus); +} + +template +PyObject* class_t::instance_number_inplace_lshift(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_lshift(other); +} + +template +PyObject* class_t::instance_number_inplace_rshift(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_rshift(other); +} + +template +PyObject* class_t::instance_number_inplace_and(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_and(other); +} + +template +PyObject* class_t::instance_number_inplace_or(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_or(other); +} + +template +PyObject* class_t::instance_number_inplace_xor(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->inplace_xor(other); +} + template PyObject* class_t::instance_lt(PyObject* obj, PyObject* other) const { diff --git a/include/boost/python/detail/types.hpp b/include/boost/python/detail/types.hpp index 2d0d0f6b..954e0213 100644 --- a/include/boost/python/detail/types.hpp +++ b/include/boost/python/detail/types.hpp @@ -57,7 +57,11 @@ class type_object_base : public python_type number_positive, number_absolute, number_nonzero, number_invert, number_lshift, number_rshift, number_and, number_xor, number_or, number_coerce, number_int, number_long, number_float, number_oct, - number_hex + number_hex, number_inplace_add, number_inplace_subtract, + number_inplace_multiply, number_inplace_divide, + number_inplace_remainder, number_inplace_power, + number_inplace_lshift, number_inplace_rshift, + number_inplace_and, number_inplace_or, number_inplace_xor }; void enable(capability); @@ -116,6 +120,18 @@ class type_object_base : public python_type virtual PyObject* instance_number_oct(PyObject*) const; virtual PyObject* instance_number_hex(PyObject*) const; + virtual PyObject* instance_number_inplace_add(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_subtract(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_multiply(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_divide(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_remainder(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_power(PyObject*, PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_lshift(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_rshift(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_and(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_or(PyObject*, PyObject*) const; + virtual PyObject* instance_number_inplace_xor(PyObject*, PyObject*) const; + public: // Callbacks for rich comparisons virtual PyObject* instance_lt(PyObject*, PyObject*) const; virtual PyObject* instance_le(PyObject*, PyObject*) const; diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index 373bbde4..1ad88ab6 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -35,12 +35,13 @@ // than MSVC on Win32 // #if defined(_WIN32) -# ifdef __GNUC__ - +# if defined(__GNUC__) && defined(__CYGWIN__) +# if PY_MAJOR_VERSION < 2 || PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION <= 2 typedef int pid_t; -# define WORD_BIT 32 -# define hypot _hypot -# include +# define WORD_BIT 32 +# define hypot _hypot +# include +# endif # if !defined(PY_MAJOR_VERSION) || PY_MAJOR_VERSION < 2 # define HAVE_CLOCK # define HAVE_STRFTIME @@ -71,6 +72,13 @@ typedef int pid_t; # define _MSC_VER 900 # endif +# include +# undef hypot // undo the evil #define left by Python. + +# elif defined(__BORLANDC__) +# include +# undef HAVE_HYPOT +# define HAVE_HYPOT 1 # elif defined(_MSC_VER) # include // prevents Python.h from defining LONGLONG_MAX, LONGLONG_MIN, and ULONGLONG_MAX # endif @@ -95,4 +103,6 @@ typedef int pid_t; #ifdef __MWERKS__ # pragma warn_possunwant off +#elif _MSC_VER +# pragma warning(disable:4786) #endif diff --git a/src/classes.cpp b/src/classes.cpp index a44c3c0a..75f8a01a 100644 --- a/src/classes.cpp +++ b/src/classes.cpp @@ -766,6 +766,64 @@ PyObject* instance::ge(PyObject* other) return callback::call_method(this, "__ge__", other); } +PyObject* instance::inplace_add(PyObject* other) +{ + return callback::call_method(this, "__iadd__", other); +} + +PyObject* instance::inplace_subtract(PyObject* other) +{ + return callback::call_method(this, "__isub__", other); +} + +PyObject* instance::inplace_multiply(PyObject* other) +{ + return callback::call_method(this, "__imul__", other); +} + +PyObject* instance::inplace_divide(PyObject* other) +{ + return callback::call_method(this, "__idiv__", other); +} + +PyObject* instance::inplace_remainder(PyObject* other) +{ + return callback::call_method(this, "__imod__", other); +} + +PyObject* instance::inplace_power(PyObject* exponent, PyObject* modulus) +{ + if (modulus == Py_None) + return callback::call_method(this, "__ipow__", exponent); + else + return callback::call_method(this, "__ipow__", exponent, modulus); +} + +PyObject* instance::inplace_lshift(PyObject* other) +{ + return callback::call_method(this, "__ilshift__", other); +} + +PyObject* instance::inplace_rshift(PyObject* other) +{ + return callback::call_method(this, "__irshift__", other); +} + +PyObject* instance::inplace_and(PyObject* other) +{ + return callback::call_method(this, "__iand__", other); +} + +PyObject* instance::inplace_or(PyObject* other) +{ + return callback::call_method(this, "__ior__", other); +} + +PyObject* instance::inplace_xor(PyObject* other) +{ + return callback::call_method(this, "__ixor__", other); +} + namespace { struct named_capability { @@ -783,6 +841,17 @@ namespace { { "__le__", detail::type_object_base::richcompare }, { "__eq__", detail::type_object_base::richcompare }, { "__ne__", detail::type_object_base::richcompare }, + { "__iadd__", detail::type_object_base::number_inplace_add }, + { "__isub__", detail::type_object_base::number_inplace_subtract }, + { "__imul__", detail::type_object_base::number_inplace_multiply }, + { "__idiv__", detail::type_object_base::number_inplace_divide }, + { "__imod__", detail::type_object_base::number_inplace_remainder }, + { "__ipow__", detail::type_object_base::number_inplace_power }, + { "__ilshift__", detail::type_object_base::number_inplace_lshift }, + { "__irshift__", detail::type_object_base::number_inplace_rshift }, + { "__iand__", detail::type_object_base::number_inplace_and }, + { "__ixor__", detail::type_object_base::number_inplace_xor }, + { "__ior__", detail::type_object_base::number_inplace_or }, { "__repr__", detail::type_object_base::repr }, { "__str__", detail::type_object_base::str }, { "__call__", detail::type_object_base::call }, diff --git a/src/gen_arg_tuple_size.py b/src/gen_arg_tuple_size.py new file mode 100644 index 00000000..68e379cb --- /dev/null +++ b/src/gen_arg_tuple_size.py @@ -0,0 +1,132 @@ +# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +# distribute this software is granted provided this copyright notice appears +# in all copies. This software is provided "as is" without express or implied +# warranty, and with no claim as to its suitability for any purpose. +# +# This work was funded in part by Lawrence Berkeley National Labs + +from gen_function import * +import string + +header = '''// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for %d-argument member functions and %d-argument free +// functions by gen_arg_tuple_size.python +''' + +_cv_qualifiers = ('', ' const', ' volatile', ' const volatile') + +def gen_arg_tuple_size(member_function_args, free_function_args = None): + if free_function_args is None: + free_function_args = member_function_args + 1 + + return_none = '''; + return detail::none();''' + + return (header % (member_function_args, free_function_args) + + ''' +#ifndef ARG_TUPLE_SIZE_DWA20011201_HPP +# define ARG_TUPLE_SIZE_DWA20011201_HPP + +namespace boost { namespace python { namespace detail { + +// Computes (at compile-time) the number of elements that a Python +// argument tuple must have in order to be passed to a wrapped C++ +// (member) function of the given type. +template struct arg_tuple_size; + +# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__BORLANDC__) + +''' + + gen_functions( +'''template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = %n); +}; + +''', free_function_args) + + + '\n' + + gen_functions( +'''template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = %+); +}; + +''', member_function_args, '') + + +'''# else + +// We will use the "sizeof() trick" to work around the lack of +// partial specialization in MSVC6 and its broken-ness in borland. +// See http://opensource.adobe.com or +// http://groups.yahoo.com/group/boost/message/5441 for +// more examples + +// This little package is used to transmit the number of arguments +// from the helper functions below to the sizeof() expression below. +// Because we can never have an array of fewer than 1 element, we +// add 1 to n and then subtract 1 from the result of sizeof() below. +template +struct char_array +{ + char elements[n+1]; +}; + +// The following helper functions are never actually called, since +// they are only used within a sizeof() expression, but the type of +// their return value is used to discriminate between various free +// and member function pointers at compile-time. + +''' + + gen_functions( +'''template +char_array<%n> arg_tuple_size_helper(R (*)(%(A%+%:, %))); + +''', free_function_args) + + + reduce(lambda x,y: x+'\n'+y + , map( + lambda cv: gen_functions( +'''template +char_array<%+> arg_tuple_size_helper(R (A0::*)(%(A%+%:, %))%1); + +''', member_function_args, cv) + , _cv_qualifiers)) + + ''' +template +struct arg_tuple_size +{ + // The sizeof() magic happens here + BOOST_STATIC_CONSTANT(std::size_t, value + = sizeof(arg_tuple_size_helper(F(0)).elements) - 1); +}; +# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +}}} // namespace boost::python::detail + +#endif // ARG_TUPLE_SIZE_DWA20011201_HPP +''') + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + member_function_args = 5 + free_function_args = 6 + else: + member_function_args = int(sys.argv[1]) + if len(sys.argv) > 2: + free_function_args = int(sys.argv[2]) + else: + free_function_args = member_function_args + + print gen_arg_tuple_size(member_function_args, free_function_args) + + diff --git a/src/gen_function.py b/src/gen_function.py index ac24ac18..dba53c3b 100644 --- a/src/gen_function.py +++ b/src/gen_function.py @@ -1,3 +1,60 @@ +r""" +>>> template = ''' template +... static PyObject* call( %1(T::*pmf)(%(A%+%:, %))%2, PyObject* args, PyObject* ) { +... PyObject* self; +... %( PyObject* a%+; +... %) if (!PyArg_ParseTuple(args, const_cast("O%(O%)"), &self%(, &a%+%))) +... return 0; +... T& target = from_python(self, type()); +... %3to_python((target.*pmf)(%( +... from_python(a%+, type())%:,%) +... ));%4 +... }''' + +>>> print gen_function(template, 0, 'R ', '', 'return ', '') + template + static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* ) { + PyObject* self; + if (!PyArg_ParseTuple(args, const_cast("O"), &self)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)( + )); + } + +>>> print gen_function(template, 2, 'R ', '', 'return ', '') + template + static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)( + from_python(a1, type()), + from_python(a2, type()) + )); + } + +>>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();') + template + static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) + return 0; + T& target = from_python(self, type()); + to_python((target.*pmf)( + from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()) + )); + return none(); + } +""" import string def _find(s, sub, start=0, end=None): @@ -35,19 +92,19 @@ def _gen_common_key(key, n, args, fill = _raise_no_argument): else: return key -def _gen_arg(template, n, args, delimiter = '%', fill = _raise_no_argument): +def _gen_arg(template, n, args, fill = _raise_no_argument): result = '' i = 0 while i < len(template): # until the template is consumed - # consume everything up to the first delimiter - delimiter_pos = _find(template, delimiter, i) + # consume everything up to the first '%' + delimiter_pos = _find(template, '%', i) result = result + template[i:delimiter_pos] - # The start position of whatever comes after the delimiter+key + # The start position of whatever comes after the '%'+key start = delimiter_pos + 2 key = template[start - 1 : start] # the key character. If there were no - # delimiters left, key will be empty + # '%'s left, key will be empty if 0 and key == 'n': result = result + `n` @@ -64,7 +121,7 @@ def gen_function(template, n, *args, **keywords): Generate a function declaration based on the given template. Sections of the template between '%(', '%)' pairs are repeated n times. If '%:' - appears in the middle, it denotes the beginning of a delimiter. + appears in the middle, it denotes the beginning of a '%'. Sections of the template between '%{', '%}' pairs are ommitted if n == 0. @@ -95,7 +152,7 @@ def gen_function(template, n, *args, **keywords): for example, >>> gen_function('%1 abc%x(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void') - 'void abc2(int a1, int a2); // all args are ints' + 'void abc2(int a0, int a1); // all args are ints' >>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x') 'x abc();' @@ -109,102 +166,54 @@ def gen_function(template, n, *args, **keywords): >>> gen_function('abc%[k%:v%]', 0, fill = lambda key, n, args, value = None: '<' + key + ',' + value + '>') 'abc' - >>> template = ''' template - ... static PyObject* call( %1(T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) { - ... PyObject* self; - ... %( PyObject* a%n; - ... %) if (!PyArg_ParseTuple(args, const_cast("O%(O%)"), &self%(, &a%n%))) - ... return 0; - ... T& target = from_python(self, type()); - ... %3to_python((target.*pmf)(%( - ... from_python(a%n, type())%:,%) - ... ));%4 - ... }''' - - >>> print gen_function(template, 0, 'R ', '', 'return ', '') - template - static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - if (!PyArg_ParseTuple(args, const_cast("O"), &self)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)( - )); - } - - >>> print gen_function(template, 2, 'R ', '', 'return ', '') - template - static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)( - from_python(a1, type()), - from_python(a2, type()) - )); - } - - >>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();') - template - static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) - return 0; - T& target = from_python(self, type()); - to_python((target.*pmf)( - from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()) - )); - return none(); - } """ - delimiter = keywords.get('delimiter', '%') + expand = (lambda s, n = n: + apply(gen_function, (s, n) + args, keywords)) + fill = keywords.get('fill', _raise_no_argument); result = '' i = 0 while i < len(template): # until the template is consumed - # consume everything up to the first delimiter - delimiter_pos = _find(template, delimiter, i) + # consume everything up to the first '%' + delimiter_pos = _find(template, '%', i) result = result + template[i:delimiter_pos] - # The start position of whatever comes after the delimiter+key + # The start position of whatever comes after the '%'+key start = delimiter_pos + 2 key = template[start - 1 : start] # the key character. If there were no - # delimiters left, key will be empty + # '%'s left, key will be empty pairs = { '(':')', '{':'}', '[':']' } if key in pairs.keys(): - end = string.find(template, delimiter + pairs[key], start) - assert end >= 0, "Matching '" + delimiter + pairs[key] +"' not found!" + end = string.find(template, '%' + pairs[key], start) + assert end >= 0, "Matching '" + '%' + pairs[key] +"' not found!" delimiter_pos = end if key == '{': if n > 0: - result = result + gen_function(template[start:end], n, args, delimiter) + result = result + expand(template[start:end]) else: - separator_pos = _find(template, delimiter + ':', - start, end) + separator_pos = _find(template, '%:', start, end) remainder = template[separator_pos+2 : end] if key == '(': - for x in range(1, n + 1): - result = result + _gen_arg(template[start:separator_pos], x, args, - delimiter) - if x != n: - result = result + remainder + for x in range(n): + + iteration = expand( + template[start:separator_pos], x) + + result = result + expand(iteration, x) + + if x != n - 1: + result = result + expand(remainder, x) else: - result = result + fill(template[start:separator_pos], n, args, value = remainder) + function_result = fill( + template[start:separator_pos], n, args, value = remainder) + result = result + expand(function_result) else: - result = result + _gen_common_key(key, n, args, fill) + result = result + expand(_gen_common_key(key, n, args, fill)) i = delimiter_pos + 2 @@ -218,8 +227,8 @@ def gen_functions(template, n, *args, **keywords): >>> print gen_functions('%1 abc(%(int a%n%:, %));%{ // all args are ints%}\n', 2, 'void'), void abc(); - void abc(int a1); // all args are ints - void abc(int a1, int a2); // all args are ints + void abc(int a0); // all args are ints + void abc(int a0, int a1); // all args are ints """ fill = keywords.get('fill', _raise_no_argument);