diff options
author | Armin Ronacher <armin.ronacher@active-4.com> | 2012-10-06 12:03:24 (GMT) |
---|---|---|
committer | Armin Ronacher <armin.ronacher@active-4.com> | 2012-10-06 12:03:24 (GMT) |
commit | aa9a79d27958ae5afb6c8769a2b342d98677c091 (patch) | |
tree | 24d49f530111a345c57f053a7f40652fa51d27a3 /Objects/abstract.c | |
parent | ef08fb1f040cb51e752c6b1322008714262fbf3e (diff) | |
download | cpython-aa9a79d27958ae5afb6c8769a2b342d98677c091.zip cpython-aa9a79d27958ae5afb6c8769a2b342d98677c091.tar.gz cpython-aa9a79d27958ae5afb6c8769a2b342d98677c091.tar.bz2 |
Issue #16148: implemented PEP 424
Diffstat (limited to 'Objects/abstract.c')
-rw-r--r-- | Objects/abstract.c | 76 |
1 files changed, 47 insertions, 29 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index a2737dd..b6fc478 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); |