diff options
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 76 | ||||
-rw-r--r-- | Objects/classobject.c | 38 | ||||
-rw-r--r-- | Objects/intobject.c | 1 | ||||
-rw-r--r-- | Objects/listobject.c | 18 | ||||
-rw-r--r-- | Objects/longobject.c | 49 | ||||
-rw-r--r-- | Objects/stringobject.c | 9 | ||||
-rw-r--r-- | Objects/tupleobject.c | 7 | ||||
-rw-r--r-- | Objects/typeobject.c | 43 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 7 |
9 files changed, 180 insertions, 68 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index 7ded61a..399656f 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -8,6 +8,8 @@ #define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \ Py_TPFLAGS_CHECKTYPES) +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + /* Shorthands to return certain errors */ static PyObject * @@ -119,10 +121,9 @@ PyObject_GetItem(PyObject *o, PyObject *key) return m->mp_subscript(o, key); if (o->ob_type->tp_as_sequence) { - if (PyInt_Check(key)) - return PySequence_GetItem(o, PyInt_AsLong(key)); - else if (PyLong_Check(key)) { - long key_value = PyLong_AsLong(key); + PyNumberMethods *nb = key->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) { + Py_ssize_t key_value = nb->nb_index(key); if (key_value == -1 && PyErr_Occurred()) return NULL; return PySequence_GetItem(o, key_value); @@ -148,10 +149,9 @@ PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) return m->mp_ass_subscript(o, key, value); if (o->ob_type->tp_as_sequence) { - if (PyInt_Check(key)) - return PySequence_SetItem(o, PyInt_AsLong(key), value); - else if (PyLong_Check(key)) { - long key_value = PyLong_AsLong(key); + PyNumberMethods *nb = key->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) { + Py_ssize_t key_value = nb->nb_index(key); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_SetItem(o, key_value, value); @@ -180,10 +180,9 @@ PyObject_DelItem(PyObject *o, PyObject *key) return m->mp_ass_subscript(o, key, (PyObject*)NULL); if (o->ob_type->tp_as_sequence) { - if (PyInt_Check(key)) - return PySequence_DelItem(o, PyInt_AsLong(key)); - else if (PyLong_Check(key)) { - long key_value = PyLong_AsLong(key); + PyNumberMethods *nb = key->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) { + Py_ssize_t key_value = nb->nb_index(key); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_DelItem(o, key_value); @@ -647,12 +646,10 @@ PyNumber_Add(PyObject *v, PyObject *w) static PyObject * sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) { - long count; - if (PyInt_Check(n)) { - count = PyInt_AsLong(n); - } - else if (PyLong_Check(n)) { - count = PyLong_AsLong(n); + Py_ssize_t count; + PyNumberMethods *nb = n->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(n) && nb->nb_index != NULL) { + count = nb->nb_index(n); if (count == -1 && PyErr_Occurred()) return NULL; } @@ -660,32 +657,7 @@ sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) return type_error( "can't multiply sequence by non-int"); } -#if LONG_MAX != INT_MAX - if (count > INT_MAX) { - PyErr_SetString(PyExc_ValueError, - "sequence repeat count too large"); - return NULL; - } - else if (count < INT_MIN) - count = INT_MIN; - /* XXX Why don't I either - - - set count to -1 whenever it's negative (after all, - sequence repeat usually treats negative numbers - as zero(); or - - - raise an exception when it's less than INT_MIN? - - I'm thinking about a hypothetical use case where some - sequence type might use a negative value as a flag of - some kind. In those cases I don't want to break the - code by mapping all negative values to -1. But I also - don't want to break e.g. []*(-sys.maxint), which is - perfectly safe, returning []. As a compromise, I do - map out-of-range negative values. - */ -#endif - return (*repeatfunc)(seq, (int)count); + return (*repeatfunc)(seq, count); } PyObject * @@ -960,6 +932,22 @@ int_from_string(const char *s, Py_ssize_t len) return x; } +/* Return a Py_ssize_t integer from the object item */ +Py_ssize_t +PyNumber_Index(PyObject *item) +{ + Py_ssize_t value = -1; + PyNumberMethods *nb = item->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { + value = nb->nb_index(item); + } + else { + PyErr_SetString(PyExc_IndexError, + "object cannot be interpreted as an index"); + } + return value; +} + PyObject * PyNumber_Int(PyObject *o) { diff --git a/Objects/classobject.c b/Objects/classobject.c index 34afb9e..037252d 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -1733,6 +1733,43 @@ instance_nonzero(PyInstanceObject *self) return outcome > 0; } +static Py_ssize_t +instance_index(PyInstanceObject *self) +{ + PyObject *func, *res; + Py_ssize_t outcome; + static PyObject *indexstr = NULL; + + if (indexstr == NULL) { + indexstr = PyString_InternFromString("__index__"); + if (indexstr == NULL) + return -1; + } + if ((func = instance_getattr(self, indexstr)) == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "object cannot be interpreted as an index"); + return -1; + } + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res == NULL) + return -1; + if (PyInt_Check(res) || PyLong_Check(res)) { + outcome = res->ob_type->tp_as_number->nb_index(res); + } + else { + PyErr_SetString(PyExc_TypeError, + "__index__ must return an int or a long"); + outcome = -1; + } + Py_DECREF(res); + return outcome; +} + + UNARY(instance_invert, "__invert__") UNARY(instance_int, "__int__") UNARY(instance_long, "__long__") @@ -2052,6 +2089,7 @@ static PyNumberMethods instance_as_number = { (binaryfunc)instance_truediv, /* nb_true_divide */ (binaryfunc)instance_ifloordiv, /* nb_inplace_floor_divide */ (binaryfunc)instance_itruediv, /* nb_inplace_true_divide */ + (lenfunc)instance_index, /* nb_index */ }; PyTypeObject PyInstance_Type = { diff --git a/Objects/intobject.c b/Objects/intobject.c index d7a64be..86e2e8c 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -1069,6 +1069,7 @@ static PyNumberMethods int_as_number = { int_true_divide, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ + (lenfunc)PyInt_AsSsize_t, /* nb_index */ }; PyTypeObject PyInt_Type = { diff --git a/Objects/listobject.c b/Objects/listobject.c index 0ff61e2..966d659 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2452,11 +2452,14 @@ PyDoc_STRVAR(list_doc, "list() -> new list\n" "list(sequence) -> new list initialized from sequence's items"); +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + static PyObject * list_subscript(PyListObject* self, PyObject* item) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(item); + PyNumberMethods *nb = item->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { + Py_ssize_t i = nb->nb_index(item); if (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) @@ -2503,14 +2506,9 @@ list_subscript(PyListObject* self, PyObject* item) static int list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) { - if (PyInt_Check(item)) { - Py_ssize_t i = PyInt_AS_LONG(item); - if (i < 0) - i += PyList_GET_SIZE(self); - return list_ass_item(self, i, value); - } - else if (PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(item); + PyNumberMethods *nb = item->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { + Py_ssize_t i = nb->nb_index(item); if (i == -1 && PyErr_Occurred()) return -1; if (i < 0) diff --git a/Objects/longobject.c b/Objects/longobject.c index 9032656..e47c292 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -241,12 +241,8 @@ PyLong_AsLong(PyObject *vv) return -1; } -/* Get a Py_ssize_t from a long int object. - Returns -1 and sets an error condition if overflow occurs. */ - -Py_ssize_t -_PyLong_AsSsize_t(PyObject *vv) -{ +static Py_ssize_t +_long_as_ssize_t(PyObject *vv) { register PyLongObject *v; size_t x, prev; Py_ssize_t i; @@ -282,7 +278,45 @@ _PyLong_AsSsize_t(PyObject *vv) overflow: PyErr_SetString(PyExc_OverflowError, "long int too large to convert to int"); - return -1; + if (sign > 0) + return PY_SSIZE_T_MAX; + else + return -PY_SSIZE_T_MAX-1; +} + +/* Get a Py_ssize_t from a long int object. + Returns -1 and sets an error condition if overflow occurs. */ + +Py_ssize_t +_PyLong_AsSsize_t(PyObject *vv) +{ + Py_ssize_t x; + + x = _long_as_ssize_t(vv); + if (PyErr_Occurred()) return -1; + return x; +} + + +/* Get a Py_ssize_t from a long int object. + Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, + and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1. + Return 0 on error, 1 on success. +*/ + +static Py_ssize_t +long_index(PyObject *vv) +{ + Py_ssize_t x; + + x = _long_as_ssize_t(vv); + if (PyErr_Occurred()) { + /* If overflow error, ignore the error */ + if (x != -1) { + PyErr_Clear(); + } + } + return x; } /* Get a C unsigned long int from a long int object. @@ -3131,6 +3165,7 @@ static PyNumberMethods long_as_number = { long_true_divide, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ + (lenfunc)long_index, /* nb_index */ }; PyTypeObject PyLong_Type = { diff --git a/Objects/stringobject.c b/Objects/stringobject.c index e2b7603..16d542a 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -1187,16 +1187,19 @@ string_hash(PyStringObject *a) return x; } +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + static PyObject* string_subscript(PyStringObject* self, PyObject* item) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(item); + PyNumberMethods *nb = item->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { + Py_ssize_t i = nb->nb_index(item); if (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) i += PyString_GET_SIZE(self); - return string_item(self,i); + return string_item(self, i); } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength, cur, i; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index c0383a1..384b355 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -584,11 +584,14 @@ static PySequenceMethods tuple_as_sequence = { (objobjproc)tuplecontains, /* sq_contains */ }; +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(item); + PyNumberMethods *nb = item->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { + Py_ssize_t i = nb->nb_index(item); if (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9837e38..681fb21 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3051,6 +3051,9 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) COPYNUM(nb_inplace_true_divide); COPYNUM(nb_inplace_floor_divide); } + if (base->tp_flags & Py_TPFLAGS_HAVE_INDEX) { + COPYNUM(nb_index); + } } if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) { @@ -4344,6 +4347,44 @@ slot_nb_nonzero(PyObject *self) return result; } + +static Py_ssize_t +slot_nb_index(PyObject *self) +{ + PyObject *func, *args; + static PyObject *index_str; + Py_ssize_t result = -1; + + func = lookup_maybe(self, "__index__", &index_str); + if (func == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "object cannot be interpreted as an index"); + } + return -1; + } + args = PyTuple_New(0); + if (args != NULL) { + PyObject *temp = PyObject_Call(func, args, NULL); + Py_DECREF(args); + if (temp != NULL) { + if (PyInt_Check(temp) || PyLong_Check(temp)) { + result = + temp->ob_type->tp_as_number->nb_index(temp); + } + else { + PyErr_SetString(PyExc_TypeError, + "__index__ must return an int or a long"); + result = -1; + } + Py_DECREF(temp); + } + } + Py_DECREF(func); + return result; +} + + SLOT0(slot_nb_invert, "__invert__") SLOT1BIN(slot_nb_lshift, nb_lshift, "__lshift__", "__rlshift__") SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__") @@ -5069,6 +5110,8 @@ static slotdef slotdefs[] = { "oct(x)"), UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc, "hex(x)"), + NBSLOT("__index__", nb_index, slot_nb_index, wrap_lenfunc, + "x[y:z] <==> x[y.__index__():z.__index__()]"), IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, wrap_binaryfunc, "+"), IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract, diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4146f1d..a0d3de9 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -6460,11 +6460,14 @@ static PySequenceMethods unicode_as_sequence = { (objobjproc)PyUnicode_Contains, /*sq_contains*/ }; +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + static PyObject* unicode_subscript(PyUnicodeObject* self, PyObject* item) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(item); + PyNumberMethods *nb = item->ob_type->tp_as_number; + if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { + Py_ssize_t i = nb->nb_index(item); if (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) |