summaryrefslogtreecommitdiff
path: root/Objects/abstract.c
diff options
context:
space:
mode:
authorArmin Ronacher <armin.ronacher@active-4.com>2012-10-06 14:03:24 +0200
committerArmin Ronacher <armin.ronacher@active-4.com>2012-10-06 14:03:24 +0200
commitb88a8dfe8dec8b24ce278c645ceb2cc901462cf8 (patch)
treed18a726eed60ab945c3f38ac9ba2990870a15b4c /Objects/abstract.c
parent9a6ec11c5bce87f27559debad03bcd6a7885e591 (diff)
downloadcpython-b88a8dfe8dec8b24ce278c645ceb2cc901462cf8.tar.gz
Issue #16148: implemented PEP 424
Diffstat (limited to 'Objects/abstract.c')
-rw-r--r--Objects/abstract.c76
1 files changed, 47 insertions, 29 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c
index a2737dd5f4..b6fc478595 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -64,49 +64,67 @@ PyObject_Length(PyObject *o)
}
#define PyObject_Length PyObject_Size
+int
+_PyObject_HasLen(PyObject *o) {
+ return (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_length) ||
+ (Py_TYPE(o)->tp_as_mapping && Py_TYPE(o)->tp_as_mapping->mp_length);
+}
/* 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. If one of the calls fails,
- this function returns -1.
+ or o.__length_hint__(). If those methods aren't found. If one of the calls
+ fails this function returns -1.
*/
Py_ssize_t
-_PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
+PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
{
_Py_IDENTIFIER(__length_hint__);
- PyObject *ro, *hintmeth;
- Py_ssize_t rv;
-
- /* try o.__len__() */
- rv = PyObject_Size(o);
- if (rv >= 0)
- return rv;
- if (PyErr_Occurred()) {
- if (!PyErr_ExceptionMatches(PyExc_TypeError))
+ Py_ssize_t res = PyObject_Length(o);
+ if (res < 0 && PyErr_Occurred()) {
+ if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
return -1;
+ }
PyErr_Clear();
}
-
- /* try o.__length_hint__() */
- hintmeth = _PyObject_LookupSpecial(o, &PyId___length_hint__);
- if (hintmeth == NULL) {
- if (PyErr_Occurred())
+ else {
+ return res;
+ }
+ PyObject *hint = _PyObject_LookupSpecial(o, &PyId___length_hint__);
+ if (hint == NULL) {
+ if (PyErr_Occurred()) {
return -1;
- else
+ }
+ return defaultvalue;
+ }
+ PyObject *result = PyObject_CallFunctionObjArgs(hint, NULL);
+ Py_DECREF(hint);
+ if (result == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ PyErr_Clear();
return defaultvalue;
+ }
+ return -1;
}
- ro = PyObject_CallFunctionObjArgs(hintmeth, NULL);
- Py_DECREF(hintmeth);
- if (ro == NULL) {
- if (!PyErr_ExceptionMatches(PyExc_TypeError))
- return -1;
- PyErr_Clear();
+ else if (result == Py_NotImplemented) {
+ Py_DECREF(result);
return defaultvalue;
}
- rv = PyLong_Check(ro) ? PyLong_AsSsize_t(ro) : defaultvalue;
- Py_DECREF(ro);
- return rv;
+ if (!PyLong_Check(result)) {
+ PyErr_Format(PyExc_TypeError, "Length hint must be an integer, not %s",
+ Py_TYPE(result)->tp_name);
+ Py_DECREF(result);
+ return -1;
+ }
+ defaultvalue = PyLong_AsSsize_t(result);
+ Py_DECREF(result);
+ if (defaultvalue < 0 && PyErr_Occurred()) {
+ return -1;
+ }
+ if (defaultvalue < 0) {
+ PyErr_Format(PyExc_ValueError, "__length_hint__() should return >= 0");
+ return -1;
+ }
+ return defaultvalue;
}
PyObject *
@@ -1687,7 +1705,7 @@ PySequence_Tuple(PyObject *v)
return NULL;
/* Guess result size and allocate space. */
- n = _PyObject_LengthHint(v, 10);
+ n = PyObject_LengthHint(v, 10);
if (n == -1)
goto Fail;
result = PyTuple_New(n);