summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/abstract.c76
-rw-r--r--Objects/bytearrayobject.c2
-rw-r--r--Objects/bytesobject.c2
-rw-r--r--Objects/iterobject.c11
-rw-r--r--Objects/listobject.c2
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;