Skip to content

Commit 177da8c

Browse files
Keep stop instead of len.
1 parent 175b0d3 commit 177da8c

File tree

1 file changed

+73
-83
lines changed

1 file changed

+73
-83
lines changed

Objects/rangeobject.c

Lines changed: 73 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -767,17 +767,44 @@ PyTypeObject PyRange_Type = {
767767
typedef struct {
768768
PyObject_HEAD
769769
long start;
770+
long stop;
770771
long step;
771-
long len;
772772
} rangeiterobject;
773773

774+
/* Return number of items in range (lo, hi, step). step != 0
775+
* required. The result always fits in an unsigned long.
776+
*/
777+
static unsigned long
778+
get_len_of_range(long lo, long hi, long step)
779+
{
780+
/* -------------------------------------------------------------
781+
If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty.
782+
Else for step > 0, if n values are in the range, the last one is
783+
lo + (n-1)*step, which must be <= hi-1. Rearranging,
784+
n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
785+
the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
786+
the RHS is non-negative and so truncation is the same as the
787+
floor. Letting M be the largest positive long, the worst case
788+
for the RHS numerator is hi=M, lo=-M-1, and then
789+
hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
790+
precision to compute the RHS exactly. The analysis for step < 0
791+
is similar.
792+
---------------------------------------------------------------*/
793+
assert(step != 0);
794+
if (step > 0 && lo < hi)
795+
return 1UL + (hi - 1UL - lo) / step;
796+
else if (step < 0 && lo > hi)
797+
return 1UL + (lo - 1UL - hi) / (0UL - step);
798+
else
799+
return 0UL;
800+
}
801+
774802
static PyObject *
775803
rangeiter_next(rangeiterobject *r)
776804
{
777-
if (r->len > 0) {
805+
if (r->step > 0 ? r->start < r->stop : r->start > r->stop) {
778806
long result = r->start;
779807
r->start += r->step;
780-
r->len--;
781808
return PyLong_FromLong(result);
782809
}
783810
return NULL;
@@ -786,7 +813,8 @@ rangeiter_next(rangeiterobject *r)
786813
static PyObject *
787814
rangeiter_len(rangeiterobject *r, PyObject *Py_UNUSED(ignored))
788815
{
789-
return PyLong_FromLong(r->len);
816+
unsigned long ulen = get_len_of_range(r->start, r->stop, r->step);
817+
return PyLong_FromUnsignedLong(ulen);
790818
}
791819

792820
PyDoc_STRVAR(length_hint_doc,
@@ -802,7 +830,7 @@ rangeiter_reduce(rangeiterobject *r, PyObject *Py_UNUSED(ignored))
802830
start = PyLong_FromLong(r->start);
803831
if (start == NULL)
804832
goto err;
805-
stop = PyLong_FromLong(r->start + r->len * r->step);
833+
stop = PyLong_FromLong(r->stop);
806834
if (stop == NULL)
807835
goto err;
808836
step = PyLong_FromLong(r->step);
@@ -831,10 +859,12 @@ rangeiter_setstate(rangeiterobject *r, PyObject *state)
831859
/* silently clip the index value */
832860
if (index < 0)
833861
index = 0;
834-
else if (index > r->len)
835-
index = r->len; /* exhausted iterator */
862+
else {
863+
unsigned long ulen = get_len_of_range(r->start, r->stop, r->step);
864+
if ((unsigned long)index > ulen)
865+
index = (long)ulen; /* exhausted iterator */
866+
}
836867
r->start += index * r->step;
837-
r->len -= index;
838868
Py_RETURN_NONE;
839869
}
840870

@@ -884,34 +914,6 @@ PyTypeObject PyRangeIter_Type = {
884914
0, /* tp_members */
885915
};
886916

887-
/* Return number of items in range (lo, hi, step). step != 0
888-
* required. The result always fits in an unsigned long.
889-
*/
890-
static unsigned long
891-
get_len_of_range(long lo, long hi, long step)
892-
{
893-
/* -------------------------------------------------------------
894-
If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty.
895-
Else for step > 0, if n values are in the range, the last one is
896-
lo + (n-1)*step, which must be <= hi-1. Rearranging,
897-
n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
898-
the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
899-
the RHS is non-negative and so truncation is the same as the
900-
floor. Letting M be the largest positive long, the worst case
901-
for the RHS numerator is hi=M, lo=-M-1, and then
902-
hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
903-
precision to compute the RHS exactly. The analysis for step < 0
904-
is similar.
905-
---------------------------------------------------------------*/
906-
assert(step != 0);
907-
if (step > 0 && lo < hi)
908-
return 1UL + (hi - 1UL - lo) / step;
909-
else if (step < 0 && lo > hi)
910-
return 1UL + (lo - 1UL - hi) / (0UL - step);
911-
else
912-
return 0UL;
913-
}
914-
915917
/* Initialize a rangeiter object. If the length of the rangeiter object
916918
is not representable as a C long, OverflowError is raised. */
917919

@@ -922,46 +924,38 @@ fast_range_iter(long start, long stop, long step, long len)
922924
if (it == NULL)
923925
return NULL;
924926
it->start = start;
927+
it->stop = stop;
925928
it->step = step;
926-
it->len = len;
927929
return (PyObject *)it;
928930
}
929931

930932
typedef struct {
931933
PyObject_HEAD
932934
PyObject *start;
935+
PyObject *stop;
933936
PyObject *step;
934-
PyObject *len;
935937
} longrangeiterobject;
936938

937939
static PyObject *
938940
longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
939941
{
940-
Py_INCREF(r->len);
941-
return r->len;
942+
return compute_range_length(r->start, r->stop, r->step);
942943
}
943944

944945
static PyObject *
945946
longrangeiter_reduce(longrangeiterobject *r, PyObject *Py_UNUSED(ignored))
946947
{
947-
PyObject *product, *stop=NULL;
948948
PyObject *range;
949949

950-
/* create a range object for pickling. Must calculate the "stop" value */
951-
product = PyNumber_Multiply(r->len, r->step);
952-
if (product == NULL)
953-
return NULL;
954-
stop = PyNumber_Add(r->start, product);
955-
Py_DECREF(product);
956-
if (stop == NULL)
957-
return NULL;
950+
/* create a range object for pickling. */
958951
Py_INCREF(r->start);
952+
Py_INCREF(r->stop);
959953
Py_INCREF(r->step);
960954
range = (PyObject*)make_range_object(&PyRange_Type,
961-
r->start, stop, r->step);
955+
r->start, r->stop, r->step);
962956
if (range == NULL) {
963957
Py_DECREF(r->start);
964-
Py_DECREF(stop);
958+
Py_DECREF(r->stop);
965959
Py_DECREF(r->step);
966960
return NULL;
967961
}
@@ -978,23 +972,28 @@ longrangeiter_setstate(longrangeiterobject *r, PyObject *state)
978972
int cmp;
979973

980974
/* clip the value */
981-
cmp = PyObject_RichCompareBool(state, zero, Py_LT);
975+
cmp = PyObject_RichCompareBool(state, zero, Py_LE);
982976
if (cmp < 0)
983977
return NULL;
984978
if (cmp > 0) {
985-
state = zero;
979+
Py_RETURN_NONE;
986980
}
987-
else {
988-
cmp = PyObject_RichCompareBool(r->len, state, Py_LT);
989-
if (cmp < 0)
990-
return NULL;
991-
if (cmp > 0)
992-
state = r->len;
981+
PyObject *length = compute_range_length(r->start, r->stop, r->step);
982+
if (length == NULL) {
983+
return NULL;
993984
}
994-
PyObject *new_len = PyNumber_Subtract(r->len, state);
995-
if (new_len == NULL)
985+
cmp = PyObject_RichCompareBool(length, state, Py_LE);
986+
if (cmp < 0) {
987+
Py_DECREF(length);
996988
return NULL;
997-
Py_SETREF(r->len, new_len);
989+
}
990+
if (cmp > 0) {
991+
state = length;
992+
}
993+
else {
994+
Py_INCREF(state);
995+
Py_DECREF(length);
996+
}
998997
PyObject *product = PyNumber_Multiply(state, r->step);
999998
if (product == NULL)
1000999
return NULL;
@@ -1020,29 +1019,24 @@ static void
10201019
longrangeiter_dealloc(longrangeiterobject *r)
10211020
{
10221021
Py_XDECREF(r->start);
1022+
Py_XDECREF(r->stop);
10231023
Py_XDECREF(r->step);
1024-
Py_XDECREF(r->len);
10251024
PyObject_Free(r);
10261025
}
10271026

10281027
static PyObject *
10291028
longrangeiter_next(longrangeiterobject *r)
10301029
{
1031-
if (PyObject_RichCompareBool(r->len, _PyLong_GetZero(), Py_GT) != 1)
1030+
int s = _PyLong_Sign(r->step);
1031+
if (PyObject_RichCompareBool(r->start, r->stop, s > 0 ? Py_LT : Py_GT) != 1)
10321032
return NULL;
10331033

10341034
PyObject *new_start = PyNumber_Add(r->start, r->step);
10351035
if (new_start == NULL) {
10361036
return NULL;
10371037
}
1038-
PyObject *new_len = PyNumber_Subtract(r->len, _PyLong_GetOne());
1039-
if (new_len == NULL) {
1040-
Py_DECREF(new_start);
1041-
return NULL;
1042-
}
10431038
PyObject *result = r->start;
10441039
r->start = new_start;
1045-
Py_SETREF(r->len, new_len);
10461040
return result;
10471041
}
10481042

@@ -1129,11 +1123,11 @@ range_iter(PyObject *seq)
11291123
return NULL;
11301124

11311125
it->start = r->start;
1126+
it->stop = r->stop;
11321127
it->step = r->step;
1133-
it->len = r->length;
11341128
Py_INCREF(it->start);
1129+
Py_INCREF(it->stop);
11351130
Py_INCREF(it->step);
1136-
Py_INCREF(it->len);
11371131
return (PyObject *)it;
11381132
}
11391133

@@ -1142,7 +1136,7 @@ range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored))
11421136
{
11431137
rangeobject *range = (rangeobject*) seq;
11441138
longrangeiterobject *it;
1145-
PyObject *sum, *diff, *product;
1139+
PyObject *product;
11461140
long lstart, lstop, lstep, new_start, new_stop;
11471141
unsigned long ulen;
11481142

@@ -1213,22 +1207,18 @@ range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored))
12131207
return NULL;
12141208
it->start = it->step = NULL;
12151209

1216-
/* start + (len - 1) * step */
1217-
it->len = range->length;
1218-
Py_INCREF(it->len);
1219-
1220-
diff = PyNumber_Subtract(it->len, _PyLong_GetOne());
1221-
if (!diff)
1210+
/* new_stop = start - step */
1211+
it->stop = PyNumber_Subtract(range->start, range->step);
1212+
if (!it->stop)
12221213
goto create_failure;
12231214

1224-
product = PyNumber_Multiply(diff, range->step);
1225-
Py_DECREF(diff);
1215+
/* new_start = new_stop + len * step */
1216+
product = PyNumber_Multiply(range->length, range->step);
12261217
if (!product)
12271218
goto create_failure;
12281219

1229-
sum = PyNumber_Add(range->start, product);
1220+
it->start = PyNumber_Add(it->stop, product);
12301221
Py_DECREF(product);
1231-
it->start = sum;
12321222
if (!it->start)
12331223
goto create_failure;
12341224

0 commit comments

Comments
 (0)