src.org.python.modules._collections.PyDeque Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-standalone Show documentation
Show all versions of jython-standalone 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.
package org.python.modules._collections;
import org.python.core.PyIterator;
import org.python.core.PyObject;
import org.python.core.PyTuple;
import org.python.core.PyType;
import org.python.core.Py;
import org.python.core.PyException;
import org.python.core.PyBuiltinCallable;
import org.python.core.ThreadState;
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedType;
import org.python.expose.MethodType;
/**
* PyDeque - This class implements the functionalities of Deque data structure. Deques are a
* generalization of stacks and queues (the name is pronounced 'deck' and is short for 'double-ended
* queue'). Deques support thread-safe, memory efficient appends and pops from either side of the
* deque with approximately the same O(1) performance in either direction.
*
* Though list objects support similar operations, they are optimized for fast fixed-length
* operations and incur O(n) memory movement costs for pop(0) and insert(0, v) operations which
* change both the size and position of the underlying data representation.
*
* collections.deque([iterable]) - returns a new deque object initialized left-to-right (using
* append()) with data from iterable. If iterable is not specified, the new deque is empty.
*/
@ExposedType(name = "collections.deque")
public class PyDeque extends PyObject {
public static final PyType TYPE = PyType.fromClass(PyDeque.class);
private int size = 0;
private Node header = new Node(null, null, null);
public PyDeque() {
this(TYPE);
}
public PyDeque(PyType subType) {
super(subType);
header.left = header.right = header;
}
@ExposedNew
@ExposedMethod
final void deque___init__(PyObject[] args, String[] kwds) {
if (kwds.length > 0) {
throw Py.TypeError("deque() does not take keyword arguments");
}
int nargs = args.length;
if (nargs > 1) {
throw PyBuiltinCallable.DefaultInfo.unexpectedCall(nargs, false, "deque", 0, 1);
}
if (nargs == 0) {
return;
}
deque_extend(args[0]);
}
/**
* Add obj to the right side of the deque.
*/
@ExposedMethod
final void deque_append(PyObject obj) {
addBefore(obj, header);
}
/**
* Add obj to the left side of the deque.
*/
@ExposedMethod
final void deque_appendleft(PyObject obj) {
addBefore(obj, header.right);
}
private Node addBefore(PyObject obj, Node node) {
Node newNode = new Node(obj, node, node.left);
newNode.left.right = newNode;
newNode.right.left = newNode;
size++;
return newNode;
}
/**
* Remove all elements from the deque leaving it with length 0.
*/
@ExposedMethod
final void deque_clear() {
Node node = header.right;
while (node != header) {
Node right = node.right;
node.left = null;
node.right = null;
node.data = null;
node = right;
}
header.right = header.left = header;
size = 0;
}
/**
* Extend the right side of the deque by appending elements from the
* iterable argument.
*/
@ExposedMethod
final void deque_extend(PyObject iterable) {
for (PyObject item : iterable.asIterable()) {
deque_append(item);
}
}
/**
* Extend the left side of the deque by appending elements from iterable.
* Note, the series of left appends results in reversing the order of
* elements in the iterable argument.
*/
@ExposedMethod
final void deque_extendleft(PyObject iterable) {
for (PyObject item : iterable.asIterable()) {
deque_appendleft(item);
}
}
/**
* Remove and return an element from the right side of the deque. If no
* elements are present, raises an IndexError.
*/
@ExposedMethod
final PyObject deque_pop() {
return removeNode(header.left);
}
/**
* Remove and return an element from the left side of the deque. If no
* elements are present, raises an IndexError.
*/
@ExposedMethod
final PyObject deque_popleft() {
return removeNode(header.right);
}
private PyObject removeNode(Node node) {
if (node == header) {
throw Py.IndexError("pop from an empty deque");
}
PyObject obj = node.data;
node.left.right = node.right;
node.right.left = node.left;
node.right = null;
node.left = null;
node.data = null;
size--;
return obj;
}
/**
* Removed the first occurrence of value. If not found, raises a
* ValueError.
*/
@ExposedMethod
final PyObject deque_remove(PyObject value) {
int n = size;
Node tmp = header.right;
boolean match = false;
for (int i = 0; i < n; i++) {
if (tmp.data.equals(value)) {
match = true;
}
if (n != size) {
throw Py.IndexError("deque mutated during remove().");
}
if (match) {
return removeNode(tmp);
}
tmp = tmp.right;
}
throw Py.ValueError("deque.remove(x): x not in deque");
}
/**
* Rotate the deque n steps to the right. If n is negative, rotate to the
* left. Rotating one step to the right is equivalent to: d.appendleft(d.pop()).
*/
@ExposedMethod(defaults = {"1"})
final void deque_rotate(int steps) {
if (size == 0) {
return;
}
int halfsize = (size + 1) >> 1;
if (steps > halfsize || steps < -halfsize) {
steps %= size;
if (steps > halfsize) {
steps -= size;
} else if (steps < -halfsize) {
steps += size;
}
}
//rotate right
for (int i = 0; i < steps; i++) {
deque_appendleft(deque_pop());
}
//rotate left
for (int i = 0; i > steps; i--) {
deque_append(deque_popleft());
}
}
public String toString() {
return deque_toString();
}
@ExposedMethod(names = "__repr__")
final String deque_toString() {
ThreadState ts = Py.getThreadState();
if (!ts.enterRepr(this)) {
return "[...]";
}
StringBuilder buf = new StringBuilder("deque").append("([");
for (Node tmp = header.right; tmp != header; tmp = tmp.right) {
buf.append(tmp.data.__repr__().toString());
if (tmp.right != header) {
buf.append(", ");
}
}
buf.append("])");
ts.exitRepr(this);
return buf.toString();
}
public int __len__() {
return deque___len__();
}
@ExposedMethod
final int deque___len__() {
return size;
}
public boolean __nonzero__() {
return deque___nonzero__();
}
@ExposedMethod
final boolean deque___nonzero__() {
return size != 0;
}
public PyObject __finditem__(PyObject key) {
try {
return deque___getitem__(key);
} catch (PyException pe) {
if (pe.match(Py.KeyError)) {
return null;
}
throw pe;
}
}
@ExposedMethod
final PyObject deque___getitem__(PyObject index) {
return getNode(index).data;
}
public void __setitem__(PyObject index, PyObject value) {
deque___setitem__(index, value);
}
@ExposedMethod
final void deque___setitem__(PyObject index, PyObject value) {
Node node = getNode(index).right;
removeNode(node.left);
addBefore(value, node);
}
public void __delitem__(PyObject key) {
deque___delitem__(key);
}
@ExposedMethod
final void deque___delitem__(PyObject key) {
removeNode(getNode(key));
}
private Node getNode(PyObject index) {
int pos = 0;
if (!index.isIndex()) {
throw Py.TypeError(String.format("sequence index must be integer, not '%.200s'",
index.getType().fastGetName()));
}
pos = index.asIndex(Py.IndexError);
if (pos < 0) {
pos += size;
}
if (pos < 0 || pos >= size) {
throw Py.IndexError("index out of range: " + index);
}
Node tmp = header;
if (pos < (size >> 1)) {
for (int i = 0; i <= pos; i++) {
tmp = tmp.right;
}
} else {
for (int i = size - 1; i >= pos; i--) {
tmp = tmp.left;
}
}
return tmp;
}
public PyObject __iter__() {
return deque___iter__();
}
@ExposedMethod
final PyObject deque___iter__() {
return new PyDequeIter();
}
public synchronized PyObject __eq__(PyObject o) {
return deque___eq__(o);
}
@ExposedMethod(type = MethodType.BINARY)
final synchronized PyObject deque___eq__(PyObject o) {
if (!(getType() == o.getType()) && !(getType().isSubType(o.getType()))) {
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;
}
public synchronized PyObject __ne__(PyObject o) {
return deque___ne__(o);
}
@ExposedMethod(type = MethodType.BINARY)
final synchronized PyObject deque___ne__(PyObject o) {
if (!(getType() == o.getType()) && !(getType().isSubType(o.getType()))) {
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;
}
public synchronized PyObject __lt__(PyObject o) {
return deque___lt__(o);
}
@ExposedMethod(type = MethodType.BINARY)
final synchronized PyObject deque___lt__(PyObject o) {
if (!(getType() == o.getType()) && !(getType().isSubType(o.getType()))) {
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));
}
public synchronized PyObject __le__(PyObject o) {
return deque___le__(o);
}
@ExposedMethod(type = MethodType.BINARY)
final synchronized PyObject deque___le__(PyObject o) {
if (!(getType() == o.getType()) && !(getType().isSubType(o.getType()))) {
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));
}
public synchronized PyObject __gt__(PyObject o) {
return deque___gt__(o);
}
@ExposedMethod(type = MethodType.BINARY)
final synchronized PyObject deque___gt__(PyObject o) {
if (!(getType() == o.getType()) && !(getType().isSubType(o.getType()))) {
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));
}
public synchronized PyObject __ge__(PyObject o) {
return deque___ge__(o);
}
@ExposedMethod(type = MethodType.BINARY)
final synchronized PyObject deque___ge__(PyObject o) {
if (!(getType() == o.getType()) && !(getType().isSubType(o.getType()))) {
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));
}
// 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;
}
public int hashCode() {
return deque_hashCode();
}
@ExposedMethod(names = "__hash__")
final int deque_hashCode() {
throw Py.TypeError("deque objects are unhashable");
}
public PyObject __reduce__() {
return deque___reduce__();
}
@ExposedMethod
final PyObject deque___reduce__() {
PyObject dict = getDict();
if (dict == null) {
dict = Py.None;
}
return new PyTuple(getType(), Py.EmptyTuple, dict, __iter__());
}
@ExposedMethod
final PyObject deque___copy__() {
PyDeque pd = (PyDeque)this.getType().__call__();
pd.deque_extend(this);
return pd;
}
@Override
public boolean isMappingType() {
return false;
}
@Override
public boolean isSequenceType() {
return true;
}
private static class Node {
private Node left;
private Node right;
private PyObject data;
Node(PyObject data, Node right, Node left) {
this.data = data;
this.right = right;
this.left = left;
}
}
private class PyDequeIter extends PyIterator {
private Node lastReturned = header;
private int itersize;
public PyDequeIter() {
itersize = size;
}
public PyObject __iternext__() {
if (itersize != size) {
throw Py.RuntimeError("deque changed size during iteration");
}
if (lastReturned.right != header) {
lastReturned = lastReturned.right;
return lastReturned.data;
}
return null;
}
}
}