summaryrefslogtreecommitdiffstats
path: root/Objects/abstract.c
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2007-12-06 00:56:53 (GMT)
committerRaymond Hettinger <python@rcn.com>2007-12-06 00:56:53 (GMT)
commit4e2f714031654eb4174393454c008961b636f539 (patch)
treee415e4318c986483c73d9e5e01b9434a7be9ce83 /Objects/abstract.c
parent923ad7a9488c9b514c8e27315179ada1d142f3e5 (diff)
downloadcpython-4e2f714031654eb4174393454c008961b636f539.zip
cpython-4e2f714031654eb4174393454c008961b636f539.tar.gz
cpython-4e2f714031654eb4174393454c008961b636f539.tar.bz2
Fix Issue 1045.
Factor-out common calling code by simplifying the length_hint API. Speed-up the function by caching the PyObject_String for the attribute lookup.
Diffstat (limited to 'Objects/abstract.c')
-rw-r--r--Objects/abstract.c68
1 files changed, 38 insertions, 30 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 1cb4ef8..4c8ef83 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -82,29 +82,47 @@ PyObject_Length(PyObject *o)
}
#define PyObject_Length PyObject_Size
+
+/* The length hint function returns a non-negative value from o.__len__()
+ or o.__length_hint__(). If those methods aren't found or return a negative
+ value, then the defaultvalue is returned. This function never fails.
+ Accordingly, it will mask exceptions raised in either method.
+*/
+
Py_ssize_t
-_PyObject_LengthHint(PyObject *o)
+_PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
{
- Py_ssize_t rv = PyObject_Size(o);
- if (rv != -1)
+ static PyObject *hintstrobj = NULL;
+ PyObject *ro;
+ Py_ssize_t rv;
+
+ /* try o.__len__() */
+ rv = PyObject_Size(o);
+ if (rv >= 0)
return rv;
- if (PyErr_ExceptionMatches(PyExc_TypeError) ||
- PyErr_ExceptionMatches(PyExc_AttributeError)) {
- PyObject *err_type, *err_value, *err_tb, *ro;
-
- PyErr_Fetch(&err_type, &err_value, &err_tb);
- ro = PyObject_CallMethod(o, "__length_hint__", NULL);
- if (ro != NULL) {
- rv = PyInt_AsLong(ro);
- Py_DECREF(ro);
- Py_XDECREF(err_type);
- Py_XDECREF(err_value);
- Py_XDECREF(err_tb);
- return rv;
- }
- PyErr_Restore(err_type, err_value, err_tb);
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ /* cache a hashed version of the attribute string */
+ if (hintstrobj == NULL) {
+ hintstrobj = PyString_InternFromString("__length_hint__");
+ if (hintstrobj == NULL)
+ goto defaultcase;
}
- return -1;
+
+ /* try o.__length_hint__() */
+ ro = PyObject_CallMethodObjArgs(o, hintstrobj, NULL);
+ if (ro == NULL)
+ goto defaultcase;
+ rv = PyInt_AsLong(ro);
+ Py_DECREF(ro);
+ if (rv >= 0)
+ return rv;
+
+defaultcase:
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ return defaultvalue;
}
PyObject *
@@ -1505,17 +1523,7 @@ PySequence_Tuple(PyObject *v)
return NULL;
/* Guess result size and allocate space. */
- n = _PyObject_LengthHint(v);
- if (n < 0) {
- if (PyErr_Occurred()
- && !PyErr_ExceptionMatches(PyExc_TypeError)
- && !PyErr_ExceptionMatches(PyExc_AttributeError)) {
- Py_DECREF(it);
- return NULL;
- }
- PyErr_Clear();
- n = 10; /* arbitrary */
- }
+ n = _PyObject_LengthHint(v, 10);
result = PyTuple_New(n);
if (result == NULL)
goto Fail;