src.org.python.core.PySequence Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython Show documentation
Show all versions of jython Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
// 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 {
/**
* A delegate that handles index checking and manipulation for get, set and del operations on
* this sequence in the form of a "pluggable behaviour". Because different types of sequence
* exhibit subtly different behaviour, there is scope for subclasses to customise the behaviour
* with their own extension of SequenceIndexDelegate
.
*/
protected SequenceIndexDelegate delegator;
/**
* Construct a PySequence for the given sub-type with the default index behaviour.
*
* @param type actual (Python) type of sub-class
*/
protected PySequence(PyType type) {
super(type);
delegator = new DefaultIndexDelegate();
}
/**
* Construct a PySequence for the given sub-type with custom index behaviour. In practice,
* restrictions on the construction of inner classes will mean null has to be passed and the
* actual delegator assigned later.
*
* @param type actual (Python) type of sub-class
* @param behaviour specific index behaviour (or null)
*/
protected PySequence(PyType type, SequenceIndexDelegate behaviour) {
super(type);
delegator = behaviour;
}
// These methods must be defined for any sequence
/**
* Returns the element of the sequence at the given index. This is an extension point called by
* PySequence in its implementation of {@link #__getitem__} It is guaranteed by PySequence that
* when it calls pyget(int)
the index is within the bounds of the array. Any other
* clients must make the same guarantee.
*
* @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);
/**
* Returns a (concrete subclass of) PySequence that repeats the given sequence, as in the
* implementation of __mul__
for strings.
*
* @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 indexed element of the sequence to the given value. This is an extension point
* called by PySequence in its implementation of {@link #__setitem__} It is guaranteed by
* PySequence that when it calls pyset(int) the index is within the bounds of the array. Any
* other clients must make the same guarantee.
*
* @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 according to Python slice assignment semantics. If the step
* size is one, it is a simple slice and the operation is equivalent to deleting that slice,
* then inserting the value at that position, regarding the value as a sequence (if possible) or
* as a single element if it is not a sequence. If the step size is not one, but
* start==stop
, it is equivalent to insertion at that point. If the step size is
* not one, and start!=stop
, the slice defines a certain number of elements to be
* replaced, and the value must be a sequence of exactly that many elements (or convertible to
* such a 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.
* @param value an object consistent with the slice assignment
*/
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()));
}
/**
* Deletes an element from the sequence (and closes up the gap).
*
* @param index index of the element to delete.
*/
protected void del(int index) {
delslice(index, index, 1, 1); // Raises TypeError (for immutable types).
}
/**
* Deletes a contiguous sub-sequence (and closes up the gap).
*
* @param start the position of the first element.
* @param stop one more than the position of the last element.
*/
protected void delRange(int start, int stop) {
delslice(start, stop, 1, Math.abs(stop - start)); // Raises TypeError (for immutable types).
}
/**
* Deletes a simple or extended slice and closes up the gap(s). The slice parameters
* [start:stop:step]
mean what they would in Python, after application of
* the "end-relative" rules for negative numbers and None
. The count n
* is as supplied by {@link PySlice#indicesEx(int)}. This method is unsafe in that slice
* parameters are assumed correct.
*
* @param start the position of the first element.
* @param stop beyond the position of the last element (not necessarily just beyond).
* @param step from one element to the next (positive or negative)
* @param n number of elements to delete
*/
protected void delslice(int start, int stop, int step, int n) {
// Raises TypeError (for immutable types).
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) || o.getType() == PyObject.TYPE) {
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) || o.getType() == PyObject.TYPE) {
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) || o.getType() == PyObject.TYPE) {
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) || o.getType() == PyObject.TYPE) {
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) || o.getType() == PyObject.TYPE) {
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) || o.getType() == PyObject.TYPE) {
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 sequences 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 index
such that it's ≥0 and ≤ __len__. If index
* 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;
}
/**
* Class defining the default behaviour of sequences with respect to slice assignment, etc.,
* which is the one correct for list
.
*/
protected class DefaultIndexDelegate extends 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);
}
};
}