@@ -75,17 +75,6 @@ static PyMemberDef encoder_members[] = {
7575 {NULL }
7676};
7777
78- /*
79- * A two-level accumulator of unicode objects that avoids both the overhead
80- * of keeping a huge number of small separate objects, and the quadratic
81- * behaviour of using a naive repeated concatenation scheme.
82- */
83-
84- typedef struct {
85- PyObject * large ; /* A list of previously accumulated large strings */
86- PyObject * small ; /* Pending small strings */
87- } accumulator ;
88-
8978static PyObject *
9079join_list_unicode (PyObject * lst )
9180{
@@ -99,96 +88,6 @@ join_list_unicode(PyObject *lst)
9988 return PyUnicode_Join (sep , lst );
10089}
10190
102- static int
103- init_accumulator (accumulator * acc )
104- {
105- acc -> large = PyList_New (0 );
106- if (acc -> large == NULL )
107- return -1 ;
108- acc -> small = PyList_New (0 );
109- if (acc -> small == NULL ) {
110- Py_CLEAR (acc -> large );
111- return -1 ;
112- }
113- return 0 ;
114- }
115-
116- static int
117- flush_accumulator (accumulator * acc )
118- {
119- Py_ssize_t nsmall = PyList_GET_SIZE (acc -> small );
120- if (nsmall ) {
121- int ret ;
122- PyObject * joined = join_list_unicode (acc -> small );
123- if (joined == NULL )
124- return -1 ;
125- if (PyList_SetSlice (acc -> small , 0 , nsmall , NULL )) {
126- Py_DECREF (joined );
127- return -1 ;
128- }
129- ret = PyList_Append (acc -> large , joined );
130- Py_DECREF (joined );
131- return ret ;
132- }
133- return 0 ;
134- }
135-
136- static int
137- accumulate_unicode (accumulator * acc , PyObject * obj )
138- {
139- int ret ;
140- Py_ssize_t nsmall ;
141- PyObject * joined ;
142- assert (PyUnicode_Check (obj ));
143-
144- if (PyList_Append (acc -> small , obj ))
145- return -1 ;
146- nsmall = PyList_GET_SIZE (acc -> small );
147- /* Each item in a list of unicode objects has an overhead (in 64-bit
148- * builds) of:
149- * - 8 bytes for the list slot
150- * - 56 bytes for the header of the unicode object
151- * that is, 64 bytes. 100000 such objects waste more than 6MB
152- * compared to a single concatenated string.
153- */
154- if (nsmall < 100000 )
155- return 0 ;
156- joined = join_list_unicode (acc -> small );
157- if (joined == NULL )
158- return -1 ;
159- if (PyList_SetSlice (acc -> small , 0 , nsmall , NULL )) {
160- Py_DECREF (joined );
161- return -1 ;
162- }
163- ret = PyList_Append (acc -> large , joined );
164- Py_DECREF (joined );
165- return ret ;
166- }
167-
168- static PyObject *
169- finish_accumulator (accumulator * acc )
170- {
171- int ret ;
172- PyObject * res ;
173-
174- ret = flush_accumulator (acc );
175- Py_CLEAR (acc -> small );
176- if (ret ) {
177- Py_CLEAR (acc -> large );
178- return NULL ;
179- }
180- res = acc -> large ;
181- acc -> large = NULL ;
182- return res ;
183- }
184-
185- static void
186- destroy_accumulator (accumulator * acc )
187- {
188- Py_CLEAR (acc -> small );
189- Py_CLEAR (acc -> large );
190- }
191-
19291/* Forward decls */
19392
19493static PyObject *
@@ -217,11 +116,11 @@ encoder_dealloc(PyObject *self);
217116static int
218117encoder_clear (PyObject * self );
219118static int
220- encoder_listencode_list (PyEncoderObject * s , accumulator * acc , PyObject * seq , Py_ssize_t indent_level );
119+ encoder_listencode_list (PyEncoderObject * s , _PyAccu * acc , PyObject * seq , Py_ssize_t indent_level );
221120static int
222- encoder_listencode_obj (PyEncoderObject * s , accumulator * acc , PyObject * obj , Py_ssize_t indent_level );
121+ encoder_listencode_obj (PyEncoderObject * s , _PyAccu * acc , PyObject * obj , Py_ssize_t indent_level );
223122static int
224- encoder_listencode_dict (PyEncoderObject * s , accumulator * acc , PyObject * dct , Py_ssize_t indent_level );
123+ encoder_listencode_dict (PyEncoderObject * s , _PyAccu * acc , PyObject * dct , Py_ssize_t indent_level );
225124static PyObject *
226125_encoded_const (PyObject * obj );
227126static void
@@ -1383,20 +1282,20 @@ encoder_call(PyObject *self, PyObject *args, PyObject *kwds)
13831282 PyObject * obj ;
13841283 Py_ssize_t indent_level ;
13851284 PyEncoderObject * s ;
1386- accumulator acc ;
1285+ _PyAccu acc ;
13871286
13881287 assert (PyEncoder_Check (self ));
13891288 s = (PyEncoderObject * )self ;
13901289 if (!PyArg_ParseTupleAndKeywords (args , kwds , "OO&:_iterencode" , kwlist ,
13911290 & obj , _convertPyInt_AsSsize_t , & indent_level ))
13921291 return NULL ;
1393- if (init_accumulator (& acc ))
1292+ if (_PyAccu_Init (& acc ))
13941293 return NULL ;
13951294 if (encoder_listencode_obj (s , & acc , obj , indent_level )) {
1396- destroy_accumulator (& acc );
1295+ _PyAccu_Destroy (& acc );
13971296 return NULL ;
13981297 }
1399- return finish_accumulator (& acc );
1298+ return _PyAccu_FinishAsList (& acc );
14001299}
14011300
14021301static PyObject *
@@ -1468,16 +1367,16 @@ encoder_encode_string(PyEncoderObject *s, PyObject *obj)
14681367}
14691368
14701369static int
1471- _steal_accumulate (accumulator * acc , PyObject * stolen )
1370+ _steal_accumulate (_PyAccu * acc , PyObject * stolen )
14721371{
14731372 /* Append stolen and then decrement its reference count */
1474- int rval = accumulate_unicode (acc , stolen );
1373+ int rval = _PyAccu_Accumulate (acc , stolen );
14751374 Py_DECREF (stolen );
14761375 return rval ;
14771376}
14781377
14791378static int
1480- encoder_listencode_obj (PyEncoderObject * s , accumulator * acc ,
1379+ encoder_listencode_obj (PyEncoderObject * s , _PyAccu * acc ,
14811380 PyObject * obj , Py_ssize_t indent_level )
14821381{
14831382 /* Encode Python object obj to a JSON term */
@@ -1570,7 +1469,7 @@ encoder_listencode_obj(PyEncoderObject *s, accumulator *acc,
15701469}
15711470
15721471static int
1573- encoder_listencode_dict (PyEncoderObject * s , accumulator * acc ,
1472+ encoder_listencode_dict (PyEncoderObject * s , _PyAccu * acc ,
15741473 PyObject * dct , Py_ssize_t indent_level )
15751474{
15761475 /* Encode Python dict dct a JSON term */
@@ -1593,7 +1492,7 @@ encoder_listencode_dict(PyEncoderObject *s, accumulator *acc,
15931492 return -1 ;
15941493 }
15951494 if (Py_SIZE (dct ) == 0 )
1596- return accumulate_unicode (acc , empty_dict );
1495+ return _PyAccu_Accumulate (acc , empty_dict );
15971496
15981497 if (s -> markers != Py_None ) {
15991498 int has_key ;
@@ -1611,7 +1510,7 @@ encoder_listencode_dict(PyEncoderObject *s, accumulator *acc,
16111510 }
16121511 }
16131512
1614- if (accumulate_unicode (acc , open_dict ))
1513+ if (_PyAccu_Accumulate (acc , open_dict ))
16151514 goto bail ;
16161515
16171516 if (s -> indent != Py_None ) {
@@ -1698,20 +1597,20 @@ encoder_listencode_dict(PyEncoderObject *s, accumulator *acc,
16981597 }
16991598
17001599 if (idx ) {
1701- if (accumulate_unicode (acc , s -> item_separator ))
1600+ if (_PyAccu_Accumulate (acc , s -> item_separator ))
17021601 goto bail ;
17031602 }
17041603
17051604 encoded = encoder_encode_string (s , kstr );
17061605 Py_CLEAR (kstr );
17071606 if (encoded == NULL )
17081607 goto bail ;
1709- if (accumulate_unicode (acc , encoded )) {
1608+ if (_PyAccu_Accumulate (acc , encoded )) {
17101609 Py_DECREF (encoded );
17111610 goto bail ;
17121611 }
17131612 Py_DECREF (encoded );
1714- if (accumulate_unicode (acc , s -> key_separator ))
1613+ if (_PyAccu_Accumulate (acc , s -> key_separator ))
17151614 goto bail ;
17161615
17171616 value = PyTuple_GET_ITEM (item , 1 );
@@ -1735,7 +1634,7 @@ encoder_listencode_dict(PyEncoderObject *s, accumulator *acc,
17351634
17361635 yield '\n' + (' ' * (_indent * _current_indent_level))
17371636 }*/
1738- if (accumulate_unicode (acc , close_dict ))
1637+ if (_PyAccu_Accumulate (acc , close_dict ))
17391638 goto bail ;
17401639 return 0 ;
17411640
@@ -1749,7 +1648,7 @@ encoder_listencode_dict(PyEncoderObject *s, accumulator *acc,
17491648
17501649
17511650static int
1752- encoder_listencode_list (PyEncoderObject * s , accumulator * acc ,
1651+ encoder_listencode_list (PyEncoderObject * s , _PyAccu * acc ,
17531652 PyObject * seq , Py_ssize_t indent_level )
17541653{
17551654 /* Encode Python list seq to a JSON term */
@@ -1776,7 +1675,7 @@ encoder_listencode_list(PyEncoderObject *s, accumulator *acc,
17761675 num_items = PySequence_Fast_GET_SIZE (s_fast );
17771676 if (num_items == 0 ) {
17781677 Py_DECREF (s_fast );
1779- return accumulate_unicode (acc , empty_array );
1678+ return _PyAccu_Accumulate (acc , empty_array );
17801679 }
17811680
17821681 if (s -> markers != Py_None ) {
@@ -1796,7 +1695,7 @@ encoder_listencode_list(PyEncoderObject *s, accumulator *acc,
17961695 }
17971696
17981697 seq_items = PySequence_Fast_ITEMS (s_fast );
1799- if (accumulate_unicode (acc , open_array ))
1698+ if (_PyAccu_Accumulate (acc , open_array ))
18001699 goto bail ;
18011700 if (s -> indent != Py_None ) {
18021701 /* TODO: DOES NOT RUN */
@@ -1810,7 +1709,7 @@ encoder_listencode_list(PyEncoderObject *s, accumulator *acc,
18101709 for (i = 0 ; i < num_items ; i ++ ) {
18111710 PyObject * obj = seq_items [i ];
18121711 if (i ) {
1813- if (accumulate_unicode (acc , s -> item_separator ))
1712+ if (_PyAccu_Accumulate (acc , s -> item_separator ))
18141713 goto bail ;
18151714 }
18161715 if (encoder_listencode_obj (s , acc , obj , indent_level ))
@@ -1828,7 +1727,7 @@ encoder_listencode_list(PyEncoderObject *s, accumulator *acc,
18281727
18291728 yield '\n' + (' ' * (_indent * _current_indent_level))
18301729 }*/
1831- if (accumulate_unicode (acc , close_array ))
1730+ if (_PyAccu_Accumulate (acc , close_array ))
18321731 goto bail ;
18331732 Py_DECREF (s_fast );
18341733 return 0 ;
0 commit comments