// Copyright (c) Corporation for National Research Initiatives package org.python.core; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; /** * The builtin xrange type. */ @ExposedType(name = "xrange", base = PyObject.class, isBaseType = false, doc = BuiltinDocs.xrange_doc) public class PyXRange extends PySequence { public static final PyType TYPE = PyType.fromClass(PyXRange.class); private final int start; private final int step; private final int len; public PyXRange(int ihigh) { this(0, ihigh, 1); } public PyXRange(int ilow, int ihigh) { this(ilow, ihigh, 1); } public PyXRange(int ilow, int ihigh, int istep) { super(TYPE); if (istep == 0) { throw Py.ValueError("xrange() arg 3 must not be zero"); } int n; if (istep > 0) { n = getLenOfRange(ilow, ihigh, istep); } else { n = getLenOfRange(ihigh, ilow, -istep); } if (n < 0) { throw Py.OverflowError("xrange() result has too many items"); } start = ilow; len = n; step = istep; } @ExposedNew static final PyObject xrange___new__(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) { ArgParser ap = new ArgParser("xrange", args, keywords, new String[] {"ilow", "ihigh", "istep"}, 1); ap.noKeywords(); int ilow = 0; int ihigh; int istep = 1; if (args.length == 1) { ihigh = ap.getInt(0); } else { ilow = ap.getInt(0); ihigh = ap.getInt(1); istep = ap.getInt(2, 1); } return new PyXRange(ilow, ihigh, istep); } /** * Return number of items in range/xrange (lo, hi, step). step > 0 required. Return * a value < 0 if & only if the true value is too large to fit in a Java int. * * @param lo int value * @param hi int value * @param step int value (> 0) * @return int length of range */ static int getLenOfRange(int lo, int hi, int step) { int n = 0; if (lo < hi) { // the base difference may be > Integer.MAX_VALUE long diff = (long)hi - (long)lo - 1; // any long > Integer.MAX_VALUE or < Integer.MIN_VALUE gets casted to a // negative number n = (int)((diff / step) + 1); } return n; } @Override public int __len__() { return xrange___len__(); } @ExposedMethod(doc = BuiltinDocs.xrange___len___doc) final int xrange___len__() { return len; } @Override public PyObject __getitem__(PyObject index) { return xrange___getitem__(index); } @ExposedMethod(doc = BuiltinDocs.xrange___getitem___doc) final PyObject xrange___getitem__(PyObject index) { PyObject ret = seq___finditem__(index); if (ret == null) { throw Py.IndexError("xrange object index out of range"); } return ret; } @ExposedMethod(doc = BuiltinDocs.xrange___iter___doc) public PyObject xrange___iter__() { return seq___iter__(); } @Override protected PyObject pyget(int i) { return Py.newInteger(start + (i % len) * step); } @Override protected PyObject getslice(int start, int stop, int step) { // not supported return null; } @Override protected PyObject repeat(int howmany) { // not supported return null; } @Override protected String unsupportedopMessage(String op, PyObject o2) { // always return the default unsupported messages instead of PySequence's return null; } @Override public String toString() { int stop = start + len * step; if (start == 0 && step == 1) { return String.format("xrange(%d)", stop); } else if (step == 1) { return String.format("xrange(%d, %d)", start, stop); } else { return String.format("xrange(%d, %d, %d)", start, stop, step); } } }