From eea6a477015d2d4074da2fb7b8b6bb713a4f2ec3 Mon Sep 17 00:00:00 2001 From: Lisandro Dalcin Date: Fri, 23 Apr 2010 13:02:07 -0300 Subject: [PATCH] support arbitrarily sized typedef integral types --- Cython/Compiler/PyrexTypes.py | 52 ++++++++---- tests/run/cpp_nonstdint.h | 89 ++++++++++++++++++++ tests/run/cpp_nonstdint.pyx | 149 ++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 17 deletions(-) create mode 100644 tests/run/cpp_nonstdint.h create mode 100644 tests/run/cpp_nonstdint.pyx diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 83005922..37e1cd04 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -721,8 +721,8 @@ static CYTHON_INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject *); """, impl=""" static CYTHON_INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) { - const %(type)s neg_one = (%(type)s)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; + const %(type)s neg_one = (%(type)s)-1, const_zero = (%(type)s)0; + const int is_unsigned = const_zero < neg_one; if (sizeof(%(type)s) == sizeof(char)) { if (is_unsigned) return (%(type)s)__Pyx_PyInt_AsUnsignedChar(x); @@ -748,17 +748,28 @@ static CYTHON_INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) { return (%(type)s)__Pyx_PyInt_AsUnsignedLongLong(x); else return (%(type)s)__Pyx_PyInt_AsSignedLongLong(x); -#if 0 - } else if (sizeof(%(type)s) > sizeof(short) && - sizeof(%(type)s) < sizeof(int)) { /* __int32 ILP64 ? */ - if (is_unsigned) - return (%(type)s)__Pyx_PyInt_AsUnsignedInt(x); - else - return (%(type)s)__Pyx_PyInt_AsSignedInt(x); -#endif + } else { + %(type)s val; + PyObject *v = __Pyx_PyNumber_Int(x); + #if PY_VERSION_HEX < 0x03000000 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } + return (%(type)s)-1; } - PyErr_SetString(PyExc_TypeError, "%(TypeName)s"); - return (%(type)s)-1; } """) @@ -768,20 +779,27 @@ static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s); """, impl=""" static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) { - const %(type)s neg_one = (%(type)s)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(%(type)s) < sizeof(long)) { + const %(type)s neg_one = (%(type)s)-1, const_zero = (%(type)s)0; + const int is_unsigned = const_zero < neg_one; + if ((sizeof(%(type)s) == sizeof(char)) || + (sizeof(%(type)s) == sizeof(short))) { return PyInt_FromLong((long)val); - } else if (sizeof(%(type)s) == sizeof(long)) { + } else if ((sizeof(%(type)s) == sizeof(int)) || + (sizeof(%(type)s) == sizeof(long))) { if (is_unsigned) return PyLong_FromUnsignedLong((unsigned long)val); else return PyInt_FromLong((long)val); - } else { /* (sizeof(%(type)s) > sizeof(long)) */ + } else if (sizeof(%(type)s) == sizeof(PY_LONG_LONG)) { if (is_unsigned) return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val); else return PyLong_FromLongLong((PY_LONG_LONG)val); + } else { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + return _PyLong_FromByteArray(bytes, sizeof(%(type)s), + little, !is_unsigned); } } """) diff --git a/tests/run/cpp_nonstdint.h b/tests/run/cpp_nonstdint.h new file mode 100644 index 00000000..480115ae --- /dev/null +++ b/tests/run/cpp_nonstdint.h @@ -0,0 +1,89 @@ +// -*- c++ -*- +#include +template +class Integral { + + unsigned char bytes[N]; + + public: + Integral() { + for (unsigned int i=0; i(const Integral &I) const + { return cmp(I) > 0; } + bool operator<=(const Integral &I) const + { return cmp(I) <= 0; } + bool operator>=(const Integral &I) const + { return cmp(I) >= 0; } + bool operator==(const Integral &I) const + { return cmp(I) == 0; } + bool operator!=(const Integral &I) const + { return cmp(I) != 0; } + + private: + static bool is_le() { + int one = 1; + return (int)*(unsigned char *)&one; + } + static unsigned int lsb() { + return is_le() ? 0 : N-1; + } + static unsigned int msb() { + return is_le() ? N-1 : 0; + } + int cmp(const Integral& J) const { + const Integral& I = *this; + unsigned char sI = I.bytes[msb()] & 0x80; + unsigned char sJ = J.bytes[msb()] & 0x80; + if (sI > sJ) return -1; + if (sI < sJ) return +1; + unsigned char bI = I.bytes[msb()] & 0x7F; + unsigned char bJ = J.bytes[msb()] & 0x7F; + int cmpabs = 0; + if (bI < bJ) + cmpabs = -1; + else if (bI > bJ) + cmpabs = +1; + else { + int incr = is_le() ? -1 : 1; + unsigned int i = msb() + incr; + while (i != lsb()) { + if (I.bytes[i] < J.bytes[i]) + { cmpabs = -1; break; } + if (I.bytes[i] > J.bytes[i]) + { cmpabs = +1; break; } + i += incr; + } + } + if (sI) return -cmpabs; + else return +cmpabs; + } + +}; + +typedef Integral<3> Int24; +typedef Integral<7> Int56; +typedef Integral<11> Int88; +typedef Integral<64> Int512; diff --git a/tests/run/cpp_nonstdint.pyx b/tests/run/cpp_nonstdint.pyx new file mode 100644 index 00000000..17c6a23e --- /dev/null +++ b/tests/run/cpp_nonstdint.pyx @@ -0,0 +1,149 @@ +cdef extern from "cpp_nonstdint.h": + ctypedef int Int24 + ctypedef int Int56 + ctypedef int Int88 + ctypedef int Int512 + +cdef object one = 1 + +# --- + +INT24_MAX = (one<<(sizeof(Int24)*8-1))-one +INT24_MIN = (-INT24_MAX-one) + +def test_int24(Int24 i): + """ + >>> str(test_int24(-1)) + '-1' + >>> str(test_int24(0)) + '0' + >>> str(test_int24(1)) + '1' + + >>> test_int24(INT24_MAX) == INT24_MAX + True + >>> test_int24(INT24_MIN) == INT24_MIN + True + + >>> test_int24(INT24_MIN-1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + >>> test_int24(INT24_MAX+1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + + >>> test_int24("123") #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: ... + """ + return i + +# --- + +INT56_MAX = (one<<(sizeof(Int56)*8-1))-one +INT56_MIN = (-INT56_MAX-one) + +def test_int56(Int56 i): + """ + >>> str(test_int56(-1)) + '-1' + >>> str(test_int56(0)) + '0' + >>> str(test_int56(1)) + '1' + + >>> test_int56(INT56_MAX) == INT56_MAX + True + >>> test_int56(INT56_MIN) == INT56_MIN + True + + >>> test_int56(INT56_MIN-1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + >>> test_int56(INT56_MAX+1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + + >>> test_int56("123") #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: ... + """ + return i + +# --- + +INT88_MAX = (one<<(sizeof(Int88)*8-1))-one +INT88_MIN = (-INT88_MAX-one) + +def test_int88(Int88 i): + """ + >>> str(test_int88(-1)) + '-1' + >>> str(test_int88(0)) + '0' + >>> str(test_int88(1)) + '1' + + >>> test_int88(INT88_MAX) == INT88_MAX + True + >>> test_int88(INT88_MIN) == INT88_MIN + True + + >>> test_int88(INT88_MIN-1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + >>> test_int88(INT88_MAX+1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + + >>> test_int88("123") #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: ... + """ + return i + +# --- + +INT512_MAX = (one<<(sizeof(Int512)*8-1))-one +INT512_MIN = (-INT512_MAX-one) + +def test_int512(Int512 i): + """ + >>> str(test_int512(-1)) + '-1' + >>> str(test_int512(0)) + '0' + >>> str(test_int512(1)) + '1' + + >>> test_int512(INT512_MAX) == INT512_MAX + True + >>> test_int512(INT512_MIN) == INT512_MIN + True + + >>> test_int512(INT512_MIN-1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + >>> test_int512(INT512_MAX+1) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + OverflowError: ... + + >>> test_int512("123") #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + TypeError: ... + """ + return i + +# --- -- 2.26.2