diff --git a/jode/jode/util/AbstractCollection.java b/jode/jode/util/AbstractCollection.java new file mode 100644 index 0000000..2853ad5 --- /dev/null +++ b/jode/jode/util/AbstractCollection.java @@ -0,0 +1,337 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// AbstractCollection.java -- Abstract implementation of most of Collection +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +package jode.util; + +import java.lang.reflect.Array; + +/** + * A basic implementation of most of the methods in the Collection interface to + * make it easier to create a collection. To create an unmodifiable Collection, + * just subclass AbstractCollection and provide implementations of the + * iterator() and size() methods. The Iterator returned by iterator() need only + * provide implementations of hasNext() and next() (that is, it may throw an + * UnsupportedOperationException if remove() is called). To create a modifiable + * Collection, you must in addition provide an implementation of the + * add(Object) method and the Iterator returned by iterator() must provide an + * implementation of remove(). Other methods should be overridden if the + * backing data structure allows for a more efficient implementation. The + * precise implementation used by AbstractCollection is documented, so that + * subclasses can tell which methods could be implemented more efficiently. + */ +public abstract class AbstractCollection implements Collection { + + /** + * Return an Iterator over this collection. The iterator must provide the + * hasNext and next methods and should in addition provide remove if the + * collection is modifiable. + */ + public abstract Iterator iterator(); + + /** + * Return the number of elements in this collection. + */ + public abstract int size(); + + /** + * Add an object to the collection. This implementation always throws an + * UnsupportedOperationException - it should be overridden if the collection + * is to be modifiable. + * + * @param o the object to add + * @return true if the add operation caused the Collection to change + * @exception UnsupportedOperationException if the add operation is not + * supported on this collection + */ + public boolean add(Object o) { + throw new UnsupportedOperationException(); + } + + /** + * Add all the elements of a given collection to this collection. This + * implementation obtains an Iterator over the given collection and iterates + * over it, adding each element with the add(Object) method (thus this method + * will fail with an UnsupportedOperationException if the add method does). + * + * @param c the collection to add the elements of to this collection + * @return true if the add operation caused the Collection to change + * @exception UnsupportedOperationException if the add operation is not + * supported on this collection + */ + public boolean addAll(Collection c) { + Iterator i = c.iterator(); + boolean modified = false; + while (i.hasNext()) { + modified |= add(i.next()); + } + return modified; + } + + /** + * Remove all elements from the collection. This implementation obtains an + * iterator over the collection and calls next and remove on it repeatedly + * (thus this method will fail with an UnsupportedOperationException if the + * Iterator's remove method does) until there are no more elements to remove. + * Many implementations will have a faster way of doing this. + * + * @exception UnsupportedOperationException if the Iterator returned by + * iterator does not provide an implementation of remove + */ + public void clear() { + Iterator i = iterator(); + while (i.hasNext()) { + i.next(); + i.remove(); + } + } + + /** + * Test whether this collection contains a given object. That is, if the + * collection has an element e such that (o == null ? e == null : + * o.equals(e)). This implementation obtains an iterator over the collection + * and iterates over it, testing each element for equality with the given + * object. If it is equal, true is returned. Otherwise false is returned when + * the end of the collection is reached. + * + * @param o the object to remove from this collection + * @return true if this collection contains an object equal to o + */ + public boolean contains(Object o) { + Iterator i = iterator(); + + // This looks crazily inefficient, but it takes the test o==null outside + // the loop, saving time, and also saves needing to store the result of + // i.next() each time. + if (o == null) { + while (i.hasNext()) { + if (i.next() == null) { + return true; + } + } + } else { + while (i.hasNext()) { + if (o.equals(i.next())) { + return true; + } + } + } + return false; + } + + /** + * Tests whether this collection contains all the elements in a given + * collection. This implementation iterates over the given collection, + * testing whether each element is contained in this collection. If any one + * is not, false is returned. Otherwise true is returned. + * + * @param c the collection to test against + * @return true if this collection contains all the elements in the given + * collection + */ + public boolean containsAll(Collection c) { + Iterator i = c.iterator(); + while (i.hasNext()) { + if (!contains(i.next())) { + return false; + } + } + return true; + } + + /** + * Test whether this collection is empty. This implementation returns + * size() == 0. + * + * @return true if this collection is empty. + */ + public boolean isEmpty() { + return size() == 0; + } + + /** + * Remove a single instance of an object from this collection. That is, + * remove one element e such that (o == null ? e == null : o.equals(e)), if + * such an element exists. This implementation obtains an iterator over the + * collection and iterates over it, testing each element for equality with + * the given object. If it is equal, it is removed by the iterator's remove + * method (thus this method will fail with an UnsupportedOperationException + * if the Iterator's remove method does). After the first element has been + * removed, true is returned; if the end of the collection is reached, false + * is returned. + * + * @param o the object to remove from this collection + * @return true if the remove operation caused the Collection to change, or + * equivalently if the collection did contain o. + * @exception UnsupportedOperationException if this collection's Iterator + * does not support the remove method + */ + public boolean remove(Object o) { + Iterator i = iterator(); + + // This looks crazily inefficient, but it takes the test o==null outside + // the loop, saving time, and also saves needing to store the result of + // i.next() each time. + if (o == null) { + while (i.hasNext()) { + if (i.next() == null) { + i.remove(); + return true; + } + } + } else { + while (i.hasNext()) { + if (o.equals(i.next())) { + i.remove(); + return true; + } + } + } + return false; + } + + /** + * Remove from this collection all its elements that are contained in a given + * collection. This implementation iterates over this collection, and for + * each element tests if it is contained in the given collection. If so, it + * is removed by the Iterator's remove method (thus this method will fail + * with an UnsupportedOperationException if the Iterator's remove method + * does). + * + * @param c the collection to remove the elements of + * @return true if the remove operation caused the Collection to change + * @exception UnsupportedOperationException if this collection's Iterator + * does not support the remove method + */ + public boolean removeAll(Collection c) { + Iterator i = iterator(); + boolean changed = false; + while (i.hasNext()) { + if (c.contains(i.next())) { + i.remove(); + changed = true; + } + } + return changed; + } + + /** + * Remove from this collection all its elements that are not contained in a + * given collection. This implementation iterates over this collection, and + * for each element tests if it is contained in the given collection. If not, + * it is removed by the Iterator's remove method (thus this method will fail + * with an UnsupportedOperationException if the Iterator's remove method + * does). + * + * @param c the collection to retain the elements of + * @return true if the remove operation caused the Collection to change + * @exception UnsupportedOperationException if this collection's Iterator + * does not support the remove method + */ + public boolean retainAll(Collection c) { + Iterator i = iterator(); + boolean changed = false; + while (i.hasNext()) { + if (!c.contains(i.next())) { + i.remove(); + changed = true; + } + } + return changed; + } + + /** + * Return an array containing the elements of this collection. This + * implementation creates an Object array of size size() and then iterates + * over the collection, setting each element of the array from the value + * returned by the iterator. + * + * @return an array containing the elements of this collection + */ + public Object[] toArray() { + Object[] a = new Object[size()]; + Iterator i = iterator(); + for (int pos = 0; pos < a.length; pos++) { + a[pos] = i.next(); + } + return a; + } + + /** + * Copy the collection into a given array if it will fit, or into a + * dynamically created array of the same run-time type as the given array if + * not. If there is space remaining in the array, the first element after the + * end of the collection is set to null (this is only useful if the + * collection is known to contain no null elements, however). This + * implementation first tests whether the given array is large enough to hold + * all the elements of the collection. If not, the reflection API is used to + * allocate a new array of the same run-time type. Next an iterator is + * obtained over the collection and the elements are placed in the array as + * they are returned by the iterator. Finally the first spare element, if + * any, of the array is set to null, and the created array is returned. + * + * @param a the array to copy into, or of the correct run-time type + * @return the array that was produced + * @exception ClassCastException if the type of the array precludes holding + * one of the elements of the Collection + */ + public Object[] toArray(Object[] a) { + final int n = size(); + if (a.length < n) { + a = (Object[])Array.newInstance(a.getClass().getComponentType(), n); + } + Iterator i = iterator(); + for (int pos = 0; pos < n; pos++) { + a[pos] = i.next(); + } + if (a.length > n) { + a[n] = null; + } + return a; + } + + /** + * Creates a String representation of the Collection. The string returned is + * of the form "[a, b, ...]" where a and b etc are the results of calling + * toString on the elements of the collection. This implementation obtains an + * Iterator over the Collection and adds each element to a StringBuffer as it + * is returned by the iterator. + * + * @return a String representation of the Collection + */ + public String toString() { + StringBuffer s = new StringBuffer(); + s.append('['); + Iterator i = iterator(); + boolean more = i.hasNext(); + while(more) { + s.append(i.next()); + if (more = i.hasNext()) { + s.append(", "); + } + } + s.append(']'); + return s.toString(); + } +} diff --git a/jode/jode/util/AbstractList.java b/jode/jode/util/AbstractList.java new file mode 100644 index 0000000..54dd4fc --- /dev/null +++ b/jode/jode/util/AbstractList.java @@ -0,0 +1,551 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// AbstractList.java -- Abstract implementation of most of List +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Doc comments for almost everything. +// ~ Better general commenting + +package jode.util; +import java.util.NoSuchElementException; + +/** + * A basic implementation of most of the methods in the List interface to make + * it easier to create a List based on a random-access data structure. To + * create an unmodifiable list, it is only necessary to override the size() and + * get(int) methods (this contrasts with all other abstract collection classes + * which require an iterator to be provided). To make the list modifiable, the + * set(int, Object) method should also be overridden, and to make the list + * resizable, the add(int, Object) and remove(int) methods should be overridden + * too. Other methods should be overridden if the backing data structure allows + * for a more efficient implementation. The precise implementation used by + * AbstractList is documented, so that subclasses can tell which methods could + * be implemented more efficiently. + */ +public abstract class AbstractList extends AbstractCollection implements List { + + /** + * A count of the number of structural modifications that have been made to + * the list (that is, insertions and removals). + */ + protected transient int modCount = 0; + + public abstract Object get(int index); + + public void add(int index, Object o) { + throw new UnsupportedOperationException(); + } + + public boolean add(Object o) { + add(size(), o); + return true; + } + + public boolean addAll(int index, Collection c) { + Iterator i = c.iterator(); + if (i.hasNext()) { + do { + add(index++, i.next()); + } while (i.hasNext()); + return true; + } else { + return false; + } + } + + public void clear() { + removeRange(0, size()); + } + + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (!(o instanceof List)) { + return false; + } else { + Iterator i1 = iterator(); + Iterator i2 = ((List)o).iterator(); + while (i1.hasNext()) { + if (!i2.hasNext()) { + return false; + } else { + Object e = i1.next(); + if (e == null ? i2.next() != null : !e.equals(i2.next())) { + return false; + } + } + } + if (i2.hasNext()) { + return false; + } else { + return true; + } + } + } + + public int hashCode() { + int hashCode = 1; + Iterator i = iterator(); + while (i.hasNext()) { + Object obj = i.next(); + hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); + } + return hashCode; + } + + public int indexOf(Object o) { + int index = 0; + ListIterator i = listIterator(); + if (o == null) { + while (i.hasNext()) { + if (i.next() == null) { + return index; + } + index++; + } + } else { + while (i.hasNext()) { + if (o.equals(i.next())) { + return index; + } + index++; + } + } + return -1; + } + + public Iterator iterator() { + return new Iterator() { + private int knownMod = modCount; + private int position = 0; + boolean removed = true; + + private void checkMod() { + if (knownMod != modCount) { + throw new ConcurrentModificationException(); + } + } + + public boolean hasNext() { + checkMod(); + return position < size(); + } + + public Object next() { + checkMod(); + removed = false; + try { + return get(position++); + } catch (IndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + + public void remove() { + checkMod(); + if (removed) { + throw new IllegalStateException(); + } + AbstractList.this.remove(--position); + knownMod = modCount; + removed = true; + } + }; + } + + public int lastIndexOf(Object o) { + int index = size(); + ListIterator i = listIterator(index); + if (o == null) { + while (i.hasPrevious()) { + if (i.previous() == null) { + return index; + } + index--; + } + } else { + while (i.hasPrevious()) { + if (o.equals(i.previous())) { + return index; + } + index--; + } + } + return -1; + } + + public ListIterator listIterator() { + return listIterator(0); + } + + public ListIterator listIterator(final int index) { + + if (index < 0 || index > size()) { + throw new IndexOutOfBoundsException(); + } + + return new ListIterator() { + private int knownMod = modCount; + private int position = index; + private int lastReturned = -1; + + private void checkMod() { + if (knownMod != modCount) { + throw new ConcurrentModificationException(); + } + } + + public boolean hasNext() { + checkMod(); + return position < size(); + } + + public boolean hasPrevious() { + checkMod(); + return position > 0; + } + + public Object next() { + checkMod(); + if (hasNext()) { + lastReturned = position++; + return get(lastReturned); + } else { + throw new NoSuchElementException(); + } + } + + public Object previous() { + checkMod(); + if (hasPrevious()) { + lastReturned = --position; + return get(lastReturned); + } else { + throw new NoSuchElementException(); + } + } + + public int nextIndex() { + checkMod(); + return position; + } + + public int previousIndex() { + checkMod(); + return position - 1; + } + + public void remove() { + checkMod(); + if (lastReturned < 0) { + throw new IllegalStateException(); + } + AbstractList.this.remove(lastReturned); + knownMod = modCount; + position = lastReturned; + lastReturned = -1; + } + + public void set(Object o) { + checkMod(); + if (lastReturned < 0) { + throw new IllegalStateException(); + } + AbstractList.this.set(lastReturned, o); + } + + public void add(Object o) { + checkMod(); + AbstractList.this.add(position++, o); + lastReturned = -1; + knownMod = modCount; + } + }; + } + + public Object remove(int index) { + throw new UnsupportedOperationException(); + } + + /** + * Remove a subsection of the list. This is called by the clear and + * removeRange methods of the class which implements subList, which are + * difficult for subclasses to override directly. Therefore, this method + * should be overridden instead by the more efficient implementation, if one + * exists. + *

