mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	
		
			
	
	
		
			115 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			115 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/* Accumulator struct implementation */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "Python.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static PyObject *
							 | 
						||
| 
								 | 
							
								join_list_unicode(PyObject *lst)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    /* return ''.join(lst) */
							 | 
						||
| 
								 | 
							
								    PyObject *sep, *ret;
							 | 
						||
| 
								 | 
							
								    sep = PyUnicode_FromStringAndSize("", 0);
							 | 
						||
| 
								 | 
							
								    ret = PyUnicode_Join(sep, lst);
							 | 
						||
| 
								 | 
							
								    Py_DECREF(sep);
							 | 
						||
| 
								 | 
							
								    return ret;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int
							 | 
						||
| 
								 | 
							
								_PyAccu_Init(_PyAccu *acc)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    /* Lazily allocated */
							 | 
						||
| 
								 | 
							
								    acc->large = NULL;
							 | 
						||
| 
								 | 
							
								    acc->small = PyList_New(0);
							 | 
						||
| 
								 | 
							
								    if (acc->small == NULL)
							 | 
						||
| 
								 | 
							
								        return -1;
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								flush_accumulator(_PyAccu *acc)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Py_ssize_t nsmall = PyList_GET_SIZE(acc->small);
							 | 
						||
| 
								 | 
							
								    if (nsmall) {
							 | 
						||
| 
								 | 
							
								        int ret;
							 | 
						||
| 
								 | 
							
								        PyObject *joined;
							 | 
						||
| 
								 | 
							
								        if (acc->large == NULL) {
							 | 
						||
| 
								 | 
							
								            acc->large = PyList_New(0);
							 | 
						||
| 
								 | 
							
								            if (acc->large == NULL)
							 | 
						||
| 
								 | 
							
								                return -1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        joined = join_list_unicode(acc->small);
							 | 
						||
| 
								 | 
							
								        if (joined == NULL)
							 | 
						||
| 
								 | 
							
								            return -1;
							 | 
						||
| 
								 | 
							
								        if (PyList_SetSlice(acc->small, 0, nsmall, NULL)) {
							 | 
						||
| 
								 | 
							
								            Py_DECREF(joined);
							 | 
						||
| 
								 | 
							
								            return -1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        ret = PyList_Append(acc->large, joined);
							 | 
						||
| 
								 | 
							
								        Py_DECREF(joined);
							 | 
						||
| 
								 | 
							
								        return ret;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int
							 | 
						||
| 
								 | 
							
								_PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Py_ssize_t nsmall;
							 | 
						||
| 
								 | 
							
								    assert(PyUnicode_Check(unicode));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (PyList_Append(acc->small, unicode))
							 | 
						||
| 
								 | 
							
								        return -1;
							 | 
						||
| 
								 | 
							
								    nsmall = PyList_GET_SIZE(acc->small);
							 | 
						||
| 
								 | 
							
								    /* Each item in a list of unicode objects has an overhead (in 64-bit
							 | 
						||
| 
								 | 
							
								     * builds) of:
							 | 
						||
| 
								 | 
							
								     *   - 8 bytes for the list slot
							 | 
						||
| 
								 | 
							
								     *   - 56 bytes for the header of the unicode object
							 | 
						||
| 
								 | 
							
								     * that is, 64 bytes.  100000 such objects waste more than 6MB
							 | 
						||
| 
								 | 
							
								     * compared to a single concatenated string.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    if (nsmall < 100000)
							 | 
						||
| 
								 | 
							
								        return 0;
							 | 
						||
| 
								 | 
							
								    return flush_accumulator(acc);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PyObject *
							 | 
						||
| 
								 | 
							
								_PyAccu_FinishAsList(_PyAccu *acc)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int ret;
							 | 
						||
| 
								 | 
							
								    PyObject *res;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ret = flush_accumulator(acc);
							 | 
						||
| 
								 | 
							
								    Py_CLEAR(acc->small);
							 | 
						||
| 
								 | 
							
								    if (ret) {
							 | 
						||
| 
								 | 
							
								        Py_CLEAR(acc->large);
							 | 
						||
| 
								 | 
							
								        return NULL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    res = acc->large;
							 | 
						||
| 
								 | 
							
								    acc->large = NULL;
							 | 
						||
| 
								 | 
							
								    return res;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PyObject *
							 | 
						||
| 
								 | 
							
								_PyAccu_Finish(_PyAccu *acc)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    PyObject *list, *res;
							 | 
						||
| 
								 | 
							
								    if (acc->large == NULL) {
							 | 
						||
| 
								 | 
							
								        list = acc->small;
							 | 
						||
| 
								 | 
							
								        acc->small = NULL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        list = _PyAccu_FinishAsList(acc);
							 | 
						||
| 
								 | 
							
								        if (!list)
							 | 
						||
| 
								 | 
							
								            return NULL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    res = join_list_unicode(list);
							 | 
						||
| 
								 | 
							
								    Py_DECREF(list);
							 | 
						||
| 
								 | 
							
								    return res;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								_PyAccu_Destroy(_PyAccu *acc)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Py_CLEAR(acc->small);
							 | 
						||
| 
								 | 
							
								    Py_CLEAR(acc->large);
							 | 
						||
| 
								 | 
							
								}
							 |