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