|
10 | 10 | static Py_ssize_t |
11 | 11 | _getbuffer(PyObject *obj, Py_buffer *view) |
12 | 12 | { |
13 | | - PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer; |
14 | | - |
15 | | - if (buffer == NULL || buffer->bf_getbuffer == NULL) |
| 13 | + PyBufferProcs *bufferprocs; |
| 14 | + if (PyBytes_CheckExact(obj)) { |
| 15 | + /* Fast path, e.g. for .join() of many bytes objects */ |
| 16 | + Py_INCREF(obj); |
| 17 | + view->obj = obj; |
| 18 | + view->buf = PyBytes_AS_STRING(obj); |
| 19 | + view->len = PyBytes_GET_SIZE(obj); |
| 20 | + return view->len; |
| 21 | + } |
| 22 | + |
| 23 | + bufferprocs = Py_TYPE(obj)->tp_as_buffer; |
| 24 | + if (bufferprocs == NULL || bufferprocs->bf_getbuffer == NULL) |
16 | 25 | { |
17 | 26 | PyErr_Format(PyExc_TypeError, |
18 | 27 | "Type %.100s doesn't support the buffer API", |
19 | 28 | Py_TYPE(obj)->tp_name); |
20 | 29 | return -1; |
21 | 30 | } |
22 | 31 |
|
23 | | - if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) |
| 32 | + if (bufferprocs->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) |
24 | 33 | return -1; |
25 | 34 | return view->len; |
26 | 35 | } |
@@ -555,6 +564,7 @@ PyBytes_AsStringAndSize(register PyObject *obj, |
555 | 564 | #include "stringlib/fastsearch.h" |
556 | 565 | #include "stringlib/count.h" |
557 | 566 | #include "stringlib/find.h" |
| 567 | +#include "stringlib/join.h" |
558 | 568 | #include "stringlib/partition.h" |
559 | 569 | #include "stringlib/split.h" |
560 | 570 | #include "stringlib/ctype.h" |
@@ -1107,94 +1117,9 @@ Concatenate any number of bytes objects, with B in between each pair.\n\ |
1107 | 1117 | Example: b'.'.join([b'ab', b'pq', b'rs']) -> b'ab.pq.rs'."); |
1108 | 1118 |
|
1109 | 1119 | static PyObject * |
1110 | | -bytes_join(PyObject *self, PyObject *orig) |
| 1120 | +bytes_join(PyObject *self, PyObject *iterable) |
1111 | 1121 | { |
1112 | | - char *sep = PyBytes_AS_STRING(self); |
1113 | | - const Py_ssize_t seplen = PyBytes_GET_SIZE(self); |
1114 | | - PyObject *res = NULL; |
1115 | | - char *p; |
1116 | | - Py_ssize_t seqlen = 0; |
1117 | | - size_t sz = 0; |
1118 | | - Py_ssize_t i; |
1119 | | - PyObject *seq, *item; |
1120 | | - |
1121 | | - seq = PySequence_Fast(orig, ""); |
1122 | | - if (seq == NULL) { |
1123 | | - return NULL; |
1124 | | - } |
1125 | | - |
1126 | | - seqlen = PySequence_Size(seq); |
1127 | | - if (seqlen == 0) { |
1128 | | - Py_DECREF(seq); |
1129 | | - return PyBytes_FromString(""); |
1130 | | - } |
1131 | | - if (seqlen == 1) { |
1132 | | - item = PySequence_Fast_GET_ITEM(seq, 0); |
1133 | | - if (PyBytes_CheckExact(item)) { |
1134 | | - Py_INCREF(item); |
1135 | | - Py_DECREF(seq); |
1136 | | - return item; |
1137 | | - } |
1138 | | - } |
1139 | | - |
1140 | | - /* There are at least two things to join, or else we have a subclass |
1141 | | - * of the builtin types in the sequence. |
1142 | | - * Do a pre-pass to figure out the total amount of space we'll |
1143 | | - * need (sz), and see whether all argument are bytes. |
1144 | | - */ |
1145 | | - /* XXX Shouldn't we use _getbuffer() on these items instead? */ |
1146 | | - for (i = 0; i < seqlen; i++) { |
1147 | | - const size_t old_sz = sz; |
1148 | | - item = PySequence_Fast_GET_ITEM(seq, i); |
1149 | | - if (!PyBytes_Check(item) && !PyByteArray_Check(item)) { |
1150 | | - PyErr_Format(PyExc_TypeError, |
1151 | | - "sequence item %zd: expected bytes," |
1152 | | - " %.80s found", |
1153 | | - i, Py_TYPE(item)->tp_name); |
1154 | | - Py_DECREF(seq); |
1155 | | - return NULL; |
1156 | | - } |
1157 | | - sz += Py_SIZE(item); |
1158 | | - if (i != 0) |
1159 | | - sz += seplen; |
1160 | | - if (sz < old_sz || sz > PY_SSIZE_T_MAX) { |
1161 | | - PyErr_SetString(PyExc_OverflowError, |
1162 | | - "join() result is too long for bytes"); |
1163 | | - Py_DECREF(seq); |
1164 | | - return NULL; |
1165 | | - } |
1166 | | - } |
1167 | | - |
1168 | | - /* Allocate result space. */ |
1169 | | - res = PyBytes_FromStringAndSize((char*)NULL, sz); |
1170 | | - if (res == NULL) { |
1171 | | - Py_DECREF(seq); |
1172 | | - return NULL; |
1173 | | - } |
1174 | | - |
1175 | | - /* Catenate everything. */ |
1176 | | - /* I'm not worried about a PyByteArray item growing because there's |
1177 | | - nowhere in this function where we release the GIL. */ |
1178 | | - p = PyBytes_AS_STRING(res); |
1179 | | - for (i = 0; i < seqlen; ++i) { |
1180 | | - size_t n; |
1181 | | - char *q; |
1182 | | - if (i) { |
1183 | | - Py_MEMCPY(p, sep, seplen); |
1184 | | - p += seplen; |
1185 | | - } |
1186 | | - item = PySequence_Fast_GET_ITEM(seq, i); |
1187 | | - n = Py_SIZE(item); |
1188 | | - if (PyBytes_Check(item)) |
1189 | | - q = PyBytes_AS_STRING(item); |
1190 | | - else |
1191 | | - q = PyByteArray_AS_STRING(item); |
1192 | | - Py_MEMCPY(p, q, n); |
1193 | | - p += n; |
1194 | | - } |
1195 | | - |
1196 | | - Py_DECREF(seq); |
1197 | | - return res; |
| 1122 | + return stringlib_bytes_join(self, iterable); |
1198 | 1123 | } |
1199 | 1124 |
|
1200 | 1125 | PyObject * |
|
0 commit comments