/* * Javolution - Java(TM) Solution for Real-Time and Embedded Systems * Copyright (C) 2006 - Javolution (http://javolution.org/) * All rights reserved. * * Permission to use, copy, modify, and distribute this software is * freely granted, provided that this notice is preserved. */ package javolution.util; import j2me.util.Collection; import j2me.util.Iterator; import j2me.util.List; import j2me.util.ListIterator; import j2me.util.Set; import j2me.lang.UnsupportedOperationException; import j2mex.realtime.MemoryArea; import javolution.lang.Realtime; import javolution.text.Text; //import javolution.xml.XMLSerializable; /** *
This class represents collections which can quickly be iterated over * (forward or backward) in a thread-safe manner without creating new * objects and without using {@link #iterator iterators} . For example:[code] * boolean search(Object item, FastCollection c) { * for (Record r = c.head(), end = c.tail(); (r = r.getNext()) != end;) { * if (item.equals(c.valueOf(r))) return true; * } * return false; * }[/code]
* *Iterations are thread-safe as long as the {@link Record record} sequence * iterated over is not structurally modified by another thread * (objects can safely be append/prepend during iterations but not * inserted/removed).
* * Users may provide a read-only view of any {@link FastCollection}
* instance using the {@link #unmodifiable()} method (the view is
* thread-safe if iterations are thread-safe). For example:[code]
* public class Polynomial {
* private final FastTable
Finally, {@link FastCollection} may use custom {@link #getValueComparator
* comparators} for element equality or ordering if the collection is
* ordered (e.g. Implementation must ensure that removing a record from the
* collection does not affect in any way the records preceding
* the record being removed (it might affect the next records though,
* e.g. in a list collection, the indices of the subsequent records
* will change). Note: This default implementation always throws
* Note: To avoid heap allocation {@link #toArray(Object[])} is
* recommended. Note: Unlike standard Collection, this method does not try to resize
* the array using reflection (which might not be supported) if
* the array is too small. UnsupportedOperationException is raised
* if the specified array is too small for this collection.FastTree
).
*
* @author Jean-Marie Dautelle
* @version 4.2, December 18, 2006
*/
public abstract class FastCollection/*head().getNext()
holds the first collection value.
*
* @return the head record.
*/
public abstract Record head();
/**
* Returns the tail record of this collection; it is the record such as
* tail().getPrevious()
holds the last collection value.
*
* @return the tail record.
*/
public abstract Record tail();
/**
* Returns the collection value for the specified record.
*
* @param record the record whose current value is returned.
* @return the current value.
*/
public abstract Object/*{E}*/valueOf(Record record);
/**
* Deletes the specified record from this collection.
*
* UnsupportedOperationException
.true
(as per the general contract of the
* Collection.add
method).
* @throws UnsupportedOperationException if not supported.
*/
public boolean add(Object/*{E}*/value) {
throw new UnsupportedOperationException();
}
/**
* Removes the first occurrence in this collection of the specified value
* (optional operation).
*
* @param value the value to be removed from this collection.
* @return true
if this collection contained the specified
* value; false
otherwise.
* @throws UnsupportedOperationException if not supported.
*/
public boolean remove(Object value) {
final FastComparator valueComp = this.getValueComparator();
for (Record r = head(), end = tail(); (r = r.getNext()) != end;) {
if (valueComp.areEqual(value, valueOf(r))) {
delete(r);
return true;
}
}
return false;
}
/**
* Removes all of the values from this collection (optional operation).
*
* @throws UnsupportedOperationException if not supported.
*/
public void clear() {
// Removes last record until empty.
for (Record head = head(), r = tail().getPrevious(); r != head; r = r
.getPrevious()) {
delete(r);
}
}
/**
* Indicates if this collection is empty.
*
* @return true
if this collection contains no value;
* false
otherwise.
*/
public final boolean isEmpty() {
return size() == 0;
}
/**
* Indicates if this collection contains the specified value.
*
* @param value the value whose presence in this collection
* is to be tested.
* @return true
if this collection contains the specified
* value;false
otherwise.
*/
public boolean contains(Object value) {
final FastComparator valueComp = this.getValueComparator();
for (Record r = head(), end = tail(); (r = r.getNext()) != end;) {
if (valueComp.areEqual(value, valueOf(r)))
return true;
}
return false;
}
/**
* Appends all of the values in the specified collection to the end of
* this collection, in the order that they are returned by the specified
* collection's iterator or the node order if the specified collection
* is a {@link FastCollection}.
*
* @param c collection whose values are to be added to this collection.
* @return true
if this collection changed as a result of
* the call; false
otherwise.
*/
public boolean addAll(Collection/* extends E>*/c) {
if (c instanceof FastCollection)
return addAll((FastCollection) c);
boolean modified = false;
Iterator/* extends E>*/itr = c.iterator();
int pos = c.size();
while (--pos >= 0) {
if (add(itr.next())) {
modified = true;
}
}
return modified;
}
private boolean addAll(FastCollection/* extends E>*/c) {
if (c instanceof FastTable)
return addAll((FastTable) c);
boolean modified = false;
for (Record r = c.head(), end = c.tail(); (r = r.getNext()) != end;) {
if (this.add(c.valueOf(r))) {
modified = true;
}
}
return modified;
}
private boolean addAll(FastTable/* extends E>*/c) {
boolean modified = false;
for (int i=0, n = c.size(); i < n;) { // Faster than direct iterators.
if (this.add(c.get(i++))) {
modified = true;
}
}
return modified;
}
/**
* Indicates if this collection contains all of the values of the
* specified collection.
*
* @param c collection to be checked for containment in this collection.
* @return true
if this collection contains all of the values
* of the specified collection; false
otherwise.
*/
public boolean containsAll(Collection/*>*/c) {
if (c instanceof FastCollection)
return containsAll((FastCollection) c);
Iterator/*>*/itr = c.iterator();
int pos = c.size();
while (--pos >= 0) {
if (!contains(itr.next())) {
return false;
}
}
return true;
}
private boolean containsAll(FastCollection/*>*/c) {
for (Record r = c.head(), end = c.tail(); (r = r.getNext()) != end;) {
if (!contains(c.valueOf(r))) {
return false;
}
}
return true;
}
/**
* Removes from this collection all the values that are contained in the
* specified collection.
*
* @param c collection that defines which values will be removed from
* this collection.
* @return true
if this collection changed as a result of
* the call; false
otherwise.
*/
public boolean removeAll(Collection/*>*/c) {
boolean modified = false;
// Iterates from the tail and removes the record if present in c.
for (Record head = head(), r = tail().getPrevious(), previous; r != head; r = previous) {
previous = r.getPrevious(); // Saves previous.
if (c.contains(valueOf(r))) {
delete(r);
modified = true;
}
}
return modified;
}
/**
* Retains only the values in this collection that are contained in the
* specified collection.
*
* @param c collection that defines which values this set will retain.
* @return true
if this collection changed as a result of
* the call; false
otherwise.
*/
public boolean retainAll(Collection/*>*/c) {
boolean modified = false;
// Iterates from the tail and remove the record if not present in c.
for (Record head = head(), r = tail().getPrevious(), previous; r != head; r = previous) {
previous = r.getPrevious(); // Saves previous.
if (!c.contains(valueOf(r))) {
delete(r);
modified = true;
}
}
return modified;
}
/**
* Returns a new array allocated on the heap containing all of the values
* in this collection in proper sequence.
* toArray(new Object[size()])
*/
public Object[] toArray() {
return toArray(new Object[size()]);
}
/**
* Fills the specified array with the values of this collection in
* the proper sequence.
*
* array.length < size()
*/
public Object/*{String
representation of this
* {@link FastCollection}.
*
* @return toText().toString()
*/
public final String toString() {
return toText().toString();
}
/**
* Compares the specified object with this collection for equality. Returns
* true
if and only both collection contains the same values
* regardless of the order; unless this collection is a list instance
* in which case both collections must be list with the same order.
*
* @param obj the object to be compared for equality with this collection.
* @return true
if the specified object is equal to this
* collection; false
otherwise.
*/
public boolean equals(Object obj) {
if (this instanceof List)
return equalsList(obj);
return obj == this
|| (obj instanceof Collection
&& ((Collection) obj).size() == size() && containsAll((Collection) obj));
}
private boolean equalsList(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof List))
return false;
if (obj instanceof FastCollection)
return equalsList((FastCollection)obj);
List that = (List) obj;
if (this.size() != that.size())
return false;
Iterator thatIterator = that.iterator();
final FastComparator comp = this.getValueComparator();
for (Record r = head(), end = tail(); (r = r.getNext()) != end;) {
Object o1 = valueOf(r);
Object o2 = thatIterator.next();
if (!comp.areEqual(o1, o2))
return false;
}
return true;
}
private boolean equalsList(FastCollection that) {
if (this.size() != that.size())
return false;
Record t = that.head();
final FastComparator comp = this.getValueComparator();
for (Record r = head(), end = tail(); (r = r.getNext()) != end;) {
Object o1 = valueOf(r);
Object o2 = that.valueOf(t = t.getNext());
if (!comp.areEqual(o1, o2))
return false;
}
return true;
}
/**
* Returns the hash code for this collection (independent from the
* collection order; unless this collection is a list instance).
*
* @return the hash code for this collection.
*/
public int hashCode() {
if (this instanceof List)
return hashCodeList();
final FastComparator valueComp = this.getValueComparator();
int hash = 0;
for (Record r = head(), end = tail(); (r = r.getNext()) != end;) {
hash += valueComp.hashCodeOf(valueOf(r));
}
return hash;
}
private int hashCodeList() {
final FastComparator comp = this.getValueComparator();
int h = 1;
for (Record r = head(), end = tail(); (r = r.getNext()) != end;) {
h = 31 * h + comp.hashCodeOf(valueOf(r));
}
return h;
}
/**
* This interface represents the collection records which can directly be
* iterated over.
*/
public interface Record {
/**
* Returns the record before this one.
*
* @return the previous record.
*/
public Record getPrevious();
/**
* Returns the record after this one.
*
* @return the next record.
*/
public Record getNext();
}
/**
* This inner class represents an unmodifiable view over the collection.
*/
private final class Unmodifiable extends FastCollection implements
Set, List { // Allows to be used for unmodifiable set/list view.
// Implements abstract method.
public int size() {
return FastCollection.this.size();
}
// Implements abstract method.
public Record head() {
return FastCollection.this.head();
}
// Implements abstract method.
public Record tail() {
return FastCollection.this.tail();
}
// Implements abstract method.
public Object valueOf(Record record) {
return FastCollection.this.valueOf(record);
}
// Forwards...
public boolean contains(Object value) {
return (FastCollection.this).contains(value);
}
// Forwards...
public boolean containsAll(Collection c) {
return (FastCollection.this).containsAll(c);
}
// Forwards...
public FastComparator getValueComparator() {
return FastCollection.this.getValueComparator();
}
// Disallows...
public boolean add(Object obj) {
throw new UnsupportedOperationException("Unmodifiable");
}
// Disallows...
public void delete(Record node) {
throw new UnsupportedOperationException("Unmodifiable");
}
//////////////////////////////////////////
// List interface supplementary methods //
//////////////////////////////////////////
public boolean addAll(int index, Collection c) {
throw new UnsupportedOperationException("Unmodifiable");
}
public Object get(int index) {
return ((List)FastCollection.this).get(index);
}
public Object set(int index, Object element) {
throw new UnsupportedOperationException("Unmodifiable");
}
public void add(int index, Object element) {
throw new UnsupportedOperationException("Unmodifiable");
}
public Object remove(int index) {
throw new UnsupportedOperationException("Unmodifiable");
}
public int indexOf(Object o) {
return ((List)FastCollection.this).indexOf(o);
}
public int lastIndexOf(Object o) {
return ((List)FastCollection.this).lastIndexOf(o);
}
public ListIterator listIterator() {
throw new UnsupportedOperationException(
"List iterator not supported for unmodifiable collection");
}
public ListIterator listIterator(int index) {
throw new UnsupportedOperationException(
"List iterator not supported for unmodifiable collection");
}
public List subList(int fromIndex, int toIndex) {
throw new UnsupportedOperationException(
"Sub-List not supported for unmodifiable collection");
}
}
}