@@ -26,15 +26,27 @@ class int "PyObject *" "&PyLong_Type"
26
26
_Py_IDENTIFIER (little );
27
27
_Py_IDENTIFIER (big );
28
28
29
- /* convert a PyLong of size 1, 0 or -1 to an sdigit */
30
- #define MEDIUM_VALUE (x ) (assert(-1 <= Py_SIZE(x) && Py_SIZE(x) <= 1), \
31
- Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \
32
- (Py_SIZE(x) == 0 ? (sdigit)0 : \
33
- (sdigit)(x)->ob_digit[0]))
29
+ /* Is this PyLong of size 1, 0 or -1? */
30
+ #define IS_MEDIUM_VALUE (x ) (((size_t)Py_SIZE(x)) + 1U < 3U)
31
+
32
+ /* convert a PyLong of size 1, 0 or -1 to a C integer */
33
+ static inline stwodigits
34
+ medium_value (PyLongObject * x )
35
+ {
36
+ assert (IS_MEDIUM_VALUE (x ));
37
+ return ((stwodigits )Py_SIZE (x )) * x -> ob_digit [0 ];
38
+ }
34
39
35
40
#define IS_SMALL_INT (ival ) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
36
41
#define IS_SMALL_UINT (ival ) ((ival) < NSMALLPOSINTS)
37
42
43
+ static inline int is_medium_int (stwodigits x )
44
+ {
45
+ /* Take care that we are comparing unsigned values. */
46
+ twodigits x_plus_mask = ((twodigits )x ) + PyLong_MASK ;
47
+ return x_plus_mask < ((twodigits )PyLong_MASK ) + PyLong_BASE ;
48
+ }
49
+
38
50
static PyObject *
39
51
get_small_int (sdigit ival )
40
52
{
@@ -47,33 +59,16 @@ get_small_int(sdigit ival)
47
59
static PyLongObject *
48
60
maybe_small_long (PyLongObject * v )
49
61
{
50
- if (v && Py_ABS ( Py_SIZE ( v )) <= 1 ) {
51
- sdigit ival = MEDIUM_VALUE (v );
62
+ if (v && IS_MEDIUM_VALUE ( v ) ) {
63
+ stwodigits ival = medium_value (v );
52
64
if (IS_SMALL_INT (ival )) {
53
65
Py_DECREF (v );
54
- return (PyLongObject * )get_small_int (ival );
66
+ return (PyLongObject * )get_small_int (( sdigit ) ival );
55
67
}
56
68
}
57
69
return v ;
58
70
}
59
71
60
- /* If a freshly-allocated int is already shared, it must
61
- be a small integer, so negating it must go to PyLong_FromLong */
62
- Py_LOCAL_INLINE (void )
63
- _PyLong_Negate (PyLongObject * * x_p )
64
- {
65
- PyLongObject * x ;
66
-
67
- x = (PyLongObject * )* x_p ;
68
- if (Py_REFCNT (x ) == 1 ) {
69
- Py_SET_SIZE (x , - Py_SIZE (x ));
70
- return ;
71
- }
72
-
73
- * x_p = (PyLongObject * )PyLong_FromLong (- MEDIUM_VALUE (x ));
74
- Py_DECREF (x );
75
- }
76
-
77
72
/* For int multiplication, use the O(N**2) school algorithm unless
78
73
* both operands contain more than KARATSUBA_CUTOFF digits (this
79
74
* being an internal Python int digit, in base BASE).
@@ -121,18 +116,21 @@ PyLongObject *
121
116
_PyLong_New (Py_ssize_t size )
122
117
{
123
118
PyLongObject * result ;
124
- /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
125
- sizeof(digit)*size. Previous incarnations of this code used
126
- sizeof(PyVarObject) instead of the offsetof, but this risks being
127
- incorrect in the presence of padding between the PyVarObject header
128
- and the digits. */
129
119
if (size > (Py_ssize_t )MAX_LONG_DIGITS ) {
130
120
PyErr_SetString (PyExc_OverflowError ,
131
121
"too many digits in integer" );
132
122
return NULL ;
133
123
}
124
+ /* Fast operations for single digit integers (including zero)
125
+ * assume that there is always at least one digit present. */
126
+ Py_ssize_t ndigits = size ? size : 1 ;
127
+ /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
128
+ sizeof(digit)*size. Previous incarnations of this code used
129
+ sizeof(PyVarObject) instead of the offsetof, but this risks being
130
+ incorrect in the presence of padding between the PyVarObject header
131
+ and the digits. */
134
132
result = PyObject_Malloc (offsetof(PyLongObject , ob_digit ) +
135
- size * sizeof (digit ));
133
+ ndigits * sizeof (digit ));
136
134
if (!result ) {
137
135
PyErr_NoMemory ();
138
136
return NULL ;
@@ -152,9 +150,9 @@ _PyLong_Copy(PyLongObject *src)
152
150
if (i < 0 )
153
151
i = - (i );
154
152
if (i < 2 ) {
155
- sdigit ival = MEDIUM_VALUE (src );
153
+ stwodigits ival = medium_value (src );
156
154
if (IS_SMALL_INT (ival )) {
157
- return get_small_int (ival );
155
+ return get_small_int (( sdigit ) ival );
158
156
}
159
157
}
160
158
result = _PyLong_New (i );
@@ -167,65 +165,126 @@ _PyLong_Copy(PyLongObject *src)
167
165
return (PyObject * )result ;
168
166
}
169
167
170
- /* Create a new int object from a C long int */
168
+ static PyObject *
169
+ _PyLong_FromMedium (sdigit x )
170
+ {
171
+ assert (!IS_SMALL_INT (x ));
172
+ assert (is_medium_int (x ));
173
+ /* We could use a freelist here */
174
+ PyLongObject * v = PyObject_Malloc (sizeof (PyLongObject ));
175
+ if (v == NULL ) {
176
+ PyErr_NoMemory ();
177
+ return NULL ;
178
+ }
179
+ Py_ssize_t sign = x < 0 ? -1 : 1 ;
180
+ digit abs_x = x < 0 ? - x : x ;
181
+ _PyObject_InitVar ((PyVarObject * )v , & PyLong_Type , sign );
182
+ v -> ob_digit [0 ] = abs_x ;
183
+ return (PyObject * )v ;
184
+ }
171
185
172
- PyObject *
173
- PyLong_FromLong ( long ival )
186
+ static PyObject *
187
+ _PyLong_FromLarge ( stwodigits ival )
174
188
{
175
- PyLongObject * v ;
176
- unsigned long abs_ival ;
177
- unsigned long t ; /* unsigned so >> doesn't propagate sign bit */
178
- int ndigits = 0 ;
189
+ twodigits abs_ival ;
179
190
int sign ;
191
+ assert (!is_medium_int (ival ));
180
192
193
+ if (ival < 0 ) {
194
+ /* negate: can't write this as abs_ival = -ival since that
195
+ invokes undefined behaviour when ival is LONG_MIN */
196
+ abs_ival = 0U - (twodigits )ival ;
197
+ sign = -1 ;
198
+ }
199
+ else {
200
+ abs_ival = (twodigits )ival ;
201
+ sign = 1 ;
202
+ }
203
+ /* Must be at least two digits */
204
+ assert (abs_ival >> PyLong_SHIFT != 0 );
205
+ twodigits t = abs_ival >> (PyLong_SHIFT * 2 );
206
+ Py_ssize_t ndigits = 2 ;
207
+ while (t ) {
208
+ ++ ndigits ;
209
+ t >>= PyLong_SHIFT ;
210
+ }
211
+ PyLongObject * v = _PyLong_New (ndigits );
212
+ if (v != NULL ) {
213
+ digit * p = v -> ob_digit ;
214
+ Py_SET_SIZE (v , ndigits * sign );
215
+ t = abs_ival ;
216
+ while (t ) {
217
+ * p ++ = Py_SAFE_DOWNCAST (
218
+ t & PyLong_MASK , twodigits , digit );
219
+ t >>= PyLong_SHIFT ;
220
+ }
221
+ }
222
+ return (PyObject * )v ;
223
+ }
224
+
225
+ /* Create a new int object from a C word-sized int */
226
+ static inline PyObject *
227
+ _PyLong_FromSTwoDigits (stwodigits x )
228
+ {
229
+ if (IS_SMALL_INT (x )) {
230
+ return get_small_int ((sdigit )x );
231
+ }
232
+ assert (x != 0 );
233
+ if (is_medium_int (x )) {
234
+ return _PyLong_FromMedium ((sdigit )x );
235
+ }
236
+ return _PyLong_FromLarge (x );
237
+ }
238
+
239
+ /* If a freshly-allocated int is already shared, it must
240
+ be a small integer, so negating it must go to PyLong_FromLong */
241
+ Py_LOCAL_INLINE (void )
242
+ _PyLong_Negate (PyLongObject * * x_p )
243
+ {
244
+ PyLongObject * x ;
245
+
246
+ x = (PyLongObject * )* x_p ;
247
+ if (Py_REFCNT (x ) == 1 ) {
248
+ Py_SET_SIZE (x , - Py_SIZE (x ));
249
+ return ;
250
+ }
251
+
252
+ * x_p = (PyLongObject * )_PyLong_FromSTwoDigits (- medium_value (x ));
253
+ Py_DECREF (x );
254
+ }
255
+
256
+ /* Create a new int object from a C long int */
257
+ PyObject *
258
+ PyLong_FromLong (long ival )
259
+ {
181
260
if (IS_SMALL_INT (ival )) {
182
261
return get_small_int ((sdigit )ival );
183
262
}
184
-
263
+ unsigned long abs_ival ;
264
+ int sign ;
185
265
if (ival < 0 ) {
186
266
/* negate: can't write this as abs_ival = -ival since that
187
267
invokes undefined behaviour when ival is LONG_MIN */
188
- abs_ival = 0U - (unsigned long )ival ;
268
+ abs_ival = 0U - (twodigits )ival ;
189
269
sign = -1 ;
190
270
}
191
271
else {
192
272
abs_ival = (unsigned long )ival ;
193
- sign = ival == 0 ? 0 : 1 ;
273
+ sign = 1 ;
194
274
}
195
-
196
275
/* Fast path for single-digit ints */
197
276
if (!(abs_ival >> PyLong_SHIFT )) {
198
- v = _PyLong_New (1 );
199
- if (v ) {
200
- Py_SET_SIZE (v , sign );
201
- v -> ob_digit [0 ] = Py_SAFE_DOWNCAST (
202
- abs_ival , unsigned long , digit );
203
- }
204
- return (PyObject * )v ;
205
- }
206
-
207
- #if PyLong_SHIFT == 15
208
- /* 2 digits */
209
- if (!(abs_ival >> 2 * PyLong_SHIFT )) {
210
- v = _PyLong_New (2 );
211
- if (v ) {
212
- Py_SET_SIZE (v , 2 * sign );
213
- v -> ob_digit [0 ] = Py_SAFE_DOWNCAST (
214
- abs_ival & PyLong_MASK , unsigned long , digit );
215
- v -> ob_digit [1 ] = Py_SAFE_DOWNCAST (
216
- abs_ival >> PyLong_SHIFT , unsigned long , digit );
217
- }
218
- return (PyObject * )v ;
277
+ return _PyLong_FromMedium ((sdigit )ival );
219
278
}
220
- #endif
221
-
222
- /* Larger numbers: loop to determine number of digits */
223
- t = abs_ival ;
279
+ /* Must be at least two digits.
280
+ * Do shift in two steps to avoid undefined behavior. */
281
+ unsigned long t = ( abs_ival >> PyLong_SHIFT ) >> PyLong_SHIFT ;
282
+ Py_ssize_t ndigits = 2 ;
224
283
while (t ) {
225
284
++ ndigits ;
226
285
t >>= PyLong_SHIFT ;
227
286
}
228
- v = _PyLong_New (ndigits );
287
+ PyLongObject * v = _PyLong_New (ndigits );
229
288
if (v != NULL ) {
230
289
digit * p = v -> ob_digit ;
231
290
Py_SET_SIZE (v , ndigits * sign );
@@ -2860,12 +2919,12 @@ PyLong_AsDouble(PyObject *v)
2860
2919
PyErr_SetString (PyExc_TypeError , "an integer is required" );
2861
2920
return -1.0 ;
2862
2921
}
2863
- if (Py_ABS ( Py_SIZE ( v )) <= 1 ) {
2922
+ if (IS_MEDIUM_VALUE ( v ) ) {
2864
2923
/* Fast path; single digit long (31 bits) will cast safely
2865
2924
to double. This improves performance of FP/long operations
2866
2925
by 20%.
2867
2926
*/
2868
- return (double )MEDIUM_VALUE ((PyLongObject * )v );
2927
+ return (double )medium_value ((PyLongObject * )v );
2869
2928
}
2870
2929
x = _PyLong_Frexp ((PyLongObject * )v , & exponent );
2871
2930
if ((x == -1.0 && PyErr_Occurred ()) || exponent > DBL_MAX_EXP ) {
@@ -3067,8 +3126,8 @@ long_add(PyLongObject *a, PyLongObject *b)
3067
3126
3068
3127
CHECK_BINOP (a , b );
3069
3128
3070
- if (Py_ABS ( Py_SIZE ( a )) <= 1 && Py_ABS ( Py_SIZE ( b )) <= 1 ) {
3071
- return PyLong_FromLong ( MEDIUM_VALUE (a ) + MEDIUM_VALUE (b ));
3129
+ if (IS_MEDIUM_VALUE ( a ) && IS_MEDIUM_VALUE ( b ) ) {
3130
+ return _PyLong_FromSTwoDigits ( medium_value (a ) + medium_value (b ));
3072
3131
}
3073
3132
if (Py_SIZE (a ) < 0 ) {
3074
3133
if (Py_SIZE (b ) < 0 ) {
@@ -3101,8 +3160,8 @@ long_sub(PyLongObject *a, PyLongObject *b)
3101
3160
3102
3161
CHECK_BINOP (a , b );
3103
3162
3104
- if (Py_ABS ( Py_SIZE ( a )) <= 1 && Py_ABS ( Py_SIZE ( b )) <= 1 ) {
3105
- return PyLong_FromLong ( MEDIUM_VALUE (a ) - MEDIUM_VALUE (b ));
3163
+ if (IS_MEDIUM_VALUE ( a ) && IS_MEDIUM_VALUE ( b ) ) {
3164
+ return _PyLong_FromSTwoDigits ( medium_value (a ) - medium_value (b ));
3106
3165
}
3107
3166
if (Py_SIZE (a ) < 0 ) {
3108
3167
if (Py_SIZE (b ) < 0 ) {
@@ -3536,9 +3595,9 @@ long_mul(PyLongObject *a, PyLongObject *b)
3536
3595
CHECK_BINOP (a , b );
3537
3596
3538
3597
/* fast path for single-digit multiplication */
3539
- if (Py_ABS ( Py_SIZE ( a )) <= 1 && Py_ABS ( Py_SIZE ( b )) <= 1 ) {
3540
- stwodigits v = ( stwodigits )( MEDIUM_VALUE ( a )) * MEDIUM_VALUE (b );
3541
- return PyLong_FromLongLong (( long long ) v );
3598
+ if (IS_MEDIUM_VALUE ( a ) && IS_MEDIUM_VALUE ( b ) ) {
3599
+ stwodigits v = medium_value ( a ) * medium_value (b );
3600
+ return _PyLong_FromSTwoDigits ( v );
3542
3601
}
3543
3602
3544
3603
z = k_mul (a , b );
@@ -4343,8 +4402,8 @@ long_invert(PyLongObject *v)
4343
4402
{
4344
4403
/* Implement ~x as -(x+1) */
4345
4404
PyLongObject * x ;
4346
- if (Py_ABS ( Py_SIZE ( v )) <= 1 )
4347
- return PyLong_FromLong ( - ( MEDIUM_VALUE ( v ) + 1 ));
4405
+ if (IS_MEDIUM_VALUE ( v ) )
4406
+ return _PyLong_FromSTwoDigits (~ medium_value ( v ));
4348
4407
x = (PyLongObject * ) long_add (v , (PyLongObject * )_PyLong_GetOne ());
4349
4408
if (x == NULL )
4350
4409
return NULL ;
@@ -4358,8 +4417,8 @@ static PyObject *
4358
4417
long_neg (PyLongObject * v )
4359
4418
{
4360
4419
PyLongObject * z ;
4361
- if (Py_ABS ( Py_SIZE ( v )) <= 1 )
4362
- return PyLong_FromLong ( - MEDIUM_VALUE (v ));
4420
+ if (IS_MEDIUM_VALUE ( v ) )
4421
+ return _PyLong_FromSTwoDigits ( - medium_value (v ));
4363
4422
z = (PyLongObject * )_PyLong_Copy (v );
4364
4423
if (z != NULL )
4365
4424
Py_SET_SIZE (z , - (Py_SIZE (v )));
@@ -4704,28 +4763,37 @@ long_bitwise(PyLongObject *a,
4704
4763
static PyObject *
4705
4764
long_and (PyObject * a , PyObject * b )
4706
4765
{
4707
- PyObject * c ;
4708
4766
CHECK_BINOP (a , b );
4709
- c = long_bitwise ((PyLongObject * )a , '&' , (PyLongObject * )b );
4710
- return c ;
4767
+ PyLongObject * x = (PyLongObject * )a ;
4768
+ PyLongObject * y = (PyLongObject * )b ;
4769
+ if (IS_MEDIUM_VALUE (x ) && IS_MEDIUM_VALUE (y )) {
4770
+ return _PyLong_FromSTwoDigits (medium_value (x ) & medium_value (y ));
4771
+ }
4772
+ return long_bitwise (x , '&' , y );
4711
4773
}
4712
4774
4713
4775
static PyObject *
4714
4776
long_xor (PyObject * a , PyObject * b )
4715
4777
{
4716
- PyObject * c ;
4717
4778
CHECK_BINOP (a , b );
4718
- c = long_bitwise ((PyLongObject * )a , '^' , (PyLongObject * )b );
4719
- return c ;
4779
+ PyLongObject * x = (PyLongObject * )a ;
4780
+ PyLongObject * y = (PyLongObject * )b ;
4781
+ if (IS_MEDIUM_VALUE (x ) && IS_MEDIUM_VALUE (y )) {
4782
+ return _PyLong_FromSTwoDigits (medium_value (x ) ^ medium_value (y ));
4783
+ }
4784
+ return long_bitwise (x , '^' , y );
4720
4785
}
4721
4786
4722
4787
static PyObject *
4723
4788
long_or (PyObject * a , PyObject * b )
4724
4789
{
4725
- PyObject * c ;
4726
4790
CHECK_BINOP (a , b );
4727
- c = long_bitwise ((PyLongObject * )a , '|' , (PyLongObject * )b );
4728
- return c ;
4791
+ PyLongObject * x = (PyLongObject * )a ;
4792
+ PyLongObject * y = (PyLongObject * )b ;
4793
+ if (IS_MEDIUM_VALUE (x ) && IS_MEDIUM_VALUE (y )) {
4794
+ return _PyLong_FromSTwoDigits (medium_value (x ) | medium_value (y ));
4795
+ }
4796
+ return long_bitwise (x , '|' , y );
4729
4797
}
4730
4798
4731
4799
static PyObject *
0 commit comments