Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d0880d5

Browse files
committed
Simplify and optimize formatlong()
* Remove _PyBytes_FormatLong(): inline it into formatlong() * the input type is always a long, so remove the code for bool * don't duplicate the string if the length does not change * Use PyUnicode_DATA() instead of _PyUnicode_AsString()
1 parent 19b409a commit d0880d5

3 files changed

Lines changed: 128 additions & 152 deletions

File tree

Include/bytesobject.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ PyAPI_FUNC(void) PyBytes_Concat(PyObject **, PyObject *);
6262
PyAPI_FUNC(void) PyBytes_ConcatAndDel(PyObject **, PyObject *);
6363
#ifndef Py_LIMITED_API
6464
PyAPI_FUNC(int) _PyBytes_Resize(PyObject **, Py_ssize_t);
65-
PyAPI_FUNC(PyObject *) _PyBytes_FormatLong(PyObject*, int, int,
66-
int, char**, int*);
6765
#endif
6866
PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t,
6967
const char *, Py_ssize_t,

Objects/bytesobject.c

Lines changed: 0 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,149 +2860,6 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
28602860
return 0;
28612861
}
28622862

2863-
/* _PyBytes_FormatLong emulates the format codes d, u, o, x and X, and
2864-
* the F_ALT flag, for Python's long (unbounded) ints. It's not used for
2865-
* Python's regular ints.
2866-
* Return value: a new PyBytes*, or NULL if error.
2867-
* . *pbuf is set to point into it,
2868-
* *plen set to the # of chars following that.
2869-
* Caller must decref it when done using pbuf.
2870-
* The string starting at *pbuf is of the form
2871-
* "-"? ("0x" | "0X")? digit+
2872-
* "0x"/"0X" are present only for x and X conversions, with F_ALT
2873-
* set in flags. The case of hex digits will be correct,
2874-
* There will be at least prec digits, zero-filled on the left if
2875-
* necessary to get that many.
2876-
* val object to be converted
2877-
* flags bitmask of format flags; only F_ALT is looked at
2878-
* prec minimum number of digits; 0-fill on left if needed
2879-
* type a character in [duoxX]; u acts the same as d
2880-
*
2881-
* CAUTION: o, x and X conversions on regular ints can never
2882-
* produce a '-' sign, but can for Python's unbounded ints.
2883-
*/
2884-
PyObject*
2885-
_PyBytes_FormatLong(PyObject *val, int flags, int prec, int type,
2886-
char **pbuf, int *plen)
2887-
{
2888-
PyObject *result = NULL;
2889-
char *buf;
2890-
Py_ssize_t i;
2891-
int sign; /* 1 if '-', else 0 */
2892-
int len; /* number of characters */
2893-
Py_ssize_t llen;
2894-
int numdigits; /* len == numnondigits + numdigits */
2895-
int numnondigits = 0;
2896-
2897-
/* Avoid exceeding SSIZE_T_MAX */
2898-
if (prec > INT_MAX-3) {
2899-
PyErr_SetString(PyExc_OverflowError,
2900-
"precision too large");
2901-
return NULL;
2902-
}
2903-
2904-
switch (type) {
2905-
case 'd':
2906-
case 'u':
2907-
/* Special-case boolean: we want 0/1 */
2908-
if (PyBool_Check(val))
2909-
result = PyNumber_ToBase(val, 10);
2910-
else
2911-
result = Py_TYPE(val)->tp_str(val);
2912-
break;
2913-
case 'o':
2914-
numnondigits = 2;
2915-
result = PyNumber_ToBase(val, 8);
2916-
break;
2917-
case 'x':
2918-
case 'X':
2919-
numnondigits = 2;
2920-
result = PyNumber_ToBase(val, 16);
2921-
break;
2922-
default:
2923-
assert(!"'type' not in [duoxX]");
2924-
}
2925-
if (!result)
2926-
return NULL;
2927-
2928-
buf = _PyUnicode_AsString(result);
2929-
if (!buf) {
2930-
Py_DECREF(result);
2931-
return NULL;
2932-
}
2933-
2934-
/* To modify the string in-place, there can only be one reference. */
2935-
if (Py_REFCNT(result) != 1) {
2936-
PyErr_BadInternalCall();
2937-
return NULL;
2938-
}
2939-
llen = PyUnicode_GetLength(result);
2940-
if (llen > INT_MAX) {
2941-
PyErr_SetString(PyExc_ValueError,
2942-
"string too large in _PyBytes_FormatLong");
2943-
return NULL;
2944-
}
2945-
len = (int)llen;
2946-
if (buf[len-1] == 'L') {
2947-
--len;
2948-
buf[len] = '\0';
2949-
}
2950-
sign = buf[0] == '-';
2951-
numnondigits += sign;
2952-
numdigits = len - numnondigits;
2953-
assert(numdigits > 0);
2954-
2955-
/* Get rid of base marker unless F_ALT */
2956-
if (((flags & F_ALT) == 0 &&
2957-
(type == 'o' || type == 'x' || type == 'X'))) {
2958-
assert(buf[sign] == '0');
2959-
assert(buf[sign+1] == 'x' || buf[sign+1] == 'X' ||
2960-
buf[sign+1] == 'o');
2961-
numnondigits -= 2;
2962-
buf += 2;
2963-
len -= 2;
2964-
if (sign)
2965-
buf[0] = '-';
2966-
assert(len == numnondigits + numdigits);
2967-
assert(numdigits > 0);
2968-
}
2969-
2970-
/* Fill with leading zeroes to meet minimum width. */
2971-
if (prec > numdigits) {
2972-
PyObject *r1 = PyBytes_FromStringAndSize(NULL,
2973-
numnondigits + prec);
2974-
char *b1;
2975-
if (!r1) {
2976-
Py_DECREF(result);
2977-
return NULL;
2978-
}
2979-
b1 = PyBytes_AS_STRING(r1);
2980-
for (i = 0; i < numnondigits; ++i)
2981-
*b1++ = *buf++;
2982-
for (i = 0; i < prec - numdigits; i++)
2983-
*b1++ = '0';
2984-
for (i = 0; i < numdigits; i++)
2985-
*b1++ = *buf++;
2986-
*b1 = '\0';
2987-
Py_DECREF(result);
2988-
result = r1;
2989-
buf = PyBytes_AS_STRING(result);
2990-
len = numnondigits + prec;
2991-
}
2992-
2993-
/* Fix up case for hex conversions. */
2994-
if (type == 'X') {
2995-
/* Need to convert all lower case letters to upper case.
2996-
and need to convert 0x to 0X (and -0x to -0X). */
2997-
for (i = 0; i < len; i++)
2998-
if (buf[i] >= 'a' && buf[i] <= 'x')
2999-
buf[i] -= 'a'-'A';
3000-
}
3001-
*pbuf = buf;
3002-
*plen = len;
3003-
return result;
3004-
}
3005-
30062863
void
30072864
PyBytes_Fini(void)
30082865
{

Objects/unicodeobject.c

Lines changed: 128 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13438,19 +13438,140 @@ formatfloat(PyObject *v, int flags, int prec, int type)
1343813438
return result;
1343913439
}
1344013440

