mirror of
https://github.com/python/cpython
synced 2026-09-29 12:10:30 +03:00
Checking in the code for PEP 357.
This was mostly written by Travis Oliphant. I've inspected it all; Neal Norwitz and MvL have also looked at it (in an earlier incarnation).
This commit is contained in:
parent
9d7855076a
commit
38fff8c4e4
19 changed files with 269 additions and 150 deletions
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue