Coverage Report

Created: 2025-07-11 06:59

/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
}