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