--- bltinmodule.rev62728.trunk.c 2008-05-06 12:33:14.000000000 -0700 +++ bltinmodule3.c 2008-05-08 12:28:33.000000000 -0700 @@ -2221,6 +2221,7 @@ static PyObject* builtin_sum(PyObject *self, PyObject *args) { +#ifdef SLOW_SUM /* Slow summation */ PyObject *seq; PyObject *result = NULL; PyObject *temp, *item, *iter; @@ -2249,103 +2250,150 @@ 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); + for(;;) { + item = PyIter_Next(iter); + if (item == NULL) { + /* error, or end-of-sequence */ + if (PyErr_Occurred()) { + Py_DECREF(result); + result = NULL; + } + break; + } + temp = PyNumber_Add(result, item); Py_DECREF(result); - result = NULL; - while(result == NULL) { + Py_DECREF(item); + result = temp; + if (result == NULL) + break; + } + Py_DECREF(iter); + return result; + +#else /* Fast summation */ + PyObject *seq, *iter, *item; + PyObject *sum = NULL; + + if (!PyArg_UnpackTuple(args, "sum", 1, 2, &seq, &sum)) + return NULL; + + iter = PyObject_GetIter(seq); + if (iter == NULL) + return NULL; + + if (sum == NULL) { + sum = PyInt_FromLong(0); + if (sum == NULL) { + Py_DECREF(iter); + return NULL; + } + } else { + /* reject string values for 'start' parameter */ + 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); + } + + /* get very first item as + representative type */ + item = PyIter_Next(iter); + if (item == NULL) { + Py_DECREF(iter); + if (PyErr_Occurred()) { + Py_DECREF(sum); + sum = NULL; + } + return sum; + } + + /* keep adding ints */ + if (PyInt_CheckExact(item) && PyInt_CheckExact(sum)) { + /* sum is most likely zero */ + long i_sum = PyInt_AS_LONG(item); + Py_DECREF(item); + item = sum; + do { + long i = PyInt_AS_LONG(item); + if (i) { + long x = i_sum + i; + if ((x ^ i_sum) < 0 && (x ^ i) < 0) + break; /* int overflow */ + i_sum = x; + } + Py_DECREF(item); item = PyIter_Next(iter); if (item == NULL) { Py_DECREF(iter); if (PyErr_Occurred()) return NULL; - return PyInt_FromLong(i_result); + return PyInt_FromLong(i_sum); } - 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); + } while (PyInt_CheckExact(item)); + sum = PyInt_FromLong(i_sum); + if (sum == NULL) { Py_DECREF(item); - result = temp; - if (result == NULL) { - Py_DECREF(iter); - return 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) { + /* keep adding floats and ints */ + if (PyFloat_CheckExact(item) && (PyFloat_CheckExact(sum) || + PyInt_CheckExact(sum))) { + double f, f_sum = PyFloat_AS_DOUBLE(item); + Py_DECREF(item); + item = sum; + for (;;) { + if (PyFloat_CheckExact(item)) + f = PyFloat_AS_DOUBLE(item); + else if (PyInt_CheckExact(item)) + f = (double)PyInt_AS_LONG(item); + else + break; + Py_DECREF(item); + PyFPE_START_PROTECT("add", Py_DECREF(iter); return NULL) + f_sum += f; + PyFPE_END_PROTECT(f_sum) + 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; + return PyFloat_FromDouble(f_sum); } - result = PyFloat_FromDouble(f_result); - temp = PyNumber_Add(result, item); - Py_DECREF(result); + } + sum = PyFloat_FromDouble(f_sum); + if (sum == NULL) { Py_DECREF(item); - result = temp; - if (result == NULL) { - Py_DECREF(iter); - return NULL; - } + Py_DECREF(iter); + return NULL; } } -#endif - for(;;) { - item = PyIter_Next(iter); - if (item == NULL) { - /* error, or end-of-sequence */ - if (PyErr_Occurred()) { - Py_DECREF(result); - result = NULL; - } - break; - } - temp = PyNumber_Add(result, item); - Py_DECREF(result); + /* add any remaining items */ + do { + PyObject *tmp = PyNumber_Add(sum, item); Py_DECREF(item); - result = temp; - if (result == NULL) - break; - } + Py_DECREF(sum); + sum = tmp; + if (sum == NULL) { + Py_DECREF(iter); + return NULL; + } + item = PyIter_Next(iter); + } while (item != NULL); Py_DECREF(iter); - return result; + if (PyErr_Occurred()) { + Py_DECREF(sum); + sum = NULL; + } + return sum; +#endif } PyDoc_STRVAR(sum_doc,