mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 23:13:34 +00:00
Status lines for Emacs and Vim have been added to Python sources so they'll be easier to edit using Python's preferred coding style. Some DNS helper functions have been broken up into multiple files. It's nice to have one function per file whenever possible, since that way we don't need -ffunction-sections. Another reason it's good to have small source files, is because the build will be enforcing resource limits on compilation and testing soon.
148 lines
4.6 KiB
C++
148 lines
4.6 KiB
C++
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Python 3 │
|
|
│ https://docs.python.org/3/license.html │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
/* clang-format off */
|
|
|
|
/* stringlib: bytes joining implementation */
|
|
|
|
#if STRINGLIB_IS_UNICODE
|
|
#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);
|
|
PyErr_NoMemory();
|
|
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
|
|
* bytes-like.
|
|
*/
|
|
for (i = 0, nbufs = 0; i < seqlen; i++) {
|
|
Py_ssize_t itemlen;
|
|
item = PySequence_Fast_GET_ITEM(seq, i);
|
|
if (PyBytes_CheckExact(item)) {
|
|
/* Fast path. */
|
|
Py_INCREF(item);
|
|
buffers[i].obj = item;
|
|
buffers[i].buf = PyBytes_AS_STRING(item);
|
|
buffers[i].len = PyBytes_GET_SIZE(item);
|
|
}
|
|
else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"sequence item %zd: expected a bytes-like object, "
|
|
"%.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);
|
|
if (!seplen) {
|
|
/* fast path */
|
|
for (i = 0; i < nbufs; i++) {
|
|
Py_ssize_t n = buffers[i].len;
|
|
char *q = buffers[i].buf;
|
|
memcpy(p, q, n);
|
|
p += n;
|
|
}
|
|
goto done;
|
|
}
|
|
for (i = 0; i < nbufs; i++) {
|
|
Py_ssize_t n;
|
|
char *q;
|
|
if (i) {
|
|
memcpy(p, sepstr, seplen);
|
|
p += seplen;
|
|
}
|
|
n = buffers[i].len;
|
|
q = buffers[i].buf;
|
|
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
|