| /* Accumulator struct implementation */ | 
 |  | 
 | #include "Python.h" | 
 | #include "accu.h" | 
 |  | 
 | static PyObject * | 
 | join_list_unicode(PyObject *lst) | 
 | { | 
 |     /* return ''.join(lst) */ | 
 |     PyObject *sep, *ret; | 
 |     sep = PyUnicode_FromStringAndSize("", 0); | 
 |     ret = PyUnicode_Join(sep, lst); | 
 |     Py_DECREF(sep); | 
 |     return ret; | 
 | } | 
 |  | 
 | int | 
 | _PyAccu_Init(_PyAccu *acc) | 
 | { | 
 |     /* Lazily allocated */ | 
 |     acc->large = NULL; | 
 |     acc->small = PyList_New(0); | 
 |     if (acc->small == NULL) | 
 |         return -1; | 
 |     return 0; | 
 | } | 
 |  | 
 | static int | 
 | flush_accumulator(_PyAccu *acc) | 
 | { | 
 |     Py_ssize_t nsmall = PyList_GET_SIZE(acc->small); | 
 |     if (nsmall) { | 
 |         int ret; | 
 |         PyObject *joined; | 
 |         if (acc->large == NULL) { | 
 |             acc->large = PyList_New(0); | 
 |             if (acc->large == NULL) | 
 |                 return -1; | 
 |         } | 
 |         joined = join_list_unicode(acc->small); | 
 |         if (joined == NULL) | 
 |             return -1; | 
 |         if (PyList_SetSlice(acc->small, 0, nsmall, NULL)) { | 
 |             Py_DECREF(joined); | 
 |             return -1; | 
 |         } | 
 |         ret = PyList_Append(acc->large, joined); | 
 |         Py_DECREF(joined); | 
 |         return ret; | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | int | 
 | _PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode) | 
 | { | 
 |     Py_ssize_t nsmall; | 
 |     assert(PyUnicode_Check(unicode)); | 
 |  | 
 |     if (PyList_Append(acc->small, unicode)) | 
 |         return -1; | 
 |     nsmall = PyList_GET_SIZE(acc->small); | 
 |     /* Each item in a list of unicode objects has an overhead (in 64-bit | 
 |      * builds) of: | 
 |      *   - 8 bytes for the list slot | 
 |      *   - 56 bytes for the header of the unicode object | 
 |      * that is, 64 bytes.  100000 such objects waste more than 6 MiB | 
 |      * compared to a single concatenated string. | 
 |      */ | 
 |     if (nsmall < 100000) | 
 |         return 0; | 
 |     return flush_accumulator(acc); | 
 | } | 
 |  | 
 | PyObject * | 
 | _PyAccu_FinishAsList(_PyAccu *acc) | 
 | { | 
 |     int ret; | 
 |     PyObject *res; | 
 |  | 
 |     ret = flush_accumulator(acc); | 
 |     Py_CLEAR(acc->small); | 
 |     if (ret) { | 
 |         Py_CLEAR(acc->large); | 
 |         return NULL; | 
 |     } | 
 |     res = acc->large; | 
 |     acc->large = NULL; | 
 |     return res; | 
 | } | 
 |  | 
 | PyObject * | 
 | _PyAccu_Finish(_PyAccu *acc) | 
 | { | 
 |     PyObject *list, *res; | 
 |     if (acc->large == NULL) { | 
 |         list = acc->small; | 
 |         acc->small = NULL; | 
 |     } | 
 |     else { | 
 |         list = _PyAccu_FinishAsList(acc); | 
 |         if (!list) | 
 |             return NULL; | 
 |     } | 
 |     res = join_list_unicode(list); | 
 |     Py_DECREF(list); | 
 |     return res; | 
 | } | 
 |  | 
 | void | 
 | _PyAccu_Destroy(_PyAccu *acc) | 
 | { | 
 |     Py_CLEAR(acc->small); | 
 |     Py_CLEAR(acc->large); | 
 | } |