blob: 21753cb5041cc25d01277834b6cb71b9c2938fff [file] [log] [blame]
Antoine Pitroucfc22b42012-10-16 21:07:23 +02001/* stringlib: bytes joining implementation */
2
3#if STRINGLIB_SIZEOF_CHAR != 1
4#error join.h only compatible with byte-wise strings
5#endif
6
7Py_LOCAL_INLINE(PyObject *)
8STRINGLIB(bytes_join)(PyObject *sep, PyObject *iterable)
9{
10 char *sepstr = STRINGLIB_STR(sep);
11 const Py_ssize_t seplen = STRINGLIB_LEN(sep);
12 PyObject *res = NULL;
13 char *p;
14 Py_ssize_t seqlen = 0;
15 Py_ssize_t sz = 0;
16 Py_ssize_t i, nbufs;
17 PyObject *seq, *item;
18 Py_buffer *buffers = NULL;
19#define NB_STATIC_BUFFERS 10
20 Py_buffer static_buffers[NB_STATIC_BUFFERS];
21
22 seq = PySequence_Fast(iterable, "can only join an iterable");
23 if (seq == NULL) {
24 return NULL;
25 }
26
27 seqlen = PySequence_Fast_GET_SIZE(seq);
28 if (seqlen == 0) {
29 Py_DECREF(seq);
30 return STRINGLIB_NEW(NULL, 0);
31 }
32#ifndef STRINGLIB_MUTABLE
33 if (seqlen == 1) {
34 item = PySequence_Fast_GET_ITEM(seq, 0);
35 if (STRINGLIB_CHECK_EXACT(item)) {
36 Py_INCREF(item);
37 Py_DECREF(seq);
38 return item;
39 }
40 }
41#endif
42 if (seqlen > NB_STATIC_BUFFERS) {
43 buffers = PyMem_NEW(Py_buffer, seqlen);
44 if (buffers == NULL) {
45 Py_DECREF(seq);
46 return NULL;
47 }
48 }
49 else {
50 buffers = static_buffers;
51 }
52
53 /* Here is the general case. Do a pre-pass to figure out the total
54 * amount of space we'll need (sz), and see whether all arguments are
55 * buffer-compatible.
56 */
57 for (i = 0, nbufs = 0; i < seqlen; i++) {
58 Py_ssize_t itemlen;
59 item = PySequence_Fast_GET_ITEM(seq, i);
60 if (_getbuffer(item, &buffers[i]) < 0) {
61 PyErr_Format(PyExc_TypeError,
62 "sequence item %zd: expected bytes, bytearray, "
63 "or an object with the buffer interface, %.80s found",
64 i, Py_TYPE(item)->tp_name);
65 goto error;
66 }
67 nbufs = i + 1; /* for error cleanup */
68 itemlen = buffers[i].len;
69 if (itemlen > PY_SSIZE_T_MAX - sz) {
70 PyErr_SetString(PyExc_OverflowError,
71 "join() result is too long");
72 goto error;
73 }
74 sz += itemlen;
75 if (i != 0) {
76 if (seplen > PY_SSIZE_T_MAX - sz) {
77 PyErr_SetString(PyExc_OverflowError,
78 "join() result is too long");
79 goto error;
80 }
81 sz += seplen;
82 }
83 if (seqlen != PySequence_Fast_GET_SIZE(seq)) {
84 PyErr_SetString(PyExc_RuntimeError,
85 "sequence changed size during iteration");
86 goto error;
87 }
88 }
89
90 /* Allocate result space. */
91 res = STRINGLIB_NEW(NULL, sz);
92 if (res == NULL)
93 goto error;
94
95 /* Catenate everything. */
96 p = STRINGLIB_STR(res);
97 for (i = 0; i < nbufs; i++) {
98 Py_ssize_t n;
99 char *q;
100 if (i) {
101 Py_MEMCPY(p, sepstr, seplen);
102 p += seplen;
103 }
104 n = buffers[i].len;
105 q = buffers[i].buf;
106 Py_MEMCPY(p, q, n);
107 p += n;
108 }
109 goto done;
110
111error:
112 res = NULL;
113done:
114 Py_DECREF(seq);
115 for (i = 0; i < nbufs; i++)
116 PyBuffer_Release(&buffers[i]);
117 if (buffers != static_buffers)
118 PyMem_FREE(buffers);
119 return res;
120}
121
122#undef NB_STATIC_BUFFERS