Skip to content

Commit c6734ee

Browse files
sir-sigurdgpshead
authored andcommitted
bpo-37802: Slightly improve perfomance of PyLong_FromUnsigned*() (GH-15192)
1 parent 8d88e8c commit c6734ee

File tree

2 files changed

+45
-77
lines changed

2 files changed

+45
-77
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Slightly improve performance of :c:func:`PyLong_FromUnsignedLong`,
2+
:c:func:`PyLong_FromUnsignedLongLong` and :c:func:`PyLong_FromSize_t`.
3+
Patch by Sergey Fedoseev.

Objects/longobject.c

Lines changed: 42 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ PyObject *_PyLong_One = NULL;
4343
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
4444

4545
#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
46+
#define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS)
4647

4748
#ifdef COUNT_ALLOCS
4849
Py_ssize_t _Py_quick_int_allocs, _Py_quick_neg_int_allocs;
@@ -78,6 +79,7 @@ maybe_small_long(PyLongObject *v)
7879
}
7980
#else
8081
#define IS_SMALL_INT(ival) 0
82+
#define IS_SMALL_UINT(ival) 0
8183
#define get_small_int(ival) (Py_UNREACHABLE(), NULL)
8284
#define maybe_small_long(val) (val)
8385
#endif
@@ -378,32 +380,52 @@ PyLong_FromLong(long ival)
378380
return (PyObject *)v;
379381
}
380382

383+
#define PYLONG_FROM_UINT(INT_TYPE, ival) \
384+
do { \
385+
if (IS_SMALL_UINT(ival)) { \
386+
return get_small_int((ival)); \
387+
} \
388+
/* Count the number of Python digits. */ \
389+
Py_ssize_t ndigits = 0; \
390+
INT_TYPE t = (ival); \
391+
while (t) { \
392+
++ndigits; \
393+
t >>= PyLong_SHIFT; \
394+
} \
395+
PyLongObject *v = _PyLong_New(ndigits); \
396+
if (v == NULL) { \
397+
return NULL; \
398+
} \
399+
digit *p = v->ob_digit; \
400+
while ((ival)) { \
401+
*p++ = (digit)((ival) & PyLong_MASK); \
402+
(ival) >>= PyLong_SHIFT; \
403+
} \
404+
return (PyObject *)v; \
405+
} while(0)
406+
381407
/* Create a new int object from a C unsigned long int */
382408

383409
PyObject *
384410
PyLong_FromUnsignedLong(unsigned long ival)
385411
{
386-
PyLongObject *v;
387-
unsigned long t;
388-
int ndigits = 0;
412+
PYLONG_FROM_UINT(unsigned long, ival);
413+
}
389414

390-
if (ival < PyLong_BASE)
391-
return PyLong_FromLong(ival);
392-
/* Count the number of Python digits. */
393-
t = ival;
394-
while (t) {
395-
++ndigits;
396-
t >>= PyLong_SHIFT;
397-
}
398-
v = _PyLong_New(ndigits);
399-
if (v != NULL) {
400-
digit *p = v->ob_digit;
401-
while (ival) {
402-
*p++ = (digit)(ival & PyLong_MASK);
403-
ival >>= PyLong_SHIFT;
404-
}
405-
}
406-
return (PyObject *)v;
415+
/* Create a new int object from a C unsigned long long int. */
416+
417+
PyObject *
418+
PyLong_FromUnsignedLongLong(unsigned long long ival)
419+
{
420+
PYLONG_FROM_UINT(unsigned long long, ival);
421+
}
422+
423+
/* Create a new int object from a C size_t. */
424+
425+
PyObject *
426+
PyLong_FromSize_t(size_t ival)
427+
{
428+
PYLONG_FROM_UINT(size_t, ival);
407429
}
408430

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

1189-
/* Create a new int object from a C unsigned long long int. */
1190-
1191-
PyObject *
1192-
PyLong_FromUnsignedLongLong(unsigned long long ival)
1193-
{
1194-
PyLongObject *v;
1195-
unsigned long long t;
1196-
int ndigits = 0;
1197-
1198-
if (ival < PyLong_BASE)
1199-
return PyLong_FromLong((long)ival);
1200-
/* Count the number of Python digits. */
1201-
t = ival;
1202-
while (t) {
1203-
++ndigits;
1204-
t >>= PyLong_SHIFT;
1205-
}
1206-
v = _PyLong_New(ndigits);
1207-
if (v != NULL) {
1208-
digit *p = v->ob_digit;
1209-
while (ival) {
1210-
*p++ = (digit)(ival & PyLong_MASK);
1211-
ival >>= PyLong_SHIFT;
1212-
}
1213-
}
1214-
return (PyObject *)v;
1215-
}
1216-
12171211
/* Create a new int object from a C Py_ssize_t. */
12181212

12191213
PyObject *
@@ -1257,35 +1251,6 @@ PyLong_FromSsize_t(Py_ssize_t ival)
12571251
return (PyObject *)v;
12581252
}
12591253

1260-
/* Create a new int object from a C size_t. */
1261-
1262-
PyObject *
1263-
PyLong_FromSize_t(size_t ival)
1264-
{
1265-
PyLongObject *v;
1266-
size_t t;
1267-
int ndigits = 0;
1268-
1269-
if (ival < PyLong_BASE)
1270-
return PyLong_FromLong((long)ival);
1271-
/* Count the number of Python digits. */
1272-
t = ival;
1273-
while (t) {
1274-
++ndigits;
1275-
t >>= PyLong_SHIFT;
1276-
}
1277-
v = _PyLong_New(ndigits);
1278-
if (v != NULL) {
1279-
digit *p = v->ob_digit;
1280-
Py_SIZE(v) = ndigits;
1281-
while (ival) {
1282-
*p++ = (digit)(ival & PyLong_MASK);
1283-
ival >>= PyLong_SHIFT;
1284-
}
1285-
}
1286-
return (PyObject *)v;
1287-
}
1288-
12891254
/* Get a C long long int from an int object or any object that has an
12901255
__int__ method. Return -1 and set an error if overflow occurs. */
12911256

0 commit comments

Comments
 (0)