diff options
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 76 | ||||
-rw-r--r-- | Objects/bytearrayobject.c | 2 | ||||
-rw-r--r-- | Objects/bytesobject.c | 2 | ||||
-rw-r--r-- | Objects/iterobject.c | 11 | ||||
-rw-r--r-- | Objects/listobject.c | 2 |
5 files changed, 58 insertions, 35 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); diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 2bb3a29..26c76d2 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2282,7 +2282,7 @@ bytearray_extend(PyByteArrayObject *self, PyObject *arg) return NULL; /* Try to determine the length of the argument. 32 is arbitrary. */ - buf_size = _PyObject_LengthHint(arg, 32); + buf_size = PyObject_LengthHint(arg, 32); if (buf_size == -1) { Py_DECREF(it); return NULL; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index bf9259f..25c2326 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2651,7 +2651,7 @@ PyBytes_FromObject(PyObject *x) } /* For iterator version, create a string object and resize as needed */ - size = _PyObject_LengthHint(x, 64); + size = PyObject_LengthHint(x, 64); if (size == -1 && PyErr_Occurred()) return NULL; /* Allocate an extra byte to prevent PyBytes_FromStringAndSize() from diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 3cfbeaf..cf4af5b 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -76,9 +76,14 @@ iter_len(seqiterobject *it) Py_ssize_t seqsize, len; if (it->it_seq) { - seqsize = PySequence_Size(it->it_seq); - if (seqsize == -1) - return NULL; + if (_PyObject_HasLen(it->it_seq)) { + seqsize = PySequence_Size(it->it_seq); + if (seqsize == -1) + return NULL; + } + else { + return Py_NotImplemented; + } len = seqsize - it->it_index; if (len >= 0) return PyLong_FromSsize_t(len); diff --git a/Objects/listobject.c b/Objects/listobject.c index 6e0d094..4cc34b5 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -826,7 +826,7 @@ listextend(PyListObject *self, PyObject *b) iternext = *it->ob_type->tp_iternext; /* Guess a result list size. */ - n = _PyObject_LengthHint(b, 8); + n = PyObject_LengthHint(b, 8); if (n == -1) { Py_DECREF(it); return NULL; |