Skip to content

Commit ed9be47

Browse files
committed
Add Missing fast path in PyLong_From*() functions for compact integers
1 parent 86c1a60 commit ed9be47

File tree

1 file changed

+61
-59
lines changed

1 file changed

+61
-59
lines changed

Objects/longobject.c

Lines changed: 61 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,65 @@ maybe_small_long(PyLongObject *v)
115115
if (PyErr_CheckSignals()) PyTryBlock \
116116
} while(0)
117117

118+
#define PYLONG_FROM_SIGNED(INT_TYPE, ival) \
119+
do { \
120+
if (IS_SMALL_INT(ival)) { \
121+
return get_small_int((sdigit)(ival)); \
122+
} \
123+
if (-(INT_TYPE)PyLong_MASK <= (ival) && (ival) <= (INT_TYPE)PyLong_MASK) { \
124+
return _PyLong_FromMedium((sdigit)(ival)); \
125+
} \
126+
/* Count digits (at least two - smaller cases were handled above). */ \
127+
INT_TYPE abs_ival = (ival) < 0 ? 0U-(INT_TYPE)(ival) : (INT_TYPE)(ival); \
128+
/* Do shift in two steps to avoid possible undefined behavior. */ \
129+
INT_TYPE t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT; \
130+
Py_ssize_t ndigits = 2; \
131+
while (t) { \
132+
++ndigits; \
133+
t >>= PyLong_SHIFT; \
134+
} \
135+
PyLongObject *v = _PyLong_New(ndigits); \
136+
if (v == NULL) { \
137+
return NULL; \
138+
} \
139+
digit *p = v->long_value.ob_digit; \
140+
_PyLong_SetSignAndDigitCount(v, (ival) < 0 ? -1 : 1, ndigits); \
141+
t = abs_ival; \
142+
while (t) { \
143+
*p++ = (digit)(t & PyLong_MASK); \
144+
t >>= PyLong_SHIFT; \
145+
} \
146+
return (PyObject *)v; \
147+
} while(0)
148+
149+
#define PYLONG_FROM_UINT(INT_TYPE, ival) \
150+
do { \
151+
if (IS_SMALL_UINT(ival)) { \
152+
return get_small_int((sdigit)(ival)); \
153+
} \
154+
if ((ival) <= PyLong_MASK) { \
155+
return _PyLong_FromMedium((sdigit)(ival)); \
156+
} \
157+
/* Count the number of Python digits. */ \
158+
Py_ssize_t ndigits = 0; \
159+
INT_TYPE t = (ival); \
160+
while (t) { \
161+
++ndigits; \
162+
t >>= PyLong_SHIFT; \
163+
} \
164+
PyLongObject *v = _PyLong_New(ndigits); \
165+
if (v == NULL) { \
166+
return NULL; \
167+
} \
168+
digit *p = v->long_value.ob_digit; \
169+
t = (ival); \
170+
while (t) { \
171+
*p++ = (digit)(t & PyLong_MASK); \
172+
t >>= PyLong_SHIFT; \
173+
} \
174+
return (PyObject *)v; \
175+
} while(0)
176+
118177
/* Normalize (remove leading zeros from) an int object.
119178
Doesn't attempt to free the storage--in most cases, due to the nature
120179
of the algorithms used, this could save at most be one word anyway. */
@@ -318,66 +377,9 @@ _PyLong_Negate(PyLongObject **x_p)
318377
PyObject *
319378
PyLong_FromLong(long ival)
320379
{
321-
PyLongObject *v;
322-
unsigned long abs_ival, t;
323-
int ndigits;
324-
325-
/* Handle small and medium cases. */
326-
if (IS_SMALL_INT(ival)) {
327-
return get_small_int((sdigit)ival);
328-
}
329-
if (-(long)PyLong_MASK <= ival && ival <= (long)PyLong_MASK) {
330-
return _PyLong_FromMedium((sdigit)ival);
331-
}
332-
333-
/* Count digits (at least two - smaller cases were handled above). */
334-
abs_ival = ival < 0 ? 0U-(unsigned long)ival : (unsigned long)ival;
335-
/* Do shift in two steps to avoid possible undefined behavior. */
336-
t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT;
337-
ndigits = 2;
338-
while (t) {
339-
++ndigits;
340-
t >>= PyLong_SHIFT;
341-
}
342-
343-
/* Construct output value. */
344-
v = _PyLong_New(ndigits);
345-
if (v != NULL) {
346-
digit *p = v->long_value.ob_digit;
347-
_PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits);
348-
t = abs_ival;
349-
while (t) {
350-
*p++ = (digit)(t & PyLong_MASK);
351-
t >>= PyLong_SHIFT;
352-
}
353-
}
354-
return (PyObject *)v;
380+
PYLONG_FROM_SIGNED(long, ival);
355381
}
356382

357-
#define PYLONG_FROM_UINT(INT_TYPE, ival) \
358-
do { \
359-
if (IS_SMALL_UINT(ival)) { \
360-
return get_small_int((sdigit)(ival)); \
361-
} \
362-
/* Count the number of Python digits. */ \
363-
Py_ssize_t ndigits = 0; \
364-
INT_TYPE t = (ival); \
365-
while (t) { \
366-
++ndigits; \
367-
t >>= PyLong_SHIFT; \
368-
} \
369-
PyLongObject *v = _PyLong_New(ndigits); \
370-
if (v == NULL) { \
371-
return NULL; \
372-
} \
373-
digit *p = v->long_value.ob_digit; \
374-
while ((ival)) { \
375-
*p++ = (digit)((ival) & PyLong_MASK); \
376-
(ival) >>= PyLong_SHIFT; \
377-
} \
378-
return (PyObject *)v; \
379-
} while(0)
380-
381383
/* Create a new int object from a C unsigned long int */
382384

383385
PyObject *
@@ -399,7 +401,7 @@ PyLong_FromUnsignedLongLong(unsigned long long ival)
399401
PyObject *
400402
PyLong_FromSize_t(size_t ival)
401403
{
402-
PYLONG_FROM_UINT(size_t, ival);
404+
PYLONG_FROM_SIGNED(size_t, ival);
403405
}
404406

405407
/* Create a new int object from a C double */

0 commit comments

Comments
 (0)