/src/Python-3.8.3/Objects/stringlib/join.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* stringlib: bytes joining implementation */ |
2 | | |
3 | | #if STRINGLIB_IS_UNICODE |
4 | | #error join.h only compatible with byte-wise strings |
5 | | #endif |
6 | | |
7 | | Py_LOCAL_INLINE(PyObject *) |
8 | | STRINGLIB(bytes_join)(PyObject *sep, PyObject *iterable) |
9 | 1 | { |
10 | 1 | char *sepstr = STRINGLIB_STR(sep); |
11 | 1 | const Py_ssize_t seplen = STRINGLIB_LEN(sep); |
12 | 1 | PyObject *res = NULL; |
13 | 1 | char *p; |
14 | 1 | Py_ssize_t seqlen = 0; |
15 | 1 | Py_ssize_t sz = 0; |
16 | 1 | Py_ssize_t i, nbufs; |
17 | 1 | PyObject *seq, *item; |
18 | 1 | Py_buffer *buffers = NULL; |
19 | 1 | #define NB_STATIC_BUFFERS 10 |
20 | 1 | Py_buffer static_buffers[NB_STATIC_BUFFERS]; |
21 | | |
22 | 1 | seq = PySequence_Fast(iterable, "can only join an iterable"); |
23 | 1 | if (seq == NULL) { |
24 | 0 | return NULL; |
25 | 0 | } |
26 | | |
27 | 1 | seqlen = PySequence_Fast_GET_SIZE(seq); |
28 | 1 | if (seqlen == 0) { |
29 | 0 | Py_DECREF(seq); |
30 | 0 | return STRINGLIB_NEW(NULL, 0); |
31 | 0 | } |
32 | | #ifndef STRINGLIB_MUTABLE |
33 | 1 | if (seqlen == 1) { |
34 | 1 | item = PySequence_Fast_GET_ITEM(seq, 0); |
35 | 1 | if (STRINGLIB_CHECK_EXACT(item)) { |
36 | 1 | Py_INCREF(item); |
37 | 1 | Py_DECREF(seq); |
38 | 1 | return item; |
39 | 1 | } |
40 | 1 | } |
41 | 0 | #endif |
42 | 0 | if (seqlen > NB_STATIC_BUFFERS) { |
43 | 0 | buffers = PyMem_NEW(Py_buffer, seqlen); |
44 | 0 | if (buffers == NULL) { |
45 | 0 | Py_DECREF(seq); |
46 | 0 | PyErr_NoMemory(); |
47 | 0 | return NULL; |
48 | 0 | } |
49 | 0 | } |
50 | 0 | else { |
51 | 0 | buffers = static_buffers; |
52 | 0 | } |
53 | | |
54 | | /* Here is the general case. Do a pre-pass to figure out the total |
55 | | * amount of space we'll need (sz), and see whether all arguments are |
56 | | * bytes-like. |
57 | | */ |
58 | 0 | for (i = 0, nbufs = 0; i < seqlen; i++) { |
59 | 0 | Py_ssize_t itemlen; |
60 | 0 | item = PySequence_Fast_GET_ITEM(seq, i); |
61 | 0 | if (PyBytes_CheckExact(item)) { |
62 | | /* Fast path. */ |
63 | 0 | Py_INCREF(item); |
64 | 0 | buffers[i].obj = item; |
65 | 0 | buffers[i].buf = PyBytes_AS_STRING(item); |
66 | 0 | buffers[i].len = PyBytes_GET_SIZE(item); |
67 | 0 | } |
68 | 0 | else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) { |
69 | 0 | PyErr_Format(PyExc_TypeError, |
70 | 0 | "sequence item %zd: expected a bytes-like object, " |
71 | 0 | "%.80s found", |
72 | 0 | i, Py_TYPE(item)->tp_name); |
73 | 0 | goto error; |
74 | 0 | } |
75 | 0 | nbufs = i + 1; /* for error cleanup */ |
76 | 0 | itemlen = buffers[i].len; |
77 | 0 | if (itemlen > PY_SSIZE_T_MAX - sz) { |
78 | 0 | PyErr_SetString(PyExc_OverflowError, |
79 | 0 | "join() result is too long"); |
80 | 0 | goto error; |
81 | 0 | } |
82 | 0 | sz += itemlen; |
83 | 0 | if (i != 0) { |
84 | 0 | if (seplen > PY_SSIZE_T_MAX - sz) { |
85 | 0 | PyErr_SetString(PyExc_OverflowError, |
86 | 0 | "join() result is too long"); |
87 | 0 | goto error; |
88 | 0 | } |
89 | 0 | sz += seplen; |
90 | 0 | } |
91 | 0 | if (seqlen != PySequence_Fast_GET_SIZE(seq)) { |
92 | 0 | PyErr_SetString(PyExc_RuntimeError, |
93 | 0 | "sequence changed size during iteration"); |
94 | 0 | goto error; |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | /* Allocate result space. */ |
99 | 0 | res = STRINGLIB_NEW(NULL, sz); |
100 | 0 | if (res == NULL) |
101 | 0 | goto error; |
102 | | |
103 | | /* Catenate everything. */ |
104 | 0 | p = STRINGLIB_STR(res); |
105 | 0 | if (!seplen) { |
106 | | /* fast path */ |
107 | 0 | for (i = 0; i < nbufs; i++) { |
108 | 0 | Py_ssize_t n = buffers[i].len; |
109 | 0 | char *q = buffers[i].buf; |
110 | 0 | memcpy(p, q, n); |
111 | 0 | p += n; |
112 | 0 | } |
113 | 0 | goto done; |
114 | 0 | } |
115 | 0 | for (i = 0; i < nbufs; i++) { |
116 | 0 | Py_ssize_t n; |
117 | 0 | char *q; |
118 | 0 | if (i) { |
119 | 0 | memcpy(p, sepstr, seplen); |
120 | 0 | p += seplen; |
121 | 0 | } |
122 | 0 | n = buffers[i].len; |
123 | 0 | q = buffers[i].buf; |
124 | 0 | memcpy(p, q, n); |
125 | 0 | p += n; |
126 | 0 | } |
127 | 0 | goto done; |
128 | | |
129 | 0 | error: |
130 | 0 | res = NULL; |
131 | 0 | done: |
132 | 0 | Py_DECREF(seq); |
133 | 0 | for (i = 0; i < nbufs; i++) |
134 | 0 | PyBuffer_Release(&buffers[i]); |
135 | 0 | if (buffers != static_buffers) |
136 | 0 | PyMem_FREE(buffers); |
137 | 0 | return res; |
138 | 0 | } Unexecuted instantiation: bytearrayobject.c:stringlib_bytes_join bytesobject.c:stringlib_bytes_join Line | Count | Source | 9 | 1 | { | 10 | 1 | char *sepstr = STRINGLIB_STR(sep); | 11 | 1 | const Py_ssize_t seplen = STRINGLIB_LEN(sep); | 12 | 1 | PyObject *res = NULL; | 13 | 1 | char *p; | 14 | 1 | Py_ssize_t seqlen = 0; | 15 | 1 | Py_ssize_t sz = 0; | 16 | 1 | Py_ssize_t i, nbufs; | 17 | 1 | PyObject *seq, *item; | 18 | 1 | Py_buffer *buffers = NULL; | 19 | 1 | #define NB_STATIC_BUFFERS 10 | 20 | 1 | Py_buffer static_buffers[NB_STATIC_BUFFERS]; | 21 | | | 22 | 1 | seq = PySequence_Fast(iterable, "can only join an iterable"); | 23 | 1 | if (seq == NULL) { | 24 | 0 | return NULL; | 25 | 0 | } | 26 | | | 27 | 1 | seqlen = PySequence_Fast_GET_SIZE(seq); | 28 | 1 | if (seqlen == 0) { | 29 | 0 | Py_DECREF(seq); | 30 | 0 | return STRINGLIB_NEW(NULL, 0); | 31 | 0 | } | 32 | 1 | #ifndef STRINGLIB_MUTABLE | 33 | 1 | if (seqlen == 1) { | 34 | 1 | item = PySequence_Fast_GET_ITEM(seq, 0); | 35 | 1 | if (STRINGLIB_CHECK_EXACT(item)) { | 36 | 1 | Py_INCREF(item); | 37 | 1 | Py_DECREF(seq); | 38 | 1 | return item; | 39 | 1 | } | 40 | 1 | } | 41 | 0 | #endif | 42 | 0 | if (seqlen > NB_STATIC_BUFFERS) { | 43 | 0 | buffers = PyMem_NEW(Py_buffer, seqlen); | 44 | 0 | if (buffers == NULL) { | 45 | 0 | Py_DECREF(seq); | 46 | 0 | PyErr_NoMemory(); | 47 | 0 | return NULL; | 48 | 0 | } | 49 | 0 | } | 50 | 0 | else { | 51 | 0 | buffers = static_buffers; | 52 | 0 | } | 53 | | | 54 | | /* Here is the general case. Do a pre-pass to figure out the total | 55 | | * amount of space we'll need (sz), and see whether all arguments are | 56 | | * bytes-like. | 57 | | */ | 58 | 0 | for (i = 0, nbufs = 0; i < seqlen; i++) { | 59 | 0 | Py_ssize_t itemlen; | 60 | 0 | item = PySequence_Fast_GET_ITEM(seq, i); | 61 | 0 | if (PyBytes_CheckExact(item)) { | 62 | | /* Fast path. */ | 63 | 0 | Py_INCREF(item); | 64 | 0 | buffers[i].obj = item; | 65 | 0 | buffers[i].buf = PyBytes_AS_STRING(item); | 66 | 0 | buffers[i].len = PyBytes_GET_SIZE(item); | 67 | 0 | } | 68 | 0 | else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) { | 69 | 0 | PyErr_Format(PyExc_TypeError, | 70 | 0 | "sequence item %zd: expected a bytes-like object, " | 71 | 0 | "%.80s found", | 72 | 0 | i, Py_TYPE(item)->tp_name); | 73 | 0 | goto error; | 74 | 0 | } | 75 | 0 | nbufs = i + 1; /* for error cleanup */ | 76 | 0 | itemlen = buffers[i].len; | 77 | 0 | if (itemlen > PY_SSIZE_T_MAX - sz) { | 78 | 0 | PyErr_SetString(PyExc_OverflowError, | 79 | 0 | "join() result is too long"); | 80 | 0 | goto error; | 81 | 0 | } | 82 | 0 | sz += itemlen; | 83 | 0 | if (i != 0) { | 84 | 0 | if (seplen > PY_SSIZE_T_MAX - sz) { | 85 | 0 | PyErr_SetString(PyExc_OverflowError, | 86 | 0 | "join() result is too long"); | 87 | 0 | goto error; | 88 | 0 | } | 89 | 0 | sz += seplen; | 90 | 0 | } | 91 | 0 | if (seqlen != PySequence_Fast_GET_SIZE(seq)) { | 92 | 0 | PyErr_SetString(PyExc_RuntimeError, | 93 | 0 | "sequence changed size during iteration"); | 94 | 0 | goto error; | 95 | 0 | } | 96 | 0 | } | 97 | | | 98 | | /* Allocate result space. */ | 99 | 0 | res = STRINGLIB_NEW(NULL, sz); | 100 | 0 | if (res == NULL) | 101 | 0 | goto error; | 102 | | | 103 | | /* Catenate everything. */ | 104 | 0 | p = STRINGLIB_STR(res); | 105 | 0 | if (!seplen) { | 106 | | /* fast path */ | 107 | 0 | for (i = 0; i < nbufs; i++) { | 108 | 0 | Py_ssize_t n = buffers[i].len; | 109 | 0 | char *q = buffers[i].buf; | 110 | 0 | memcpy(p, q, n); | 111 | 0 | p += n; | 112 | 0 | } | 113 | 0 | goto done; | 114 | 0 | } | 115 | 0 | for (i = 0; i < nbufs; i++) { | 116 | 0 | Py_ssize_t n; | 117 | 0 | char *q; | 118 | 0 | if (i) { | 119 | 0 | memcpy(p, sepstr, seplen); | 120 | 0 | p += seplen; | 121 | 0 | } | 122 | 0 | n = buffers[i].len; | 123 | 0 | q = buffers[i].buf; | 124 | 0 | memcpy(p, q, n); | 125 | 0 | p += n; | 126 | 0 | } | 127 | 0 | goto done; | 128 | | | 129 | 0 | error: | 130 | 0 | res = NULL; | 131 | 0 | done: | 132 | 0 | Py_DECREF(seq); | 133 | 0 | for (i = 0; i < nbufs; i++) | 134 | 0 | PyBuffer_Release(&buffers[i]); | 135 | 0 | if (buffers != static_buffers) | 136 | 0 | PyMem_FREE(buffers); | 137 | 0 | return res; | 138 | 0 | } |
|
139 | | |
140 | | #undef NB_STATIC_BUFFERS |