// Copyright (c) Corporation for National Research Initiatives package org.python.core; /** * The abstract superclass of PyObjects that implements a Sequence. Minimize the work in * creating such objects. * * Method names are designed to make it possible for subclasses of PySequence to implement * java.util.List. * * Subclasses must also implement get, getslice, and repeat methods. * * Subclasses that are mutable should also implement: set, setslice, del, and delRange. */ public abstract class PySequence extends PyObject { protected PySequence(PyType type) { super(type); } // These methods must be defined for any sequence /** * @param index index of element to return. * @return the element at the given position in the list. */ protected abstract PyObject pyget(int index); /** * Returns a range of elements from the sequence. * * @param start the position of the first element. * @param stop one more than the position of the last element. * @param step the step size. * @return a sequence corresponding the the given range of elements. */ protected abstract PyObject getslice(int start, int stop, int step); /** * Repeats the given sequence. * * @param count the number of times to repeat the sequence. * @return this sequence repeated count times. */ protected abstract PyObject repeat(int count); // These methods only apply to mutable sequences /** * Sets the given element of the sequence. * * @param index index of the element to set. * @param value the value to set this element to. */ protected void pyset(int index, PyObject value) { throw Py.TypeError("can't assign to immutable object"); } /** * Sets the given range of elements. */ protected void setslice(int start, int stop, int step, PyObject value) { throw Py.TypeError(String.format("'%s' object does not support item assignment", getType().fastGetName())); } protected void del(int i) { throw Py.TypeError(String.format("'%s' object does not support item deletion", getType().fastGetName())); } protected void delRange(int start, int stop) { throw Py.TypeError(String.format("'%s' object does not support item deletion", getType().fastGetName())); } @Override public boolean __nonzero__() { return seq___nonzero__(); } final boolean seq___nonzero__() { return __len__() != 0; } @Override public PyObject __iter__() { return seq___iter__(); } final PyObject seq___iter__() { return new PySequenceIter(this); } @Override public PyObject __eq__(PyObject o) { return seq___eq__(o); } final PyObject seq___eq__(PyObject o) { if (!isSubType(o)) { return null; } int tl = __len__(); int ol = o.__len__(); if (tl != ol) { return Py.False; } int i = cmp(this, tl, o, ol); return i < 0 ? Py.True : Py.False; } @Override public PyObject __ne__(PyObject o) { return seq___ne__(o); } final PyObject seq___ne__(PyObject o) { if (!isSubType(o)) { return null; } int tl = __len__(); int ol = o.__len__(); if (tl != ol) { return Py.True; } int i = cmp(this, tl, o, ol); return i < 0 ? Py.False : Py.True; } @Override public PyObject __lt__(PyObject o) { return seq___lt__(o); } final PyObject seq___lt__(PyObject o) { if (!isSubType(o)) { return null; } int i = cmp(this, -1, o, -1); if (i < 0) { return i == -1 ? Py.True : Py.False; } return __finditem__(i)._lt(o.__finditem__(i)); } @Override public PyObject __le__(PyObject o) { return seq___le__(o); } final PyObject seq___le__(PyObject o) { if (!isSubType(o)) { return null; } int i = cmp(this, -1, o, -1); if (i < 0) { return i == -1 || i == -2 ? Py.True : Py.False; } return __finditem__(i)._le(o.__finditem__(i)); } @Override public PyObject __gt__(PyObject o) { return seq___gt__(o); } final PyObject seq___gt__(PyObject o) { if (!isSubType(o)) { return null; } int i = cmp(this, -1, o, -1); if (i < 0) { return i == -3 ? Py.True : Py.False; } return __finditem__(i)._gt(o.__finditem__(i)); } @Override public PyObject __ge__(PyObject o) { return seq___ge__(o); } final PyObject seq___ge__(PyObject o) { if (!isSubType(o)) { return null; } int i = cmp(this, -1, o, -1); if (i < 0) { return i == -3 || i == -2 ? Py.True : Py.False; } return __finditem__(i)._ge(o.__finditem__(i)); } /** * isSubType tailored for PySequence binops. * * @param other PyObject * @return true if subclass of other */ protected boolean isSubType(PyObject other) { PyType type = getType(); PyType otherType = other.getType(); return type == otherType || type.isSubType(otherType); } /** * Compare the specified object/length pairs. * * @return value >= 0 is the index where the sequences differs. * -1: reached the end of o1 without a difference * -2: reached the end of both seqeunces without a difference * -3: reached the end of o2 without a difference */ protected static int cmp(PyObject o1, int ol1, PyObject o2, int ol2) { if (ol1 < 0) { ol1 = o1.__len__(); } if (ol2 < 0) { ol2 = o2.__len__(); } for (int i = 0; i < ol1 && i < ol2; i++) { if (!o1.__getitem__(i).equals(o2.__getitem__(i))) { return i; } } if (ol1 == ol2) { return -2; } return ol1 < ol2 ? -1 : -3; } /** * Return a copy of a sequence where the __len__() method is telling the truth. */ protected static PySequence fastSequence(PyObject seq, String msg) { if (seq instanceof PySequence) { return (PySequence)seq; } PyList list = new PyList(); PyObject iter = Py.iter(seq, msg); for (PyObject item = null; (item = iter.__iternext__()) != null;) { list.append(item); } return list; } /** * Make step a long in case adding the start, stop and step together overflows an int. */ protected static final int sliceLength(int start, int stop, long step) { int ret; if (step > 0) { ret = (int)((stop - start + step - 1) / step); } else { ret = (int)((stop - start + step + 1) / step); } if (ret < 0) { return 0; } return ret; } /** * Adjusts <code>index</code> such that it's >= 0 and <= __len__. If * <code>index</code> starts off negative, it's treated as an index from the end of * the sequence going back to the start. */ protected int boundToSequence(int index) { int length = __len__(); if (index < 0) { index += length; if (index < 0) { index = 0; } } else if (index > length) { index = length; } return index; } @Override public PyObject __finditem__(int index) { return seq___finditem__(index); } final PyObject seq___finditem__(int index) { return delegator.checkIdxAndFindItem(index); } @Override public PyObject __finditem__(PyObject index) { return seq___finditem__(index); } final PyObject seq___finditem__(PyObject index) { return delegator.checkIdxAndFindItem(index); } @Override public PyObject __getitem__(PyObject index) { return seq___getitem__(index); } final PyObject seq___getitem__(PyObject index) { return delegator.checkIdxAndGetItem(index); } @Override public boolean isMappingType() throws PyIgnoreMethodTag { return false; } @Override public boolean isNumberType() throws PyIgnoreMethodTag { return false; } @Override public PyObject __getslice__(PyObject start, PyObject stop, PyObject step) { return seq___getslice__(start, stop, step); } final PyObject seq___getslice__(PyObject start, PyObject stop, PyObject step) { return delegator.getSlice(new PySlice(start, stop, step)); } @Override public void __setslice__(PyObject start, PyObject stop, PyObject step, PyObject value) { seq___setslice__(start, stop, step, value); } final void seq___setslice__(PyObject start, PyObject stop, PyObject step, PyObject value) { if (value == null) { value = step; step = null; } delegator.checkIdxAndSetSlice(new PySlice(start, stop, step), value); } @Override public void __delslice__(PyObject start, PyObject stop, PyObject step) { seq___delslice__(start, stop, step); } final void seq___delslice__(PyObject start, PyObject stop, PyObject step) { delegator.checkIdxAndDelItem(new PySlice(start, stop, step)); } @Override public void __setitem__(int index, PyObject value) { delegator.checkIdxAndSetItem(index, value); } @Override public void __setitem__(PyObject index, PyObject value) { seq___setitem__(index, value); } final void seq___setitem__(PyObject index, PyObject value) { delegator.checkIdxAndSetItem(index, value); } @Override public void __delitem__(PyObject index) { seq___delitem__(index); } final void seq___delitem__(PyObject index) { delegator.checkIdxAndDelItem(index); } @Override public synchronized Object __tojava__(Class<?> c) throws PyIgnoreMethodTag { if (c.isArray()) { Class<?> component = c.getComponentType(); try { int n = __len__(); PyArray array = new PyArray(component, n); for (int i = 0; i < n; i++) { PyObject o = pyget(i); array.set(i, o); } return array.getArray(); } catch (Throwable t) { // ok } } return super.__tojava__(c); } /** * Return sequence-specific error messages suitable for substitution. * * {0} is the op name. {1} is the left operand type. {2} is the right operand type. */ @Override protected String unsupportedopMessage(String op, PyObject o2) { if (op.equals("*")) { return "can''t multiply sequence by non-int of type ''{2}''"; } return null; } /** * Return sequence-specific error messages suitable for substitution. * * {0} is the op name. {1} is the left operand type. {2} is the right operand type. */ @Override protected String runsupportedopMessage(String op, PyObject o2) { if (op.equals("*")) { return "can''t multiply sequence by non-int of type ''{1}''"; } return null; } @Override public boolean isSequenceType() { return true; } protected final SequenceIndexDelegate delegator = new SequenceIndexDelegate() { @Override public String getTypeName() { return getType().fastGetName(); } @Override public void setItem(int idx, PyObject value) { pyset(idx, value); } @Override public void setSlice(int start, int stop, int step, PyObject value) { setslice(start, stop, step, value); } @Override public int len() { return __len__(); } @Override public void delItem(int idx) { del(idx); } @Override public void delItems(int start, int stop) { delRange(start, stop); } @Override public PyObject getItem(int idx) { return pyget(idx); } @Override public PyObject getSlice(int start, int stop, int step) { return getslice(start, stop, step); } }; }