-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
GH-101291: Rearrange the size bits in PyLongObject #102464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
0ec07e4
292b9d0
5c54894
029aaa4
b56e6da
91269fc
c48e825
449c0e2
c5ba601
4b3a3e8
9ef9d2c
9c408c1
548d656
3e3fefd
391fb51
df8c7d3
bc14fa6
54c6f1b
ce6bfb2
4c1956b
301158b
1aa1891
bf2a9af
169f521
90f9072
f143443
a0d661e
145a2e4
638a98f
7f5acc0
b06bb6f
a19b0a7
87f49b2
f764aa8
9843ac0
d6cb917
469d26f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -112,7 +112,7 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( | |
|
|
||
| /* Return 1 if the argument is positive single digit int */ | ||
| static inline int | ||
| _PyLong_IsPositiveSingleDigit(const PyObject* op) { | ||
| _PyLong_IsPositiveSingleDigit(const PyLongObject* op) { | ||
| /* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. | ||
|
|
||
| We perform a fast check using a single comparison by casting from int | ||
|
|
@@ -131,7 +131,7 @@ _PyLong_IsPositiveSingleDigit(const PyObject* op) { | |
|
|
||
|
|
||
| static inline int | ||
| _PyLong_IsSingleDigit(const PyObject* op) { | ||
| _PyLong_IsSingleDigit(const PyLongObject* op) { | ||
| assert(PyLong_Check(op)); | ||
| Py_ssize_t signed_size = Py_SIZE(op); | ||
| return ((size_t)(signed_size+1)) <= 2; | ||
|
|
@@ -152,7 +152,6 @@ _PyLong_DigitCount(const PyLongObject *op) | |
| return Py_ABS(Py_SIZE(op)); | ||
| } | ||
|
|
||
|
|
||
| static inline bool | ||
| _PyLong_IsNegative(const PyLongObject *op) | ||
| { | ||
|
|
@@ -166,6 +165,14 @@ _PyLong_IsZero(const PyLongObject *op) | |
| return Py_SIZE(op) == 0; | ||
| } | ||
|
|
||
| static inline int | ||
| _PyLong_NonZeroSign(const PyLongObject *op) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name confused me -- why not just
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it shouldn't be called with It probably should be called on compact ints either. I'll check if it is, and rename it.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've renamed it to |
||
| { | ||
| assert(PyLong_Check(op)); | ||
| assert(!_PyLong_IsZero(op)); | ||
| return ((Py_SIZE(op) > 0) << 1) - 1; | ||
| } | ||
|
|
||
| static inline bool | ||
| _PyLong_IsPositive(const PyLongObject *op) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -184,15 +184,15 @@ _PyLong_New(Py_ssize_t size) | |||||||||
| } | ||||||||||
|
|
||||||||||
| PyLongObject * | ||||||||||
| _PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits) | ||||||||||
| _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) | ||||||||||
| { | ||||||||||
| assert(digit_count >= 0); | ||||||||||
| PyLongObject *result = _PyLong_New(digit_count); | ||||||||||
| if (result == NULL) { | ||||||||||
| PyErr_NoMemory(); | ||||||||||
| return NULL; | ||||||||||
| } | ||||||||||
| assert(sign >= -1 && sign <= 1); | ||||||||||
| int sign = negative ? -1 : 1; | ||||||||||
| result->long_value.ob_size = sign * digit_count; | ||||||||||
| memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); | ||||||||||
| return result; | ||||||||||
|
|
@@ -201,22 +201,16 @@ _PyLong_FromDigits(int sign, Py_ssize_t digit_count, digit *digits) | |||||||||
| PyObject * | ||||||||||
| _PyLong_Copy(PyLongObject *src) | ||||||||||
| { | ||||||||||
| Py_ssize_t i; | ||||||||||
|
|
||||||||||
| assert(src != NULL); | ||||||||||
| i = Py_SIZE(src); | ||||||||||
| int sign = 1; | ||||||||||
| if (i < 0) { | ||||||||||
| i = -i; | ||||||||||
| sign = -1; | ||||||||||
| } | ||||||||||
| if (i < 2) { | ||||||||||
|
|
||||||||||
| if (_PyLong_IsSingleDigit(src)) { | ||||||||||
| stwodigits ival = medium_value(src); | ||||||||||
| if (IS_SMALL_INT(ival)) { | ||||||||||
| return get_small_int((sdigit)ival); | ||||||||||
| } | ||||||||||
| } | ||||||||||
| return (PyObject *)_PyLong_FromDigits(sign, i, src->long_value.ob_digit); | ||||||||||
| int size = _PyLong_DigitCount(src); | ||||||||||
| return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| static PyObject * | ||||||||||
|
|
@@ -300,7 +294,7 @@ _PyLong_AssignValue(PyObject **target, Py_ssize_t value) | |||||||||
| return 0; | ||||||||||
| } | ||||||||||
| else if (old != NULL && PyLong_CheckExact(old) && | ||||||||||
| Py_REFCNT(old) == 1 && _PyLong_IsPositiveSingleDigit(old) && | ||||||||||
| Py_REFCNT(old) == 1 && _PyLong_IsPositiveSingleDigit((PyLongObject *)old) && | ||||||||||
| (size_t)value <= PyLong_MASK) | ||||||||||
| { | ||||||||||
| // Mutate in place if there are no other references the old | ||||||||||
|
|
@@ -533,27 +527,14 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) | |||||||||
| return -1; | ||||||||||
| do_decref = 1; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| res = -1; | ||||||||||
| i = Py_SIZE(v); | ||||||||||
|
|
||||||||||
| switch (i) { | ||||||||||
| case -1: | ||||||||||
| res = -(sdigit)v->long_value.ob_digit[0]; | ||||||||||
| break; | ||||||||||
| case 0: | ||||||||||
| res = 0; | ||||||||||
| break; | ||||||||||
| case 1: | ||||||||||
| res = v->long_value.ob_digit[0]; | ||||||||||
| break; | ||||||||||
| default: | ||||||||||
| sign = 1; | ||||||||||
| if (_PyLong_IsSingleDigit(v)) { | ||||||||||
| res = _PyLong_SingleDigitValue(v); | ||||||||||
| } | ||||||||||
| else { | ||||||||||
| res = -1; | ||||||||||
| i = _PyLong_DigitCount(v); | ||||||||||
| sign = _PyLong_NonZeroSign(v); | ||||||||||
| x = 0; | ||||||||||
| if (i < 0) { | ||||||||||
| sign = -1; | ||||||||||
| i = -(i); | ||||||||||
| } | ||||||||||
| while (--i >= 0) { | ||||||||||
| prev = x; | ||||||||||
| x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; | ||||||||||
|
|
@@ -563,8 +544,8 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) | |||||||||
| } | ||||||||||
| } | ||||||||||
| /* Haven't lost any bits, but casting to long requires extra | ||||||||||
| * care (see comment above). | ||||||||||
| */ | ||||||||||
| * care (see comment above). | ||||||||||
| */ | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Accidental reformat?
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||||||||||
| if (x <= (unsigned long)LONG_MAX) { | ||||||||||
| res = (long)x * sign; | ||||||||||
| } | ||||||||||
|
|
@@ -638,18 +619,12 @@ PyLong_AsSsize_t(PyObject *vv) { | |||||||||
| } | ||||||||||
|
|
||||||||||
| v = (PyLongObject *)vv; | ||||||||||
| i = Py_SIZE(v); | ||||||||||
| switch (i) { | ||||||||||
| case -1: return -(sdigit)v->long_value.ob_digit[0]; | ||||||||||
| case 0: return 0; | ||||||||||
| case 1: return v->long_value.ob_digit[0]; | ||||||||||
| if (_PyLong_IsSingleDigit(v)) { | ||||||||||
| return _PyLong_SingleDigitValue(v); | ||||||||||
| } | ||||||||||
| sign = 1; | ||||||||||
| i = _PyLong_DigitCount(v); | ||||||||||
| sign = _PyLong_NonZeroSign(v); | ||||||||||
| x = 0; | ||||||||||
| if (i < 0) { | ||||||||||
| sign = -1; | ||||||||||
| i = -(i); | ||||||||||
| } | ||||||||||
| while (--i >= 0) { | ||||||||||
| prev = x; | ||||||||||
| x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; | ||||||||||
|
|
@@ -737,17 +712,16 @@ PyLong_AsSize_t(PyObject *vv) | |||||||||
| } | ||||||||||
|
|
||||||||||
| v = (PyLongObject *)vv; | ||||||||||
| i = Py_SIZE(v); | ||||||||||
| x = 0; | ||||||||||
| if (i < 0) { | ||||||||||
| if (_PyLong_IsPositiveSingleDigit(v)) { | ||||||||||
| return _PyLong_SingleDigitValue(v); | ||||||||||
| } | ||||||||||
| if (_PyLong_IsNegative(v)) { | ||||||||||
| PyErr_SetString(PyExc_OverflowError, | ||||||||||
| "can't convert negative value to size_t"); | ||||||||||
| return (size_t) -1; | ||||||||||
| } | ||||||||||
| switch (i) { | ||||||||||
| case 0: return 0; | ||||||||||
| case 1: return v->long_value.ob_digit[0]; | ||||||||||
| } | ||||||||||
| i = _PyLong_DigitCount(v); | ||||||||||
| x = 0; | ||||||||||
| while (--i >= 0) { | ||||||||||
| prev = x; | ||||||||||
| x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; | ||||||||||
|
|
@@ -769,24 +743,18 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) | |||||||||
| PyLongObject *v; | ||||||||||
| unsigned long x; | ||||||||||
| Py_ssize_t i; | ||||||||||
| int sign; | ||||||||||
|
|
||||||||||
| if (vv == NULL || !PyLong_Check(vv)) { | ||||||||||
| PyErr_BadInternalCall(); | ||||||||||
| return (unsigned long) -1; | ||||||||||
| } | ||||||||||
| v = (PyLongObject *)vv; | ||||||||||
| i = Py_SIZE(v); | ||||||||||
| switch (i) { | ||||||||||
| case 0: return 0; | ||||||||||
| case 1: return v->long_value.ob_digit[0]; | ||||||||||
| if (_PyLong_IsPositiveSingleDigit(v)) { | ||||||||||
| return _PyLong_SingleDigitValue(v); | ||||||||||
| } | ||||||||||
| sign = 1; | ||||||||||
| i = _PyLong_DigitCount(v); | ||||||||||
| int sign = _PyLong_NonZeroSign(v); | ||||||||||
| x = 0; | ||||||||||
| if (i < 0) { | ||||||||||
| sign = -1; | ||||||||||
| i = -i; | ||||||||||
| } | ||||||||||
| while (--i >= 0) { | ||||||||||
| x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; | ||||||||||
| } | ||||||||||
|
|
@@ -4696,7 +4664,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) | |||||||||
|
|
||||||||||
| /* if modulus == 1: | ||||||||||
| return 0 */ | ||||||||||
| if (_PyLong_IsPositiveSingleDigit((PyObject *)c) && (c->long_value.ob_digit[0] == 1)) { | ||||||||||
| if (_PyLong_IsPositiveSingleDigit(c) && (c->long_value.ob_digit[0] == 1)) { | ||||||||||
| z = (PyLongObject *)PyLong_FromLong(0L); | ||||||||||
| goto Done; | ||||||||||
| } | ||||||||||
|
|
||||||||||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be the new implementation of
_PyLong_Sign(), if_PyLong_NonCompactSign()is removed? This gets rid of a branch in the proposed version of_PyLong_Sign().There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They sure look identical to me. Maybe Mark has plans and maybe the compiler would optimize this anyway?
could just become
return F(x);.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want the freedom to implement the "compact" and non-compact forms differently.
They have the same implementation at the moment, but that will change.
_PyLong_Sign()is part of the ABI, so we need to retain it. But almost all code using_PyLong_Sign()actually wants to know if an int is negative and should be using_PyLong_IsNegative().