| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  | /* stringlib: bytes joining implementation */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-16 09:42:29 +03:00
										 |  |  | #if STRINGLIB_IS_UNICODE
 | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  | #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); | 
					
						
							| 
									
										
										
										
											2012-12-02 07:56:42 +01:00
										 |  |  |             PyErr_NoMemory(); | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2014-12-05 22:25:22 +02:00
										 |  |  |      * bytes-like. | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     for (i = 0, nbufs = 0; i < seqlen; i++) { | 
					
						
							|  |  |  |         Py_ssize_t itemlen; | 
					
						
							|  |  |  |         item = PySequence_Fast_GET_ITEM(seq, i); | 
					
						
							| 
									
										
										
										
											2015-02-03 01:21:08 +02:00
										 |  |  |         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) { | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  |             PyErr_Format(PyExc_TypeError, | 
					
						
							| 
									
										
										
										
											2014-12-05 22:25:22 +02:00
										 |  |  |                          "sequence item %zd: expected a bytes-like object, " | 
					
						
							|  |  |  |                          "%.80s found", | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  |                          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); | 
					
						
							| 
									
										
										
										
											2012-10-20 23:08:34 +02:00
										 |  |  |     if (!seplen) { | 
					
						
							|  |  |  |         /* fast path */ | 
					
						
							|  |  |  |         for (i = 0; i < nbufs; i++) { | 
					
						
							|  |  |  |             Py_ssize_t n = buffers[i].len; | 
					
						
							|  |  |  |             char *q = buffers[i].buf; | 
					
						
							| 
									
										
										
										
											2016-09-13 20:22:02 +02:00
										 |  |  |             memcpy(p, q, n); | 
					
						
							| 
									
										
										
										
											2012-10-20 23:08:34 +02:00
										 |  |  |             p += n; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         goto done; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  |     for (i = 0; i < nbufs; i++) { | 
					
						
							|  |  |  |         Py_ssize_t n; | 
					
						
							|  |  |  |         char *q; | 
					
						
							|  |  |  |         if (i) { | 
					
						
							| 
									
										
										
										
											2016-09-13 20:22:02 +02:00
										 |  |  |             memcpy(p, sepstr, seplen); | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  |             p += seplen; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         n = buffers[i].len; | 
					
						
							|  |  |  |         q = buffers[i].buf; | 
					
						
							| 
									
										
										
										
											2016-09-13 20:22:02 +02:00
										 |  |  |         memcpy(p, q, n); | 
					
						
							| 
									
										
										
										
											2012-10-16 21:07:23 +02:00
										 |  |  |         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
 |