Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Slightly improve performance of :c:func:`PyLong_FromUnsignedLong`,
:c:func:`PyLong_FromUnsignedLongLong` and :c:func:`PyLong_FromSize_t`.
Patch by Sergey Fedoseev.
119 changes: 42 additions & 77 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ PyObject *_PyLong_One = NULL;
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
#define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS)

#ifdef COUNT_ALLOCS
Py_ssize_t _Py_quick_int_allocs, _Py_quick_neg_int_allocs;
Expand Down Expand Up @@ -78,6 +79,7 @@ maybe_small_long(PyLongObject *v)
}
#else
#define IS_SMALL_INT(ival) 0
#define IS_SMALL_UINT(ival) 0
#define get_small_int(ival) (Py_UNREACHABLE(), NULL)
#define maybe_small_long(val) (val)
#endif
Expand Down Expand Up @@ -378,32 +380,52 @@ PyLong_FromLong(long ival)
return (PyObject *)v;
}

#define PYLONG_FROM_UINT(INT_TYPE, ival) \
do { \
if (IS_SMALL_UINT(ival)) { \
return get_small_int((ival)); \
} \
/* Count the number of Python digits. */ \
Py_ssize_t ndigits = 0; \
INT_TYPE t = (ival); \
while (t) { \
++ndigits; \
t >>= PyLong_SHIFT; \
} \
PyLongObject *v = _PyLong_New(ndigits); \
if (v == NULL) { \
return NULL; \
} \
digit *p = v->ob_digit; \
while ((ival)) { \
*p++ = (digit)((ival) & PyLong_MASK); \
(ival) >>= PyLong_SHIFT; \
} \
return (PyObject *)v; \
} while(0)

/* Create a new int object from a C unsigned long int */

PyObject *
PyLong_FromUnsignedLong(unsigned long ival)
{
PyLongObject *v;
unsigned long t;
int ndigits = 0;
PYLONG_FROM_UINT(unsigned long, ival);
}

if (ival < PyLong_BASE)
return PyLong_FromLong(ival);
/* Count the number of Python digits. */
t = ival;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
}
v = _PyLong_New(ndigits);
if (v != NULL) {
digit *p = v->ob_digit;
while (ival) {
*p++ = (digit)(ival & PyLong_MASK);
ival >>= PyLong_SHIFT;
}
}
return (PyObject *)v;
/* Create a new int object from a C unsigned long long int. */

PyObject *
PyLong_FromUnsignedLongLong(unsigned long long ival)
{
PYLONG_FROM_UINT(unsigned long long, ival);
}

/* Create a new int object from a C size_t. */

PyObject *
PyLong_FromSize_t(size_t ival)
{
PYLONG_FROM_UINT(size_t, ival);
}

/* Create a new int object from a C double */
Expand Down Expand Up @@ -1186,34 +1208,6 @@ PyLong_FromLongLong(long long ival)
return (PyObject *)v;
}

/* Create a new int object from a C unsigned long long int. */

PyObject *
PyLong_FromUnsignedLongLong(unsigned long long ival)
{
PyLongObject *v;
unsigned long long t;
int ndigits = 0;

if (ival < PyLong_BASE)
return PyLong_FromLong((long)ival);
/* Count the number of Python digits. */
t = ival;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
}
v = _PyLong_New(ndigits);
if (v != NULL) {
digit *p = v->ob_digit;
while (ival) {
*p++ = (digit)(ival & PyLong_MASK);
ival >>= PyLong_SHIFT;
}
}
return (PyObject *)v;
}

/* Create a new int object from a C Py_ssize_t. */

PyObject *
Expand Down Expand Up @@ -1257,35 +1251,6 @@ PyLong_FromSsize_t(Py_ssize_t ival)
return (PyObject *)v;
}

/* Create a new int object from a C size_t. */

PyObject *
PyLong_FromSize_t(size_t ival)
{
PyLongObject *v;
size_t t;
int ndigits = 0;

if (ival < PyLong_BASE)
return PyLong_FromLong((long)ival);
/* Count the number of Python digits. */
t = ival;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
}
v = _PyLong_New(ndigits);
if (v != NULL) {
digit *p = v->ob_digit;
Py_SIZE(v) = ndigits;
while (ival) {
*p++ = (digit)(ival & PyLong_MASK);
ival >>= PyLong_SHIFT;
}
}
return (PyObject *)v;
}

/* Get a C long long int from an int object or any object that has an
__int__ method. Return -1 and set an error if overflow occurs. */

Expand Down