Commit eea6a477 authored by Lisandro Dalcin's avatar Lisandro Dalcin

support arbitrarily sized typedef integral types

parent 067c4694
......@@ -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);
}
}
""")
......
// -*- c++ -*-
#include <stdio.h>
template<unsigned int N>
class Integral {
unsigned char bytes[N];
public:
Integral() {
for (unsigned int i=0; i<N; i++)
bytes[i] = 0;
}
Integral(const Integral &I) {
for (unsigned int i=0; i<N; i++)
bytes[i] = I.bytes[i];
}
Integral(signed char I) {
unsigned char p = (I<0) ? 0xFF : 0x00;
for (unsigned int i=0; i<N; i++)
bytes[i] = p;
bytes[lsb()] = *(unsigned char*)&I;
}
operator signed char() const {
return *(signed char*)&bytes[lsb()];
}
Integral& operator=(const Integral &I) {
for (unsigned int i=0; i<N; i++)
bytes[i] = I.bytes[i];
return *this;
}
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; }
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;
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
# ---
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment