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