Index: Modules/_ctypes/_ctypes.c =================================================================== --- Modules/_ctypes/_ctypes.c (revision 78631) +++ Modules/_ctypes/_ctypes.c (working copy) @@ -2029,6 +2029,8 @@ return NULL; } }; + /* Machine arithmetics support */ + result->tp_as_number = _PyCData_NumberMethods(proto_str); return (PyObject *)result; } Index: Modules/_ctypes/ctypes.h =================================================================== --- Modules/_ctypes/ctypes.h (revision 78631) +++ Modules/_ctypes/ctypes.h (working copy) @@ -63,15 +63,22 @@ */ union value { char c[16]; + signed char b; + unsigned char B; + short h; + unsigned short H; short s; int i; + unsigned int I; long l; + unsigned long L; float f; double d; #ifdef HAVE_LONG_LONG PY_LONG_LONG ll; #endif long double D; + long double g; }; /* @@ -441,6 +448,9 @@ extern PyObject *_ctypes_ptrtype_cache; PyObject *_ctypes_get_errobj(int **pspace); +extern PyNumberMethods* +_PyCData_NumberMethods(const char *proto); + #ifdef MS_WIN32 extern PyObject *ComError; #endif Index: Modules/_ctypes/cnumber.c =================================================================== --- Modules/_ctypes/cnumber.c (revision 0) +++ Modules/_ctypes/cnumber.c (revision 0) @@ -0,0 +1,105 @@ +/* Machine arithmetics support */ +#include "Python.h" + +#include +#ifdef MS_WIN32 +#include +#endif +#include "ctypes.h" +#include + +#define EXPR_add(code, x, y) x + y +#define EXPR_subtract(code, x, y) x - y +#define EXPR_multiply(code, x, y) x * y +#define EXPR_divide(code, x, y) x / y +#define EXPR_remainder(code, x, y) x % y + +#define EXPR_positive(x) +x +#define EXPR_negative(x) -x + +#define SUFFIX_d(x) x +#define SUFFIX_f(x) x ## f +#define SUFFIX_g(x) x ## l + + +#define DEF_BINOP(code, opname) \ +static PyObject * \ +code##_##opname(CDataObject *x, CDataObject *y) \ +{ \ + CDataObject *result; \ + result = (CDataObject *)Py_TYPE(x)->tp_new(x->ob_type, NULL, NULL); \ + if (result != NULL) \ + result->b_value.code = EXPR_##opname(code, x->b_value.code, y->b_value.code); \ + return (PyObject *)result; \ +} +#define DEF_UNOP(code, opname) \ +static PyObject * \ +code##_##opname(CDataObject *x) \ +{\ + CDataObject *result; \ + result = (CDataObject *)Py_TYPE(x)->tp_new(x->ob_type, NULL, NULL); \ + if (result != NULL)\ + result->b_value.code = EXPR_##opname(x->b_value.code); \ + return (PyObject *)result; \ +} + +/* NB: The order must match PyNumberMethods order */ +#define BINOP_LIST(code) \ + BIN(code, add) \ + BIN(code, subtract) \ + BIN(code, multiply) \ + BIN(code, divide) \ + BIN(code, remainder) + +/* NB: The order must match PyNumberMethods order */ +#define UNOP_LIST(code) \ + UN(code, negative) \ + UN(code, positive) + +#define BITOP_LIST(code) + +#define INT_CODES C(b)C(B)C(h)C(H)C(i)C(I)C(l)C(L) +#define FLOAT_CODES C(d)C(f)C(g) +#define C(x) BINOP_LIST(x) +#define BIN DEF_BINOP +INT_CODES +#undef EXPR_remainder +#define EXPR_remainder(code, x, y) SUFFIX_ ## code(fmod)(x, y) +FLOAT_CODES +#undef BIN +#undef C + +#define C(x) UNOP_LIST(x) +#define UN DEF_UNOP +INT_CODES FLOAT_CODES +#undef UN +#undef C + +struct tableentry { + char *code; + PyNumberMethods methods; +}; + +struct tableentry +number_methods_table[] = { +#define BIN(code, opname) (binaryfunc)code##_##opname, +#define UN(code, opname) (unaryfunc)code##_##opname, +#define C(code) {#code, {BINOP_LIST(code)0,0,UNOP_LIST(code)}}, + INT_CODES FLOAT_CODES +#undef C +#undef UN +#undef BIN + {0, {0}} /* centinel */ +}; + +PyNumberMethods * +_PyCData_NumberMethods(const char *proto) +{ + struct tableentry *entry; + + for (entry = number_methods_table; entry->code; ++entry) { + if (*entry->code == *proto) + return &entry->methods; + } + return NULL; +} Index: Lib/ctypes/test/test_numbers.py =================================================================== --- Lib/ctypes/test/test_numbers.py (revision 78631) +++ Lib/ctypes/test/test_numbers.py (working copy) @@ -219,6 +219,61 @@ ## def test_perf(self): ## check_perf() +class NumberOpsTestCase(unittest.TestCase): + ctype = c_double + def test_arithmetics(self): + a = self.ctype(2) + b = self.ctype(1) + self.assertEqual((a + b).value, 3) + self.assertEqual((a - b).value, 1) + self.assertEqual((a / b).value, 2) + self.assertEqual((a % b).value, 0) + self.assertEqual((+a).value, 2) + + def test_negative(self): + a = self.ctype(2) + self.assertEqual((-a).value, -2) + +class UnsignedTest: + def test_negative(self): + a = self.ctype(1) + self.assertEqual((-a).value, 2**(8*sizeof(self.ctype)) - 1) + + +class ByteOpsTestCase(NumberOpsTestCase): + ctype = c_byte + +class UByteOpsTestCase(UnsignedTest, NumberOpsTestCase): + ctype = c_ubyte + +class ShortOpsTestCase(NumberOpsTestCase): + ctype = c_short + +class UShortOpsTestCase(UnsignedTest, NumberOpsTestCase): + ctype = c_ushort + +class IntOpsTestCase(NumberOpsTestCase): + ctype = c_int + +class UIntOpsTestCase(UnsignedTest, NumberOpsTestCase): + ctype = c_uint + +class LongOpsTestCase(NumberOpsTestCase): + ctype = c_long + +class ULongOpsTestCase(UnsignedTest, NumberOpsTestCase): + ctype = c_ulong + +class FloatOpsTestCase(NumberOpsTestCase): + ctype = c_float + +class LongdoubleOpsTestCase(NumberOpsTestCase): + ctype = c_longdouble + +class ByteOpsTestCase(NumberOpsTestCase): + ctype = c_byte + + from ctypes import _SimpleCData class c_int_S(_SimpleCData): _type_ = "i"