13441+
/* formatlong() emulates the format codes d, u, o, x and X, and
13442+
* the F_ALT flag, for Python's long (unbounded) ints. It's not used for
13443+
* Python's regular ints.
13444+
* Return value: a new PyUnicodeObject*, or NULL if error.
13445+
* The output string is of the form
13446+
* "-"? ("0x" | "0X")? digit+
13447+
* "0x"/"0X" are present only for x and X conversions, with F_ALT
13448+
* set in flags. The case of hex digits will be correct,
13449+
* There will be at least prec digits, zero-filled on the left if
13450+
* necessary to get that many.
13451+
* val object to be converted
13452+
* flags bitmask of format flags; only F_ALT is looked at
13453+
* prec minimum number of digits; 0-fill on left if needed
13454+
* type a character in [duoxX]; u acts the same as d
13455+
*
13456+
* CAUTION: o, x and X conversions on regular ints can never
13457+
* produce a '-' sign, but can for Python's unbounded ints.
13458+
*/
1344113459
static PyObject*
1344213460
formatlong(PyObject *val, int flags, int prec, int type)
1344313461
{
13462+
PyObject *result = NULL;
1344413463
char *buf;
13445-
int len;
13446-
PyObject *str; /* temporary string object. */
13447-
PyObject *result;
13464+
Py_ssize_t i;
13465+
int sign; /* 1 if '-', else 0 */
13466+
int len; /* number of characters */
13467+
Py_ssize_t llen;
13468+
int numdigits; /* len == numnondigits + numdigits */
13469+
int numnondigits = 0;
13470+
13471+
/* Avoid exceeding SSIZE_T_MAX */
13472+
if (prec > INT_MAX-3) {
13473+
PyErr_SetString(PyExc_OverflowError,
13474+
"precision too large");
13475+
return NULL;
13476+
}
1344813477

13449-
str = _PyBytes_FormatLong(val, flags, prec, type, &buf, &len);
13450-
if (!str)
13478+
assert(PyLong_Check(val));
13479+
13480+
switch (type) {
13481+
case 'd':
13482+
case 'u':
13483+
/* Special-case boolean: we want 0/1 */
13484+
result = Py_TYPE(val)->tp_str(val);
13485+
break;
13486+
case 'o':
13487+
numnondigits = 2;
13488+
result = PyNumber_ToBase(val, 8);
13489+
break;
13490+
case 'x':
13491+
case 'X':
13492+
numnondigits = 2;
13493+
result = PyNumber_ToBase(val, 16);
13494+
break;
13495+
default:
13496+
assert(!"'type' not in [duoxX]");
13497+
}
13498+
if (!result)
1345113499
return NULL;
13452-
result = PyUnicode_DecodeASCII(buf, len, NULL);
13453-
Py_DECREF(str);
13500+
13501+
assert(unicode_modifiable(result));
13502+
assert(PyUnicode_IS_READY(result));
13503+
assert(PyUnicode_IS_ASCII(result));
13504+
13505+
/* To modify the string in-place, there can only be one reference. */
13506+
if (Py_REFCNT(result) != 1) {
13507+
PyErr_BadInternalCall();
13508+
return NULL;
13509+
}
13510+
buf = PyUnicode_DATA(result);
13511+
llen = PyUnicode_GET_LENGTH(result);
13512+
if (llen > INT_MAX) {
13513+
PyErr_SetString(PyExc_ValueError,
13514+
"string too large in _PyBytes_FormatLong");
13515+
return NULL;
13516+
}
13517+
len = (int)llen;
13518+
sign = buf[0] == '-';
13519+
numnondigits += sign;
13520+
numdigits = len - numnondigits;
13521+
assert(numdigits > 0);
13522+
13523+
/* Get rid of base marker unless F_ALT */
13524+
if (((flags & F_ALT) == 0 &&
13525+
(type == 'o' || type == 'x' || type == 'X'))) {
13526+
assert(buf[sign] == '0');
13527+
assert(buf[sign+1] == 'x' || buf[sign+1] == 'X' ||
13528+
buf[sign+1] == 'o');
13529+
numnondigits -= 2;
13530+
buf += 2;
13531+
len -= 2;
13532+
if (sign)
13533+
buf[0] = '-';
13534+
assert(len == numnondigits + numdigits);
13535+
assert(numdigits > 0);
13536+
}
13537+
13538+
/* Fill with leading zeroes to meet minimum width. */
13539+
if (prec > numdigits) {
13540+
PyObject *r1 = PyBytes_FromStringAndSize(NULL,
13541+
numnondigits + prec);
13542+
char *b1;
13543+
if (!r1) {
13544+
Py_DECREF(result);
13545+
return NULL;
13546+
}
13547+
b1 = PyBytes_AS_STRING(r1);
13548+
for (i = 0; i < numnondigits; ++i)
13549+
*b1++ = *buf++;
13550+
for (i = 0; i < prec - numdigits; i++)
13551+
*b1++ = '0';
13552+
for (i = 0; i < numdigits; i++)
13553+
*b1++ = *buf++;
13554+
*b1 = '\0';
13555+
Py_DECREF(result);
13556+
result = r1;
13557+
buf = PyBytes_AS_STRING(result);
13558+
len = numnondigits + prec;
13559+
}
13560+
13561+
/* Fix up case for hex conversions. */
13562+
if (type == 'X') {
13563+
/* Need to convert all lower case letters to upper case.
13564+
and need to convert 0x to 0X (and -0x to -0X). */
13565+
for (i = 0; i < len; i++)
13566+
if (buf[i] >= 'a' && buf[i] <= 'x')
13567+
buf[i] -= 'a'-'A';
13568+
}
13569+
if (!PyUnicode_Check(result) || len != PyUnicode_GET_LENGTH(result)) {
13570+
PyObject *unicode;
13571+
unicode = unicode_fromascii((unsigned char *)buf, len);
13572+
Py_DECREF(result);
13573+
result = unicode;
13574+
}
1345413575
return result;
1345513576
}
1345613577

0 commit comments

Comments
 (0)