// Copyright (c) Corporation for National Research Initiatives // Implementation of the standard Python list objects package org.python.core; import java.util.Vector; class ListFunctions extends PyBuiltinFunctionSet { ListFunctions(String name, int index, int argcount) { super(name, index, argcount, argcount, true, null); } ListFunctions(String name, int index, int minargs, int maxargs) { super(name, index, minargs, maxargs, true, null); } public PyObject __call__() { PyList list = (PyList)__self__; switch (index) { case 1: list.reverse(); return Py.None; case 2: list.sort(null); return Py.None; case 3: return new PyInteger(list.__len__()); default: throw argCountError(0); } } public PyObject __call__(PyObject arg) { PyList list = (PyList)__self__; switch (index) { case 2: list.sort(arg); return Py.None; case 10: list.append(arg); return Py.None; case 11: return new PyInteger(list.count(arg)); case 12: return new PyInteger(list.index(arg)); case 13: list.remove(arg); return Py.None; case 14: list.extend(arg); return Py.None; case 15: return list.__add__(arg); default: throw argCountError(1); } } public PyObject __call__(PyObject arg1, PyObject arg2) { PyList list = (PyList)__self__; switch (index) { case 20: if (!(arg1 instanceof PyInteger)) { throw Py.TypeError( "illegal argument type for built-in operation"); } int index = ((PyInteger)arg1).getValue(); list.insert(index, arg2); return Py.None; default: throw argCountError(2); } } } /** * A builtin python list. */ public class PyList extends PySequence implements ClassDictInit { protected PyObject[] list; protected int length; protected static PyObject __methods__; static { PyList list = new PyList(); String[] methods = { "append", "count", "extend", "index", "insert", "pop", "remove", "reverse", "sort"}; for (int i = 0; i < methods.length; i++) list.append(new PyString(methods[i])); __methods__ = list; } /** Internal use only. Do not call this method explicit. */ public static void classDictInit(PyObject dict) { PySequence.classDictInit(dict); dict.__setitem__("reverse", new ListFunctions("reverse", 1, 0)); dict.__setitem__("sort", new ListFunctions("sort", 2, 0, 1)); dict.__setitem__("__len__", new ListFunctions("__len__", 3, 0)); dict.__setitem__("append", new ListFunctions("append", 10, 1)); dict.__setitem__("count", new ListFunctions("count", 11, 1)); dict.__setitem__("index", new ListFunctions("index", 12, 1)); dict.__setitem__("remove", new ListFunctions("remove", 13, 1)); dict.__setitem__("extend", new ListFunctions("extend", 14, 1)); dict.__setitem__("__add__", new ListFunctions("__add__", 15, 1)); dict.__setitem__("insert", new ListFunctions("insert", 20, 2)); // hide these from Python! dict.__setitem__("initModule", null); dict.__setitem__("toString", null); dict.__setitem__("hashCode", null); } public PyList() { this(Py.EmptyObjects); } public PyList(Vector ilist) { this(new PyObject[ilist.size()]); for (int i=0; i 0 && stop < start) stop = start; int n = sliceLength(start, stop, step); PyObject[] newList = new PyObject[n]; if (step == 1) { System.arraycopy(list, start, newList, 0, stop-start); return new PyList(newList); } int j = 0; for (int i=start; j length || newLength < length) { resize(newLength); System.arraycopy(list, stop, list, stop+(newLength-length), length-stop); if (newLength < length) { for (i = newLength; i < length; i++) list[i] = null; } } // else if (newLength < length) { // System.arraycopy(list, stop, list, stop+(newLength-length), // length-stop); // this.length = newLength; // } PyObject[] otherList = null; if (value instanceof PyTuple) otherList = ((PyTuple)value).list; if (value instanceof PyList) { otherList = ((PyList)value).list; if (otherList == list) otherList = (PyObject[])otherList.clone(); } if (otherList != null) { System.arraycopy(otherList, 0, list, start, n); } else { for(i=0; i 0) buf.append(((PyObject)list[length-1]).__repr__().toString()); buf.append("]"); ts.exitRepr(this); return buf.toString(); } protected void resize(int n) { if (list.length < n) { PyObject[] newList = new PyObject[(int)(n*1.5)]; System.arraycopy(list, 0, newList, 0, length); list = newList; } length = n; } /** * Add a single element to the end of list. * * @param o the element to add. */ public void append(PyObject o) { resize(length+1); list[length-1] = o; } /** * Return the number elements in the list that equals the argument. * * @param o the argument to test for. Testing is done with * the == operator. */ public int count(PyObject o) { int count = 0; int n = length; PyObject[] list = this.list; for (int i=0; i== operator. */ public int index(PyObject o) { return _index(o, "list.index(x): x not in list"); } private int _index(PyObject o, String message) { int n = length; PyObject[] list = this.list; int i=0; for (; i * Same as s[index:index] = [o] if index >= 0. * * @param index the position where the element will be inserted. * @param o the element to insert. */ public void insert(int index, PyObject o) { if (index < 0) index = 0; if (index > length) index = length; resize(length+1); System.arraycopy(list, index, list, index+1, length-index-1); list[index] = o; } /** * Remove the first occurence of the argument from the list. * The elements arecompared with the == operator. *
* Same as del s[s.index(x)] * * @param o the element to search for and remove. */ public void remove(PyObject o) { del(_index(o, "list.remove(x): x not in list")); } /** * Reverses the items of s in place. * The reverse() methods modify the list in place for economy * of space when reversing a large list. It doesn't return the * reversed list to remind you of this side effect. */ public void reverse() { PyObject tmp; int n = length; PyObject[] list = this.list; int j = n-1; for (int i=0; in indexed element in the * list. * * @param n the index of the element to remove and return. */ public PyObject pop(int n) { if (length==0) { throw Py.IndexError("pop from empty list"); } if (n < 0) n += length; if (n < 0 || n >= length) throw Py.IndexError("pop index out of range"); PyObject v = list[n]; setslice(n, n+1, 1, Py.EmptyTuple); return v; } /** * Append the elements in the argument sequence to the end of the list. *
* Same as s[len(s):len(s)] = o. * * @param o the sequence of items to append to the list. */ public void extend(PyObject o) { setslice(length, length, 1, o); } public PyObject __iadd__(PyObject o) { extend(fastSequence(o, "argument to += must be a sequence")); return this; } /* Implementation is taken from Python 1.5 as written by Guido van * Rossum Port to Java is by Jim Hugunin. This function will almost * certainly go away with the builtin sorting provided by JDK 1.2 */ /* New quicksort implementation for arrays of object pointers. Thanks * to discussions with Tim Peters. */ /* Comparison function. Takes care of calling a user-supplied * comparison function (any callable Python object). Calls the * standard comparison function, cmpobject(), if the user-supplied * function is NULL. */ private static int docompare(PyObject x, PyObject y, PyObject compare, String cmpop) { if (compare == null) { /* NOTE: we rely on the fact here that the sorting algorithm only ever checks whether k<0, i.e., whether x= off) { PyObject q = array[j]; if (docompare(q, key, compare, "<=") <= 0) break; array[j+1] = q; array[j] = key; } } } /* MINSIZE is the smallest array we care to partition; smaller arrays * are sorted using a straight insertion sort (above). It must be at * least 2 for the quicksort implementation to work. Assuming that * comparisons are more expensive than everything else (and this is a * good assumption for Python), it should be 10, which is the cutoff * point: quicksort requires more comparisons than insertion sort for * smaller arrays. */ private static final int MINSIZE = 10; /* STACKSIZE is the size of our work stack. A rough estimate is that * this allows us to sort arrays of MINSIZE * 2**STACKSIZE, or large * enough. (Because of the way we push the biggest partition first, * the worst case occurs when all subarrays are always partitioned * exactly in two.) */ private static final int STACKSIZE = 64; /* Quicksort algorithm. If an exception occurred; in this * case we leave the array partly sorted but otherwise in good health * (i.e. no items have been removed or duplicated). */ private static void quicksort(PyObject[] array, int off, int size, PyObject compare) { PyObject tmp, pivot, left, right; int lo, hi, l, r; int top, k, n, n2; int[] lostack = new int[STACKSIZE]; int[] histack = new int[STACKSIZE]; /* Start out with the whole array on the work stack */ lostack[0] = off; histack[0] = off+size; top = 1; /* Repeat until the work stack is empty */ while (--top >= 0) { lo = lostack[top]; hi = histack[top]; /* If it's a small one, use straight insertion sort */ n = hi - lo; if (n < MINSIZE) { /* * skip it. The insertion sort at the end will catch these */ continue; } /* Choose median of first, middle and last item as pivot */ l = lo + (n>>1); /* Middle */ r = hi - 1; /* Last */ left = array[l]; right = array[lo]; if (docompare(left, right, compare, "<") < 0) { array[lo] = left; array[l] = right; } left = array[r]; right = array[l]; if (docompare(left, right, compare, "<") < 0) { array[r] = left; array[l] = right; } left = array[l]; right = array[lo]; if (docompare(left, right, compare, "<") < 0) { array[lo] = left; array[l] = right; } pivot = array[l]; /* Partition the array */ l = lo+1; r = hi-2; for (;;) { /* Move left index to element > pivot */ while (l < hi) { if (docompare(array[l], pivot, compare, "<") >= 0) break; l++; } /* Move right index to element < pivot */ while (r >= lo) { if (docompare(pivot, array[r], compare, "<") >= 0) break; r--; } /* If they met, we're through */ if (l < r) { /* Swap elements and continue */ tmp = array[l]; array[l] = array[r]; array[r] = tmp; l++; r--; } else if (l == r) { l++; r--; break; } if (l > r) break; } /* We have now reached the following conditions: lo <= r < l <= hi all x in [lo,r) are <= pivot all x in [r,l) are == pivot all x in [l,hi) are >= pivot The partitions are [lo,r) and [l,hi) */ /* Push biggest partition first */ n = r - lo; n2 = hi - l; if (n > n2) { /* First one is bigger */ if (n > MINSIZE) { lostack[top] = lo; histack[top++] = r; if (n2 > MINSIZE) { lostack[top] = l; histack[top++] = hi; } } } else { /* Second one is bigger */ if (n2 > MINSIZE) { lostack[top] = l; histack[top++] = hi; if (n > MINSIZE) { lostack[top] = lo; histack[top++] = r; } } } /* Should assert top < STACKSIZE-1 */ } /* Ouch - even if I screwed up the quicksort above, the * insertionsort below will cover up the problem - just a * performance hit would be noticable. */ /* insertionsort is pretty fast on the partially sorted list */ insertionsort(array, off, size, compare); } /** * Sort the items of the list in place. The compare argument is a * function of two arguments (list items) which should return * -1, 0 or 1 depending on whether the first argument is * considered smaller than, equal to, or larger than the second * argument. Note that this slows the sorting process down * considerably; e.g. to sort a list in reverse order it is much * faster to use calls to the methods sort() and reverse() than * to use the built-in function sort() with a comparison function * that reverses the ordering of the elements. * * @param compare the comparison function. */ public synchronized void sort(PyObject compare) { MergeState ms = new MergeState(list, length, compare); ms.sort(); } /** * Sort the items of the list in place. Items is compared with the * normal relative comparison operators. */ public void sort() { sort(null); } // __class__ boilerplate -- see PyObject for details public static PyClass __class__; protected PyClass getPyClass() { return __class__; } public int hashCode() { throw Py.TypeError("unhashable type"); } }