| 1 | /* Range object implementation */
|
|---|
| 2 |
|
|---|
| 3 | #include "Python.h"
|
|---|
| 4 |
|
|---|
| 5 | typedef struct {
|
|---|
| 6 | PyObject_HEAD
|
|---|
| 7 | long start;
|
|---|
| 8 | long step;
|
|---|
| 9 | long len;
|
|---|
| 10 | } rangeobject;
|
|---|
| 11 |
|
|---|
| 12 | /* Return number of items in range/xrange (lo, hi, step). step > 0
|
|---|
| 13 | * required. Return a value < 0 if & only if the true value is too
|
|---|
| 14 | * large to fit in a signed long.
|
|---|
| 15 | */
|
|---|
| 16 | static long
|
|---|
| 17 | get_len_of_range(long lo, long hi, long step)
|
|---|
| 18 | {
|
|---|
| 19 | /* -------------------------------------------------------------
|
|---|
| 20 | If lo >= hi, the range is empty.
|
|---|
| 21 | Else if n values are in the range, the last one is
|
|---|
| 22 | lo + (n-1)*step, which must be <= hi-1. Rearranging,
|
|---|
| 23 | n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
|
|---|
| 24 | the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
|
|---|
| 25 | the RHS is non-negative and so truncation is the same as the
|
|---|
| 26 | floor. Letting M be the largest positive long, the worst case
|
|---|
| 27 | for the RHS numerator is hi=M, lo=-M-1, and then
|
|---|
| 28 | hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
|
|---|
| 29 | precision to compute the RHS exactly.
|
|---|
| 30 | ---------------------------------------------------------------*/
|
|---|
| 31 | long n = 0;
|
|---|
| 32 | if (lo < hi) {
|
|---|
| 33 | unsigned long uhi = (unsigned long)hi;
|
|---|
| 34 | unsigned long ulo = (unsigned long)lo;
|
|---|
| 35 | unsigned long diff = uhi - ulo - 1;
|
|---|
| 36 | n = (long)(diff / (unsigned long)step + 1);
|
|---|
| 37 | }
|
|---|
| 38 | return n;
|
|---|
| 39 | }
|
|---|
| 40 |
|
|---|
| 41 | static PyObject *
|
|---|
| 42 | range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|---|
| 43 | {
|
|---|
| 44 | rangeobject *obj;
|
|---|
| 45 | long ilow = 0, ihigh = 0, istep = 1;
|
|---|
| 46 | long n;
|
|---|
| 47 |
|
|---|
| 48 | if (!_PyArg_NoKeywords("xrange()", kw))
|
|---|
| 49 | return NULL;
|
|---|
| 50 |
|
|---|
| 51 | if (PyTuple_Size(args) <= 1) {
|
|---|
| 52 | if (!PyArg_ParseTuple(args,
|
|---|
| 53 | "l;xrange() requires 1-3 int arguments",
|
|---|
| 54 | &ihigh))
|
|---|
| 55 | return NULL;
|
|---|
| 56 | }
|
|---|
| 57 | else {
|
|---|
| 58 | if (!PyArg_ParseTuple(args,
|
|---|
| 59 | "ll|l;xrange() requires 1-3 int arguments",
|
|---|
| 60 | &ilow, &ihigh, &istep))
|
|---|
| 61 | return NULL;
|
|---|
| 62 | }
|
|---|
| 63 | if (istep == 0) {
|
|---|
| 64 | PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
|
|---|
| 65 | return NULL;
|
|---|
| 66 | }
|
|---|
| 67 | if (istep > 0)
|
|---|
| 68 | n = get_len_of_range(ilow, ihigh, istep);
|
|---|
| 69 | else
|
|---|
| 70 | n = get_len_of_range(ihigh, ilow, -istep);
|
|---|
| 71 | if (n < 0) {
|
|---|
| 72 | PyErr_SetString(PyExc_OverflowError,
|
|---|
| 73 | "xrange() result has too many items");
|
|---|
| 74 | return NULL;
|
|---|
| 75 | }
|
|---|
| 76 |
|
|---|
| 77 | obj = PyObject_New(rangeobject, &PyRange_Type);
|
|---|
|
|---|