(original) (raw)

--- bltinmodule.rev62728.trunk.c 2008-05-06 12:33:14.000000000 -0700 +++ bltinmodule2.c 2008-05-07 12:27:49.000000000 -0700 @@ -2221,9 +2221,9 @@ static PyObject* builtin_sum(PyObject *self, PyObject *args) { - PyObject *seq; +#ifdef SLOW_SUM /* Slow summation */ + PyObject *seq, *item, *iter, *temp; PyObject *result = NULL; - PyObject *temp, *item, *iter; if (!PyArg_UnpackTuple(args, "sum", 1, 2, &seq, &result)) return NULL; @@ -2249,84 +2249,6 @@ Py_INCREF(result); } -#ifndef SLOW_SUM - /* Fast addition by keeping temporary sums in C instead of new Python objects. - Assumes all inputs are the same type. If the assumption fails, default - to the more general routine. - */ - if (PyInt_CheckExact(result)) { - long i_result = PyInt_AS_LONG(result); - Py_DECREF(result); - result = NULL; - while(result == NULL) { - item = PyIter_Next(iter); - if (item == NULL) { - Py_DECREF(iter); - if (PyErr_Occurred()) - return NULL; - return PyInt_FromLong(i_result); - } - if (PyInt_CheckExact(item)) { - long b = PyInt_AS_LONG(item); - long x = i_result + b; - if ((x^i_result) >= 0 || (x^b) >= 0) { - i_result = x; - Py_DECREF(item); - continue; - } - } - /* Either overflowed or is not an int. Restore real objects and process normally */ - result = PyInt_FromLong(i_result); - temp = PyNumber_Add(result, item); - Py_DECREF(result); - Py_DECREF(item); - result = temp; - if (result == NULL) { - Py_DECREF(iter); - return NULL; - } - } - } - - if (PyFloat_CheckExact(result)) { - double f_result = PyFloat_AS_DOUBLE(result); - Py_DECREF(result); - result = NULL; - while(result == NULL) { - item = PyIter_Next(iter); - if (item == NULL) { - Py_DECREF(iter); - if (PyErr_Occurred()) - return NULL; - return PyFloat_FromDouble(f_result); - } - if (PyFloat_CheckExact(item)) { - PyFPE_START_PROTECT("add", return 0) - f_result += PyFloat_AS_DOUBLE(item); - PyFPE_END_PROTECT(f_result) - Py_DECREF(item); - continue; - } - if (PyInt_CheckExact(item)) { - PyFPE_START_PROTECT("add", return 0) - f_result += (double)PyInt_AS_LONG(item); - PyFPE_END_PROTECT(f_result) - Py_DECREF(item); - continue; - } - result = PyFloat_FromDouble(f_result); - temp = PyNumber_Add(result, item); - Py_DECREF(result); - Py_DECREF(item); - result = temp; - if (result == NULL) { - Py_DECREF(iter); - return NULL; - } - } - } -#endif - for(;;) { item = PyIter_Next(iter); if (item == NULL) { @@ -2346,6 +2268,142 @@ } Py_DECREF(iter); return result; + +#else /* Fast summation */ + PyObject *seq, *iter, *item, *tmp; + PyObject *sum = NULL; + double f_sum = 0.0; + long i_sum = 0; + char some_i = 0; /* no ints */ + char some_f = 0; /* no floats */ + + if (!PyArg_UnpackTuple(args, "sum", 1, 2, &seq, &sum)) + return NULL; + + iter = PyObject_GetIter(seq); + if (iter == NULL) + return NULL; + + if (sum != NULL) { /* reject string values for 'start' */ + if (PyObject_TypeCheck(sum, &PyBaseString_Type)) { + PyErr_SetString(PyExc_TypeError, + "sum() can't sum strings [use ''.join(seq) instead]"); + Py_DECREF(iter); + return NULL; + } + Py_INCREF(sum); + } + + /* Add ints and floats into separate, + partial C sums i_sum resp. f_sum and + any other objects into Python sum. */ + for(;;) { + item = PyIter_Next(iter); + if (item == NULL) { + /* end-of-seq or error */ + Py_DECREF(iter); + if (PyErr_Occurred()) { + Py_XDECREF(sum); + return NULL; + } + break; + } + if (PyInt_CheckExact(item)) { + long i = PyInt_AS_LONG(item); + long x = i_sum + i; + if ((x ^ i_sum) >= 0 || (x ^ i) >= 0) { + i_sum = x; + some_i = 1; /* some ints */ + Py_DECREF(item); + continue; + } + /* handle ints overflow */ + tmp = PyInt_FromLong(i_sum); + if (tmp != NULL) { + Py_DECREF(item); + /* reset i_sum to item's int, + presumably the smaller */ + i_sum = i; + some_i = 1; /* some ints */ + if (sum == NULL) { + /* no 'start', set sum to + i_sum instead of 0 */ + sum = tmp; + continue; + } + /* add i_sum into sum */ + item = tmp; + } else /* ignore error */ + PyErr_Clear(); + + } else if (PyFloat_CheckExact(item)) { + double f = PyFloat_AS_DOUBLE(item); + Py_DECREF(item); + PyFPE_START_PROTECT("add", + Py_DECREF(iter); + Py_XDECREF(sum); + return NULL) + f_sum += f; + PyFPE_END_PROTECT(f_sum) + some_f = 1; /* some floats */ + continue; + } + /* non-int, non-float or int overflow */ + if (sum == NULL) { + /* no 'start', use ints + i_sum instead of 0 */ + sum = PyInt_FromLong(i_sum); + if (sum == NULL) { + Py_DECREF(item); + Py_DECREF(iter); + return NULL; + } + i_sum = 0; + some_i = 0; /* no ints */ + } + tmp = PyNumber_Add(sum, item); + Py_DECREF(sum); + Py_DECREF(item); + sum = tmp; + if (sum == NULL) { + Py_DECREF(iter); + return NULL; + } + } + + /* add ints and floats to sum, even + for zero i_sum and f_sum to force + type errors as with SLOW_SUM */ + if (some_f) { + if (i_sum != 0) { + PyFPE_START_PROTECT("add", + Py_XDECREF(sum); + return NULL) + f_sum += (double)i_sum; + PyFPE_END_PROTECT(f_sum) + } + item = PyFloat_FromDouble(f_sum); + } else if (some_i) + item = PyInt_FromLong(i_sum); + else { /* nothing to add */ + if (sum == NULL) /* empty seq */ + sum = PyInt_FromLong(0); + return sum; + } + /* add item to final sum */ + if (sum == NULL) + sum = item; + else if (item == NULL) { + Py_DECREF(sum); + sum = NULL; + } else { + tmp = PyNumber_Add(sum, item); + Py_DECREF(sum); + Py_DECREF(item); + sum = tmp; + } + return sum; +#endif } PyDoc_STRVAR(sum_doc,