+ * This implementation first checks for illegal or out of range arguments. It + * then obtains a ListIterator over the list using listIterator(fromIndex). + * It then calls next() and remove() on this iterator repeatedly, toIndex - + * fromIndex times. + * + * @param fromIndex the index, inclusive, to remove from. + * @param toIndex the index, exclusive, to remove to. + * @exception UnsupportedOperationException if this list does not support + * the removeRange operation. + * @exception IndexOutOfBoundsException if fromIndex > toIndex || fromIndex < + * 0 || toIndex > size(). + */ + protected void removeRange(int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException(); + } else if (fromIndex < 0 || toIndex > size()) { + throw new IndexOutOfBoundsException(); + } else { + ListIterator i = listIterator(fromIndex); + for (int index = fromIndex; index < toIndex; index++) { + i.next(); + i.remove(); + } + } + } + + public Object set(int index, Object o) { + throw new UnsupportedOperationException(); + } + + public List subList(final int fromIndex, final int toIndex) { + + // Note that within this class two fields called modCount are inherited - + // one from the superclass, and one from the outer class. These are + // explicitly disambiguated in the code by referring to "this.modCount" + // and "AbstractList.this.modCount". + // The code uses both these two fields and *no other* to provide fail-fast + // behaviour. For correct operation, the two fields should contain equal + // values. Therefore, if this.modCount != AbstractList.this.modCount, there + // has been a concurrent modification. This is all achieved purely by using + // the modCount field, precisely according to the docs of AbstractList. + // See the methods upMod and checkMod. + + return new AbstractList() { + + private final int offset = fromIndex; + private int size = toIndex - fromIndex; + + { // This is an instance initializer, called whenever this anonymous + // class is instantiated. + upMod(); + } + + /** + * This method checks the two modCount fields to ensure that there has + * not been a concurrent modification. It throws an exception if there + * has been, and otherwise returns normally. + * Note that since this method is private, it will be inlined. + * + * @exception ConcurrentModificationException if there has been a + * concurrent modification. + */ + private void checkMod() { + if (this.modCount != AbstractList.this.modCount) { + throw new ConcurrentModificationException(); + } + } + + /** + * This method is called after every method that causes a structural + * modification to the backing list. It updates the local modCount field + * to match that of the backing list. + * Note that since this method is private, it will be inlined. + */ + private void upMod() { + this.modCount = AbstractList.this.modCount; + } + + /** + * This method checks that a value is between 0 and size (inclusive). If + * it is not, an exception is thrown. + * Note that since this method is private, it will be inlined. + * + * @exception IndexOutOfBoundsException if the value is out of range. + */ + private void checkBoundsInclusive(int index) { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(); + } + } + + /** + * This method checks that a value is between 0 (inclusive) and size + * (exclusive). If it is not, an exception is thrown. + * Note that since this method is private, it will be inlined. + * + * @exception IndexOutOfBoundsException if the value is out of range. + */ + private void checkBoundsExclusive(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(); + } + } + + public int size() { + checkMod(); + return size; + } + + public Iterator iterator() { + return listIterator(); + } + + public ListIterator listIterator(final int index) { + + checkMod(); + checkBoundsInclusive(index); + + return new ListIterator() { + ListIterator i = AbstractList.this.listIterator(index + offset); + int position = index; + + public boolean hasNext() { + checkMod(); + return position < size; + } + + public boolean hasPrevious() { + checkMod(); + return position > 0; + } + + public Object next() { + if (position < size) { + Object o = i.next(); + position++; + return o; + } else { + throw new NoSuchElementException(); + } + } + + public Object previous() { + if (position > 0) { + Object o = i.previous(); + position--; + return o; + } else { + throw new NoSuchElementException(); + } + } + + public int nextIndex() { + return offset + i.nextIndex(); + } + + public int previousIndex() { + return offset + i.previousIndex(); + } + + public void remove() { + i.remove(); + upMod(); + size--; + position = nextIndex(); + } + + public void set(Object o) { + i.set(o); + } + + public void add(Object o) { + i.add(o); + upMod(); + size++; + position++; + } + + // Here is the reason why the various modCount fields are mostly + // ignored in this wrapper listIterator. + // IF the backing listIterator is failfast, then the following holds: + // Using any other method on this list will call a corresponding + // method on the backing list *after* the backing listIterator + // is created, which will in turn cause a ConcurrentModException + // when this listIterator comes to use the backing one. So it is + // implicitly failfast. + // If the backing listIterator is NOT failfast, then the whole of + // this list isn't failfast, because the modCount field of the + // backing list is not valid. It would still be *possible* to + // make the iterator failfast wrt modifications of the sublist + // only, but somewhat pointless when the list can be changed under + // us. + // Either way, no explicit handling of modCount is needed. + // However upMod() must be called in add and remove, and size + // must also be updated in these two methods, since they do not go + // through the corresponding methods of the subList. + + }; + } + + public Object set(int index, Object o) { + checkMod(); + checkBoundsExclusive(index); + o = AbstractList.this.set(index + offset, o); + upMod(); + return o; + } + + public Object get(int index) { + checkMod(); + checkBoundsExclusive(index); + return AbstractList.this.get(index + offset); + } + + public void add(int index, Object o) { + checkMod(); + checkBoundsInclusive(index); + AbstractList.this.add(index + offset, o); + upMod(); + size++; + } + + public Object remove(int index) { + checkMod(); + checkBoundsExclusive(index); + Object o = AbstractList.this.remove(index + offset); + upMod(); + size--; + return o; + } + + public void removeRange(int fromIndex2, int toIndex2) { + checkMod(); + checkBoundsExclusive(fromIndex2); + checkBoundsInclusive(toIndex2); + + // this call will catch the toIndex2 < fromIndex2 condition + AbstractList.this.removeRange(offset + fromIndex2, offset + toIndex2); + upMod(); + size -= toIndex2 - fromIndex2; + } + + public boolean addAll(int index, Collection c) { + checkMod(); + checkBoundsInclusive(index); + int s = AbstractList.this.size(); + boolean result = AbstractList.this.addAll(offset + index, c); + upMod(); + size += AbstractList.this.size() - s; + return result; + } + }; + } +} diff --git a/jode/jode/util/AbstractMap.java b/jode/jode/util/AbstractMap.java new file mode 100644 index 0000000..fd57b75 --- /dev/null +++ b/jode/jode/util/AbstractMap.java @@ -0,0 +1,280 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// AbstractMap.java -- Abstract implementation of most of Map +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com), +// Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// comments +// test suite + +package jode.util; + +public abstract class AbstractMap implements Map { + + public void clear() + { + entrySet().clear(); + } + + public boolean containsKey( Object key ) + { + Object k; + Iterator entries = entrySet().iterator(); + + while( entries.hasNext() ) + { + k = ((Map.Entry)entries.next()).getKey(); + if( key == null ? k == null : key.equals( k ) ) + return true; + } + + return false; + } + + public boolean containsValue( Object value ) + { + Object v; + Iterator entries = entrySet().iterator(); + + while( entries.hasNext() ) + { + v = ((Map.Entry)entries.next()).getValue(); + if( value == null ? v == null : value.equals( v ) ) + return true; + } + + return false; + } + + public abstract Set entrySet(); + + public boolean equals( Object o ) + { + if( this == o ) + return true; + + if( o == null || !( o instanceof Map ) ) + return false; + + Map m = (Map)o; + if( m.size() != size() ) + return false; + + Object key, value1, value2; + Map.Entry entry; + Iterator entries = entrySet().iterator(); + while( entries.hasNext() ) + { + entry = (Map.Entry)entries.next(); + key = entry.getKey(); + value1 = entry.getValue(); + value2 = m.get( key ); + + if( !( ( value1 == null && value2 == null ) + || value1.equals( value2 ) ) ) + return false; + } + + return true; + } + + public Object get( Object key ) + { + Object k; + Map.Entry entry; + Iterator entries = entrySet().iterator(); + + while( entries.hasNext() ) + { + entry = (Map.Entry)entries.next(); + k = entry.getKey(); + if( key == null ? k == null : key.equals( k ) ) + return entry.getValue(); + } + + return null; + } + + public int hashCode() + { + int hashcode = 0; + Iterator entries = entrySet().iterator(); + + while( entries.hasNext() ) + hashcode += entries.next().hashCode(); + + return hashcode; + } + + public boolean isEmpty() + { + return size() == 0; + } + + public Set keySet() + { + if( this.keySet == null ) + { + this.keySet = + new AbstractSet() + { + public int size() + { + return AbstractMap.this.size(); + } + + public boolean contains(Object key) + { + return AbstractMap.this.containsKey(key); + } + + public Iterator iterator() + { + return new Iterator() + { + Iterator map_iterator = AbstractMap.this.entrySet().iterator(); + + public boolean hasNext() + { + return map_iterator.hasNext(); + } + + public Object next() + { + return ((Map.Entry)map_iterator.next()).getKey(); + } + + public void remove() + { + map_iterator.remove(); + } + }; + } + }; + } + + return this.keySet; + } + + public Object put( Object key, Object value ) + { + throw new UnsupportedOperationException(); + } + + public void putAll( Map m ) + { + Map.Entry entry; + Iterator entries = m.entrySet().iterator(); + while( entries.hasNext() ) + { + entry = (Map.Entry)entries.next(); + put( entry.getKey(), entry.getValue() ); + } + } + + public Object remove( Object key ) + { + Object k, value; + Map.Entry entry; + Iterator entries = entrySet().iterator(); + + while( entries.hasNext() ) + { + entry = (Map.Entry)entries.next(); + k = entry.getKey(); + if( key == null ? k == null : key.equals( k ) ) + { + value = entry.getValue(); + entries.remove(); + return value; + } + } + + return null; + } + + public int size() + { + return entrySet().size(); + } + + public String toString() + { + Map.Entry entry; + String rep = "AbstractMap< "; + Iterator entries = entrySet().iterator(); + + while( entries.hasNext() ) + { + entry = (Map.Entry)entries.next(); + rep += entry.getKey() + " -> " + entry.getValue() + ", "; + } + + return rep.substring( 0, rep.length() - 2 ) + " >"; + } + + public Collection values() + { + if( this.valueCollection == null ) + { + this.valueCollection = + new AbstractCollection() + { + public int size() + { + return AbstractMap.this.size(); + } + + public Iterator iterator() + { + return new Iterator() + { + Iterator map_iterator = AbstractMap.this.entrySet().iterator(); + + public boolean hasNext() + { + return map_iterator.hasNext(); + } + + public Object next() + { + return ((Map.Entry)map_iterator.next()).getValue(); + } + + public void remove() + { + map_iterator.remove(); + } + }; + } + }; + } + + return this.valueCollection; + } + + + private Collection valueCollection = null; + private Set keySet = null; +} diff --git a/jode/jode/util/AbstractSequentialList.java b/jode/jode/util/AbstractSequentialList.java new file mode 100644 index 0000000..03aa06e --- /dev/null +++ b/jode/jode/util/AbstractSequentialList.java @@ -0,0 +1,111 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// AbstractSequentialList.java -- List implementation for sequential access +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Lots of doc comments still missing. +// ~ The class comment should include a description of what should be overridden +// to provide what features, as should the listIterator comment. + +package jode.util; + +/** + * Abstract superclass to make it easier to implement the List interface when + * backed by a sequential-access store, such as a linked list. + */ +public abstract class AbstractSequentialList extends AbstractList { + + /** + * Returns a ListIterator over the list, starting from position index. + * Subclasses must provide an implementation of this method. + * + * @exception IndexOutOfBoundsException if index < 0 || index > size() + */ + public abstract ListIterator listIterator(int index); + + /** + * Add an element to the list at a given index. This implementation obtains a + * ListIterator positioned at the specified index, and then adds the element + * using the ListIterator's add method. + * + * @param index the position to add the element + * @param o the element to insert + * @exception IndexOutOfBoundsException if index < 0 || index > size() + * @exception UnsupportedOperationException if the iterator returned by + * listIterator(index) does not support the add method. + */ + public void add(int index, Object o) { + ListIterator i = listIterator(index); + i.add(o); + } + + public boolean addAll(int index, Collection c) { + boolean changed = false; + Iterator ci = c.iterator(); + ListIterator i = listIterator(index); + while (ci.hasNext()) { + i.add(ci.next()); + changed = true; + } + return changed; + } + + public Object get(int index) { + ListIterator i = listIterator(index); + if (!i.hasNext()) { + throw new IndexOutOfBoundsException(); + } + return i.next(); + } + + /** + * Return an Iterator over this List. This implementation returns + * listIterator(). + * + * @return an Iterator over this List + */ + public Iterator iterator() { + return listIterator(); + } + + public Object remove(int index) { + ListIterator i = listIterator(index); + if (!i.hasNext()) { + throw new IndexOutOfBoundsException(); + } + Object removed = i.next(); + i.remove(); + return removed; + } + + public Object set(int index, Object o) { + ListIterator i = listIterator(index); + if (!i.hasNext()) { + throw new IndexOutOfBoundsException(); + } + Object old = i.next(); + i.set(o); + return old; + } +} diff --git a/jode/jode/util/AbstractSet.java b/jode/jode/util/AbstractSet.java new file mode 100644 index 0000000..cc99633 --- /dev/null +++ b/jode/jode/util/AbstractSet.java @@ -0,0 +1,78 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// AbstractSet.java -- Abstract implementation of most of Set +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +package jode.util; + +/** + * An abstract implementation of Set to make it easier to create your own + * implementations. In order to create a Set, subclass AbstractSet and + * implement the same methods that are required for AbstractCollection + * (although these methods must of course meet the requirements that Set puts + * on them - specifically, no element may be in the set more than once). This + * class simply provides implementations of equals() and hashCode() to fulfil + * the requirements placed on them by the Set interface. + */ +public abstract class AbstractSet extends AbstractCollection implements Set { + + /** + * Tests whether the given object is equal to this Set. This implementation + * first checks whether this set is the given object, and returns + * true if so. Otherwise, if o is a Set and is the same size as this one, it + * returns the result of calling containsAll on the given Set. Otherwise, it + * returns false. + * + * @param o the Object to be tested for equality with this Set + * @return true if the given object is equal to this Set + */ + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof Set && ((Set)o).size() == size()) { + return containsAll((Collection)o); + } else { + return false; + } + } + + /** + * Returns a hash code for this Set. The hash code of a Set is the sum of the + * hash codes of all its elements, except that the hash code of null is + * defined to be zero. This implementation obtains an Iterator over the Set, + * and sums the results. + * + * @return a hash code for this Set + */ + public int hashCode() { + int hash = 0; + Iterator i = iterator(); + while (i.hasNext()) { + try { + hash += i.next().hashCode(); + } catch (NullPointerException e) { + } + } + return hash; + } +} diff --git a/jode/jode/util/Arrays.java b/jode/jode/util/Arrays.java new file mode 100644 index 0000000..1949ac9 --- /dev/null +++ b/jode/jode/util/Arrays.java @@ -0,0 +1,1685 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// Arrays.java -- Utility class with methods to operate on arrays +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Fix the behaviour of sort and binarySearch as applied to float and double +// arrays containing NaN values. See the JDC, bug ID 4143272. + +package jode.util; + +/** + * This class contains various static utility methods performing operations on + * arrays, and a method to provide a List "view" of an array to facilitate + * using arrays with Collection-based APIs. + */ +public class Arrays { + + /** + * This class is non-instantiable. + */ + private Arrays() { + } + + /** + * Perform a binary search of a byte array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(byte[] a, byte key) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final byte d = a[mid]; + if (d == key) { + return mid; + } else if (d > key) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Perform a binary search of a char array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(char[] a, char key) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final char d = a[mid]; + if (d == key) { + return mid; + } else if (d > key) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Perform a binary search of a double array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(double[] a, double key) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final double d = a[mid]; + if (d == key) { + return mid; + } else if (d > key) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Perform a binary search of a float array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(float[] a, float key) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final float d = a[mid]; + if (d == key) { + return mid; + } else if (d > key) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Perform a binary search of an int array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(int[] a, int key) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final int d = a[mid]; + if (d == key) { + return mid; + } else if (d > key) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Perform a binary search of a long array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(long[] a, long key) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final long d = a[mid]; + if (d == key) { + return mid; + } else if (d > key) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Perform a binary search of a short array for a key. The array must be + * sorted (as by the sort() method) - if it is not, the behaviour of this + * method is undefined, and may be an infinite loop. If the array contains + * the key more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(short[] a, short key) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final short d = a[mid]; + if (d == key) { + return mid; + } else if (d > key) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Compare two objects with or without a Comparator. If c is null, uses the + * natural ordering. Slightly slower than doing it inline if the JVM isn't + * clever, but worth it for removing a duplicate of the sort and search code. + * Note: This same code is used in Collections + */ + private static int compare(Object o1, Object o2, Comparator c) { + if (c == null) { + return ((Comparable)o1).compareTo(o2); + } else { + return c.compare(o1, o2); + } + } + + /** + * This method does the work for the Object binary search methods. If the + * specified comparator is null, uses the natural ordering. + */ + private static int objectSearch(Object[] a, Object key, final Comparator c) { + int low = 0; + int hi = a.length - 1; + int mid = 0; + while (low <= hi) { + mid = (low + hi) >> 1; + final int d = compare(key, a[mid], c); + if (d == 0) { + return mid; + } else if (d < 0) { + hi = mid - 1; + } else { + low = ++mid; // This gets the insertion point right on the last loop + } + } + return -mid - 1; + } + + /** + * Perform a binary search of an Object array for a key, using the natural + * ordering of the elements. The array must be sorted (as by the sort() + * method) - if it is not, the behaviour of this method is undefined, and may + * be an infinite loop. Further, the key must be comparable with every item + * in the array. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this (JCL) + * implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @exception ClassCastException if key could not be compared with one of the + * elements of a + * @exception NullPointerException if a null element has compareTo called + */ + public static int binarySearch(Object[] a, Object key) { + return objectSearch(a, key, null); + } + + /** + * Perform a binary search of an Object array for a key, using a supplied + * Comparator. The array must be sorted (as by the sort() method with the + * same Comparator) - if it is not, the behaviour of this method is + * undefined, and may be an infinite loop. Further, the key must be + * comparable with every item in the array. If the array contains the key + * more than once, any one of them may be found. Note: although the + * specification allows for an infinite loop if the array is unsorted, it + * will not happen in this (JCL) implementation. + * + * @param a the array to search (must be sorted) + * @param key the value to search for + * @param c the comparator by which the array is sorted + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @exception ClassCastException if key could not be compared with one of the + * elements of a + */ + public static int binarySearch(Object[] a, Object key, Comparator c) { + if (c == null) { + throw new NullPointerException(); + } + return objectSearch(a, key, c); + } + + /** + * Compare two byte arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(byte[] a1, byte[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two char arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(char[] a1, char[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two double arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(double[] a1, double[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two float arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(float[] a1, float[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two long arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(long[] a1, long[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two short arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(short[] a1, short[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two boolean arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(boolean[] a1, boolean[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two int arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a2 is of the same length + * as a1, and for each 0 <= i < a1.length, a1[i] == a2[i] + */ + public static boolean equals(int[] a1, int[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Compare two Object arrays for equality. + * + * @param a1 the first array to compare + * @param a2 the second array to compare + * @returns true if a1 and a2 are both null, or if a1 is of the same length + * as a2, and for each 0 <= i < a.length, a1[i] == null ? a2[i] == null : + * a1[i].equals(a2[i]). + */ + public static boolean equals(Object[] a1, Object[] a2) { + + // Quick test which saves comparing elements of the same array, and also + // catches the case that both are null. + if (a1 == a2) { + return true; + } + try { + + // If they're the same length, test each element + if (a1.length == a2.length) { + for (int i = 0; i < a1.length; i++) { + if (!(a1[i] == null ? a2[i] == null : a1[i].equals(a2[i]))) { + return false; + } + } + return true; + } + + // If a1 == null or a2 == null but not both then we will get a NullPointer + } catch (NullPointerException e) { + } + + return false; + } + + /** + * Fill an array with a boolean value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(boolean[] a, boolean val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a boolean value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(boolean[] a, int fromIndex, int toIndex, + boolean val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with a byte value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(byte[] a, byte val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a byte value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(byte[] a, int fromIndex, int toIndex, byte val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with a char value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(char[] a, char val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a char value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(char[] a, int fromIndex, int toIndex, char val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with a double value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(double[] a, double val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a double value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(double[] a, int fromIndex, int toIndex, double val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with a float value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(float[] a, float val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a float value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(float[] a, int fromIndex, int toIndex, float val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with an int value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(int[] a, int val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with an int value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(int[] a, int fromIndex, int toIndex, int val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with a long value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(long[] a, long val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a long value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(long[] a, int fromIndex, int toIndex, long val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with a short value. + * + * @param a the array to fill + * @param val the value to fill it with + */ + public static void fill(short[] a, short val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with a short value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + */ + public static void fill(short[] a, int fromIndex, int toIndex, short val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + /** + * Fill an array with an Object value. + * + * @param a the array to fill + * @param val the value to fill it with + * @exception ClassCastException if val is not an instance of the element + * type of a. + */ + public static void fill(Object[] a, Object val) { + // This implementation is slightly inefficient timewise, but the extra + // effort over inlining it is O(1) and small, and I refuse to repeat code + // if it can be helped. + fill(a, 0, a.length, val); + } + + /** + * Fill a range of an array with an Object value. + * + * @param a the array to fill + * @param fromIndex the index to fill from, inclusive + * @param toIndex the index to fill to, exclusive + * @param val the value to fill with + * @exception ClassCastException if val is not an instance of the element + * type of a. + */ + public static void fill(Object[] a, int fromIndex, int toIndex, Object val) { + for (int i = fromIndex; i < toIndex; i++) { + a[i] = val; + } + } + + // Thanks to Paul Fisher for finding this quicksort algorithm + // as specified by Sun and porting it to Java. + + /** + * Sort a byte array into ascending order. The sort algorithm is an optimised + * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's + * "Engineering a Sort Function", Software-Practice and Experience, Vol. + * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n) + * performance on many arrays that would take quadratic time with a standard + * quicksort. + * + * @param a the array to sort + */ + public static void sort(byte[] a) { + qsort(a, 0, a.length); + } + + private static short cmp(byte i, byte j) { + return (short)(i-j); + } + + private static int med3(int a, int b, int c, byte[] d) { + return cmp(d[a], d[b]) < 0 ? + (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a) + : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a); + } + + private static void swap(int i, int j, byte[] a) { + byte c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + private static void qsort(byte[] a, int start, int n) { + // use an insertion sort on small arrays + if (n < 7) { + for (int i = start + 1; i < start + n; i++) + for (int j = i; j > 0 && cmp(a[j-1], a[j]) > 0; j--) + swap(j, j-1, a); + return; + } + + int pm = n/2; // small arrays, middle element + if (n > 7) { + int pl = start; + int pn = start + n-1; + + if (n > 40) { // big arrays, pseudomedian of 9 + int s = n/8; + pl = med3(pl, pl+s, pl+2*s, a); + pm = med3(pm-s, pm, pm+s, a); + pn = med3(pn-2*s, pn-s, pn, a); + } + pm = med3(pl, pm, pn, a); // mid-size, med of 3 + } + + int pa, pb, pc, pd, pv; + short r; + + pv = start; swap(pv, pm, a); + pa = pb = start; + pc = pd = start + n-1; + + for (;;) { + while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0) { + if (r == 0) { swap(pa, pb, a); pa++; } + pb++; + } + while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0) { + if (r == 0) { swap(pc, pd, a); pd--; } + pc--; + } + if (pb > pc) break; + swap(pb, pc, a); + pb++; + pc--; + } + int pn = start + n; + int s; + s = Math.min(pa-start, pb-pa); vecswap(start, pb-s, s, a); + s = Math.min(pd-pc, pn-pd-1); vecswap(pb, pn-s, s, a); + if ((s = pb-pa) > 1) qsort(a, start, s); + if ((s = pd-pc) > 1) qsort(a, pn-s, s); + } + + private static void vecswap(int i, int j, int n, byte[] a) { + for (; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Sort a char array into ascending order. The sort algorithm is an optimised + * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's + * "Engineering a Sort Function", Software-Practice and Experience, Vol. + * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n) + * performance on many arrays that would take quadratic time with a standard + * quicksort. + * + * @param a the array to sort + */ + public static void sort(char[] a) { + qsort(a, 0, a.length); + } + + private static int cmp(char i, char j) { + return i-j; + } + + private static int med3(int a, int b, int c, char[] d) { + return cmp(d[a], d[b]) < 0 ? + (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a) + : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a); + } + + private static void swap(int i, int j, char[] a) { + char c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + private static void qsort(char[] a, int start, int n) { + // use an insertion sort on small arrays + if (n < 7) { + for (int i = start + 1; i < start + n; i++) + for (int j = i; j > 0 && cmp(a[j-1], a[j]) > 0; j--) + swap(j, j-1, a); + return; + } + + int pm = n/2; // small arrays, middle element + if (n > 7) { + int pl = start; + int pn = start + n-1; + + if (n > 40) { // big arrays, pseudomedian of 9 + int s = n/8; + pl = med3(pl, pl+s, pl+2*s, a); + pm = med3(pm-s, pm, pm+s, a); + pn = med3(pn-2*s, pn-s, pn, a); + } + pm = med3(pl, pm, pn, a); // mid-size, med of 3 + } + + int pa, pb, pc, pd, pv; + int r; + + pv = start; swap(pv, pm, a); + pa = pb = start; + pc = pd = start + n-1; + + for (;;) { + while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0) { + if (r == 0) { swap(pa, pb, a); pa++; } + pb++; + } + while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0) { + if (r == 0) { swap(pc, pd, a); pd--; } + pc--; + } + if (pb > pc) break; + swap(pb, pc, a); + pb++; + pc--; + } + int pn = start + n; + int s; + s = Math.min(pa-start, pb-pa); vecswap(start, pb-s, s, a); + s = Math.min(pd-pc, pn-pd-1); vecswap(pb, pn-s, s, a); + if ((s = pb-pa) > 1) qsort(a, start, s); + if ((s = pd-pc) > 1) qsort(a, pn-s, s); + } + + private static void vecswap(int i, int j, int n, char[] a) { + for (; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Sort a double array into ascending order. The sort algorithm is an + * optimised quicksort, as described in Jon L. Bentley and M. Douglas + * McIlroy's "Engineering a Sort Function", Software-Practice and Experience, + * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n) + * performance on many arrays that would take quadratic time with a standard + * quicksort. Note that this implementation, like Sun's, has undefined + * behaviour if the array contains any NaN values. + * + * @param a the array to sort + */ + public static void sort(double[] a) { + qsort(a, 0, a.length); + } + + private static double cmp(double i, double j) { + return i-j; + } + + private static int med3(int a, int b, int c, double[] d) { + return cmp(d[a], d[b]) < 0 ? + (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a) + : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a); + } + + private static void swap(int i, int j, double[] a) { + double c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + private static void qsort(double[] a, int start, int n) { + // use an insertion sort on small arrays + if (n < 7) { + for (int i = start + 1; i < start + n; i++) + for (int j = i; j > 0 && cmp(a[j-1], a[j]) > 0; j--) + swap(j, j-1, a); + return; + } + + int pm = n/2; // small arrays, middle element + if (n > 7) { + int pl = start; + int pn = start + n-1; + + if (n > 40) { // big arrays, pseudomedian of 9 + int s = n/8; + pl = med3(pl, pl+s, pl+2*s, a); + pm = med3(pm-s, pm, pm+s, a); + pn = med3(pn-2*s, pn-s, pn, a); + } + pm = med3(pl, pm, pn, a); // mid-size, med of 3 + } + + int pa, pb, pc, pd, pv; + double r; + + pv = start; swap(pv, pm, a); + pa = pb = start; + pc = pd = start + n-1; + + for (;;) { + while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0) { + if (r == 0) { swap(pa, pb, a); pa++; } + pb++; + } + while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0) { + if (r == 0) { swap(pc, pd, a); pd--; } + pc--; + } + if (pb > pc) break; + swap(pb, pc, a); + pb++; + pc--; + } + int pn = start + n; + int s; + s = Math.min(pa-start, pb-pa); vecswap(start, pb-s, s, a); + s = Math.min(pd-pc, pn-pd-1); vecswap(pb, pn-s, s, a); + if ((s = pb-pa) > 1) qsort(a, start, s); + if ((s = pd-pc) > 1) qsort(a, pn-s, s); + } + + private static void vecswap(int i, int j, int n, double[] a) { + for (; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Sort a float array into ascending order. The sort algorithm is an + * optimised quicksort, as described in Jon L. Bentley and M. Douglas + * McIlroy's "Engineering a Sort Function", Software-Practice and Experience, + * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n) + * performance on many arrays that would take quadratic time with a standard + * quicksort. Note that this implementation, like Sun's, has undefined + * behaviour if the array contains any NaN values. + * + * @param a the array to sort + */ + public static void sort(float[] a) { + qsort(a, 0, a.length); + } + + private static float cmp(float i, float j) { + return i-j; + } + + private static int med3(int a, int b, int c, float[] d) { + return cmp(d[a], d[b]) < 0 ? + (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a) + : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a); + } + + private static void swap(int i, int j, float[] a) { + float c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + private static void qsort(float[] a, int start, int n) { + // use an insertion sort on small arrays + if (n < 7) { + for (int i = start + 1; i < start + n; i++) + for (int j = i; j > 0 && cmp(a[j-1], a[j]) > 0; j--) + swap(j, j-1, a); + return; + } + + int pm = n/2; // small arrays, middle element + if (n > 7) { + int pl = start; + int pn = start + n-1; + + if (n > 40) { // big arrays, pseudomedian of 9 + int s = n/8; + pl = med3(pl, pl+s, pl+2*s, a); + pm = med3(pm-s, pm, pm+s, a); + pn = med3(pn-2*s, pn-s, pn, a); + } + pm = med3(pl, pm, pn, a); // mid-size, med of 3 + } + + int pa, pb, pc, pd, pv; + float r; + + pv = start; swap(pv, pm, a); + pa = pb = start; + pc = pd = start + n-1; + + for (;;) { + while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0) { + if (r == 0) { swap(pa, pb, a); pa++; } + pb++; + } + while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0) { + if (r == 0) { swap(pc, pd, a); pd--; } + pc--; + } + if (pb > pc) break; + swap(pb, pc, a); + pb++; + pc--; + } + int pn = start + n; + int s; + s = Math.min(pa-start, pb-pa); vecswap(start, pb-s, s, a); + s = Math.min(pd-pc, pn-pd-1); vecswap(pb, pn-s, s, a); + if ((s = pb-pa) > 1) qsort(a, start, s); + if ((s = pd-pc) > 1) qsort(a, pn-s, s); + } + + private static void vecswap(int i, int j, int n, float[] a) { + for (; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Sort an int array into ascending order. The sort algorithm is an optimised + * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's + * "Engineering a Sort Function", Software-Practice and Experience, Vol. + * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n) + * performance on many arrays that would take quadratic time with a standard + * quicksort. + * + * @param a the array to sort + */ + public static void sort(int[] a) { + qsort(a, 0, a.length); + } + + private static long cmp(int i, int j) { + return (long)i-(long)j; + } + + private static int med3(int a, int b, int c, int[] d) { + return cmp(d[a], d[b]) < 0 ? + (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a) + : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a); + } + + private static void swap(int i, int j, int[] a) { + int c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + private static void qsort(int[] a, int start, int n) { + // use an insertion sort on small arrays + if (n < 7) { + for (int i = start + 1; i < start + n; i++) + for (int j = i; j > 0 && cmp(a[j-1], a[j]) > 0; j--) + swap(j, j-1, a); + return; + } + + int pm = n/2; // small arrays, middle element + if (n > 7) { + int pl = start; + int pn = start + n-1; + + if (n > 40) { // big arrays, pseudomedian of 9 + int s = n/8; + pl = med3(pl, pl+s, pl+2*s, a); + pm = med3(pm-s, pm, pm+s, a); + pn = med3(pn-2*s, pn-s, pn, a); + } + pm = med3(pl, pm, pn, a); // mid-size, med of 3 + } + + int pa, pb, pc, pd, pv; + long r; + + pv = start; swap(pv, pm, a); + pa = pb = start; + pc = pd = start + n-1; + + for (;;) { + while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0) { + if (r == 0) { swap(pa, pb, a); pa++; } + pb++; + } + while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0) { + if (r == 0) { swap(pc, pd, a); pd--; } + pc--; + } + if (pb > pc) break; + swap(pb, pc, a); + pb++; + pc--; + } + int pn = start + n; + int s; + s = Math.min(pa-start, pb-pa); vecswap(start, pb-s, s, a); + s = Math.min(pd-pc, pn-pd-1); vecswap(pb, pn-s, s, a); + if ((s = pb-pa) > 1) qsort(a, start, s); + if ((s = pd-pc) > 1) qsort(a, pn-s, s); + } + + private static void vecswap(int i, int j, int n, int[] a) { + for (; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Sort a long array into ascending order. The sort algorithm is an optimised + * quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's + * "Engineering a Sort Function", Software-Practice and Experience, Vol. + * 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n) + * performance on many arrays that would take quadratic time with a standard + * quicksort. + * + * @param a the array to sort + */ + public static void sort(long[] a) { + qsort(a, 0, a.length); + } + + // The "cmp" method has been removed from here and replaced with direct + // compares in situ, to avoid problems with overflow if the difference + // between two numbers is bigger than a long will hold. + // One particular change as a result is the use of r1 and r2 in qsort + + private static int med3(int a, int b, int c, long[] d) { + return d[a] < d[b] ? + (d[b] < d[c] ? b : d[a] < d[c] ? c : a) + : (d[b] > d[c] ? b : d[a] > d[c] ? c : a); + } + + private static void swap(int i, int j, long[] a) { + long c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + private static void qsort(long[] a, int start, int n) { + // use an insertion sort on small arrays + if (n < 7) { + for (int i = start + 1; i < start + n; i++) + for (int j = i; j > 0 && a[j-1] > a[j]; j--) + swap(j, j-1, a); + return; + } + + int pm = n/2; // small arrays, middle element + if (n > 7) { + int pl = start; + int pn = start + n-1; + + if (n > 40) { // big arrays, pseudomedian of 9 + int s = n/8; + pl = med3(pl, pl+s, pl+2*s, a); + pm = med3(pm-s, pm, pm+s, a); + pn = med3(pn-2*s, pn-s, pn, a); + } + pm = med3(pl, pm, pn, a); // mid-size, med of 3 + } + + int pa, pb, pc, pd, pv; + long r1, r2; + + pv = start; swap(pv, pm, a); + pa = pb = start; + pc = pd = start + n-1; + + for (;;) { + while (pb <= pc && (r1 = a[pb]) <= (r2 = a[pv])) { + if (r1 == r2) { swap(pa, pb, a); pa++; } + pb++; + } + while (pc >= pb && (r1 = a[pc]) >= (r2 = a[pv])) { + if (r1 == r2) { swap(pc, pd, a); pd--; } + pc--; + } + if (pb > pc) break; + swap(pb, pc, a); + pb++; + pc--; + } + int pn = start + n; + int s; + s = Math.min(pa-start, pb-pa); vecswap(start, pb-s, s, a); + s = Math.min(pd-pc, pn-pd-1); vecswap(pb, pn-s, s, a); + if ((s = pb-pa) > 1) qsort(a, start, s); + if ((s = pd-pc) > 1) qsort(a, pn-s, s); + } + + private static void vecswap(int i, int j, int n, long[] a) { + for (; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * Sort a short array into ascending order. The sort algorithm is an + * optimised quicksort, as described in Jon L. Bentley and M. Douglas + * McIlroy's "Engineering a Sort Function", Software-Practice and Experience, + * Vol. 23(11) P. 1249-1265 (November 1993). This algorithm gives nlog(n) + * performance on many arrays that would take quadratic time with a standard + * quicksort. + * + * @param a the array to sort + */ + public static void sort(short[] a) { + qsort(a, 0, a.length); + } + + private static int cmp(short i, short j) { + return i-j; + } + + private static int med3(int a, int b, int c, short[] d) { + return cmp(d[a], d[b]) < 0 ? + (cmp(d[b], d[c]) < 0 ? b : cmp(d[a], d[c]) < 0 ? c : a) + : (cmp(d[b], d[c]) > 0 ? b : cmp(d[a], d[c]) > 0 ? c : a); + } + + private static void swap(int i, int j, short[] a) { + short c = a[i]; + a[i] = a[j]; + a[j] = c; + } + + private static void qsort(short[] a, int start, int n) { + // use an insertion sort on small arrays + if (n < 7) { + for (int i = start + 1; i < start + n; i++) + for (int j = i; j > 0 && cmp(a[j-1], a[j]) > 0; j--) + swap(j, j-1, a); + return; + } + + int pm = n/2; // small arrays, middle element + if (n > 7) { + int pl = start; + int pn = start + n-1; + + if (n > 40) { // big arrays, pseudomedian of 9 + int s = n/8; + pl = med3(pl, pl+s, pl+2*s, a); + pm = med3(pm-s, pm, pm+s, a); + pn = med3(pn-2*s, pn-s, pn, a); + } + pm = med3(pl, pm, pn, a); // mid-size, med of 3 + } + + int pa, pb, pc, pd, pv; + int r; + + pv = start; swap(pv, pm, a); + pa = pb = start; + pc = pd = start + n-1; + + for (;;) { + while (pb <= pc && (r = cmp(a[pb], a[pv])) <= 0) { + if (r == 0) { swap(pa, pb, a); pa++; } + pb++; + } + while (pc >= pb && (r = cmp(a[pc], a[pv])) >= 0) { + if (r == 0) { swap(pc, pd, a); pd--; } + pc--; + } + if (pb > pc) break; + swap(pb, pc, a); + pb++; + pc--; + } + int pn = start + n; + int s; + s = Math.min(pa-start, pb-pa); vecswap(start, pb-s, s, a); + s = Math.min(pd-pc, pn-pd-1); vecswap(pb, pn-s, s, a); + if ((s = pb-pa) > 1) qsort(a, start, s); + if ((s = pd-pc) > 1) qsort(a, pn-s, s); + } + + private static void vecswap(int i, int j, int n, short[] a) { + for (; n > 0; i++, j++, n--) + swap(i, j, a); + } + + /** + * The bulk of the work for the object sort routines. If c is null, + * uses the natural ordering. + * In general, the code attempts to be simple rather than fast, the idea + * being that a good optimising JIT will be able to optimise it better than I + * can, and if I try it will make it more confusing for the JIT. The + * exception is in declaring values "final", which I do whenever there is no + * need for them ever to change - this may give slight speedups. + */ + private static void mergeSort(Object[] a, final Comparator c) { + final int n = a.length; + Object[] x = a; + Object[] y = new Object[n]; + Object[] t = null; // t is used for swapping x and y + + // The merges are done in this loop + for (int sizenf = 1; sizenf < n; sizenf <<= 1) { + final int size = sizenf; // Slightly inelegant but probably speeds us up + + for (int startnf = 0; startnf < n; startnf += size << 1) { + final int start = startnf; // see above with size and sizenf + + // size2 is the size of the second sublist, which may not be the same + // as the first if we are at the end of the list. + final int size2 = n - start - size < size ? n - start - size : size; + + // The second list is empty or the elements are already in order - no + // need to merge + if (size2 <= 0 || + compare(x[start + size - 1], x[start + size], c) <= 0) { + System.arraycopy(x, start, y, start, size + size2); + + // The two halves just need swapping - no need to merge + } else if (compare(x[start], x[start + size + size2 - 1], c) >= 0) { + System.arraycopy(x, start, y, start + size2, size); + System.arraycopy(x, start + size, y, start, size2); + + } else { + // Declare a lot of variables to save repeating calculations. + // Hopefully a decent JIT will put these in registers and make this + // fast + int p1 = start; + int p2 = start + size; + int i = start; + int d1; + + // initial value added to placate javac + int d2 = -1; + + // The main merge loop; terminates as soon as either half is ended + // You'd think you needed to use & rather than && to make sure d2 + // gets calculated even if d1 == 0, but in fact if this is the case, + // d2 hasn't changed since the last iteration. + while ((d1 = start + size - p1) > 0 && + (d2 = start + size + size2 - p2) > 0) { + y[i++] = x[(compare(x[p1], x[p2], c) <= 0) ? p1++ : p2++]; + } + + // Finish up by copying the remainder of whichever half wasn't + // finished. + System.arraycopy(x, d1 > 0 ? p1 : p2, y, i, d1 > 0 ? d1 : d2); + } + } + t = x; x = y; y = t; // swap x and y ready for the next merge + } + + // make sure the result ends up back in the right place. + if (x != a) { + System.arraycopy(x, 0, a, 0, n); + } + } + + /** + * Sort an array of Objects according to their natural ordering. The sort is + * guaranteed to be stable, that is, equal elements will not be reordered. + * The sort algorithm is a mergesort with the merge omitted if the last + * element of one half comes before the first element of the other half. This + * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a + * copy of the array. + * + * @param a the array to be sorted + * @exception ClassCastException if any two elements are not mutually + * comparable + * @exception NullPointerException if an element is null (since + * null.compareTo cannot work) + */ + public static void sort(Object[] a) { + mergeSort(a, null); + } + + /** + * Sort an array of Objects according to a Comparator. The sort is + * guaranteed to be stable, that is, equal elements will not be reordered. + * The sort algorithm is a mergesort with the merge omitted if the last + * element of one half comes before the first element of the other half. This + * algorithm gives guaranteed O(nlog(n)) time, at the expense of making a + * copy of the array. + * + * @param a the array to be sorted + * @param c a Comparator to use in sorting the array + * @exception ClassCastException if any two elements are not mutually + * comparable by the Comparator provided + */ + public static void sort(Object[] a, Comparator c) { + + // Passing null to mergeSort would use the natural ordering. This is wrong + // by the spec and not in the reference implementation. + if (c == null) { + throw new NullPointerException(); + } + mergeSort(a, c); + } + + /** + * Returns a list "view" of the specified array. This method is intended to + * make it easy to use the Collections API with existing array-based APIs and + * programs. + * + * @param a the array to return a view of + * @returns a fixed-size list, changes to which "write through" to the array + */ + public static List asList(final Object[] a) { + + // Check for a null argument + if (a == null) { + throw new NullPointerException(); + } + + return new ListImpl( a ); + } + + + /** + * Inner class used by asList(Object[]) to provide a list interface + * to an array. The methods are all simple enough to be self documenting. + * Note: When Sun fully specify serialized forms, this class will have to + * be renamed. + */ + private static class ListImpl extends AbstractList { + + ListImpl(Object[] a) { + this.a = a; + } + + public Object get(int index) { + return a[index]; + } + + public int size() { + return a.length; + } + + public Object set(int index, Object element) { + Object old = a[index]; + a[index] = element; + return old; + } + + private Object[] a; + } + +} diff --git a/jode/jode/util/Collection.java b/jode/jode/util/Collection.java new file mode 100644 index 0000000..9279326 --- /dev/null +++ b/jode/jode/util/Collection.java @@ -0,0 +1,234 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// Collection.java -- Interface that represents a collection of objects +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Maybe some more @see clauses would be helpful. + +package jode.util; + +/** + * Interface that represents a collection of objects. This interface is the + * root of the collection hierarchy, and does not provide any guarantees about + * the order of its elements or whether or not duplicate elements are + * permitted. + *

+ * All methods of this interface that are defined to modify the collection are + * defined as optional. An optional operation may throw an + * UnsupportedOperationException if the data backing this collection does not + * support such a modification. This may mean that the data structure is + * immutable, or that it is read-only but may change ("unmodifiable"), or + * that it is modifiable but of fixed size (such as an array), or any number + * of other combinations. + *

+ * A class that wishes to implement this interface should consider subclassing + * AbstractCollection, which provides basic implementations of most of the + * methods of this interface. Classes that are prepared to make guarantees + * about ordering or about absence of duplicate elements should consider + * implementing List or Set respectively, both of which are subinterfaces of + * Collection. + *

+ * A general-purpose implementation of the Collection interface should in most + * cases provide at least two constructors: One which takes no arguments and + * creates an empty collection, and one which takes a Collection as an argument + * and returns a collection containing the same elements (that is, creates a + * copy of the argument using its own implementation). + * + * @see java.util.List + * @see java.util.Set + * @see java.util.AbstractCollection + */ +public interface Collection { + + /** + * Add an element to this collection. + * + * @param o the object to add. + * @returns true if the collection was modified as a result of this action. + * @exception UnsupportedOperationException if this collection does not + * support the add operation. + * @exception ClassCastException if o cannot be added to this collection due + * to its type. + * @exception IllegalArgumentException if o cannot be added to this + * collection for some other reason. + */ + boolean add(Object o); + + /** + * Add the contents of a given collection to this collection. + * + * @param c the collection to add. + * @returns true if the collection was modified as a result of this action. + * @exception UnsupportedOperationException if this collection does not + * support the addAll operation. + * @exception ClassCastException if some element of c cannot be added to this + * collection due to its type. + * @exception IllegalArgumentException if some element of c cannot be added + * to this collection for some other reason. + */ + boolean addAll(Collection c); + + /** + * Clear the collection, such that a subsequent call to isEmpty() would + * return true. + * + * @exception UnsupportedOperationException if this collection does not + * support the clear operation. + */ + void clear(); + + /** + * Test whether this collection contains a given object as one of its + * elements. + * + * @param o the element to look for. + * @returns true if this collection contains at least one element e such that + * o == null ? e == null : o.equals(e). + */ + boolean contains(Object o); + + /** + * Test whether this collection contains every element in a given collection. + * + * @param c the collection to test for. + * @returns true if for every element o in c, contains(o) would return true. + */ + boolean containsAll(Collection c); + + /** + * Test whether this collection is equal to some object. The Collection + * interface does not explicitly require any behaviour from this method, and + * it may be left to the default implementation provided by Object. The Set + * and List interfaces do, however, require specific behaviour from this + * method. + *

+ * If an implementation of Collection, which is not also an implementation of + * Set or List, should choose to implement this method, it should take care + * to obey the contract of the equals method of Object. In particular, care + * should be taken to return false when o is a Set or a List, in order to + * preserve the symmetry of the relation. + * + * @param o the object to compare to this collection. + * @returns true if the o is equal to this collection. + */ + boolean equals(Object o); + + /** + * Obtain a hash code for this collection. The Collection interface does not + * explicitly require any behaviour from this method, and it may be left to + * the default implementation provided by Object. The Set and List interfaces + * do, however, require specific behaviour from this method. + *

+ * If an implementation of Collection, which is not also an implementation of + * Set or List, should choose to implement this method, it should take care + * to obey the contract of the hashCode method of Object. Note that this + * method renders it impossible to correctly implement both Set and List, as + * the required implementations are mutually exclusive. + * + * @returns a hash code for this collection. + */ + int hashCode(); + + /** + * Test whether this collection is empty, that is, if size() == 0. + * + * @returns true if this collection contains no elements. + */ + boolean isEmpty(); + + /** + * Obtain an Iterator over this collection. + * + * @returns an Iterator over the elements of this collection, in any order. + */ + Iterator iterator(); + + /** + * Remove a single occurrence of an object from this collection. That is, + * remove an element e, if one exists, such that o == null ? e == null + * : o.equals(e). + * + * @param o the object to remove. + * @returns true if the collection changed as a result of this call, that is, + * if the collection contained at least one occurrence of o. + * @exception UnsupportedOperationException if this collection does not + * support the remove operation. + */ + boolean remove(Object o); + + /** + * Remove all elements of a given collection from this collection. That is, + * remove every element e such that c.contains(e). + * + * @returns true if this collection was modified as a result of this call. + * @exception UnsupportedOperationException if this collection does not + * support the removeAll operation. + */ + boolean removeAll(Collection c); + + /** + * Remove all elements of this collection that are not contained in a given + * collection. That is, remove every element e such that !c.contains(e). + * + * @returns true if this collection was modified as a result of this call. + * @exception UnsupportedOperationException if this collection does not + * support the retainAll operation. + */ + boolean retainAll(Collection c); + + /** + * Get the number of elements in this collection. + * + * @returns the number of elements in the collection. + */ + int size(); + + /** + * Copy the current contents of this collection into an array. + * + * @returns an array of type Object[] and length equal to the size of this + * collection, containing the elements currently in this collection, in + * any order. + */ + Object[] toArray(); + + /** + * Copy the current contents of this collection into an array. If the array + * passed as an argument has length less than the size of this collection, an + * array of the same run-time type as a, and length equal to the size of this + * collection, is allocated using Reflection. Otherwise, a itself is used. + * The elements of this collection are copied into it, and if there is space + * in the array, the following element is set to null. The resultant array is + * returned. + * Note: The fact that the following element is set to null is only useful + * if it is known that this collection does not contain any null elements. + * + * @param a the array to copy this collection into. + * @returns an array containing the elements currently in this collection, in + * any order. + * @exception ArrayStoreException if the type of any element of the + * collection is not a subtype of the element type of a. + */ + Object[] toArray(Object[] a); +} diff --git a/jode/jode/util/Collections.java b/jode/jode/util/Collections.java new file mode 100644 index 0000000..7a414b2 --- /dev/null +++ b/jode/jode/util/Collections.java @@ -0,0 +1,1413 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// Collections.java -- Utility class with methods to operate on collections +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Serialization is very much broken. Blame Sun for not specifying it. +// ~ The synchronized* and unmodifiable* methods don't have doc-comments. + +package jode.util; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Random; +import java.util.NoSuchElementException; + +/** + * Utility class consisting of static methods that operate on, or return + * Collections. Contains methods to sort, search, reverse, fill and shuffle + * Collections, methods to facilitate interoperability with legacy APIs that + * are unaware of collections, a method to return a list which consists of + * multiple copies of one element, and methods which "wrap" collections to give + * them extra properties, such as thread-safety and unmodifiability. + */ +public class Collections { + + /** + * This class is non-instantiable. + */ + private Collections() { + } + + /** + * An immutable, empty Set. + * Note: This implementation isn't Serializable, although it should be by the + * spec. + */ + public static final Set EMPTY_SET = new AbstractSet() { + + public int size() { + return 0; + } + + // This is really cheating! I think it's perfectly valid, though - the + // more conventional code is here, commented out, in case anyone disagrees. + public Iterator iterator() { + return EMPTY_LIST.iterator(); + } + + // public Iterator iterator() { + // return new Iterator() { + // + // public boolean hasNext() { + // return false; + // } + // + // public Object next() { + // throw new NoSuchElementException(); + // } + // + // public void remove() { + // throw new UnsupportedOperationException(); + // } + // }; + // } + + }; + + /** + * An immutable, empty List. + * Note: This implementation isn't serializable, although it should be by the + * spec. + */ + public static final List EMPTY_LIST = new AbstractList() { + + public int size() { + return 0; + } + + public Object get(int index) { + throw new IndexOutOfBoundsException(); + } + }; + + /** + * Compare two objects with or without a Comparator. If c is null, uses the + * natural ordering. Slightly slower than doing it inline if the JVM isn't + * clever, but worth it for removing a duplicate of the search code. + * Note: This same code is used in Arrays (for sort as well as search) + */ + private static int compare(Object o1, Object o2, Comparator c) { + if (c == null) { + return ((Comparable)o1).compareTo(o2); + } else { + return c.compare(o1, o2); + } + } + + /** + * The hard work for the search routines. If the Comparator given is null, + * uses the natural ordering of the elements. + */ + private static int search(List l, Object key, final Comparator c) { + + int pos = 0; + + // We use a linear search using an iterator if we can guess that the list + // is sequential-access. + if (l instanceof AbstractSequentialList) { + ListIterator i = l.listIterator(); + while (i.hasNext()) { + final int d = compare(key, i.next(), c); + if (d == 0) { + return pos; + } else if (d < 0) { + return -pos - 1; + } + pos++; + } + + // We assume the list is random-access, and use a binary search + } else { + int low = 0; + int hi = l.size() - 1; + while (low <= hi) { + pos = (low + hi) >> 1; + final int d = compare(key, l.get(pos), c); + if (d == 0) { + return pos; + } else if (d < 0) { + hi = pos - 1; + } else { + low = ++pos; // This gets the insertion point right on the last loop + } + } + } + + // If we failed to find it, we do the same whichever search we did. + return -pos - 1; + } + + /** + * Perform a binary search of a List for a key, using the natural ordering of + * the elements. The list must be sorted (as by the sort() method) - if it is + * not, the behaviour of this method is undefined, and may be an infinite + * loop. Further, the key must be comparable with every item in the list. If + * the list contains the key more than once, any one of them may be found. To + * avoid pathological behaviour on sequential-access lists, a linear search + * is used if (l instanceof AbstractSequentialList). Note: although the + * specification allows for an infinite loop if the list is unsorted, it will + * not happen in this (Classpath) implementation. + * + * @param l the list to search (must be sorted) + * @param key the value to search for + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @exception ClassCastException if key could not be compared with one of the + * elements of l + * @exception NullPointerException if a null element has compareTo called + */ + public static int binarySearch(List l, Object key) { + return search(l, key, null); + } + + /** + * Perform a binary search of a List for a key, using a supplied Comparator. + * The list must be sorted (as by the sort() method with the same Comparator) + * - if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. Further, the key must be comparable with every item in the + * list. If the list contains the key more than once, any one of them may be + * found. To avoid pathological behaviour on sequential-access lists, a + * linear search is used if (l instanceof AbstractSequentialList). Note: + * although the specification allows for an infinite loop if the list is + * unsorted, it will not happen in this (Classpath) implementation. + * + * @param l the list to search (must be sorted) + * @param key the value to search for + * @param c the comparator by which the list is sorted + * @returns the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @exception ClassCastException if key could not be compared with one of the + * elements of l + */ + public static int binarySearch(List l, Object key, Comparator c) { + if (c == null) { + throw new NullPointerException(); + } + return search(l, key, c); + } + + /** + * Copy one list to another. If the destination list is longer than the + * source list, the remaining elements are unaffected. This method runs in + * linear time. + * + * @param dest the destination list. + * @param source the source list. + * @exception IndexOutOfBoundsException if the destination list is shorter + * than the source list (the elements that can be copied will be, prior to + * the exception being thrown). + * @exception UnsupportedOperationException if dest.listIterator() does not + * support the set operation. + */ + public static void copy(List dest, List source) { + Iterator i1 = source.iterator(); + ListIterator i2 = dest.listIterator(); + while (i1.hasNext()) { + i2.next(); + i2.set(i1.next()); + } + } + + /** + * Returns an Enumeration over a collection. This allows interoperability + * with legacy APIs that require an Enumeration as input. + * + * @param c the Collection to iterate over + * @returns an Enumeration backed by an Iterator over c + */ + public static Enumeration enumeration(Collection c) { + final Iterator i = c.iterator(); + return new Enumeration() { + public final boolean hasMoreElements() { + return i.hasNext(); + } + public final Object nextElement() { + return i.next(); + } + }; + } + + /** + * Replace every element of a list with a given value. This method runs in + * linear time. + * + * @param l the list to fill. + * @param val the object to vill the list with. + * @exception UnsupportedOperationException if l.listIterator() does not + * support the set operation. + */ + public static void fill(List l, Object val) { + ListIterator i = l.listIterator(); + while (i.hasNext()) { + i.next(); + i.set(val); + } + } + + /** + * Find the maximum element in a Collection, according to the natural + * ordering of the elements. This implementation iterates over the + * Collection, so it works in linear time. + * + * @param c the Collection to find the maximum element of + * @returns the maximum element of c + * @exception NoSuchElementException if c is empty + * @exception ClassCastException if elements in c are not mutually comparable + * @exception NullPointerException if null.compareTo is called + */ + public static Object max(Collection c) { + Iterator i = c.iterator(); + Comparable max = (Comparable)i.next(); // throws NoSuchElementException + while (i.hasNext()) { + Object o = i.next(); + if (max.compareTo(o) < 0) { + max = (Comparable)o; + } + } + return max; + } + + /** + * Find the maximum element in a Collection, according to a specified + * Comparator. This implementation iterates over the Collection, so it + * works in linear time. + * + * @param c the Collection to find the maximum element of + * @param order the Comparator to order the elements by + * @returns the maximum element of c + * @exception NoSuchElementException if c is empty + * @exception ClassCastException if elements in c are not mutually comparable + */ + public static Object max(Collection c, Comparator order) { + Iterator i = c.iterator(); + Object max = i.next(); // throws NoSuchElementException + while (i.hasNext()) { + Object o = i.next(); + if (order.compare(max, o) < 0) { + max = o; + } + } + return max; + } + + /** + * Find the minimum element in a Collection, according to the natural + * ordering of the elements. This implementation iterates over the + * Collection, so it works in linear time. + * + * @param c the Collection to find the minimum element of + * @returns the minimum element of c + * @exception NoSuchElementException if c is empty + * @exception ClassCastException if elements in c are not mutually comparable + * @exception NullPointerException if null.compareTo is called + */ + public static Object min(Collection c) { + Iterator i = c.iterator(); + Comparable min = (Comparable)i.next(); // throws NoSuchElementException + while (i.hasNext()) { + Object o = i.next(); + if (min.compareTo(o) > 0) { + min = (Comparable)o; + } + } + return min; + } + + /** + * Find the minimum element in a Collection, according to a specified + * Comparator. This implementation iterates over the Collection, so it + * works in linear time. + * + * @param c the Collection to find the minimum element of + * @param order the Comparator to order the elements by + * @returns the minimum element of c + * @exception NoSuchElementException if c is empty + * @exception ClassCastException if elements in c are not mutually comparable + */ + public static Object min(Collection c, Comparator order) { + Iterator i = c.iterator(); + Object min = i.next(); // throws NoSuchElementExcception + while (i.hasNext()) { + Object o = i.next(); + if (order.compare(min, o) > 0) { + min = o; + } + } + return min; + } + + /** + * Creates an immutable list consisting of the same object repeated n times. + * The returned object is tiny, consisting of only a single reference to the + * object and a count of the number of elements. It is Serializable. + * + * @param n the number of times to repeat the object + * @param o the object to repeat + * @returns a List consisting of n copies of o + * @throws IllegalArgumentException if n < 0 + */ + // It's not Serializable, because the serialized form is unspecced. + // Also I'm only assuming that it should be because I don't think it's + // stated - I just would be amazed if it isn't... + public static List nCopies(final int n, final Object o) { + + // Check for insane arguments + if (n < 0) { + throw new IllegalArgumentException(); + } + + // Create a minimal implementation of List + return new AbstractList() { + + public int size() { + return n; + } + + public Object get(int index) { + if (index < 0 || index >= n) { + throw new IndexOutOfBoundsException(); + } + return o; + } + }; + } + + /** + * Reverse a given list. This method works in linear time. + * + * @param l the list to reverse. + * @exception UnsupportedOperationException if l.listIterator() does not + * support the set operation. + */ + public static void reverse(List l) { + ListIterator i1 = l.listIterator(); + ListIterator i2 = l.listIterator(l.size()); + while (i1.nextIndex() < i2.previousIndex()) { + Object o = i1.next(); + i1.set(i2.previous()); + i2.set(o); + } + } + + /** + * Get a comparator that implements the reverse of natural ordering. This is + * intended to make it easy to sort into reverse order, by simply passing + * Collections.reverseOrder() to the sort method. The return value of this + * method is Serializable. + */ + // The return value isn't Serializable, because the spec is broken. + public static Comparator reverseOrder() { + return new Comparator() { + public int compare(Object a, Object b) { + return -((Comparable)a).compareTo(b); + } + }; + } + + /** + * Shuffle a list according to a default source of randomness. The algorithm + * used would result in a perfectly fair shuffle (that is, each element would + * have an equal chance of ending up in any position) with a perfect source + * of randomness; in practice the results are merely very close to perfect. + *

+ * This method operates in linear time on a random-access list, but may take + * quadratic time on a sequential-access list. + * Note: this (classpath) implementation will never take quadratic time, but + * it does make a copy of the list. This is in line with the behaviour of the + * sort methods and seems preferable. + * + * @param l the list to shuffle. + * @exception UnsupportedOperationException if l.listIterator() does not + * support the set operation. + */ + public static void shuffle(List l) { + shuffle(l, new Random()); + } + + /** + * Shuffle a list according to a given source of randomness. The algorithm + * used iterates backwards over the list, swapping each element with an + * element randomly selected from the elements in positions less than or + * equal to it (using r.nextInt(int)). + *

+ * This algorithm would result in a perfectly fair shuffle (that is, each + * element would have an equal chance of ending up in any position) if r were + * a perfect source of randomness. In practise (eg if r = new Random()) the + * results are merely very close to perfect. + *

+ * This method operates in linear time on a random-access list, but may take + * quadratic time on a sequential-access list. + * Note: this (classpath) implementation will never take quadratic time, but + * it does make a copy of the list. This is in line with the behaviour of the + * sort methods and seems preferable. + * + * @param l the list to shuffle. + * @param r the source of randomness to use for the shuffle. + * @exception UnsupportedOperationException if l.listIterator() does not + * support the set operation. + */ + public static void shuffle(List l, Random r) { + Object[] a = l.toArray(); // Dump l into an array + ListIterator i = l.listIterator(l.size()); + + // Iterate backwards over l + while (i.hasPrevious()) { + + // Obtain a random position to swap with. nextIndex is used so that the + // range of the random number includes the current position. +// int swap = r.nextInt(i.nextIndex()); + // Change for jode by + int swap = Math.abs(r.nextInt()) % i.nextIndex(); + + // Swap the swapth element of the array with the next element of the + // list. + Object o = i.previous(); + i.set(a[swap]); + a[swap] = o; + } + } + + /** + * Obtain an immutable Set consisting of a single element. The return value + * of this method is Serializable. + * + * @param o the single element. + * @returns an immutable Set containing only o. + */ + // It's not serializable because the spec is broken. + public static Set singleton(final Object o) { + + return new AbstractSet() { + + public int size() { + return 1; + } + + public Iterator iterator() { + return new Iterator() { + + private boolean hasNext = true; + + public boolean hasNext() { + return hasNext; + } + + public Object next() { + if (hasNext) { + hasNext = false; + return o; + } else { + throw new NoSuchElementException(); + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + /** + * Sort a list according to the natural ordering of its elements. The list + * must be modifiable, but can be of fixed size. The sort algorithm is + * precisely that used by Arrays.sort(Object[]), which offers guaranteed + * nlog(n) performance. This implementation dumps the list into an array, + * sorts the array, and then iterates over the list setting each element from + * the array. + * + * @param l the List to sort + * @exception ClassCastException if some items are not mutually comparable + * @exception UnsupportedOperationException if the List is not modifiable + */ + public static void sort(List l) { + Object[] a = l.toArray(); + Arrays.sort(a); + ListIterator i = l.listIterator(); + for (int pos = 0; pos < a.length; pos++) { + i.next(); + i.set(a[pos]); + } + } + + /** + * Sort a list according to a specified Comparator. The list must be + * modifiable, but can be of fixed size. The sort algorithm is precisely that + * used by Arrays.sort(Object[], Comparator), which offers guaranteed + * nlog(n) performance. This implementation dumps the list into an array, + * sorts the array, and then iterates over the list setting each element from + * the array. + * + * @param l the List to sort + * @param c the Comparator specifying the ordering for the elements + * @exception ClassCastException if c will not compare some pair of items + * @exception UnsupportedOperationException if the List is not modifiable + */ + public static void sort(List l, Comparator c) { + Object[] a = l.toArray(); + Arrays.sort(a, c); + ListIterator i = l.listIterator(); + for (int pos = 0; pos < a.length; pos++) { + i.next(); + i.set(a[pos]); + } + } + + // All the methods from here on in require doc-comments. + + public static Collection synchronizedCollection(Collection c) { + return new SynchronizedCollection(c); + } + public static List synchronizedList(List l) { + return new SynchronizedList(l); + } + public static Map synchronizedMap(Map m) { + return new SynchronizedMap(m); + } + public static Set synchronizedSet(Set s) { + return new SynchronizedSet(s); + } + public static SortedMap synchronizedSortedMap(SortedMap m) { + return new SynchronizedSortedMap(m); + } + public static SortedSet synchronizedSortedSet(SortedSet s) { + return new SynchronizedSortedSet(s); + } + public static Collection unmodifiableCollection(Collection c) { + return new UnmodifiableCollection(c); + } + public static List unmodifiableList(List l) { + return new UnmodifiableList(l); + } + public static Map unmodifiableMap(Map m) { + return new UnmodifiableMap(m); + } + public static Set unmodifiableSet(Set s) { + return new UnmodifiableSet(s); + } + public static SortedMap unmodifiableSortedMap(SortedMap m) { + return new UnmodifiableSortedMap(m); + } + public static SortedSet unmodifiableSortedSet(SortedSet s) { + return new UnmodifiableSortedSet(s); + } + + // Sun's spec will need to be checked for the precise names of these + // classes, for serializability's sake. However, from what I understand, + // serialization is broken for these classes anyway. + + // Note: although this code is largely uncommented, it is all very + // mechanical and there's nothing really worth commenting. + // When serialization of these classes works, we'll need doc-comments on + // them to document the serialized form. + + private static class UnmodifiableIterator implements Iterator { + private Iterator i; + + public UnmodifiableIterator(Iterator i) { + this.i = i; + } + + public Object next() { + return i.next(); + } + public boolean hasNext() { + return i.hasNext(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + } + + private static class UnmodifiableListIterator extends UnmodifiableIterator + implements ListIterator { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + private ListIterator li; + + public UnmodifiableListIterator(ListIterator li) { + super(li); + this.li = li; + } + + public boolean hasPrevious() { + return li.hasPrevious(); + } + public Object previous() { + return li.previous(); + } + public int nextIndex() { + return li.nextIndex(); + } + public int previousIndex() { + return li.previousIndex(); + } + public void add(Object o) { + throw new UnsupportedOperationException(); + } + public void set(Object o) { + throw new UnsupportedOperationException(); + } + } + + private static class UnmodifiableCollection implements Collection, Serializable { + Collection c; + + public UnmodifiableCollection(Collection c) { + this.c = c; + } + + public boolean add(Object o) { + throw new UnsupportedOperationException(); + } + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + public void clear() { + throw new UnsupportedOperationException(); + } + public boolean contains(Object o) { + return c.contains(o); + } + public boolean containsAll(Collection c1) { + return c.containsAll(c1); + } + public boolean isEmpty() { + return c.isEmpty(); + } + public Iterator iterator() { + return new UnmodifiableIterator(c.iterator()); + } + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException(); + } + public int size() { + return c.size(); + } + public Object[] toArray() { + return c.toArray(); + } + public Object[] toArray(Object[] a) { + return c.toArray(a); + } + } + + private static class UnmodifiableList extends UnmodifiableCollection + implements List { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + List l; + + public UnmodifiableList(List l) { + super(l); + this.l = l; + } + + public void add(int index, Object o) { + l.add(index, o); + } + public boolean addAll(int index, Collection c) { + return l.addAll(index, c); + } + public boolean equals(Object o) { + return l.equals(o); + } + public Object get(int index) { + return l.get(index); + } + public int hashCode() { + return l.hashCode(); + } + public int indexOf(Object o) { + return l.indexOf(o); + } + public int lastIndexOf(Object o) { + return l.lastIndexOf(o); + } + public ListIterator listIterator() { + return new UnmodifiableListIterator(l.listIterator()); + } + public ListIterator listIterator(int index) { + return new UnmodifiableListIterator(l.listIterator(index)); + } + public Object remove(int index) { + return l.remove(index); + } + public boolean remove(Object o) { + return l.remove(o); + } + public Object set(int index, Object o) { + return l.set(index, o); + } + public List subList(int fromIndex, int toIndex) { + return new UnmodifiableList(l.subList(fromIndex, toIndex)); + } + } + + private static class UnmodifiableSet extends UnmodifiableCollection implements Set { + public UnmodifiableSet(Set s) { + super(s); + } + public boolean equals(Object o) { + return c.equals(o); + } + public int hashCode() { + return c.hashCode(); + } + } + + private static class UnmodifiableSortedSet extends UnmodifiableSet + implements SortedSet { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + private SortedSet ss; + + public UnmodifiableSortedSet(SortedSet ss) { + super(ss); + this.ss = ss; + } + + public Comparator comparator() { + return ss.comparator(); + } + public Object first() { + return ss.first(); + } + public Object last() { + return ss.last(); + } + public SortedSet headSet(Object toElement) { + return new UnmodifiableSortedSet(ss.headSet(toElement)); + } + public SortedSet tailSet(Object fromElement) { + return new UnmodifiableSortedSet(ss.tailSet(fromElement)); + } + public SortedSet subSet(Object fromElement, Object toElement) { + return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement)); + } + } + + private static class UnmodifiableMap implements Map, Serializable { + + Map m; + + public UnmodifiableMap(Map m) { + this.m = m; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + public boolean containsKey(Object key) { + return m.containsKey(key); + } + public boolean containsValue(Object value) { + return m.containsValue(value); + } + + // This is one of the ickiest cases of nesting I've ever seen. It just + // means "return an UnmodifiableSet, except that the iterator() method + // returns an UnmodifiableIterator whos next() method returns an + // unmodifiable wrapper around its normal return value". + public Set entrySet() { + return new UnmodifiableSet(m.entrySet()) { + public Iterator iterator() { + return new UnmodifiableIterator(c.iterator()) { + public Object next() { + final Map.Entry e = (Map.Entry)super.next(); + return new Map.Entry() { + public Object getKey() { + return e.getKey(); + } + public Object getValue() { + return e.getValue(); + } + public Object setValue(Object value) { + throw new UnsupportedOperationException(); + } + public int hashCode() { + return e.hashCode(); + } + public boolean equals(Object o) { + return e.equals(o); + } + }; + } + }; + } + }; + } + public boolean equals(Object o) { + return m.equals(o); + } + public Object get(Object key) { + return m.get(key); + } + public Object put(Object key, Object value) { + throw new UnsupportedOperationException(); + } + public int hashCode() { + return m.hashCode(); + } + public boolean isEmpty() { + return m.isEmpty(); + } + public Set keySet() { + return new UnmodifiableSet(m.keySet()); + } + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + public Object remove(Object o) { + throw new UnsupportedOperationException(); + } + public int size() { + return m.size(); + } + public Collection values() { + return new UnmodifiableCollection(m.values()); + } + } + + private static class UnmodifiableSortedMap extends UnmodifiableMap + implements SortedMap { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + private SortedMap sm; + + public UnmodifiableSortedMap(SortedMap sm) { + super(sm); + this.sm = sm; + } + + public Comparator comparator() { + return sm.comparator(); + } + public Object firstKey() { + return sm.firstKey(); + } + public Object lastKey() { + return sm.lastKey(); + } + public SortedMap headMap(Object toKey) { + return new UnmodifiableSortedMap(sm.headMap(toKey)); + } + public SortedMap tailMap(Object fromKey) { + return new UnmodifiableSortedMap(sm.tailMap(fromKey)); + } + public SortedMap subMap(Object fromKey, Object toKey) { + return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey)); + } + } + + // All the "Synchronized" wrapper objects include a "sync" field which + // specifies what object to synchronize on. That way, nested wrappers such as + // UnmodifiableMap.keySet synchronize on the right things. + + private static class SynchronizedIterator implements Iterator { + Object sync; + private Iterator i; + + public SynchronizedIterator(Object sync, Iterator i) { + this.sync = sync; + this.i = i; + } + + public Object next() { + synchronized (sync) { + return i.next(); + } + } + public boolean hasNext() { + synchronized (sync) { + return i.hasNext(); + } + } + public void remove() { + synchronized (sync) { + i.remove(); + } + } + } + + private static class SynchronizedListIterator extends SynchronizedIterator + implements ListIterator { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + private ListIterator li; + + public SynchronizedListIterator(Object sync, ListIterator li) { + super(sync, li); + this.li = li; + } + + public boolean hasPrevious() { + synchronized (sync) { + return li.hasPrevious(); + } + } + public Object previous() { + synchronized (sync) { + return li.previous(); + } + } + public int nextIndex() { + synchronized (sync) { + return li.nextIndex(); + } + } + public int previousIndex() { + synchronized (sync) { + return li.previousIndex(); + } + } + public void add(Object o) { + synchronized (sync) { + li.add(o); + } + } + public void set(Object o) { + synchronized (sync) { + li.set(o); + } + } + } + + private static class SynchronizedCollection implements Collection, Serializable { + Object sync; + Collection c; + + public SynchronizedCollection(Collection c) { + this.sync = this; + this.c = c; + } + public SynchronizedCollection(Object sync, Collection c) { + this.c = c; + this.sync = sync; + } + + public boolean add(Object o) { + synchronized (sync) { + return c.add(o); + } + } + public boolean addAll(Collection col) { + synchronized (sync) { + return c.addAll(col); + } + } + public void clear() { + synchronized (sync) { + c.clear(); + } + } + public boolean contains(Object o) { + synchronized (sync) { + return c.contains(o); + } + } + public boolean containsAll(Collection c1) { + synchronized (sync) { + return c.containsAll(c1); + } + } + public boolean isEmpty() { + synchronized (sync) { + return c.isEmpty(); + } + } + public Iterator iterator() { + synchronized (sync) { + return new SynchronizedIterator(sync, c.iterator()); + } + } + public boolean remove(Object o) { + synchronized (sync) { + return c.remove(o); + } + } + public boolean removeAll(Collection col) { + synchronized (sync) { + return c.removeAll(col); + } + } + public boolean retainAll(Collection col) { + synchronized (sync) { + return c.retainAll(col); + } + } + public int size() { + synchronized (sync) { + return c.size(); + } + } + public Object[] toArray() { + synchronized (sync) { + return c.toArray(); + } + } + public Object[] toArray(Object[] a) { + synchronized (sync) { + return c.toArray(a); + } + } + } + + private static class SynchronizedList extends SynchronizedCollection + implements List { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + List l; + + public SynchronizedList(Object sync, List l) { + super(sync, l); + this.l = l; + } + public SynchronizedList(List l) { + super(l); + } + + public void add(int index, Object o) { + synchronized (sync) { + l.add(index, o); + } + } + public boolean addAll(int index, Collection c) { + synchronized (sync) { + return l.addAll(index, c); + } + } + public boolean equals(Object o) { + synchronized (sync) { + return l.equals(o); + } + } + public Object get(int index) { + synchronized (sync) { + return l.get(index); + } + } + public int hashCode() { + synchronized (sync) { + return l.hashCode(); + } + } + public int indexOf(Object o) { + synchronized (sync) { + return l.indexOf(o); + } + } + public int lastIndexOf(Object o) { + synchronized (sync) { + return l.lastIndexOf(o); + } + } + public ListIterator listIterator() { + synchronized (sync) { + return new SynchronizedListIterator(sync, l.listIterator()); + } + } + public ListIterator listIterator(int index) { + synchronized (sync) { + return new SynchronizedListIterator(sync, l.listIterator(index)); + } + } + public Object remove(int index) { + synchronized (sync) { + return l.remove(index); + } + } + public boolean remove(Object o) { + synchronized (sync) { + return l.remove(o); + } + } + public Object set(int index, Object o) { + synchronized (sync) { + return l.set(index, o); + } + } + public List subList(int fromIndex, int toIndex) { + synchronized (sync) { + return new SynchronizedList(l.subList(fromIndex, toIndex)); + } + } + } + + private static class SynchronizedSet extends SynchronizedCollection implements Set { + + public SynchronizedSet(Object sync, Set s) { + super(sync, s); + } + public SynchronizedSet(Set s) { + super(s); + } + + public boolean equals(Object o) { + synchronized (sync) { + return c.equals(o); + } + } + public int hashCode() { + synchronized (sync) { + return c.hashCode(); + } + } + } + + private static class SynchronizedSortedSet extends SynchronizedSet + implements SortedSet { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + private SortedSet ss; + + public SynchronizedSortedSet(Object sync, SortedSet ss) { + super(sync, ss); + this.ss = ss; + } + public SynchronizedSortedSet(SortedSet ss) { + super(ss); + } + + public Comparator comparator() { + synchronized (sync) { + return ss.comparator(); + } + } + public Object first() { + synchronized (sync) { + return ss.first(); + } + } + public Object last() { + synchronized (sync) { + return ss.last(); + } + } + public SortedSet headSet(Object toElement) { + synchronized (sync) { + return new SynchronizedSortedSet(sync, ss.headSet(toElement)); + } + } + public SortedSet tailSet(Object fromElement) { + synchronized (sync) { + return new SynchronizedSortedSet(sync, ss.tailSet(fromElement)); + } + } + public SortedSet subSet(Object fromElement, Object toElement) { + synchronized (sync) { + return new SynchronizedSortedSet(sync, ss.subSet(fromElement, toElement)); + } + } + } + + private static class SynchronizedMap implements Map, Serializable { + + Object sync; + Map m; + + public SynchronizedMap(Object sync, Map m) { + this.sync = sync; + this.m = m; + } + public SynchronizedMap(Map m) { + this.m = m; + this.sync = this; + } + + public void clear() { + synchronized (sync) { + m.clear(); + } + } + public boolean containsKey(Object key) { + synchronized (sync) { + return m.containsKey(key); + } + } + public boolean containsValue(Object value) { + synchronized (sync) { + return m.containsValue(value); + } + } + + // This is one of the ickiest cases of nesting I've ever seen. It just + // means "return an SynchronizedSet, except that the iterator() method + // returns an SynchronizedIterator whos next() method returns a + // synchronized wrapper around its normal return value". + public Set entrySet() { + synchronized (sync) { + return new SynchronizedSet(sync, m.entrySet()) { + public Iterator iterator() { + synchronized (SynchronizedMap.this.sync) { + return new SynchronizedIterator(SynchronizedMap.this.sync, c.iterator()) { + public Object next() { + synchronized (SynchronizedMap.this.sync) { + final Map.Entry e = (Map.Entry)super.next(); + return new Map.Entry() { + public Object getKey() { + synchronized (SynchronizedMap.this.sync) { + return e.getKey(); + } + } + public Object getValue() { + synchronized (SynchronizedMap.this.sync) { + return e.getValue(); + } + } + public Object setValue(Object value) { + synchronized (SynchronizedMap.this.sync) { + return e.setValue(value); + } + } + public int hashCode() { + synchronized (SynchronizedMap.this.sync) { + return e.hashCode(); + } + } + public boolean equals(Object o) { + synchronized (SynchronizedMap.this.sync) { + return e.equals(o); + } + } + }; + } + } + }; + } + } + }; + } + } + public boolean equals(Object o) { + synchronized (sync) { + return m.equals(o); + } + } + public Object get(Object key) { + synchronized (sync) { + return m.get(key); + } + } + public Object put(Object key, Object value) { + synchronized (sync) { + return m.put(key, value); + } + } + public int hashCode() { + synchronized (sync) { + return m.hashCode(); + } + } + public boolean isEmpty() { + synchronized (sync) { + return m.isEmpty(); + } + } + public Set keySet() { + synchronized (sync) { + return new SynchronizedSet(sync, m.keySet()); + } + } + public void putAll(Map map) { + synchronized (sync) { + m.putAll(map); + } + } + public Object remove(Object o) { + synchronized (sync) { + return m.remove(o); + } + } + + public int size() { + synchronized (sync) { + return m.size(); + } + } + public Collection values() { + synchronized (sync) { + return new SynchronizedCollection(sync, m.values()); + } + } + } + + private static class SynchronizedSortedMap extends SynchronizedMap + implements SortedMap { + + // This is stored both here and in the superclass, to avoid excessive + // casting. + private SortedMap sm; + + public SynchronizedSortedMap(Object sync, SortedMap sm) { + super(sync, sm); + this.sm = sm; + } + public SynchronizedSortedMap(SortedMap sm) { + super(sm); + } + + public Comparator comparator() { + synchronized (sync) { + return sm.comparator(); + } + } + public Object firstKey() { + synchronized (sync) { + return sm.firstKey(); + } + } + public Object lastKey() { + synchronized (sync) { + return sm.lastKey(); + } + } + public SortedMap headMap(Object toKey) { + return new SynchronizedSortedMap(sync, sm.headMap(toKey)); + } + public SortedMap tailMap(Object fromKey) { + return new SynchronizedSortedMap(sync, sm.tailMap(fromKey)); + } + public SortedMap subMap(Object fromKey, Object toKey) { + return new SynchronizedSortedMap(sync, sm.subMap(fromKey, toKey)); + } + } +} diff --git a/jode/jode/util/Comparable.java b/jode/jode/util/Comparable.java new file mode 100644 index 0000000..f2a7315 --- /dev/null +++ b/jode/jode/util/Comparable.java @@ -0,0 +1,51 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +/************************************************************************* +/* Comparable.java -- Interface for comparaing objects to obtain an ordering +/* +/* Copyright (c) 1998 by Free Software Foundation, Inc. +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation, version 2. (see COPYING.LIB) +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with this program; if not, write to the Free Software Foundation +/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +/*************************************************************************/ + +package jode.util; + +/** + ** Interface for objects that can be ordering among other + ** objects. The ordering can be total, such that two objects + ** only compare equal if they are equal by the equals method, or + ** partial such that this is not necessarily true. For + ** example, a case-sensitive dictionary order comparison of Strings + ** is total, but if it is case-insensitive it is partial, because + ** "abc" and "ABC" compare as equal even though "abc".equals("ABC") + ** returns false. + ** + ** @author Geoff Berry + ** + ** @since JDK1.2 + ** @see java.util.Comparator + **/ +public interface Comparable +{ + /** + ** @return a negative integer if this object is less than + ** o, zero if this object is equal to o, or + ** a positive integer if this object is greater than o + **/ + public int compareTo( Object o ); +} diff --git a/jode/jode/util/Comparator.java b/jode/jode/util/Comparator.java new file mode 100644 index 0000000..9247812 --- /dev/null +++ b/jode/jode/util/Comparator.java @@ -0,0 +1,62 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// Comparator.java -- Interface for objects that specify an ordering +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +package jode.util; + +/** + * Interface for objects that specify an ordering between objects. The ordering + * can be total, such that two objects only compare equal if they are + * equal by the equals method, or partial such that this is not + * necessarily true. For example, a case-sensitive dictionary order comparison + * of Strings is total, but if it is case-insensitive it is partial, because + * "abc" and "ABC" compare as equal even though "abc".equals("ABC") returns + * false. + *

+ * In general, Comparators should be Serializable, because when they are passed + * to Serializable data structures such as SortedMap or SortedSet, the entire + * data structure will only serialize correctly if the comparator is + * Serializable. + */ +public interface Comparator { + + /** + * Return an integer that is negative, zero or positive depending on whether + * the first argument is less than, equal to or greater than the second + * according to this ordering. This method should obey the following contract: + *

+ * + * @throws ClassCastException if the elements are not of types that can be + * compared by this ordering. + */ + int compare(Object o1, Object o2); +} diff --git a/jode/jode/util/ConcurrentModificationException.java b/jode/jode/util/ConcurrentModificationException.java new file mode 100644 index 0000000..3e3bd4c --- /dev/null +++ b/jode/jode/util/ConcurrentModificationException.java @@ -0,0 +1,53 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// ConcurrentModificationException.java -- Data structure concurrently modified +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +package jode.util; + +/** + * Exception that is thrown by the collections classes when it is detected that + * a modification has been made to a data structure when this is not allowed, + * such as when a collection is structurally modified while an Iterator is + * operating over it. In cases where this can be detected, a + * ConcurrentModificationException will be thrown. An Iterator that detects this + * condition is referred to as fail-fast. + */ +public class ConcurrentModificationException extends RuntimeException { + + /** + * Constructs a ConcurrentModificationException with no detail message. + */ + public ConcurrentModificationException() { + super(); + } + + /** + * Constructs a ConcurrentModificationException with a detail message. + * + * @param detail the detail message for the exception + */ + public ConcurrentModificationException(String detail) { + super(detail); + } +} diff --git a/jode/jode/util/Iterator.java b/jode/jode/util/Iterator.java new file mode 100644 index 0000000..2984f16 --- /dev/null +++ b/jode/jode/util/Iterator.java @@ -0,0 +1,66 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// Iterator.java -- Interface for iterating over collections +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +package jode.util; + +/** + * An object which iterates over a collection. An Iterator is used to return the + * items once only, in sequence, by successive calls to the next method. It is + * also possible to remove elements from the underlying collection by using the + * optional remove method. Iterator is intended as a replacement for the + * Enumeration interface of previous versions of Java, which did not have the + * remove method and had less conveniently named methods. + */ +public interface Iterator { + + /** + * Tests whether there are elements remaining in the collection. + * + * @return true if there is at least one more element in the collection, + * that is, if the next call to next will not throw NoSuchElementException. + */ + boolean hasNext(); + + /** + * Obtain the next element in the collection. + * + * @return the next element in the collection + * @exception NoSuchElementException if there are no more elements + */ + Object next(); + + /** + * Remove from the underlying collection the last element returned by next. + * This method can be called only once after each call to next. It does not + * affect what will be returned by subsequent calls to next. This operation is + * optional, it may throw an UnsupportedOperationException. + * + * @exception IllegalStateException if next has not yet been called or remove + * has already been called since the last call to next. + * @exception UnsupportedOperationException if this Iterator does not support + * the remove operation. + */ + void remove(); +} diff --git a/jode/jode/util/List.java b/jode/jode/util/List.java new file mode 100644 index 0000000..7e0c9ed --- /dev/null +++ b/jode/jode/util/List.java @@ -0,0 +1,331 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// List.java -- An ordered collection which allows indexed access +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Doc comment for the interface itself needs to be put into english. +// ~ Some more @see clauses might be nice. + +package jode.util; + +/** + * [This is what this doc comment will mention: + * ~ Additional restrictions on some methods. Others included for completeness. + * ~ ListIterator and what it can do + * ~ Positional and iterated access + * ~ search (but linear time) + * ~ be careful when containing self as an element, because equals and hashCode + * loop.] + */ +public interface List extends Collection { + + /** + * Insert an element into the list at a given position. + * + * @param index the location to insert the item. + * @param o the object to insert. + * @exception UnsupportedOperationException if this list does not support the + * add operation. + * @exception IndexOutOfBoundsException if index < 0 || index > size() + * @exception ClassCastException if o cannot be added to this list due to its + * type. + * @exception IllegalArgumentException if o cannot be added to this list for + * some other reason. + */ + void add(int index, Object o); + + /** + * Add an element to the end of the list. + * + * @param o the object to add. + * @returns true, as Collection defines this method as returning true if the + * list was modified as a result of this action, and it always is for a + * list. + * @exception UnsupportedOperationException if this list does not support the + * add operation. + * @exception ClassCastException if o cannot be added to this list due to its + * type. + * @exception IllegalArgumentException if o cannot be added to this list for + * some other reason. + */ + boolean add(Object o); + + /** + * Insert the contents of a collection into the list at a given position. + * + * @param index the location to insert the collection. + * @param c the collection to insert. + * @returns true if the list was modified by this action, that is, if c is + * non-empty. + * @exception UnsupportedOperationException if this list does not support the + * addAll operation. + * @exception IndexOutOfBoundsException if index < 0 || index > size() + * @exception ClassCastException if some element of c cannot be added to this + * list due to its type. + * @exception IllegalArgumentException if some element of c cannot be added + * to this list for some other reason. + */ + boolean addAll(int index, Collection c); + + /** + * Add the contents of a collection to the end of the list. + * + * @param c the collection to add. + * @returns true if the list was modified by this action, that is, if c is + * non-empty. + * @exception UnsupportedOperationException if this list does not support the + * addAll operation. + * @exception ClassCastException if some element of c cannot be added to this + * list due to its type. + * @exception IllegalArgumentException if some element of c cannot be added + * to this list for some other reason. + */ + boolean addAll(Collection c); + + /** + * Clear the list, such that a subsequent call to isEmpty() would return + * true. + * + * @exception UnsupportedOperationException if this list does not support the + * clear operation. + */ + void clear(); + + /** + * Test whether this list contains a given object as one of its elements. + * + * @param o the element to look for. + * @returns true if this list contains an element e such that o == + * null ? e == null : o.equals(e). + */ + boolean contains(Object o); + + /** + * Test whether this list contains every element in a given collection. + * + * @param c the collection to test for. + * @returns true if for every element o in c, contains(o) would return true. + */ + boolean containsAll(Collection c); + + /** + * Test whether this list is equal to another object. A List is defined to be + * equal to an object if and only if that object is also a List, and the two + * lists are equal. Two lists l1 and l2 are defined to be equal if and only + * if l1.size() == l2.size(), and for every integer n between 0 + * and l1.size() - 1 inclusive, l1.get(n) == null ? + * l2.get(n) == null : l1.get(n).equals(l2.get(n)). + * + * @param o the object to test for equality with this list. + * @returns true if o is equal to this list. + */ + boolean equals(Object o); + + /** + * Get the element at a given index in this list. + * + * @param index the index of the element to be returned. + * @returns the element at index index in this list. + * @exception IndexOutOfBoundsException if index < 0 || index >= size() + */ + Object get(int index); + + /** + * Obtain a hash code for this list. In order to obey the general contract of + * the hashCode method of class Object, this value is calculated as follows: + *
+   *   hashCode = 1;
+   *   Iterator i = list.iterator();
+   *   while (i.hasNext()) {
+   *     Object obj = i.next();
+   *     hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
+   *   }
+   * 
+ * This ensures that the general contract of Object.hashCode() is adhered to. + * + * @returns the hash code of this list. + */ + int hashCode(); + + /** + * Obtain the first index at which a given object is to be found in this + * list. + * + * @returns the least integer n such that o == null ? get(n) == null : + * o.equals(get(n)), or -1 if there is no such index. + */ + int indexOf(Object o); + + /** + * Test whether this list is empty, that is, if size() == 0. + * + * @returns true if this list contains no elements. + */ + boolean isEmpty(); + + /** + * Obtain an Iterator over this list. + * + * @returns an Iterator over the elements of this list, in order. + */ + Iterator iterator(); + + /** + * Obtain the last index at which a given object is to be found in this + * list. + * + * @returns the greatest integer n such that o == null ? get(n) == null + * : o.equals(get(n)). + */ + int lastIndexOf(Object o); + + /** + * Obtain a ListIterator over this list, starting at the beginning. + * + * @returns a ListIterator over the elements of this list, in order, starting + * at the beginning. + */ + ListIterator listIterator(); + + /** + * Obtain a ListIterator over this list, starting at a given position. + * + * @param index the position, between 0 and size() inclusive, to begin the + * iteration from. + * @returns a ListIterator over the elements of this list, in order, starting + * at index. + * @exception IndexOutOfBoundsException if index < 0 || index > size() + */ + ListIterator listIterator(int index); + + /** + * Remove the element at a given position in this list. + * + * @param index the position within the list of the object to remove. + * @returns the object that was removed. + * @exception UnsupportedOperationException if this list does not support the + * remove operation. + * @exception IndexOutOfBoundsException if index < 0 || index > size() + */ + Object remove(int index); + + /** + * Remove the first occurence of an object from this list. That is, remove + * the first element e such that o == null ? e == null : + * o.equals(e). + * + * @param o the object to remove. + * @returns true if the list changed as a result of this call, that is, if + * the list contained at least one occurrence of o. + * @exception UnsupportedOperationException if this list does not support the + * remove operation. + */ + boolean remove(Object o); + + /** + * Remove all elements of a given collection from this list. That is, remove + * every element e such that c.contains(e). + * + * @returns true if this list was modified as a result of this call. + * @exception UnsupportedOperationException if this list does not support the + * removeAll operation. + */ + boolean removeAll(Collection c); + + /** + * Remove all elements of this list that are not contained in a given + * collection. That is, remove every element e such that !c.contains(e). + * + * @returns true if this list was modified as a result of this call. + * @exception UnsupportedOperationException if this list does not support the + * retainAll operation. + */ + boolean retainAll(Collection c); + + /** + * Replace an element of this list with another object. + * + * @param index the position within this list of the element to be replaced. + * @param o the object to replace it with. + * @returns the object that was replaced. + * @exception UnsupportedOperationException if this list does not support the + * set operation. + * @exception IndexOutOfBoundsException if index < 0 || index >= size() + * @exception ClassCastException if o cannot be added to this list due to its + * type. + * @exception IllegalArgumentException if o cannot be added to this list for + * some other reason. + */ + Object set(int index, Object o); + + /** + * Get the number of elements in this list. + * + * @returns the number of elements in the list. + */ + int size(); + + /** + * Obtain a List view of a subsection of this list, from fromIndex + * (inclusive) to toIndex (exclusive). The returned list should be modifiable + * if and only if this list is modifiable. Changes to the returned list + * should be reflected in this list. If this list is structurally modified in + * any way other than through the returned list, the result of any subsequent + * operations on the returned list is undefined. + * + * @param fromIndex the index that the returned list should start from + * (inclusive). + * @param toIndex the index that the returned list should go to (exclusive). + * @returns a List backed by a subsection of this list. + * @exception IndexOutOfBoundsException if fromIndex < 0 || toIndex > size() + * || fromIndex > toIndex. + */ + List subList(int fromIndex, int toIndex); + + /** + * Copy the current contents of this list into an array. + * + * @returns an array of type Object[] and length equal to the length of this + * list, containing the elements currently in this list, in order. + */ + Object[] toArray(); + + /** + * Copy the current contents of this list into an array. If the array passed + * as an argument has length less than that of this list, an array of the + * same run-time type as a, and length equal to the length of this list, is + * allocated using Reflection. Otherwise, a itself is used. The elements of + * this list are copied into it, and if there is space in the array, the + * following element is set to null. The resultant array is returned. + * Note: The fact that the following element is set to null is only useful + * if it is known that this list does not contain any null elements. + * + * @param a the array to copy this list into. + * @returns an array containing the elements currently in this list, in + * order. + * @exception ArrayStoreException if the type of any element of the + * collection is not a subtype of the element type of a. + */ + Object[] toArray(Object[] a); +} diff --git a/jode/jode/util/ListIterator.java b/jode/jode/util/ListIterator.java new file mode 100644 index 0000000..ad72b53 --- /dev/null +++ b/jode/jode/util/ListIterator.java @@ -0,0 +1,145 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// ListIterator.java -- Extended Iterator for iterating over ordered lists +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +package jode.util; + +/** + * An extended version of Iterator to support the extra features of Lists. The + * elements may be accessed in forward or reverse order, elements may be + * replaced as well as removed, and new elements may be inserted, during the + * traversal of the list. + */ +public interface ListIterator extends Iterator { + + /** + * Tests whether there are elements remaining in the list in the forward + * direction. + * + * @return true if there is at least one more element in the list in the + * forward direction, that is, if the next call to next will not throw + * NoSuchElementException. + */ + boolean hasNext(); + + /** + * Tests whether there are elements remaining in the list in the reverse + * direction. + * + * @return true if there is at least one more element in the list in the + * reverse direction, that is, if the next call to previous will not throw + * NoSuchElementException. + */ + boolean hasPrevious(); + + /** + * Obtain the next element in the list in the forward direction. Repeated + * calls to next may be used to iterate over the entire list, or calls to next + * and previous may be used together to go forwards and backwards. Alternating + * calls to next and previous will return the same element. + * + * @return the next element in the list in the forward direction + * @exception NoSuchElementException if there are no more elements + */ + Object next(); + + /** + * Obtain the next element in the list in the reverse direction. Repeated + * calls to previous may be used to iterate backwards over the entire list, or + * calls to next and previous may be used together to go forwards and + * backwards. Alternating calls to next and previous will return the same + * element. + * + * @return the next element in the list in the reverse direction + * @exception NoSuchElementException if there are no more elements + */ + Object previous(); + + /** + * Find the index of the element that would be returned by a call to next. + * + * @return the index of the element that would be returned by a call to next, + * or list.size() if the iterator is at the end of the list. + */ + int nextIndex(); + + /** + * Find the index of the element that would be returned by a call to previous. + * + * @return the index of the element that would be returned by a call to + * previous, or -1 if the iterator is at the beginning of the list. + */ + int previousIndex(); + + /** + * Insert an element into the list at the current position of the iterator. + * The element is inserted in between the element that would be returned by + * previous and the element that would be returned by next. After the + * insertion, a subsequent call to next is unaffected, but a call to + * previous returns the item that was added. This operation is optional, it + * may throw an UnsupportedOperationException. + * + * @param o the object to insert into the list + * @exception ClassCastException the object is of a type which cannot be added + * to this list + * @exception IllegalArgumentException some other aspect of the object stops + * it being added to this list + * @exception UnsupportedOperationException if this ListIterator does not + * support the add operation + */ + void add(Object o); + + /** + * Remove from the list the element last returned by a call to next or + * previous. This method may only be called if neither add nor remove have + * been called since the last call to next or previous. This operation is + * optional, it may throw an UnsupportedOperationException. + * + * @exception IllegalStateException if neither next or previous have been + * called, or if add or remove has been called since the last call to next + * or previous. + * @exception UnsupportedOperationException if this ListIterator does not + * support the remove operation. + */ + void remove(); + + /** + * Replace the element last returned by a call to next or previous with a + * given object. This method may only be called if neither add nor remove have + * been called since the last call to next or previous. This operation is + * optional, it may throw an UnsupportedOperationException. + * + * @param o the object to replace the element with + * @exception ClassCastException the object is of a type which cannot be added + * to this list + * @exception IllegalArgumentException some other aspect of the object stops + * it being added to this list + * @exception IllegalStateException if neither next or previous have been + * called, or if add or remove has been called since the last call to next + * or previous. + * @exception UnsupportedOperationException if this ListIterator does not + * support the set operation. + */ + void set(Object o); +} diff --git a/jode/jode/util/Map.java b/jode/jode/util/Map.java new file mode 100644 index 0000000..6058c07 --- /dev/null +++ b/jode/jode/util/Map.java @@ -0,0 +1,55 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// Map.java -- An object that maps keys to values +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Doc comments for everything. + +package jode.util; + +public interface Map +{ + public void clear(); + public boolean containsKey(Object key); + public boolean containsValue(Object value); + public Set entrySet(); + public boolean equals(Object o); + public Object get(Object key); + public Object put(Object key, Object value); + public int hashCode(); + public boolean isEmpty(); + public Set keySet(); + public void putAll(Map m); + public Object remove(Object o); + public int size(); + public Collection values(); + + public static interface Entry { + public Object getKey(); + public Object getValue(); + public Object setValue(Object value); + public int hashCode(); + public boolean equals(Object o); + } +} diff --git a/jode/jode/util/Set.java b/jode/jode/util/Set.java new file mode 100644 index 0000000..69896e7 --- /dev/null +++ b/jode/jode/util/Set.java @@ -0,0 +1,46 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// Set.java -- A collection that prohibits duplicates +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Doc comments for everything. + +package jode.util; + +public interface Set extends Collection { + boolean add(Object o); + boolean addAll(Collection c); + void clear(); + boolean contains(Object o); + boolean containsAll(Collection c); + boolean equals(Object o); + int hashCode(); + boolean isEmpty(); + Iterator iterator(); + boolean remove(Object o); + boolean removeAll(Collection c); + boolean retainAll(Collection c); + int size(); + Object[] toArray(); +} diff --git a/jode/jode/util/SimpleMap.java b/jode/jode/util/SimpleMap.java new file mode 100644 index 0000000..4d532d9 --- /dev/null +++ b/jode/jode/util/SimpleMap.java @@ -0,0 +1,100 @@ +/* SimpleMap Copyright (C) 1999 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +package jode.util; +///#ifdef JDK12 +///import java.util.AbstractMap; +///import java.util.Map; +///import java.util.Iterator; +///import java.util.Set; +///#endif + +/** + * This is a very simple map, using a set as backing. + * The default backing set is a simple set, but you can specify any other + * set of Map.Entry in the constructor. + */ +public class SimpleMap extends AbstractMap { + private Set backing; + + public SimpleMap() { + backing = new SimpleSet(); + } + + public SimpleMap(int initialCapacity) { + backing = new SimpleSet(initialCapacity); + } + + public SimpleMap(Set fromSet) { + backing = fromSet; + } + + public Set entrySet() { + return backing; + } + + public static class SimpleEntry implements Map.Entry { + Object key; + Object value; + + public SimpleEntry(Object key, Object value) { + this.key = key; + this.value = value; + } + + public Object getKey() { + return key; + } + + public Object getValue() { + return value; + } + + public Object setValue(Object newValue) { + Object old = value; + value = newValue; + return old; + } + + public int hashCode() { + return key.hashCode() ^ value.hashCode(); + } + + public boolean equals(Object o) { + if (o instanceof Map.Entry) { + Map.Entry e = (Map.Entry) o; + return key.equals(e.getKey()) && value.equals(e.getValue()); + } + return false; + } + } + + public Object put(Object key, Object value) { + for (Iterator i = backing.iterator(); + i.hasNext(); ) { + Map.Entry entry = (Map.Entry) i.next(); + if (key.equals(entry.getKey())) + return entry.setValue(value); + } + backing.add(new SimpleEntry(key, value)); + return null; + } +} + + diff --git a/jode/jode/util/SortedMap.java b/jode/jode/util/SortedMap.java new file mode 100644 index 0000000..66fb250 --- /dev/null +++ b/jode/jode/util/SortedMap.java @@ -0,0 +1,38 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// SortedMap.java -- A map that makes guarantees about the order of its keys +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Doc comments for everything. + +package jode.util; + +public interface SortedMap extends Map { + Comparator comparator(); + Object firstKey(); + SortedMap headMap(Object toKey); + Object lastKey(); + SortedMap subMap(Object fromKey, Object toKey); + SortedMap tailMap(Object fromKey); +} diff --git a/jode/jode/util/SortedSet.java b/jode/jode/util/SortedSet.java new file mode 100644 index 0000000..46c54bd --- /dev/null +++ b/jode/jode/util/SortedSet.java @@ -0,0 +1,38 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +///////////////////////////////////////////////////////////////////////////// +// SortedSet.java -- A set that makes guarantees about the order of its elements +// +// Copyright (c) 1998 by Stuart Ballard (stuart.ballard@mcmail.com) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License as published +// by the Free Software Foundation, version 2. (see COPYING.LIB) +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this program; if not, write to the Free Software Foundation +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +///////////////////////////////////////////////////////////////////////////// + +// TO DO: +// ~ Doc comments for everything. + +package jode.util; + +public interface SortedSet extends Set { + Comparator comparator(); + Object first(); + SortedSet headSet(Object toElement); + Object last(); + SortedSet subSet(Object fromElement, Object toElement); + SortedSet tailSet(Object fromElement); +} diff --git a/jode/jode/util/UnsupportedOperationException.java b/jode/jode/util/UnsupportedOperationException.java new file mode 100644 index 0000000..2934959 --- /dev/null +++ b/jode/jode/util/UnsupportedOperationException.java @@ -0,0 +1,54 @@ +// This interface is taken from the Classpath project. +// Please note the different copyright holder! +// The changes I did is this comment, the package line, some +// imports from java.util and some minor jdk12 -> jdk11 fixes. +// -- Jochen Hoenicke + +/************************************************************************* +/* UnsupportedOperationException.java -- Exception thrown when an +/* unsupported operation is attempted on an object +/* +/* Copyright (c) 1998 by Free Software Foundation, Inc. +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation, version 2. (see COPYING.LIB) +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with this program; if not, write to the Free Software Foundation +/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA +/*************************************************************************/ + +package jode.util; + +/** + * This exception is thrown by an object when an operation is + * requested of it that it does not support. + * + * @since JDK 1.2 + */ +public class UnsupportedOperationException extends RuntimeException +{ + static final long serialVersionUID = -1242599979055084673L; + + /** + * Create an exception without a message. + */ + public UnsupportedOperationException() + { + super(); + } + + /** + * Create an exception with a message. + */ + public UnsupportedOperationException( String s ) + { + super(s); + } +}