Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r54919 - in trunk/libs/python: src/converter test
From: rwgk_at_[hidden]
Date: 2009-07-13 01:16:35


Author: rwgk
Date: 2009-07-13 01:16:34 EDT (Mon, 13 Jul 2009)
New Revision: 54919
URL: http://svn.boost.org/trac/boost/changeset/54919

Log:
boost::python: unsigned converter fix by Anderson Lizardo (https://svn.boost.org/trac/boost/ticket/3189)
Text files modified:
   trunk/libs/python/src/converter/builtin_converters.cpp | 25 +++++++++++++++--
   trunk/libs/python/test/test_builtin_converters.py | 56 ++++++++++++++++++++++++++++++++++-----
   2 files changed, 69 insertions(+), 12 deletions(-)

Modified: trunk/libs/python/src/converter/builtin_converters.cpp
==============================================================================
--- trunk/libs/python/src/converter/builtin_converters.cpp (original)
+++ trunk/libs/python/src/converter/builtin_converters.cpp 2009-07-13 01:16:34 EDT (Mon, 13 Jul 2009)
@@ -155,10 +155,27 @@
   {
       static T extract(PyObject* intermediate)
       {
- return numeric_cast<T>(
- PyLong_Check(intermediate)
- ? PyLong_AsUnsignedLong(intermediate)
- : PyInt_AS_LONG(intermediate));
+ if (PyLong_Check(intermediate)) {
+ // PyLong_AsUnsignedLong() checks for negative overflow, so no
+ // need to check it here.
+ unsigned long result = PyLong_AsUnsignedLong(intermediate);
+ if (PyErr_Occurred())
+ throw_error_already_set();
+ return numeric_cast<T>(result);
+ } else {
+ // None of PyInt_AsUnsigned*() functions check for negative
+ // overflow, so use PyInt_AS_LONG instead and check if number is
+ // negative, issuing the exception appropriately.
+ long result = PyInt_AS_LONG(intermediate);
+ if (PyErr_Occurred())
+ throw_error_already_set();
+ if (result < 0) {
+ PyErr_SetString(PyExc_OverflowError, "can't convert negative"
+ " value to unsigned");
+ throw_error_already_set();
+ }
+ return numeric_cast<T>(result);
+ }
       }
   };
 

Modified: trunk/libs/python/test/test_builtin_converters.py
==============================================================================
--- trunk/libs/python/test/test_builtin_converters.py (original)
+++ trunk/libs/python/test/test_builtin_converters.py 2009-07-13 01:16:34 EDT (Mon, 13 Jul 2009)
@@ -4,6 +4,24 @@
 r"""
>>> from builtin_converters_ext import *
 
+# Use ctypes to get native C type sizes
+>>> from ctypes import sizeof, c_char, c_short, c_int, c_long, c_longlong
+>>> def test_values_signed(t):
+... base = 2 ** (8 * sizeof(t) - 1)
+... return [[-base, -1, 1, base - 1], [-base - 1, base]]
+>>> def test_values_unsigned(t):
+... base = 2 ** (8 * sizeof(t))
+... return [[1, base - 1], [-1L, -1, base]]
+>>> def should_pass(method, values):
+... result = map(method, values)
+... if result != values:
+... print "Got %s but expected %s" % (result, values)
+>>> def test_overflow(method, values):
+... for v in values:
+... try: method(v)
+... except OverflowError: pass
+... else: print "OverflowError expected"
+
 # Synthesize idendity functions in case long long not supported
>>> if not 'rewrap_value_long_long' in dir():
 ... def rewrap_value_long_long(x): return long(x)
@@ -62,15 +80,37 @@
 42L
 
    show that we have range checking.
-
->>> try: rewrap_value_unsigned_short(-42)
-... except OverflowError: pass
-... else: print 'expected an OverflowError!'
-
->>> try: rewrap_value_int(sys.maxint * 2)
-... except OverflowError: pass
-... else: print 'expected an OverflowError!'
 
+>>> should_pass(rewrap_value_signed_char, test_values_signed(c_char)[0])
+>>> should_pass(rewrap_value_short, test_values_signed(c_short)[0])
+>>> should_pass(rewrap_value_int, test_values_signed(c_int)[0])
+>>> should_pass(rewrap_value_long, test_values_signed(c_long)[0])
+>>> should_pass(rewrap_value_long_long, test_values_signed(c_longlong)[0])
+
+>>> should_pass(rewrap_value_unsigned_char, test_values_unsigned(c_char)[0])
+>>> should_pass(rewrap_value_unsigned_short, test_values_unsigned(c_short)[0])
+>>> should_pass(rewrap_value_unsigned_int, test_values_unsigned(c_int)[0])
+>>> should_pass(rewrap_value_unsigned_long, test_values_unsigned(c_long)[0])
+>>> should_pass(rewrap_value_unsigned_long_long,
+... test_values_unsigned(c_longlong)[0])
+
+>>> test_overflow(rewrap_value_signed_char, test_values_signed(c_char)[1])
+>>> test_overflow(rewrap_value_short, test_values_signed(c_short)[1])
+>>> test_overflow(rewrap_value_int, test_values_signed(c_int)[1])
+>>> test_overflow(rewrap_value_long, test_values_signed(c_long)[1])
+>>> test_overflow(rewrap_value_long_long, test_values_signed(c_longlong)[1])
+
+>>> test_overflow(rewrap_value_unsigned_char, test_values_unsigned(c_char)[1])
+>>> test_overflow(rewrap_value_unsigned_short, test_values_unsigned(c_short)[1])
+>>> test_overflow(rewrap_value_unsigned_int, test_values_unsigned(c_int)[1])
+>>> test_overflow(rewrap_value_unsigned_long, test_values_unsigned(c_long)[1])
+
+# Exceptionally for PyLong_AsUnsignedLongLong(), a negative value raises
+# TypeError on Python versions prior to 2.7
+>>> for v in test_values_unsigned(c_longlong)[1]:
+... try: rewrap_value_unsigned_long_long(v)
+... except (OverflowError, TypeError): pass
+... else: print "OverflowError or TypeError expected"
 
>>> assert abs(rewrap_value_float(4.2) - 4.2) < .000001
>>> rewrap_value_double(4.2) - 4.2


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk