aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/rangeobject.c
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/tools/python3/src/Objects/rangeobject.c
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
downloadydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Objects/rangeobject.c')
-rw-r--r--contrib/tools/python3/src/Objects/rangeobject.c2240
1 files changed, 1120 insertions, 1120 deletions
diff --git a/contrib/tools/python3/src/Objects/rangeobject.c b/contrib/tools/python3/src/Objects/rangeobject.c
index d7076ac824..d686c1454e 100644
--- a/contrib/tools/python3/src/Objects/rangeobject.c
+++ b/contrib/tools/python3/src/Objects/rangeobject.c
@@ -1,83 +1,83 @@
-/* Range object implementation */
-
-#include "Python.h"
+/* Range object implementation */
+
+#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_tupleobject.h"
#include "structmember.h" // PyMemberDef
-
-/* Support objects whose length is > PY_SSIZE_T_MAX.
-
- This could be sped up for small PyLongs if they fit in a Py_ssize_t.
- This only matters on Win64. Though we could use long long which
- would presumably help perf.
-*/
-
-typedef struct {
- PyObject_HEAD
- PyObject *start;
- PyObject *stop;
- PyObject *step;
- PyObject *length;
-} rangeobject;
-
+
+/* Support objects whose length is > PY_SSIZE_T_MAX.
+
+ This could be sped up for small PyLongs if they fit in a Py_ssize_t.
+ This only matters on Win64. Though we could use long long which
+ would presumably help perf.
+*/
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *start;
+ PyObject *stop;
+ PyObject *step;
+ PyObject *length;
+} rangeobject;
+
_Py_IDENTIFIER(iter);
-/* Helper function for validating step. Always returns a new reference or
- NULL on error.
-*/
-static PyObject *
-validate_step(PyObject *step)
-{
- /* No step specified, use a step of 1. */
- if (!step)
- return PyLong_FromLong(1);
-
- step = PyNumber_Index(step);
- if (step && _PyLong_Sign(step) == 0) {
- PyErr_SetString(PyExc_ValueError,
- "range() arg 3 must not be zero");
- Py_CLEAR(step);
- }
-
- return step;
-}
-
-static PyObject *
-compute_range_length(PyObject *start, PyObject *stop, PyObject *step);
-
-static rangeobject *
-make_range_object(PyTypeObject *type, PyObject *start,
- PyObject *stop, PyObject *step)
-{
- rangeobject *obj = NULL;
- PyObject *length;
- length = compute_range_length(start, stop, step);
- if (length == NULL) {
- return NULL;
- }
- obj = PyObject_New(rangeobject, type);
- if (obj == NULL) {
- Py_DECREF(length);
- return NULL;
- }
- obj->start = start;
- obj->stop = stop;
- obj->step = step;
- obj->length = length;
- return obj;
-}
-
-/* XXX(nnorwitz): should we error check if the user passes any empty ranges?
- range(-10)
- range(0, -5)
- range(0, 5, -1)
-*/
-static PyObject *
+/* Helper function for validating step. Always returns a new reference or
+ NULL on error.
+*/
+static PyObject *
+validate_step(PyObject *step)
+{
+ /* No step specified, use a step of 1. */
+ if (!step)
+ return PyLong_FromLong(1);
+
+ step = PyNumber_Index(step);
+ if (step && _PyLong_Sign(step) == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "range() arg 3 must not be zero");
+ Py_CLEAR(step);
+ }
+
+ return step;
+}
+
+static PyObject *
+compute_range_length(PyObject *start, PyObject *stop, PyObject *step);
+
+static rangeobject *
+make_range_object(PyTypeObject *type, PyObject *start,
+ PyObject *stop, PyObject *step)
+{
+ rangeobject *obj = NULL;
+ PyObject *length;
+ length = compute_range_length(start, stop, step);
+ if (length == NULL) {
+ return NULL;
+ }
+ obj = PyObject_New(rangeobject, type);
+ if (obj == NULL) {
+ Py_DECREF(length);
+ return NULL;
+ }
+ obj->start = start;
+ obj->stop = stop;
+ obj->step = step;
+ obj->length = length;
+ return obj;
+}
+
+/* XXX(nnorwitz): should we error check if the user passes any empty ranges?
+ range(-10)
+ range(0, -5)
+ range(0, 5, -1)
+*/
+static PyObject *
range_from_array(PyTypeObject *type, PyObject *const *args, Py_ssize_t num_args)
-{
- rangeobject *obj;
- PyObject *start = NULL, *stop = NULL, *step = NULL;
-
+{
+ rangeobject *obj;
+ PyObject *start = NULL, *stop = NULL, *step = NULL;
+
switch (num_args) {
case 3:
step = args[2];
@@ -113,25 +113,25 @@ range_from_array(PyTypeObject *type, PyObject *const *args, Py_ssize_t num_args)
case 0:
PyErr_SetString(PyExc_TypeError,
"range expected at least 1 argument, got 0");
- return NULL;
+ return NULL;
default:
PyErr_Format(PyExc_TypeError,
"range expected at most 3 arguments, got %zd",
num_args);
- return NULL;
- }
- obj = make_range_object(type, start, stop, step);
+ return NULL;
+ }
+ obj = make_range_object(type, start, stop, step);
if (obj != NULL) {
- return (PyObject *) obj;
+ return (PyObject *) obj;
}
-
- /* Failed to create object, release attributes */
- Py_DECREF(start);
- Py_DECREF(stop);
- Py_DECREF(step);
- return NULL;
-}
-
+
+ /* Failed to create object, release attributes */
+ Py_DECREF(start);
+ Py_DECREF(stop);
+ Py_DECREF(step);
+ return NULL;
+}
+
static PyObject *
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
@@ -153,941 +153,941 @@ range_vectorcall(PyTypeObject *type, PyObject *const *args,
return range_from_array(type, args, nargs);
}
-PyDoc_STRVAR(range_doc,
-"range(stop) -> range object\n\
-range(start, stop[, step]) -> range object\n\
-\n\
-Return an object that produces a sequence of integers from start (inclusive)\n\
-to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1.\n\
-start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.\n\
-These are exactly the valid indices for a list of 4 elements.\n\
-When step is given, it specifies the increment (or decrement).");
-
-static void
-range_dealloc(rangeobject *r)
-{
- Py_DECREF(r->start);
- Py_DECREF(r->stop);
- Py_DECREF(r->step);
- Py_DECREF(r->length);
- PyObject_Del(r);
-}
-
-/* Return number of items in range (lo, hi, step) as a PyLong object,
- * when arguments are PyLong objects. Arguments MUST return 1 with
- * PyLong_Check(). Return NULL when there is an error.
- */
-static PyObject*
-compute_range_length(PyObject *start, PyObject *stop, PyObject *step)
-{
- /* -------------------------------------------------------------
- Algorithm is equal to that of get_len_of_range(), but it operates
- on PyObjects (which are assumed to be PyLong objects).
- ---------------------------------------------------------------*/
- int cmp_result;
- PyObject *lo, *hi;
- PyObject *diff = NULL;
- PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
- /* holds sub-expression evaluations */
-
- cmp_result = PyObject_RichCompareBool(step, _PyLong_Zero, Py_GT);
- if (cmp_result == -1)
- return NULL;
-
- if (cmp_result == 1) {
- lo = start;
- hi = stop;
- Py_INCREF(step);
- } else {
- lo = stop;
- hi = start;
- step = PyNumber_Negative(step);
- if (!step)
- return NULL;
- }
-
- /* if (lo >= hi), return length of 0. */
- cmp_result = PyObject_RichCompareBool(lo, hi, Py_GE);
- if (cmp_result != 0) {
- Py_DECREF(step);
- if (cmp_result < 0)
- return NULL;
- return PyLong_FromLong(0);
- }
-
- if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL)
- goto Fail;
-
- if ((diff = PyNumber_Subtract(tmp1, _PyLong_One)) == NULL)
- goto Fail;
-
- if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL)
- goto Fail;
-
- if ((result = PyNumber_Add(tmp2, _PyLong_One)) == NULL)
- goto Fail;
-
- Py_DECREF(tmp2);
- Py_DECREF(diff);
- Py_DECREF(step);
- Py_DECREF(tmp1);
- return result;
-
- Fail:
- Py_DECREF(step);
- Py_XDECREF(tmp2);
- Py_XDECREF(diff);
- Py_XDECREF(tmp1);
- return NULL;
-}
-
-static Py_ssize_t
-range_length(rangeobject *r)
-{
- return PyLong_AsSsize_t(r->length);
-}
-
-static PyObject *
-compute_item(rangeobject *r, PyObject *i)
-{
- PyObject *incr, *result;
- /* PyLong equivalent to:
- * return r->start + (i * r->step)
- */
- incr = PyNumber_Multiply(i, r->step);
- if (!incr)
- return NULL;
- result = PyNumber_Add(r->start, incr);
- Py_DECREF(incr);
- return result;
-}
-
-static PyObject *
-compute_range_item(rangeobject *r, PyObject *arg)
-{
- int cmp_result;
- PyObject *i, *result;
-
- /* PyLong equivalent to:
- * if (arg < 0) {
- * i = r->length + arg
- * } else {
- * i = arg
- * }
- */
- cmp_result = PyObject_RichCompareBool(arg, _PyLong_Zero, Py_LT);
- if (cmp_result == -1) {
- return NULL;
- }
- if (cmp_result == 1) {
- i = PyNumber_Add(r->length, arg);
- if (!i) {
- return NULL;
- }
- } else {
- i = arg;
- Py_INCREF(i);
- }
-
- /* PyLong equivalent to:
- * if (i < 0 || i >= r->length) {
- * <report index out of bounds>
- * }
- */
- cmp_result = PyObject_RichCompareBool(i, _PyLong_Zero, Py_LT);
- if (cmp_result == 0) {
- cmp_result = PyObject_RichCompareBool(i, r->length, Py_GE);
- }
- if (cmp_result == -1) {
- Py_DECREF(i);
- return NULL;
- }
- if (cmp_result == 1) {
- Py_DECREF(i);
- PyErr_SetString(PyExc_IndexError,
- "range object index out of range");
- return NULL;
- }
-
- result = compute_item(r, i);
- Py_DECREF(i);
- return result;
-}
-
-static PyObject *
-range_item(rangeobject *r, Py_ssize_t i)
-{
- PyObject *res, *arg = PyLong_FromSsize_t(i);
- if (!arg) {
- return NULL;
- }
- res = compute_range_item(r, arg);
- Py_DECREF(arg);
- return res;
-}
-
-static PyObject *
-compute_slice(rangeobject *r, PyObject *_slice)
-{
- PySliceObject *slice = (PySliceObject *) _slice;
- rangeobject *result;
- PyObject *start = NULL, *stop = NULL, *step = NULL;
- PyObject *substart = NULL, *substop = NULL, *substep = NULL;
- int error;
-
- error = _PySlice_GetLongIndices(slice, r->length, &start, &stop, &step);
- if (error == -1)
- return NULL;
-
- substep = PyNumber_Multiply(r->step, step);
- if (substep == NULL) goto fail;
- Py_CLEAR(step);
-
- substart = compute_item(r, start);
- if (substart == NULL) goto fail;
- Py_CLEAR(start);
-
- substop = compute_item(r, stop);
- if (substop == NULL) goto fail;
- Py_CLEAR(stop);
-
- result = make_range_object(Py_TYPE(r), substart, substop, substep);
- if (result != NULL) {
- return (PyObject *) result;
- }
-fail:
- Py_XDECREF(start);
- Py_XDECREF(stop);
- Py_XDECREF(step);
- Py_XDECREF(substart);
- Py_XDECREF(substop);
- Py_XDECREF(substep);
- return NULL;
-}
-
-/* Assumes (PyLong_CheckExact(ob) || PyBool_Check(ob)) */
-static int
-range_contains_long(rangeobject *r, PyObject *ob)
-{
- int cmp1, cmp2, cmp3;
- PyObject *tmp1 = NULL;
- PyObject *tmp2 = NULL;
- int result = -1;
-
- /* Check if the value can possibly be in the range. */
-
- cmp1 = PyObject_RichCompareBool(r->step, _PyLong_Zero, Py_GT);
- if (cmp1 == -1)
- goto end;
- if (cmp1 == 1) { /* positive steps: start <= ob < stop */
- cmp2 = PyObject_RichCompareBool(r->start, ob, Py_LE);
- cmp3 = PyObject_RichCompareBool(ob, r->stop, Py_LT);
- }
- else { /* negative steps: stop < ob <= start */
- cmp2 = PyObject_RichCompareBool(ob, r->start, Py_LE);
- cmp3 = PyObject_RichCompareBool(r->stop, ob, Py_LT);
- }
-
- if (cmp2 == -1 || cmp3 == -1) /* TypeError */
- goto end;
- if (cmp2 == 0 || cmp3 == 0) { /* ob outside of range */
- result = 0;
- goto end;
- }
-
- /* Check that the stride does not invalidate ob's membership. */
- tmp1 = PyNumber_Subtract(ob, r->start);
- if (tmp1 == NULL)
- goto end;
- tmp2 = PyNumber_Remainder(tmp1, r->step);
- if (tmp2 == NULL)
- goto end;
- /* result = ((int(ob) - start) % step) == 0 */
- result = PyObject_RichCompareBool(tmp2, _PyLong_Zero, Py_EQ);
- end:
- Py_XDECREF(tmp1);
- Py_XDECREF(tmp2);
- return result;
-}
-
-static int
-range_contains(rangeobject *r, PyObject *ob)
-{
- if (PyLong_CheckExact(ob) || PyBool_Check(ob))
- return range_contains_long(r, ob);
-
- return (int)_PySequence_IterSearch((PyObject*)r, ob,
- PY_ITERSEARCH_CONTAINS);
-}
-
-/* Compare two range objects. Return 1 for equal, 0 for not equal
- and -1 on error. The algorithm is roughly the C equivalent of
-
- if r0 is r1:
- return True
- if len(r0) != len(r1):
- return False
- if not len(r0):
- return True
- if r0.start != r1.start:
- return False
- if len(r0) == 1:
- return True
- return r0.step == r1.step
-*/
-static int
-range_equals(rangeobject *r0, rangeobject *r1)
-{
- int cmp_result;
-
- if (r0 == r1)
- return 1;
- cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ);
- /* Return False or error to the caller. */
- if (cmp_result != 1)
- return cmp_result;
- cmp_result = PyObject_Not(r0->length);
- /* Return True or error to the caller. */
- if (cmp_result != 0)
- return cmp_result;
- cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ);
- /* Return False or error to the caller. */
- if (cmp_result != 1)
- return cmp_result;
- cmp_result = PyObject_RichCompareBool(r0->length, _PyLong_One, Py_EQ);
- /* Return True or error to the caller. */
- if (cmp_result != 0)
- return cmp_result;
- return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ);
-}
-
-static PyObject *
-range_richcompare(PyObject *self, PyObject *other, int op)
-{
- int result;
-
- if (!PyRange_Check(other))
- Py_RETURN_NOTIMPLEMENTED;
- switch (op) {
- case Py_NE:
- case Py_EQ:
- result = range_equals((rangeobject*)self, (rangeobject*)other);
- if (result == -1)
- return NULL;
- if (op == Py_NE)
- result = !result;
- if (result)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
- case Py_LE:
- case Py_GE:
- case Py_LT:
- case Py_GT:
- Py_RETURN_NOTIMPLEMENTED;
- default:
- PyErr_BadArgument();
- return NULL;
- }
-}
-
-/* Hash function for range objects. Rough C equivalent of
-
- if not len(r):
- return hash((len(r), None, None))
- if len(r) == 1:
- return hash((len(r), r.start, None))
- return hash((len(r), r.start, r.step))
-*/
-static Py_hash_t
-range_hash(rangeobject *r)
-{
- PyObject *t;
- Py_hash_t result = -1;
- int cmp_result;
-
- t = PyTuple_New(3);
- if (!t)
- return -1;
- Py_INCREF(r->length);
- PyTuple_SET_ITEM(t, 0, r->length);
- cmp_result = PyObject_Not(r->length);
- if (cmp_result == -1)
- goto end;
- if (cmp_result == 1) {
- Py_INCREF(Py_None);
- Py_INCREF(Py_None);
- PyTuple_SET_ITEM(t, 1, Py_None);
- PyTuple_SET_ITEM(t, 2, Py_None);
- }
- else {
- Py_INCREF(r->start);
- PyTuple_SET_ITEM(t, 1, r->start);
- cmp_result = PyObject_RichCompareBool(r->length, _PyLong_One, Py_EQ);
- if (cmp_result == -1)
- goto end;
- if (cmp_result == 1) {
- Py_INCREF(Py_None);
- PyTuple_SET_ITEM(t, 2, Py_None);
- }
- else {
- Py_INCREF(r->step);
- PyTuple_SET_ITEM(t, 2, r->step);
- }
- }
- result = PyObject_Hash(t);
- end:
- Py_DECREF(t);
- return result;
-}
-
-static PyObject *
-range_count(rangeobject *r, PyObject *ob)
-{
- if (PyLong_CheckExact(ob) || PyBool_Check(ob)) {
- int result = range_contains_long(r, ob);
- if (result == -1)
- return NULL;
- return PyLong_FromLong(result);
- } else {
- Py_ssize_t count;
- count = _PySequence_IterSearch((PyObject*)r, ob, PY_ITERSEARCH_COUNT);
- if (count == -1)
- return NULL;
- return PyLong_FromSsize_t(count);
- }
-}
-
-static PyObject *
-range_index(rangeobject *r, PyObject *ob)
-{
- int contains;
-
- if (!PyLong_CheckExact(ob) && !PyBool_Check(ob)) {
- Py_ssize_t index;
- index = _PySequence_IterSearch((PyObject*)r, ob, PY_ITERSEARCH_INDEX);
- if (index == -1)
- return NULL;
- return PyLong_FromSsize_t(index);
- }
-
- contains = range_contains_long(r, ob);
- if (contains == -1)
- return NULL;
-
- if (contains) {
- PyObject *idx, *tmp = PyNumber_Subtract(ob, r->start);
- if (tmp == NULL)
- return NULL;
- /* idx = (ob - r.start) // r.step */
- idx = PyNumber_FloorDivide(tmp, r->step);
- Py_DECREF(tmp);
- return idx;
- }
-
- /* object is not in the range */
- PyErr_Format(PyExc_ValueError, "%R is not in range", ob);
- return NULL;
-}
-
-static PySequenceMethods range_as_sequence = {
- (lenfunc)range_length, /* sq_length */
- 0, /* sq_concat */
- 0, /* sq_repeat */
- (ssizeargfunc)range_item, /* sq_item */
- 0, /* sq_slice */
- 0, /* sq_ass_item */
- 0, /* sq_ass_slice */
- (objobjproc)range_contains, /* sq_contains */
-};
-
-static PyObject *
-range_repr(rangeobject *r)
-{
- Py_ssize_t istep;
-
- /* Check for special case values for printing. We don't always
- need the step value. We don't care about overflow. */
- istep = PyNumber_AsSsize_t(r->step, NULL);
- if (istep == -1 && PyErr_Occurred()) {
- assert(!PyErr_ExceptionMatches(PyExc_OverflowError));
- return NULL;
- }
-
- if (istep == 1)
- return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop);
- else
- return PyUnicode_FromFormat("range(%R, %R, %R)",
- r->start, r->stop, r->step);
-}
-
-/* Pickling support */
-static PyObject *
-range_reduce(rangeobject *r, PyObject *args)
-{
- return Py_BuildValue("(O(OOO))", Py_TYPE(r),
- r->start, r->stop, r->step);
-}
-
-static PyObject *
-range_subscript(rangeobject* self, PyObject* item)
-{
+PyDoc_STRVAR(range_doc,
+"range(stop) -> range object\n\
+range(start, stop[, step]) -> range object\n\
+\n\
+Return an object that produces a sequence of integers from start (inclusive)\n\
+to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1.\n\
+start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.\n\
+These are exactly the valid indices for a list of 4 elements.\n\
+When step is given, it specifies the increment (or decrement).");
+
+static void
+range_dealloc(rangeobject *r)
+{
+ Py_DECREF(r->start);
+ Py_DECREF(r->stop);
+ Py_DECREF(r->step);
+ Py_DECREF(r->length);
+ PyObject_Del(r);
+}
+
+/* Return number of items in range (lo, hi, step) as a PyLong object,
+ * when arguments are PyLong objects. Arguments MUST return 1 with
+ * PyLong_Check(). Return NULL when there is an error.
+ */
+static PyObject*
+compute_range_length(PyObject *start, PyObject *stop, PyObject *step)
+{
+ /* -------------------------------------------------------------
+ Algorithm is equal to that of get_len_of_range(), but it operates
+ on PyObjects (which are assumed to be PyLong objects).
+ ---------------------------------------------------------------*/
+ int cmp_result;
+ PyObject *lo, *hi;
+ PyObject *diff = NULL;
+ PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
+ /* holds sub-expression evaluations */
+
+ cmp_result = PyObject_RichCompareBool(step, _PyLong_Zero, Py_GT);
+ if (cmp_result == -1)
+ return NULL;
+
+ if (cmp_result == 1) {
+ lo = start;
+ hi = stop;
+ Py_INCREF(step);
+ } else {
+ lo = stop;
+ hi = start;
+ step = PyNumber_Negative(step);
+ if (!step)
+ return NULL;
+ }
+
+ /* if (lo >= hi), return length of 0. */
+ cmp_result = PyObject_RichCompareBool(lo, hi, Py_GE);
+ if (cmp_result != 0) {
+ Py_DECREF(step);
+ if (cmp_result < 0)
+ return NULL;
+ return PyLong_FromLong(0);
+ }
+
+ if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL)
+ goto Fail;
+
+ if ((diff = PyNumber_Subtract(tmp1, _PyLong_One)) == NULL)
+ goto Fail;
+
+ if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL)
+ goto Fail;
+
+ if ((result = PyNumber_Add(tmp2, _PyLong_One)) == NULL)
+ goto Fail;
+
+ Py_DECREF(tmp2);
+ Py_DECREF(diff);
+ Py_DECREF(step);
+ Py_DECREF(tmp1);
+ return result;
+
+ Fail:
+ Py_DECREF(step);
+ Py_XDECREF(tmp2);
+ Py_XDECREF(diff);
+ Py_XDECREF(tmp1);
+ return NULL;
+}
+
+static Py_ssize_t
+range_length(rangeobject *r)
+{
+ return PyLong_AsSsize_t(r->length);
+}
+
+static PyObject *
+compute_item(rangeobject *r, PyObject *i)
+{
+ PyObject *incr, *result;
+ /* PyLong equivalent to:
+ * return r->start + (i * r->step)
+ */
+ incr = PyNumber_Multiply(i, r->step);
+ if (!incr)
+ return NULL;
+ result = PyNumber_Add(r->start, incr);
+ Py_DECREF(incr);
+ return result;
+}
+
+static PyObject *
+compute_range_item(rangeobject *r, PyObject *arg)
+{
+ int cmp_result;
+ PyObject *i, *result;
+
+ /* PyLong equivalent to:
+ * if (arg < 0) {
+ * i = r->length + arg
+ * } else {
+ * i = arg
+ * }
+ */
+ cmp_result = PyObject_RichCompareBool(arg, _PyLong_Zero, Py_LT);
+ if (cmp_result == -1) {
+ return NULL;
+ }
+ if (cmp_result == 1) {
+ i = PyNumber_Add(r->length, arg);
+ if (!i) {
+ return NULL;
+ }
+ } else {
+ i = arg;
+ Py_INCREF(i);
+ }
+
+ /* PyLong equivalent to:
+ * if (i < 0 || i >= r->length) {
+ * <report index out of bounds>
+ * }
+ */
+ cmp_result = PyObject_RichCompareBool(i, _PyLong_Zero, Py_LT);
+ if (cmp_result == 0) {
+ cmp_result = PyObject_RichCompareBool(i, r->length, Py_GE);
+ }
+ if (cmp_result == -1) {
+ Py_DECREF(i);
+ return NULL;
+ }
+ if (cmp_result == 1) {
+ Py_DECREF(i);
+ PyErr_SetString(PyExc_IndexError,
+ "range object index out of range");
+ return NULL;
+ }
+
+ result = compute_item(r, i);
+ Py_DECREF(i);
+ return result;
+}
+
+static PyObject *
+range_item(rangeobject *r, Py_ssize_t i)
+{
+ PyObject *res, *arg = PyLong_FromSsize_t(i);
+ if (!arg) {
+ return NULL;
+ }
+ res = compute_range_item(r, arg);
+ Py_DECREF(arg);
+ return res;
+}
+
+static PyObject *
+compute_slice(rangeobject *r, PyObject *_slice)
+{
+ PySliceObject *slice = (PySliceObject *) _slice;
+ rangeobject *result;
+ PyObject *start = NULL, *stop = NULL, *step = NULL;
+ PyObject *substart = NULL, *substop = NULL, *substep = NULL;
+ int error;
+
+ error = _PySlice_GetLongIndices(slice, r->length, &start, &stop, &step);
+ if (error == -1)
+ return NULL;
+
+ substep = PyNumber_Multiply(r->step, step);
+ if (substep == NULL) goto fail;
+ Py_CLEAR(step);
+
+ substart = compute_item(r, start);
+ if (substart == NULL) goto fail;
+ Py_CLEAR(start);
+
+ substop = compute_item(r, stop);
+ if (substop == NULL) goto fail;
+ Py_CLEAR(stop);
+
+ result = make_range_object(Py_TYPE(r), substart, substop, substep);
+ if (result != NULL) {
+ return (PyObject *) result;
+ }
+fail:
+ Py_XDECREF(start);
+ Py_XDECREF(stop);
+ Py_XDECREF(step);
+ Py_XDECREF(substart);
+ Py_XDECREF(substop);
+ Py_XDECREF(substep);
+ return NULL;
+}
+
+/* Assumes (PyLong_CheckExact(ob) || PyBool_Check(ob)) */
+static int
+range_contains_long(rangeobject *r, PyObject *ob)
+{
+ int cmp1, cmp2, cmp3;
+ PyObject *tmp1 = NULL;
+ PyObject *tmp2 = NULL;
+ int result = -1;
+
+ /* Check if the value can possibly be in the range. */
+
+ cmp1 = PyObject_RichCompareBool(r->step, _PyLong_Zero, Py_GT);
+ if (cmp1 == -1)
+ goto end;
+ if (cmp1 == 1) { /* positive steps: start <= ob < stop */
+ cmp2 = PyObject_RichCompareBool(r->start, ob, Py_LE);
+ cmp3 = PyObject_RichCompareBool(ob, r->stop, Py_LT);
+ }
+ else { /* negative steps: stop < ob <= start */
+ cmp2 = PyObject_RichCompareBool(ob, r->start, Py_LE);
+ cmp3 = PyObject_RichCompareBool(r->stop, ob, Py_LT);
+ }
+
+ if (cmp2 == -1 || cmp3 == -1) /* TypeError */
+ goto end;
+ if (cmp2 == 0 || cmp3 == 0) { /* ob outside of range */
+ result = 0;
+ goto end;
+ }
+
+ /* Check that the stride does not invalidate ob's membership. */
+ tmp1 = PyNumber_Subtract(ob, r->start);
+ if (tmp1 == NULL)
+ goto end;
+ tmp2 = PyNumber_Remainder(tmp1, r->step);
+ if (tmp2 == NULL)
+ goto end;
+ /* result = ((int(ob) - start) % step) == 0 */
+ result = PyObject_RichCompareBool(tmp2, _PyLong_Zero, Py_EQ);
+ end:
+ Py_XDECREF(tmp1);
+ Py_XDECREF(tmp2);
+ return result;
+}
+
+static int
+range_contains(rangeobject *r, PyObject *ob)
+{
+ if (PyLong_CheckExact(ob) || PyBool_Check(ob))
+ return range_contains_long(r, ob);
+
+ return (int)_PySequence_IterSearch((PyObject*)r, ob,
+ PY_ITERSEARCH_CONTAINS);
+}
+
+/* Compare two range objects. Return 1 for equal, 0 for not equal
+ and -1 on error. The algorithm is roughly the C equivalent of
+
+ if r0 is r1:
+ return True
+ if len(r0) != len(r1):
+ return False
+ if not len(r0):
+ return True
+ if r0.start != r1.start:
+ return False
+ if len(r0) == 1:
+ return True
+ return r0.step == r1.step
+*/
+static int
+range_equals(rangeobject *r0, rangeobject *r1)
+{
+ int cmp_result;
+
+ if (r0 == r1)
+ return 1;
+ cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ);
+ /* Return False or error to the caller. */
+ if (cmp_result != 1)
+ return cmp_result;
+ cmp_result = PyObject_Not(r0->length);
+ /* Return True or error to the caller. */
+ if (cmp_result != 0)
+ return cmp_result;
+ cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ);
+ /* Return False or error to the caller. */
+ if (cmp_result != 1)
+ return cmp_result;
+ cmp_result = PyObject_RichCompareBool(r0->length, _PyLong_One, Py_EQ);
+ /* Return True or error to the caller. */
+ if (cmp_result != 0)
+ return cmp_result;
+ return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ);
+}
+
+static PyObject *
+range_richcompare(PyObject *self, PyObject *other, int op)
+{
+ int result;
+
+ if (!PyRange_Check(other))
+ Py_RETURN_NOTIMPLEMENTED;
+ switch (op) {
+ case Py_NE:
+ case Py_EQ:
+ result = range_equals((rangeobject*)self, (rangeobject*)other);
+ if (result == -1)
+ return NULL;
+ if (op == Py_NE)
+ result = !result;
+ if (result)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ case Py_LE:
+ case Py_GE:
+ case Py_LT:
+ case Py_GT:
+ Py_RETURN_NOTIMPLEMENTED;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+}
+
+/* Hash function for range objects. Rough C equivalent of
+
+ if not len(r):
+ return hash((len(r), None, None))
+ if len(r) == 1:
+ return hash((len(r), r.start, None))
+ return hash((len(r), r.start, r.step))
+*/
+static Py_hash_t
+range_hash(rangeobject *r)
+{
+ PyObject *t;
+ Py_hash_t result = -1;
+ int cmp_result;
+
+ t = PyTuple_New(3);
+ if (!t)
+ return -1;
+ Py_INCREF(r->length);
+ PyTuple_SET_ITEM(t, 0, r->length);
+ cmp_result = PyObject_Not(r->length);
+ if (cmp_result == -1)
+ goto end;
+ if (cmp_result == 1) {
+ Py_INCREF(Py_None);
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(t, 1, Py_None);
+ PyTuple_SET_ITEM(t, 2, Py_None);
+ }
+ else {
+ Py_INCREF(r->start);
+ PyTuple_SET_ITEM(t, 1, r->start);
+ cmp_result = PyObject_RichCompareBool(r->length, _PyLong_One, Py_EQ);
+ if (cmp_result == -1)
+ goto end;
+ if (cmp_result == 1) {
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(t, 2, Py_None);
+ }
+ else {
+ Py_INCREF(r->step);
+ PyTuple_SET_ITEM(t, 2, r->step);
+ }
+ }
+ result = PyObject_Hash(t);
+ end:
+ Py_DECREF(t);
+ return result;
+}
+
+static PyObject *
+range_count(rangeobject *r, PyObject *ob)
+{
+ if (PyLong_CheckExact(ob) || PyBool_Check(ob)) {
+ int result = range_contains_long(r, ob);
+ if (result == -1)
+ return NULL;
+ return PyLong_FromLong(result);
+ } else {
+ Py_ssize_t count;
+ count = _PySequence_IterSearch((PyObject*)r, ob, PY_ITERSEARCH_COUNT);
+ if (count == -1)
+ return NULL;
+ return PyLong_FromSsize_t(count);
+ }
+}
+
+static PyObject *
+range_index(rangeobject *r, PyObject *ob)
+{
+ int contains;
+
+ if (!PyLong_CheckExact(ob) && !PyBool_Check(ob)) {
+ Py_ssize_t index;
+ index = _PySequence_IterSearch((PyObject*)r, ob, PY_ITERSEARCH_INDEX);
+ if (index == -1)
+ return NULL;
+ return PyLong_FromSsize_t(index);
+ }
+
+ contains = range_contains_long(r, ob);
+ if (contains == -1)
+ return NULL;
+
+ if (contains) {
+ PyObject *idx, *tmp = PyNumber_Subtract(ob, r->start);
+ if (tmp == NULL)
+ return NULL;
+ /* idx = (ob - r.start) // r.step */
+ idx = PyNumber_FloorDivide(tmp, r->step);
+ Py_DECREF(tmp);
+ return idx;
+ }
+
+ /* object is not in the range */
+ PyErr_Format(PyExc_ValueError, "%R is not in range", ob);
+ return NULL;
+}
+
+static PySequenceMethods range_as_sequence = {
+ (lenfunc)range_length, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc)range_item, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ (objobjproc)range_contains, /* sq_contains */
+};
+
+static PyObject *
+range_repr(rangeobject *r)
+{
+ Py_ssize_t istep;
+
+ /* Check for special case values for printing. We don't always
+ need the step value. We don't care about overflow. */
+ istep = PyNumber_AsSsize_t(r->step, NULL);
+ if (istep == -1 && PyErr_Occurred()) {
+ assert(!PyErr_ExceptionMatches(PyExc_OverflowError));
+ return NULL;
+ }
+
+ if (istep == 1)
+ return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop);
+ else
+ return PyUnicode_FromFormat("range(%R, %R, %R)",
+ r->start, r->stop, r->step);
+}
+
+/* Pickling support */
+static PyObject *
+range_reduce(rangeobject *r, PyObject *args)
+{
+ return Py_BuildValue("(O(OOO))", Py_TYPE(r),
+ r->start, r->stop, r->step);
+}
+
+static PyObject *
+range_subscript(rangeobject* self, PyObject* item)
+{
if (_PyIndex_Check(item)) {
- PyObject *i, *result;
- i = PyNumber_Index(item);
- if (!i)
- return NULL;
- result = compute_range_item(self, i);
- Py_DECREF(i);
- return result;
- }
- if (PySlice_Check(item)) {
- return compute_slice(self, item);
- }
- PyErr_Format(PyExc_TypeError,
- "range indices must be integers or slices, not %.200s",
+ PyObject *i, *result;
+ i = PyNumber_Index(item);
+ if (!i)
+ return NULL;
+ result = compute_range_item(self, i);
+ Py_DECREF(i);
+ return result;
+ }
+ if (PySlice_Check(item)) {
+ return compute_slice(self, item);
+ }
+ PyErr_Format(PyExc_TypeError,
+ "range indices must be integers or slices, not %.200s",
Py_TYPE(item)->tp_name);
- return NULL;
-}
-
-
-static PyMappingMethods range_as_mapping = {
- (lenfunc)range_length, /* mp_length */
- (binaryfunc)range_subscript, /* mp_subscript */
- (objobjargproc)0, /* mp_ass_subscript */
-};
-
-static int
-range_bool(rangeobject* self)
-{
- return PyObject_IsTrue(self->length);
-}
-
-static PyNumberMethods range_as_number = {
- .nb_bool = (inquiry)range_bool,
-};
-
-static PyObject * range_iter(PyObject *seq);
+ return NULL;
+}
+
+
+static PyMappingMethods range_as_mapping = {
+ (lenfunc)range_length, /* mp_length */
+ (binaryfunc)range_subscript, /* mp_subscript */
+ (objobjargproc)0, /* mp_ass_subscript */
+};
+
+static int
+range_bool(rangeobject* self)
+{
+ return PyObject_IsTrue(self->length);
+}
+
+static PyNumberMethods range_as_number = {
+ .nb_bool = (inquiry)range_bool,
+};
+
+static PyObject * range_iter(PyObject *seq);
static PyObject * range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored));
-
-PyDoc_STRVAR(reverse_doc,
-"Return a reverse iterator.");
-
-PyDoc_STRVAR(count_doc,
-"rangeobject.count(value) -> integer -- return number of occurrences of value");
-
-PyDoc_STRVAR(index_doc,
+
+PyDoc_STRVAR(reverse_doc,
+"Return a reverse iterator.");
+
+PyDoc_STRVAR(count_doc,
+"rangeobject.count(value) -> integer -- return number of occurrences of value");
+
+PyDoc_STRVAR(index_doc,
"rangeobject.index(value) -> integer -- return index of value.\n"
-"Raise ValueError if the value is not present.");
-
-static PyMethodDef range_methods[] = {
+"Raise ValueError if the value is not present.");
+
+static PyMethodDef range_methods[] = {
{"__reversed__", range_reverse, METH_NOARGS, reverse_doc},
- {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS},
- {"count", (PyCFunction)range_count, METH_O, count_doc},
- {"index", (PyCFunction)range_index, METH_O, index_doc},
- {NULL, NULL} /* sentinel */
-};
-
-static PyMemberDef range_members[] = {
- {"start", T_OBJECT_EX, offsetof(rangeobject, start), READONLY},
- {"stop", T_OBJECT_EX, offsetof(rangeobject, stop), READONLY},
- {"step", T_OBJECT_EX, offsetof(rangeobject, step), READONLY},
- {0}
-};
-
-PyTypeObject PyRange_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "range", /* Name of this type */
- sizeof(rangeobject), /* Basic object size */
- 0, /* Item size for varobject */
- (destructor)range_dealloc, /* tp_dealloc */
+ {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS},
+ {"count", (PyCFunction)range_count, METH_O, count_doc},
+ {"index", (PyCFunction)range_index, METH_O, index_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyMemberDef range_members[] = {
+ {"start", T_OBJECT_EX, offsetof(rangeobject, start), READONLY},
+ {"stop", T_OBJECT_EX, offsetof(rangeobject, stop), READONLY},
+ {"step", T_OBJECT_EX, offsetof(rangeobject, step), READONLY},
+ {0}
+};
+
+PyTypeObject PyRange_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "range", /* Name of this type */
+ sizeof(rangeobject), /* Basic object size */
+ 0, /* Item size for varobject */
+ (destructor)range_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
0, /* tp_as_async */
- (reprfunc)range_repr, /* tp_repr */
- &range_as_number, /* tp_as_number */
- &range_as_sequence, /* tp_as_sequence */
- &range_as_mapping, /* tp_as_mapping */
- (hashfunc)range_hash, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- range_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- range_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- range_iter, /* tp_iter */
- 0, /* tp_iternext */
- range_methods, /* tp_methods */
- range_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- range_new, /* tp_new */
+ (reprfunc)range_repr, /* tp_repr */
+ &range_as_number, /* tp_as_number */
+ &range_as_sequence, /* tp_as_sequence */
+ &range_as_mapping, /* tp_as_mapping */
+ (hashfunc)range_hash, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ range_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ range_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ range_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ range_methods, /* tp_methods */
+ range_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ range_new, /* tp_new */
.tp_vectorcall = (vectorcallfunc)range_vectorcall
-};
-
-/*********************** range Iterator **************************/
-
-/* There are 2 types of iterators, one for C longs, the other for
- Python ints (ie, PyObjects). This should make iteration fast
- in the normal case, but possible for any numeric value.
-*/
-
-typedef struct {
- PyObject_HEAD
- long index;
- long start;
- long step;
- long len;
-} rangeiterobject;
-
-static PyObject *
-rangeiter_next(rangeiterobject *r)
-{
- if (r->index < r->len)
- /* cast to unsigned to avoid possible signed overflow
- in intermediate calculations. */
- return PyLong_FromLong((long)(r->start +
- (unsigned long)(r->index++) * r->step));
- return NULL;
-}
-
-static PyObject *
+};
+
+/*********************** range Iterator **************************/
+
+/* There are 2 types of iterators, one for C longs, the other for
+ Python ints (ie, PyObjects). This should make iteration fast
+ in the normal case, but possible for any numeric value.
+*/
+
+typedef struct {
+ PyObject_HEAD
+ long index;
+ long start;
+ long step;
+ long len;
+} rangeiterobject;
+
+static PyObject *
+rangeiter_next(rangeiterobject *r)
+{
+ if (r->index < r->len)
+ /* cast to unsigned to avoid possible signed overflow
+ in intermediate calculations. */
+ return PyLong_FromLong((long)(r->start +
+ (unsigned long)(r->index++) * r->step));
+ return NULL;
+}
+
+static PyObject *
rangeiter_len(rangeiterobject *r, PyObject *Py_UNUSED(ignored))
-{
- return PyLong_FromLong(r->len - r->index);
-}
-
-PyDoc_STRVAR(length_hint_doc,
- "Private method returning an estimate of len(list(it)).");
-
-static PyObject *
+{
+ return PyLong_FromLong(r->len - r->index);
+}
+
+PyDoc_STRVAR(length_hint_doc,
+ "Private method returning an estimate of len(list(it)).");
+
+static PyObject *
rangeiter_reduce(rangeiterobject *r, PyObject *Py_UNUSED(ignored))
-{
- PyObject *start=NULL, *stop=NULL, *step=NULL;
- PyObject *range;
-
- /* create a range object for pickling */
- start = PyLong_FromLong(r->start);
- if (start == NULL)
- goto err;
- stop = PyLong_FromLong(r->start + r->len * r->step);
- if (stop == NULL)
- goto err;
- step = PyLong_FromLong(r->step);
- if (step == NULL)
- goto err;
- range = (PyObject*)make_range_object(&PyRange_Type,
- start, stop, step);
- if (range == NULL)
- goto err;
- /* return the result */
+{
+ PyObject *start=NULL, *stop=NULL, *step=NULL;
+ PyObject *range;
+
+ /* create a range object for pickling */
+ start = PyLong_FromLong(r->start);
+ if (start == NULL)
+ goto err;
+ stop = PyLong_FromLong(r->start + r->len * r->step);
+ if (stop == NULL)
+ goto err;
+ step = PyLong_FromLong(r->step);
+ if (step == NULL)
+ goto err;
+ range = (PyObject*)make_range_object(&PyRange_Type,
+ start, stop, step);
+ if (range == NULL)
+ goto err;
+ /* return the result */
return Py_BuildValue("N(N)l", _PyEval_GetBuiltinId(&PyId_iter),
range, r->index);
-err:
- Py_XDECREF(start);
- Py_XDECREF(stop);
- Py_XDECREF(step);
- return NULL;
-}
-
-static PyObject *
-rangeiter_setstate(rangeiterobject *r, PyObject *state)
-{
- long index = PyLong_AsLong(state);
- if (index == -1 && PyErr_Occurred())
- return NULL;
- /* silently clip the index value */
- if (index < 0)
- index = 0;
- else if (index > r->len)
- index = r->len; /* exhausted iterator */
- r->index = index;
- Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
-PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
-
-static PyMethodDef rangeiter_methods[] = {
- {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
- length_hint_doc},
- {"__reduce__", (PyCFunction)rangeiter_reduce, METH_NOARGS,
- reduce_doc},
- {"__setstate__", (PyCFunction)rangeiter_setstate, METH_O,
- setstate_doc},
- {NULL, NULL} /* sentinel */
-};
-
-PyTypeObject PyRangeIter_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "range_iterator", /* tp_name */
- sizeof(rangeiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)PyObject_Del, /* tp_dealloc */
+err:
+ Py_XDECREF(start);
+ Py_XDECREF(stop);
+ Py_XDECREF(step);
+ return NULL;
+}
+
+static PyObject *
+rangeiter_setstate(rangeiterobject *r, PyObject *state)
+{
+ long index = PyLong_AsLong(state);
+ if (index == -1 && PyErr_Occurred())
+ return NULL;
+ /* silently clip the index value */
+ if (index < 0)
+ index = 0;
+ else if (index > r->len)
+ index = r->len; /* exhausted iterator */
+ r->index = index;
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
+PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
+
+static PyMethodDef rangeiter_methods[] = {
+ {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
+ length_hint_doc},
+ {"__reduce__", (PyCFunction)rangeiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)rangeiter_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+PyTypeObject PyRangeIter_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "range_iterator", /* tp_name */
+ sizeof(rangeiterobject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)PyObject_Del, /* tp_dealloc */
0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)rangeiter_next, /* tp_iternext */
- rangeiter_methods, /* tp_methods */
- 0, /* tp_members */
-};
-
-/* Return number of items in range (lo, hi, step). step != 0
- * required. The result always fits in an unsigned long.
- */
-static unsigned long
-get_len_of_range(long lo, long hi, long step)
-{
- /* -------------------------------------------------------------
- If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty.
- Else for step > 0, if n values are in the range, the last one is
- lo + (n-1)*step, which must be <= hi-1. Rearranging,
- n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
- the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
- the RHS is non-negative and so truncation is the same as the
- floor. Letting M be the largest positive long, the worst case
- for the RHS numerator is hi=M, lo=-M-1, and then
- hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
- precision to compute the RHS exactly. The analysis for step < 0
- is similar.
- ---------------------------------------------------------------*/
- assert(step != 0);
- if (step > 0 && lo < hi)
- return 1UL + (hi - 1UL - lo) / step;
- else if (step < 0 && lo > hi)
- return 1UL + (lo - 1UL - hi) / (0UL - step);
- else
- return 0UL;
-}
-
-/* Initialize a rangeiter object. If the length of the rangeiter object
- is not representable as a C long, OverflowError is raised. */
-
-static PyObject *
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)rangeiter_next, /* tp_iternext */
+ rangeiter_methods, /* tp_methods */
+ 0, /* tp_members */
+};
+
+/* Return number of items in range (lo, hi, step). step != 0
+ * required. The result always fits in an unsigned long.
+ */
+static unsigned long
+get_len_of_range(long lo, long hi, long step)
+{
+ /* -------------------------------------------------------------
+ If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty.
+ Else for step > 0, if n values are in the range, the last one is
+ lo + (n-1)*step, which must be <= hi-1. Rearranging,
+ n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
+ the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
+ the RHS is non-negative and so truncation is the same as the
+ floor. Letting M be the largest positive long, the worst case
+ for the RHS numerator is hi=M, lo=-M-1, and then
+ hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
+ precision to compute the RHS exactly. The analysis for step < 0
+ is similar.
+ ---------------------------------------------------------------*/
+ assert(step != 0);
+ if (step > 0 && lo < hi)
+ return 1UL + (hi - 1UL - lo) / step;
+ else if (step < 0 && lo > hi)
+ return 1UL + (lo - 1UL - hi) / (0UL - step);
+ else
+ return 0UL;
+}
+
+/* Initialize a rangeiter object. If the length of the rangeiter object
+ is not representable as a C long, OverflowError is raised. */
+
+static PyObject *
fast_range_iter(long start, long stop, long step, long len)
-{
- rangeiterobject *it = PyObject_New(rangeiterobject, &PyRangeIter_Type);
- if (it == NULL)
- return NULL;
- it->start = start;
- it->step = step;
+{
+ rangeiterobject *it = PyObject_New(rangeiterobject, &PyRangeIter_Type);
+ if (it == NULL)
+ return NULL;
+ it->start = start;
+ it->step = step;
it->len = len;
- it->index = 0;
- return (PyObject *)it;
-}
-
-typedef struct {
- PyObject_HEAD
- PyObject *index;
- PyObject *start;
- PyObject *step;
- PyObject *len;
-} longrangeiterobject;
-
-static PyObject *
-longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
-{
- return PyNumber_Subtract(r->len, r->index);
-}
-
-static PyObject *
+ it->index = 0;
+ return (PyObject *)it;
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *index;
+ PyObject *start;
+ PyObject *step;
+ PyObject *len;
+} longrangeiterobject;
+
+static PyObject *
+longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
+{
+ return PyNumber_Subtract(r->len, r->index);
+}
+
+static PyObject *
longrangeiter_reduce(longrangeiterobject *r, PyObject *Py_UNUSED(ignored))
-{
- PyObject *product, *stop=NULL;
- PyObject *range;
-
- /* create a range object for pickling. Must calculate the "stop" value */
- product = PyNumber_Multiply(r->len, r->step);
- if (product == NULL)
- return NULL;
- stop = PyNumber_Add(r->start, product);
- Py_DECREF(product);
- if (stop == NULL)
- return NULL;
- Py_INCREF(r->start);
- Py_INCREF(r->step);
- range = (PyObject*)make_range_object(&PyRange_Type,
- r->start, stop, r->step);
- if (range == NULL) {
- Py_DECREF(r->start);
- Py_DECREF(stop);
- Py_DECREF(r->step);
- return NULL;
- }
-
- /* return the result */
+{
+ PyObject *product, *stop=NULL;
+ PyObject *range;
+
+ /* create a range object for pickling. Must calculate the "stop" value */
+ product = PyNumber_Multiply(r->len, r->step);
+ if (product == NULL)
+ return NULL;
+ stop = PyNumber_Add(r->start, product);
+ Py_DECREF(product);
+ if (stop == NULL)
+ return NULL;
+ Py_INCREF(r->start);
+ Py_INCREF(r->step);
+ range = (PyObject*)make_range_object(&PyRange_Type,
+ r->start, stop, r->step);
+ if (range == NULL) {
+ Py_DECREF(r->start);
+ Py_DECREF(stop);
+ Py_DECREF(r->step);
+ return NULL;
+ }
+
+ /* return the result */
return Py_BuildValue("N(N)O", _PyEval_GetBuiltinId(&PyId_iter),
range, r->index);
-}
-
-static PyObject *
-longrangeiter_setstate(longrangeiterobject *r, PyObject *state)
-{
- int cmp;
-
- /* clip the value */
- cmp = PyObject_RichCompareBool(state, _PyLong_Zero, Py_LT);
- if (cmp < 0)
- return NULL;
- if (cmp > 0) {
- state = _PyLong_Zero;
- }
- else {
- cmp = PyObject_RichCompareBool(r->len, state, Py_LT);
- if (cmp < 0)
- return NULL;
- if (cmp > 0)
- state = r->len;
- }
- Py_INCREF(state);
- Py_XSETREF(r->index, state);
- Py_RETURN_NONE;
-}
-
-static PyMethodDef longrangeiter_methods[] = {
- {"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS,
- length_hint_doc},
- {"__reduce__", (PyCFunction)longrangeiter_reduce, METH_NOARGS,
- reduce_doc},
- {"__setstate__", (PyCFunction)longrangeiter_setstate, METH_O,
- setstate_doc},
- {NULL, NULL} /* sentinel */
-};
-
-static void
-longrangeiter_dealloc(longrangeiterobject *r)
-{
- Py_XDECREF(r->index);
- Py_XDECREF(r->start);
- Py_XDECREF(r->step);
- Py_XDECREF(r->len);
- PyObject_Del(r);
-}
-
-static PyObject *
-longrangeiter_next(longrangeiterobject *r)
-{
- PyObject *product, *new_index, *result;
- if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1)
- return NULL;
-
- new_index = PyNumber_Add(r->index, _PyLong_One);
- if (!new_index)
- return NULL;
-
- product = PyNumber_Multiply(r->index, r->step);
- if (!product) {
- Py_DECREF(new_index);
- return NULL;
- }
-
- result = PyNumber_Add(r->start, product);
- Py_DECREF(product);
- if (result) {
- Py_SETREF(r->index, new_index);
- }
- else {
- Py_DECREF(new_index);
- }
-
- return result;
-}
-
-PyTypeObject PyLongRangeIter_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "longrange_iterator", /* tp_name */
- sizeof(longrangeiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)longrangeiter_dealloc, /* tp_dealloc */
+}
+
+static PyObject *
+longrangeiter_setstate(longrangeiterobject *r, PyObject *state)
+{
+ int cmp;
+
+ /* clip the value */
+ cmp = PyObject_RichCompareBool(state, _PyLong_Zero, Py_LT);
+ if (cmp < 0)
+ return NULL;
+ if (cmp > 0) {
+ state = _PyLong_Zero;
+ }
+ else {
+ cmp = PyObject_RichCompareBool(r->len, state, Py_LT);
+ if (cmp < 0)
+ return NULL;
+ if (cmp > 0)
+ state = r->len;
+ }
+ Py_INCREF(state);
+ Py_XSETREF(r->index, state);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef longrangeiter_methods[] = {
+ {"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS,
+ length_hint_doc},
+ {"__reduce__", (PyCFunction)longrangeiter_reduce, METH_NOARGS,
+ reduce_doc},
+ {"__setstate__", (PyCFunction)longrangeiter_setstate, METH_O,
+ setstate_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+static void
+longrangeiter_dealloc(longrangeiterobject *r)
+{
+ Py_XDECREF(r->index);
+ Py_XDECREF(r->start);
+ Py_XDECREF(r->step);
+ Py_XDECREF(r->len);
+ PyObject_Del(r);
+}
+
+static PyObject *
+longrangeiter_next(longrangeiterobject *r)
+{
+ PyObject *product, *new_index, *result;
+ if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1)
+ return NULL;
+
+ new_index = PyNumber_Add(r->index, _PyLong_One);
+ if (!new_index)
+ return NULL;
+
+ product = PyNumber_Multiply(r->index, r->step);
+ if (!product) {
+ Py_DECREF(new_index);
+ return NULL;
+ }
+
+ result = PyNumber_Add(r->start, product);
+ Py_DECREF(product);
+ if (result) {
+ Py_SETREF(r->index, new_index);
+ }
+ else {
+ Py_DECREF(new_index);
+ }
+
+ return result;
+}
+
+PyTypeObject PyLongRangeIter_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "longrange_iterator", /* tp_name */
+ sizeof(longrangeiterobject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)longrangeiter_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)longrangeiter_next, /* tp_iternext */
- longrangeiter_methods, /* tp_methods */
- 0,
-};
-
-static PyObject *
-range_iter(PyObject *seq)
-{
- rangeobject *r = (rangeobject *)seq;
- longrangeiterobject *it;
- long lstart, lstop, lstep;
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)longrangeiter_next, /* tp_iternext */
+ longrangeiter_methods, /* tp_methods */
+ 0,
+};
+
+static PyObject *
+range_iter(PyObject *seq)
+{
+ rangeobject *r = (rangeobject *)seq;
+ longrangeiterobject *it;
+ long lstart, lstop, lstep;
unsigned long ulen;
-
- assert(PyRange_Check(seq));
-
- /* If all three fields and the length convert to long, use the int
- * version */
- lstart = PyLong_AsLong(r->start);
- if (lstart == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- goto long_range;
- }
- lstop = PyLong_AsLong(r->stop);
- if (lstop == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- goto long_range;
- }
- lstep = PyLong_AsLong(r->step);
- if (lstep == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- goto long_range;
- }
+
+ assert(PyRange_Check(seq));
+
+ /* If all three fields and the length convert to long, use the int
+ * version */
+ lstart = PyLong_AsLong(r->start);
+ if (lstart == -1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ goto long_range;
+ }
+ lstop = PyLong_AsLong(r->stop);
+ if (lstop == -1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ goto long_range;
+ }
+ lstep = PyLong_AsLong(r->step);
+ if (lstep == -1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ goto long_range;
+ }
ulen = get_len_of_range(lstart, lstop, lstep);
if (ulen > (unsigned long)LONG_MAX) {
- goto long_range;
- }
+ goto long_range;
+ }
/* check for potential overflow of lstart + ulen * lstep */
if (ulen) {
if (lstep > 0) {
@@ -1100,127 +1100,127 @@ range_iter(PyObject *seq)
}
}
return fast_range_iter(lstart, lstop, lstep, (long)ulen);
-
- long_range:
- it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
- if (it == NULL)
- return NULL;
-
- it->start = r->start;
- it->step = r->step;
- it->len = r->length;
- it->index = _PyLong_Zero;
- Py_INCREF(it->start);
- Py_INCREF(it->step);
- Py_INCREF(it->len);
- Py_INCREF(it->index);
- return (PyObject *)it;
-}
-
-static PyObject *
+
+ long_range:
+ it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
+ if (it == NULL)
+ return NULL;
+
+ it->start = r->start;
+ it->step = r->step;
+ it->len = r->length;
+ it->index = _PyLong_Zero;
+ Py_INCREF(it->start);
+ Py_INCREF(it->step);
+ Py_INCREF(it->len);
+ Py_INCREF(it->index);
+ return (PyObject *)it;
+}
+
+static PyObject *
range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored))
-{
- rangeobject *range = (rangeobject*) seq;
- longrangeiterobject *it;
- PyObject *sum, *diff, *product;
- long lstart, lstop, lstep, new_start, new_stop;
- unsigned long ulen;
-
- assert(PyRange_Check(seq));
-
- /* reversed(range(start, stop, step)) can be expressed as
- range(start+(n-1)*step, start-step, -step), where n is the number of
- integers in the range.
-
- If each of start, stop, step, -step, start-step, and the length
- of the iterator is representable as a C long, use the int
- version. This excludes some cases where the reversed range is
- representable as a range_iterator, but it's good enough for
- common cases and it makes the checks simple. */
-
- lstart = PyLong_AsLong(range->start);
- if (lstart == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- goto long_range;
- }
- lstop = PyLong_AsLong(range->stop);
- if (lstop == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- goto long_range;
- }
- lstep = PyLong_AsLong(range->step);
- if (lstep == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- goto long_range;
- }
- /* check for possible overflow of -lstep */
- if (lstep == LONG_MIN)
- goto long_range;
-
- /* check for overflow of lstart - lstep:
-
- for lstep > 0, need only check whether lstart - lstep < LONG_MIN.
- for lstep < 0, need only check whether lstart - lstep > LONG_MAX
-
- Rearrange these inequalities as:
-
- lstart - LONG_MIN < lstep (lstep > 0)
- LONG_MAX - lstart < -lstep (lstep < 0)
-
- and compute both sides as unsigned longs, to avoid the
- possibility of undefined behaviour due to signed overflow. */
-
- if (lstep > 0) {
- if ((unsigned long)lstart - LONG_MIN < (unsigned long)lstep)
- goto long_range;
- }
- else {
- if (LONG_MAX - (unsigned long)lstart < 0UL - lstep)
- goto long_range;
- }
-
- ulen = get_len_of_range(lstart, lstop, lstep);
- if (ulen > (unsigned long)LONG_MAX)
- goto long_range;
-
- new_stop = lstart - lstep;
- new_start = (long)(new_stop + ulen * lstep);
+{
+ rangeobject *range = (rangeobject*) seq;
+ longrangeiterobject *it;
+ PyObject *sum, *diff, *product;
+ long lstart, lstop, lstep, new_start, new_stop;
+ unsigned long ulen;
+
+ assert(PyRange_Check(seq));
+
+ /* reversed(range(start, stop, step)) can be expressed as
+ range(start+(n-1)*step, start-step, -step), where n is the number of
+ integers in the range.
+
+ If each of start, stop, step, -step, start-step, and the length
+ of the iterator is representable as a C long, use the int
+ version. This excludes some cases where the reversed range is
+ representable as a range_iterator, but it's good enough for
+ common cases and it makes the checks simple. */
+
+ lstart = PyLong_AsLong(range->start);
+ if (lstart == -1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ goto long_range;
+ }
+ lstop = PyLong_AsLong(range->stop);
+ if (lstop == -1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ goto long_range;
+ }
+ lstep = PyLong_AsLong(range->step);
+ if (lstep == -1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ goto long_range;
+ }
+ /* check for possible overflow of -lstep */
+ if (lstep == LONG_MIN)
+ goto long_range;
+
+ /* check for overflow of lstart - lstep:
+
+ for lstep > 0, need only check whether lstart - lstep < LONG_MIN.
+ for lstep < 0, need only check whether lstart - lstep > LONG_MAX
+
+ Rearrange these inequalities as:
+
+ lstart - LONG_MIN < lstep (lstep > 0)
+ LONG_MAX - lstart < -lstep (lstep < 0)
+
+ and compute both sides as unsigned longs, to avoid the
+ possibility of undefined behaviour due to signed overflow. */
+
+ if (lstep > 0) {
+ if ((unsigned long)lstart - LONG_MIN < (unsigned long)lstep)
+ goto long_range;
+ }
+ else {
+ if (LONG_MAX - (unsigned long)lstart < 0UL - lstep)
+ goto long_range;
+ }
+
+ ulen = get_len_of_range(lstart, lstop, lstep);
+ if (ulen > (unsigned long)LONG_MAX)
+ goto long_range;
+
+ new_stop = lstart - lstep;
+ new_start = (long)(new_stop + ulen * lstep);
return fast_range_iter(new_start, new_stop, -lstep, (long)ulen);
-
-long_range:
- it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
- if (it == NULL)
- return NULL;
- it->index = it->start = it->step = NULL;
-
- /* start + (len - 1) * step */
- it->len = range->length;
- Py_INCREF(it->len);
-
- diff = PyNumber_Subtract(it->len, _PyLong_One);
- if (!diff)
- goto create_failure;
-
- product = PyNumber_Multiply(diff, range->step);
- Py_DECREF(diff);
- if (!product)
- goto create_failure;
-
- sum = PyNumber_Add(range->start, product);
- Py_DECREF(product);
- it->start = sum;
- if (!it->start)
- goto create_failure;
-
- it->step = PyNumber_Negative(range->step);
- if (!it->step)
- goto create_failure;
-
- it->index = _PyLong_Zero;
- Py_INCREF(it->index);
- return (PyObject *)it;
-
-create_failure:
- Py_DECREF(it);
- return NULL;
-}
+
+long_range:
+ it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
+ if (it == NULL)
+ return NULL;
+ it->index = it->start = it->step = NULL;
+
+ /* start + (len - 1) * step */
+ it->len = range->length;
+ Py_INCREF(it->len);
+
+ diff = PyNumber_Subtract(it->len, _PyLong_One);
+ if (!diff)
+ goto create_failure;
+
+ product = PyNumber_Multiply(diff, range->step);
+ Py_DECREF(diff);
+ if (!product)
+ goto create_failure;
+
+ sum = PyNumber_Add(range->start, product);
+ Py_DECREF(product);
+ it->start = sum;
+ if (!it->start)
+ goto create_failure;
+
+ it->step = PyNumber_Negative(range->step);
+ if (!it->step)
+ goto create_failure;
+
+ it->index = _PyLong_Zero;
+ Py_INCREF(it->index);
+ return (PyObject *)it;
+
+create_failure:
+ Py_DECREF(it);
+ return NULL;
+}