Branch data Line data Source code
1 : : /* Accumulator struct implementation */ 2 : : 3 : : #include "Python.h" 4 : : #include "pycore_accu.h" 5 : : 6 : : static PyObject * 7 : 12734 : join_list_unicode(PyObject *lst) 8 : : { 9 : : /* return ''.join(lst) */ 10 : : PyObject *sep, *ret; 11 : 12734 : sep = PyUnicode_FromStringAndSize("", 0); 12 : 12734 : ret = PyUnicode_Join(sep, lst); 13 : 12734 : Py_DECREF(sep); 14 : 12734 : return ret; 15 : : } 16 : : 17 : : int 18 : 1480015 : _PyAccu_Init(_PyAccu *acc) 19 : : { 20 : : /* Lazily allocated */ 21 : 1480015 : acc->large = NULL; 22 : 1480015 : acc->small = PyList_New(0); 23 [ - + ]: 1480015 : if (acc->small == NULL) 24 : 0 : return -1; 25 : 1480015 : return 0; 26 : : } 27 : : 28 : : static int 29 : 1091 : flush_accumulator(_PyAccu *acc) 30 : : { 31 : 1091 : Py_ssize_t nsmall = PyList_GET_SIZE(acc->small); 32 [ + - ]: 1091 : if (nsmall) { 33 : : int ret; 34 : : PyObject *joined; 35 [ + - ]: 1091 : if (acc->large == NULL) { 36 : 1091 : acc->large = PyList_New(0); 37 [ - + ]: 1091 : if (acc->large == NULL) 38 : 0 : return -1; 39 : : } 40 : 1091 : joined = join_list_unicode(acc->small); 41 [ - + ]: 1091 : if (joined == NULL) 42 : 0 : return -1; 43 [ - + ]: 1091 : if (PyList_SetSlice(acc->small, 0, nsmall, NULL)) { 44 : 0 : Py_DECREF(joined); 45 : 0 : return -1; 46 : : } 47 : 1091 : ret = PyList_Append(acc->large, joined); 48 : 1091 : Py_DECREF(joined); 49 : 1091 : return ret; 50 : : } 51 : 0 : return 0; 52 : : } 53 : : 54 : : int 55 : 279348 : _PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode) 56 : : { 57 : : Py_ssize_t nsmall; 58 : : assert(PyUnicode_Check(unicode)); 59 : : 60 [ - + ]: 279348 : if (PyList_Append(acc->small, unicode)) 61 : 0 : return -1; 62 : 279348 : nsmall = PyList_GET_SIZE(acc->small); 63 : : /* Each item in a list of unicode objects has an overhead (in 64-bit 64 : : * builds) of: 65 : : * - 8 bytes for the list slot 66 : : * - 56 bytes for the header of the unicode object 67 : : * that is, 64 bytes. 100000 such objects waste more than 6 MiB 68 : : * compared to a single concatenated string. 69 : : */ 70 [ + - ]: 279348 : if (nsmall < 100000) 71 : 279348 : return 0; 72 : 0 : return flush_accumulator(acc); 73 : : } 74 : : 75 : : PyObject * 76 : 1091 : _PyAccu_FinishAsList(_PyAccu *acc) 77 : : { 78 : : int ret; 79 : : PyObject *res; 80 : : 81 : 1091 : ret = flush_accumulator(acc); 82 [ + - ]: 1091 : Py_CLEAR(acc->small); 83 [ - + ]: 1091 : if (ret) { 84 [ # # ]: 0 : Py_CLEAR(acc->large); 85 : 0 : return NULL; 86 : : } 87 : 1091 : res = acc->large; 88 : 1091 : acc->large = NULL; 89 : 1091 : return res; 90 : : } 91 : : 92 : : PyObject * 93 : 11643 : _PyAccu_Finish(_PyAccu *acc) 94 : : { 95 : : PyObject *list, *res; 96 [ + - ]: 11643 : if (acc->large == NULL) { 97 : 11643 : list = acc->small; 98 : 11643 : acc->small = NULL; 99 : : } 100 : : else { 101 : 0 : list = _PyAccu_FinishAsList(acc); 102 [ # # ]: 0 : if (!list) 103 : 0 : return NULL; 104 : : } 105 : 11643 : res = join_list_unicode(list); 106 : 11643 : Py_DECREF(list); 107 : 11643 : return res; 108 : : } 109 : : 110 : : void 111 : 2962432 : _PyAccu_Destroy(_PyAccu *acc) 112 : : { 113 [ + + ]: 2962432 : Py_CLEAR(acc->small); 114 [ - + ]: 2962432 : Py_CLEAR(acc->large); 115 : 2962432 : }