Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Include/internal/pycore_long.h
12 views
1
#ifndef Py_INTERNAL_LONG_H
2
#define Py_INTERNAL_LONG_H
3
#ifdef __cplusplus
4
extern "C" {
5
#endif
6
7
#ifndef Py_BUILD_CORE
8
# error "this header requires Py_BUILD_CORE define"
9
#endif
10
11
#include "pycore_global_objects.h" // _PY_NSMALLNEGINTS
12
#include "pycore_runtime.h" // _PyRuntime
13
14
/*
15
* Default int base conversion size limitation: Denial of Service prevention.
16
*
17
* Chosen such that this isn't wildly slow on modern hardware and so that
18
* everyone's existing deployed numpy test suite passes before
19
* https://github.com/numpy/numpy/issues/22098 is widely available.
20
*
21
* $ python -m timeit -s 's = "1"*4300' 'int(s)'
22
* 2000 loops, best of 5: 125 usec per loop
23
* $ python -m timeit -s 's = "1"*4300; v = int(s)' 'str(v)'
24
* 1000 loops, best of 5: 311 usec per loop
25
* (zen2 cloud VM)
26
*
27
* 4300 decimal digits fits a ~14284 bit number.
28
*/
29
#define _PY_LONG_DEFAULT_MAX_STR_DIGITS 4300
30
/*
31
* Threshold for max digits check. For performance reasons int() and
32
* int.__str__() don't checks values that are smaller than this
33
* threshold. Acts as a guaranteed minimum size limit for bignums that
34
* applications can expect from CPython.
35
*
36
* % python -m timeit -s 's = "1"*640; v = int(s)' 'str(int(s))'
37
* 20000 loops, best of 5: 12 usec per loop
38
*
39
* "640 digits should be enough for anyone." - gps
40
* fits a ~2126 bit decimal number.
41
*/
42
#define _PY_LONG_MAX_STR_DIGITS_THRESHOLD 640
43
44
#if ((_PY_LONG_DEFAULT_MAX_STR_DIGITS != 0) && \
45
(_PY_LONG_DEFAULT_MAX_STR_DIGITS < _PY_LONG_MAX_STR_DIGITS_THRESHOLD))
46
# error "_PY_LONG_DEFAULT_MAX_STR_DIGITS smaller than threshold."
47
#endif
48
49
50
/* runtime lifecycle */
51
52
extern PyStatus _PyLong_InitTypes(PyInterpreterState *);
53
extern void _PyLong_FiniTypes(PyInterpreterState *interp);
54
55
56
/* other API */
57
58
#define _PyLong_SMALL_INTS _Py_SINGLETON(small_ints)
59
60
// _PyLong_GetZero() and _PyLong_GetOne() must always be available
61
// _PyLong_FromUnsignedChar must always be available
62
#if _PY_NSMALLPOSINTS < 257
63
# error "_PY_NSMALLPOSINTS must be greater than or equal to 257"
64
#endif
65
66
// Return a borrowed reference to the zero singleton.
67
// The function cannot return NULL.
68
static inline PyObject* _PyLong_GetZero(void)
69
{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS]; }
70
71
// Return a borrowed reference to the one singleton.
72
// The function cannot return NULL.
73
static inline PyObject* _PyLong_GetOne(void)
74
{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+1]; }
75
76
static inline PyObject* _PyLong_FromUnsignedChar(unsigned char i)
77
{
78
return Py_NewRef((PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+i]);
79
}
80
81
PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right);
82
PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right);
83
PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right);
84
85
/* Used by Python/mystrtoul.c, _PyBytes_FromHex(),
86
_PyBytes_DecodeEscape(), etc. */
87
PyAPI_DATA(unsigned char) _PyLong_DigitValue[256];
88
89
/* Format the object based on the format_spec, as defined in PEP 3101
90
(Advanced String Formatting). */
91
PyAPI_FUNC(int) _PyLong_FormatAdvancedWriter(
92
_PyUnicodeWriter *writer,
93
PyObject *obj,
94
PyObject *format_spec,
95
Py_ssize_t start,
96
Py_ssize_t end);
97
98
PyAPI_FUNC(int) _PyLong_FormatWriter(
99
_PyUnicodeWriter *writer,
100
PyObject *obj,
101
int base,
102
int alternate);
103
104
PyAPI_FUNC(char*) _PyLong_FormatBytesWriter(
105
_PyBytesWriter *writer,
106
char *str,
107
PyObject *obj,
108
int base,
109
int alternate);
110
111
/* Long value tag bits:
112
* 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1.
113
* 2: Reserved for immortality bit
114
* 3+ Unsigned digit count
115
*/
116
#define SIGN_MASK 3
117
#define SIGN_ZERO 1
118
#define SIGN_NEGATIVE 2
119
#define NON_SIZE_BITS 3
120
121
/* The functions _PyLong_IsCompact and _PyLong_CompactValue are defined
122
* in Include/cpython/longobject.h, since they need to be inline.
123
*
124
* "Compact" values have at least one bit to spare,
125
* so that addition and subtraction can be performed on the values
126
* without risk of overflow.
127
*
128
* The inline functions need tag bits.
129
* For readability, rather than do `#define SIGN_MASK _PyLong_SIGN_MASK`
130
* we define them to the numbers in both places and then assert that
131
* they're the same.
132
*/
133
static_assert(SIGN_MASK == _PyLong_SIGN_MASK, "SIGN_MASK does not match _PyLong_SIGN_MASK");
134
static_assert(NON_SIZE_BITS == _PyLong_NON_SIZE_BITS, "NON_SIZE_BITS does not match _PyLong_NON_SIZE_BITS");
135
136
/* All *compact" values are guaranteed to fit into
137
* a Py_ssize_t with at least one bit to spare.
138
* In other words, for 64 bit machines, compact
139
* will be signed 63 (or fewer) bit values
140
*/
141
142
/* Return 1 if the argument is compact int */
143
static inline int
144
_PyLong_IsNonNegativeCompact(const PyLongObject* op) {
145
assert(PyLong_Check(op));
146
return op->long_value.lv_tag <= (1 << NON_SIZE_BITS);
147
}
148
149
150
static inline int
151
_PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) {
152
assert(PyLong_Check(a));
153
assert(PyLong_Check(b));
154
return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS);
155
}
156
157
static inline bool
158
_PyLong_IsZero(const PyLongObject *op)
159
{
160
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO;
161
}
162
163
static inline bool
164
_PyLong_IsNegative(const PyLongObject *op)
165
{
166
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE;
167
}
168
169
static inline bool
170
_PyLong_IsPositive(const PyLongObject *op)
171
{
172
return (op->long_value.lv_tag & SIGN_MASK) == 0;
173
}
174
175
static inline Py_ssize_t
176
_PyLong_DigitCount(const PyLongObject *op)
177
{
178
assert(PyLong_Check(op));
179
return op->long_value.lv_tag >> NON_SIZE_BITS;
180
}
181
182
/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonCompactSign(op) */
183
static inline Py_ssize_t
184
_PyLong_SignedDigitCount(const PyLongObject *op)
185
{
186
assert(PyLong_Check(op));
187
Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK);
188
return sign * (Py_ssize_t)(op->long_value.lv_tag >> NON_SIZE_BITS);
189
}
190
191
static inline int
192
_PyLong_CompactSign(const PyLongObject *op)
193
{
194
assert(PyLong_Check(op));
195
assert(_PyLong_IsCompact(op));
196
return 1 - (op->long_value.lv_tag & SIGN_MASK);
197
}
198
199
static inline int
200
_PyLong_NonCompactSign(const PyLongObject *op)
201
{
202
assert(PyLong_Check(op));
203
assert(!_PyLong_IsCompact(op));
204
return 1 - (op->long_value.lv_tag & SIGN_MASK);
205
}
206
207
/* Do a and b have the same sign? */
208
static inline int
209
_PyLong_SameSign(const PyLongObject *a, const PyLongObject *b)
210
{
211
return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK);
212
}
213
214
#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS))
215
216
static inline void
217
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
218
{
219
assert(size >= 0);
220
assert(-1 <= sign && sign <= 1);
221
assert(sign != 0 || size == 0);
222
op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size);
223
}
224
225
static inline void
226
_PyLong_SetDigitCount(PyLongObject *op, Py_ssize_t size)
227
{
228
assert(size >= 0);
229
op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK);
230
}
231
232
#define NON_SIZE_MASK ~((1 << NON_SIZE_BITS) - 1)
233
234
static inline void
235
_PyLong_FlipSign(PyLongObject *op) {
236
unsigned int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK);
237
op->long_value.lv_tag &= NON_SIZE_MASK;
238
op->long_value.lv_tag |= flipped_sign;
239
}
240
241
#define _PyLong_DIGIT_INIT(val) \
242
{ \
243
.ob_base = _PyObject_HEAD_INIT(&PyLong_Type) \
244
.long_value = { \
245
.lv_tag = TAG_FROM_SIGN_AND_SIZE( \
246
(val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \
247
(val) == 0 ? 0 : 1), \
248
{ ((val) >= 0 ? (val) : -(val)) }, \
249
} \
250
}
251
252
#define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0)
253
#define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1)
254
255
#ifdef __cplusplus
256
}
257
#endif
258
#endif /* !Py_INTERNAL_LONG_H */
259
260