@@ -36,10 +36,24 @@ static PyObject *_cstring_new(PyTypeObject *type, const char *value, Py_ssize_t
36
36
return (PyObject * )new ;
37
37
}
38
38
39
+ static PyObject * _cstring_realloc (PyObject * self , Py_ssize_t len ) {
40
+ struct cstring * new = (struct cstring * )PyObject_Realloc (self , sizeof (struct cstring ) + len + 1 );
41
+ if (!new )
42
+ return PyErr_NoMemory ();
43
+ Py_SET_SIZE (new , len + 1 );
44
+ new -> hash = -1 ;
45
+ return (PyObject * )new ;
46
+ }
47
+
48
+ static PyObject * _cstring_copy (PyObject * self ) {
49
+ return _cstring_new (Py_TYPE (self ), CSTRING_VALUE (self ), Py_SIZE (self ) - 1 );
50
+ }
51
+
39
52
static PyObject * cstring_new_empty (void ) {
40
53
return _cstring_new (& cstring_type , "" , 0 );
41
54
}
42
55
56
+
43
57
static const char * _obj_as_string_and_size (PyObject * o , Py_ssize_t * s ) {
44
58
if (PyUnicode_Check (o ))
45
59
return PyUnicode_AsUTF8AndSize (o , s );
@@ -147,6 +161,29 @@ static Py_ssize_t cstring_len(PyObject *self) {
147
161
return Py_SIZE (self ) - 1 ;
148
162
}
149
163
164
+ static PyObject * _concat_in_place (PyObject * self , PyObject * other ) {
165
+ if (!other )
166
+ return PyErr_BadArgument (), NULL ;
167
+ if (!_ensure_cstring (other ))
168
+ return NULL ;
169
+ if (!self )
170
+ return _cstring_copy (other ); /* new (mutable) copy with refcnt=1 */
171
+ if (!_ensure_cstring (self ))
172
+ return NULL ;
173
+ if (Py_REFCNT (self ) > 1 )
174
+ return PyErr_BadInternalCall (), NULL ;
175
+
176
+ Py_ssize_t origlen = cstring_len (self );
177
+ Py_ssize_t newlen = origlen + cstring_len (other );
178
+ PyObject * new = _cstring_realloc (self , newlen );
179
+ if (!new )
180
+ return NULL ;
181
+
182
+ memcpy (CSTRING_VALUE_AT (new , origlen ), CSTRING_VALUE (other ), cstring_len (other ));
183
+ * CSTRING_VALUE_AT (new , newlen ) = '\0' ;
184
+ return new ;
185
+ }
186
+
150
187
static PyObject * cstring_concat (PyObject * left , PyObject * right ) {
151
188
if (!_ensure_cstring (left ))
152
189
return NULL ;
@@ -456,6 +493,37 @@ PyObject *cstring_isupper(PyObject *self, PyObject *args) {
456
493
Py_RETURN_FALSE ;
457
494
}
458
495
496
+ PyDoc_STRVAR (join__doc__ , "" );
497
+ PyObject * cstring_join (PyObject * self , PyObject * arg ) {
498
+ PyObject * iter = PyObject_GetIter (arg );
499
+ if (!iter )
500
+ return NULL ;
501
+
502
+ PyObject * result = NULL ;
503
+ PyObject * item = NULL ;
504
+
505
+ while ((item = PyIter_Next (iter )) != NULL ) {
506
+ if (result ) {
507
+ PyObject * next = _concat_in_place (result , self );
508
+ if (!next )
509
+ goto fail ;
510
+ result = next ;
511
+ }
512
+ PyObject * next = _concat_in_place (result , item );
513
+ if (!next )
514
+ goto fail ;
515
+ Py_DECREF (item );
516
+ result = next ;
517
+ }
518
+
519
+ return result ;
520
+
521
+ fail :
522
+ Py_XDECREF (item );
523
+ Py_XDECREF (result );
524
+ return NULL ;
525
+ }
526
+
459
527
PyDoc_STRVAR (lower__doc__ , "" );
460
528
PyObject * cstring_lower (PyObject * self , PyObject * args ) {
461
529
struct cstring * new = CSTRING_ALLOC (Py_TYPE (self ), Py_SIZE (self ));
@@ -589,7 +657,7 @@ static PyMethodDef cstring_methods[] = {
589
657
{"isspace" , cstring_isspace , METH_NOARGS , isspace__doc__ },
590
658
/* TODO: istitle */
591
659
{"isupper" , cstring_isupper , METH_NOARGS , isupper__doc__ },
592
- /* TODO: join */
660
+ { "join" , cstring_join , METH_O , join__doc__ },
593
661
/* TODO: ljust */
594
662
{"lower" , cstring_lower , METH_NOARGS , lower__doc__ },
595
663
/* TODO: lstrip */
0 commit comments