All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.python.core.PySequence Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 2.7.4
Show newest version
// 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);
        }
    };
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy