-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue #15958: bytes.join and bytearray.join now accept arbitrary buff…
…er objects.
- Loading branch information
Showing
5 changed files
with
167 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* stringlib: bytes joining implementation */ | ||
|
||
#if STRINGLIB_SIZEOF_CHAR != 1 | ||
#error join.h only compatible with byte-wise strings | ||
#endif | ||
|
||
Py_LOCAL_INLINE(PyObject *) | ||
STRINGLIB(bytes_join)(PyObject *sep, PyObject *iterable) | ||
{ | ||
char *sepstr = STRINGLIB_STR(sep); | ||
const Py_ssize_t seplen = STRINGLIB_LEN(sep); | ||
PyObject *res = NULL; | ||
char *p; | ||
Py_ssize_t seqlen = 0; | ||
Py_ssize_t sz = 0; | ||
Py_ssize_t i, nbufs; | ||
PyObject *seq, *item; | ||
Py_buffer *buffers = NULL; | ||
#define NB_STATIC_BUFFERS 10 | ||
Py_buffer static_buffers[NB_STATIC_BUFFERS]; | ||
|
||
seq = PySequence_Fast(iterable, "can only join an iterable"); | ||
if (seq == NULL) { | ||
return NULL; | ||
} | ||
|
||
seqlen = PySequence_Fast_GET_SIZE(seq); | ||
if (seqlen == 0) { | ||
Py_DECREF(seq); | ||
return STRINGLIB_NEW(NULL, 0); | ||
} | ||
#ifndef STRINGLIB_MUTABLE | ||
if (seqlen == 1) { | ||
item = PySequence_Fast_GET_ITEM(seq, 0); | ||
if (STRINGLIB_CHECK_EXACT(item)) { | ||
Py_INCREF(item); | ||
Py_DECREF(seq); | ||
return item; | ||
} | ||
} | ||
#endif | ||
if (seqlen > NB_STATIC_BUFFERS) { | ||
buffers = PyMem_NEW(Py_buffer, seqlen); | ||
if (buffers == NULL) { | ||
Py_DECREF(seq); | ||
return NULL; | ||
} | ||
} | ||
else { | ||
buffers = static_buffers; | ||
} | ||
|
||
/* Here is the general case. Do a pre-pass to figure out the total | ||
* amount of space we'll need (sz), and see whether all arguments are | ||
* buffer-compatible. | ||
*/ | ||
for (i = 0, nbufs = 0; i < seqlen; i++) { | ||
Py_ssize_t itemlen; | ||
item = PySequence_Fast_GET_ITEM(seq, i); | ||
if (_getbuffer(item, &buffers[i]) < 0) { | ||
PyErr_Format(PyExc_TypeError, | ||
"sequence item %zd: expected bytes, bytearray, " | ||
"or an object with the buffer interface, %.80s found", | ||
i, Py_TYPE(item)->tp_name); | ||
goto error; | ||
} | ||
nbufs = i + 1; /* for error cleanup */ | ||
itemlen = buffers[i].len; | ||
if (itemlen > PY_SSIZE_T_MAX - sz) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"join() result is too long"); | ||
goto error; | ||
} | ||
sz += itemlen; | ||
if (i != 0) { | ||
if (seplen > PY_SSIZE_T_MAX - sz) { | ||
PyErr_SetString(PyExc_OverflowError, | ||
"join() result is too long"); | ||
goto error; | ||
} | ||
sz += seplen; | ||
} | ||
if (seqlen != PySequence_Fast_GET_SIZE(seq)) { | ||
PyErr_SetString(PyExc_RuntimeError, | ||
"sequence changed size during iteration"); | ||
goto error; | ||
} | ||
} | ||
|
||
/* Allocate result space. */ | ||
res = STRINGLIB_NEW(NULL, sz); | ||
if (res == NULL) | ||
goto error; | ||
|
||
/* Catenate everything. */ | ||
p = STRINGLIB_STR(res); | ||
for (i = 0; i < nbufs; i++) { | ||
Py_ssize_t n; | ||
char *q; | ||
if (i) { | ||
Py_MEMCPY(p, sepstr, seplen); | ||
p += seplen; | ||
} | ||
n = buffers[i].len; | ||
q = buffers[i].buf; | ||
Py_MEMCPY(p, q, n); | ||
p += n; | ||
} | ||
goto done; | ||
|
||
error: | ||
res = NULL; | ||
done: | ||
Py_DECREF(seq); | ||
for (i = 0; i < nbufs; i++) | ||
PyBuffer_Release(&buffers[i]); | ||
if (buffers != static_buffers) | ||
PyMem_FREE(buffers); | ||
return res; | ||
} | ||
|
||
#undef NB_STATIC_BUFFERS |