Files
Brainstorm/Common/src/com/common/util/LiteCollection.java
2014-05-30 10:31:51 -07:00

532 lines
16 KiB
Java

/*
* Copyright (c) 2002,2008 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.common.util;
import java.util.Arrays;
import com.common.comparison.Comparator;
import com.common.comparison.IComparator;
import com.common.event.*;
import com.common.exception.*;
/**
* The LiteCollection base class provides collection functionality without any event handling or synchronization.
* If you need event handling or synchronization you should use a collection class that extends Collection.
*/
public abstract class LiteCollection implements ICollection {
private boolean isChangeable = true;
/**
* LiteCollection constructor.
*/
protected LiteCollection() {
super();
}//LiteCollection()//
/**
* LiteCollection constructor.
* @param isChangeable Whether the collection may be changed. This should be false if the collection may no longer be modified.
*/
protected LiteCollection(boolean isChangeable) {
super();
this.isChangeable = isChangeable;
}//LiteCollection()//
/**
* Ensures that the collection can hold at least the number of components specified by the minimum capacity argument.
* @param minimumCapacity The desired minimum capacity of this collection (above what it currently holds).
*/
public abstract void ensureCapacity(int minimumCapacity);
/* (non-Javadoc)
* @see com.common.util.ICollection#add(java.lang.Object)
*/
public int add(Object value) {
//Verify that the collection can be modified.//
verifyIsChangeable();
return internalAdd(value);
}//add()//
/* (non-Javadoc)
* @see com.common.util.ICollection#addAll(java.lang.Object[])
*/
public boolean addAll(Object[] values) {
return addAll(values, 0, values.length);
}//addAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#addAll(java.lang.Object[], int, int)
*/
public boolean addAll(Object[] values, int offset, int length) {
boolean result = true;
//Verify that the collection can be modified.//
verifyIsChangeable();
//Resize the collection only once if it requires it at all.//
ensureCapacity(length);
//Make sure that the collection has values.//
if((values != null) && (values.length > 0) && (length + offset <= values.length) && (offset >= 0)) {
Object next = null;
//Iterate over the items to be added and add them one at a time.//
for(int index = offset; index < length; index++) {
next = values[index];
if(internalAdd(next) == -1) {
result = false;
}//if//
}//while//
}//if//
else {
result = false;
}//else//
return result;
}//addAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#addAll(com.common.util.ICollection)
*/
public boolean addAll(ICollection values) {
boolean result = true;
if(values instanceof IIndexedCollection) {
result = addAll((IIndexedCollection) values, 0, values.getSize());
}//if//
else {
//Verify that the collection can be modified.//
verifyIsChangeable();
//Resize the collection only once if it requires it at all.//
ensureCapacity(values.getSize());
//Make sure that the collection has values.//
if((values != null) && (values.getSize() > 0)) {
Object next = null;
//Iterate over the items to be added and add them one at a time.//
for(IIterator iterator = values.iterator(); iterator.hasNext(); ) {
next = iterator.next();
if(internalAdd(next) == -1) {
result = false;
}//if//
}//for//
}//if//
else {
result = false;
}//else//
}//else//
return result;
}//addAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#addAll(com.common.util.IIndexedCollection, int, int)
*/
public boolean addAll(IIndexedCollection values, int offset, int length) {
boolean result = true;
//Verify that the collection can be modified.//
verifyIsChangeable();
//Resize the collection only once if it requires it at all.//
ensureCapacity(length);
//Make sure that the collection has values.//
if((values != null) && (length > 0)) {
Object next = null;
//Iterate over the items to be added and add them one at a time.//
for(int valuesIndex = offset, count = offset + length; valuesIndex < count; valuesIndex++) {
next = values.get(valuesIndex);
if(internalAdd(next) == -1) {
result = false;
}//if//
}//for//
}//if//
else {
result = false;
}//else//
return result;
}//addAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#addAll(com.common.util.IIterator)
*/
public boolean addAll(IIterator values) {
boolean result = true;
//Verify that the collection can be modified.//
verifyIsChangeable();
//Make sure that the collection has values.//
if(values != null) {
Object next = null;
//Iterate over the items to be added and add them one at a time.//
while(values.hasNext()) {
next = values.next();
if(internalAdd(next) == -1) {
result = false;
}//if//
}//for//
}//if//
else {
result = false;
}//else//
return result;
}//addAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#collect(com.common.event.ObjectHandler1, com.common.util.IList)
*/
public IList collect(ObjectHandler1 handler, IList results) {
IIterator iterator = iterator();
if(results == null) {
results = new LiteList(getSize());
}//if//
//Iterate over the items in this collection passing them to the handler, and collect the resulting values.//
while(iterator.hasNext()) {
results.add(handler.evaluate(iterator.next()));
}//while//
return results;
}//collect()//
/* (non-Javadoc)
* @see com.common.util.ICollection#containsValue(java.lang.Object)
*/
public abstract boolean containsValue(Object value);
/* (non-Javadoc)
* @see com.common.util.ICollection#getSize()
*/
public abstract int getSize();
/**
* Will add a value to the collection.
* @param value Object The value to add.
* @return The index of the addition if the collection is indexed, 0 if the collection is not indexed, or -1 if the operation failed.
*/
protected abstract int internalAdd(Object value);
/**
* Will remove a value from the collection.
* @param value Object The value to remove.
* @return boolean Will return true if the operation was successful.
*/
protected abstract boolean internalRemove(Object value);
/**
* Will remove all of the values in the collection.
* @return boolean Will return true if the operation was successful.
*/
protected abstract void internalRemoveAll();
/**
* Replaces one value with another in the collection.
* @param oldValue Object The value to replace.
* @param newValue Object The value to insert.
* @return boolean Will return true if the operation was successful.
*/
protected abstract boolean internalReplace(Object oldValue, Object newValue);
/**
* Replaces the values currently in the collection with the given collection of values.
* @param values The values to replace the ones currently in the collection.
* @return Returns true if the operation was successful.
*/
protected abstract boolean internalReplaceAll(ICollection values);
/**
* Replaces the removed values in the current collection with those in the added values collection.
* @param removedValues The values to be replaced.
* @param addedValues The values to replace the removed values. Note that the collections need not be of the same size.
* @return Whether the operation completed successfully. The operation may only partially complete if this is false.
*/
protected abstract boolean internalReplaceAll(ICollection removedValues, ICollection addedValues);
/* (non-Javadoc)
* @see com.common.util.ICollection#isChangeable()
*/
public boolean isChangeable() {
return isChangeable;
}//isChangeable()//
/* (non-Javadoc)
* @see com.common.util.ICollection#isChangeable(boolean)
*/
public void isChangeable(boolean isChangeable) {
if(!isChangeable) {
this.isChangeable = isChangeable;
}//if//
else if(this.isChangeable == isChangeable) {
//Do nothing as nothing has changed.//
}//else if//
else {
throw new RuntimeException("You may not change the collection to be changeable after it has been locked.");
}//else//
}//isChangeable()//
/* (non-Javadoc)
* @see com.common.util.ICollection#iterator()
*/
public abstract IIterator iterator();
/* (non-Javadoc)
* @see com.common.util.ICollection#perform(com.common.event.VoidHandler1)
*/
public void perform(VoidHandler1 handler) {
IIterator iterator = iterator();
//Iterate over the items in this collection passing them to the handler to perform some function.//
while(iterator.hasNext()) {
handler.evaluate(iterator.next());
}//while//
}//perform()//
/**
* Will read the collection from the stream.
* @param in java.io.ObjectInput The stream that the object data can be read from.
*/
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
}//readExternal()//
/* (non-Javadoc)
* @see com.common.util.ICollection#reject(com.common.event.BooleanHandler1, com.common.util.IList)
*/
public IList reject(BooleanHandler1 handler, IList results) {
IIterator iterator = iterator();
if(results == null) {
results = new LiteList(10, 50);
}//if//
//Iterate over the items in this collection passing them to the handler, and collect the resulting values.//
while(iterator.hasNext()) {
Object value = iterator.next();
if(!handler.evaluate(value).booleanValue()) {
results.add(value);
}//if//
}//while//
return results;
}//reject()//
/* (non-Javadoc)
* @see com.common.util.ICollection#remove(java.lang.Object)
*/
public boolean remove(Object value) {
//Verify that the collection can be modified.//
verifyIsChangeable();
return internalRemove(value);
}//remove()//
/* (non-Javadoc)
* @see com.common.util.ICollection#removeAll()
*/
public void removeAll() {
//Verify that the collection can be modified.//
verifyIsChangeable();
internalRemoveAll();
}//removeAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#removeAll(java.lang.Object[])
*/
public boolean removeAll(Object[] values) {
return removeAll(values, 0, values.length);
}//removeAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#removeAll(java.lang.Object[], int, int)
*/
public boolean removeAll(Object[] values, int offset, int length) {
boolean result = true;
//Verify that this collection can be modified.//
verifyIsChangeable();
//Make sure that there are values to remove.//
if((values != null) && (values.length > 0) && (offset >= 0) && (offset + length <= values.length)) {
Object next = null;
//Remove the values one at a time.//
for(int index = offset; index < length; index++) {
next = values[index];
if(!internalRemove(next)) {
result = false;
}//if//
}//while//
}//if//
else {
result = false;
}//else//
return result;
}//removeAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#removeAll(com.common.util.ICollection)
*/
public boolean removeAll(ICollection values) {
boolean result = true;
//Verify that this collection can be modified.//
verifyIsChangeable();
//Make sure that there are values to remove.//
if((values != null) && (values.getSize() > 0)) {
Object next = null;
//Remove the values one at a time.//
for(IIterator iterator = values.iterator(); iterator.hasNext(); ) {
next = iterator.next();
if(!internalRemove(next)) {
result = false;
}//if//
}//for//
}//if//
else {
result = false;
}//else//
return result;
}//removeAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#removeAll(com.common.util.ICollection)
*/
public boolean removeAll(IIterator values) {
boolean result = true;
//Verify that this collection can be modified.//
verifyIsChangeable();
//Make sure that there are values to remove.//
if(values != null) {
Object next = null;
//Remove the values one at a time.//
while(values.hasNext()) {
next = values.next();
if(!internalRemove(next)) {
result = false;
}//if//
}//for//
}//if//
else {
result = false;
}//else//
return result;
}//removeAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#replace(java.lang.Object, java.lang.Object)
*/
public boolean replace(Object oldValue, Object newValue) {
//Verify that this collection can be modified.//
verifyIsChangeable();
return internalReplace(oldValue, newValue);
} //replace()//
/* (non-Javadoc)
* @see com.common.util.ICollection#replaceAll(com.common.util.ICollection)
*/
public boolean replaceAll(ICollection values) {
return internalReplaceAll(values);
}//replaceAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#replaceAll(com.common.util.ICollection, com.common.util.ICollection)
*/
public boolean replaceAll(ICollection removedValues, ICollection addedValues) {
return internalReplaceAll(removedValues, addedValues);
}//replaceAll()//
/* (non-Javadoc)
* @see com.common.util.ICollection#select(com.common.event.BooleanHandler1, com.common.util.IList)
*/
public IList select(BooleanHandler1 handler, IList results) {
IIterator iterator = iterator();
if(results == null) {
results = new LiteList(10, 50);
}//if//
//Iterate over the items in this collection passing them to the handler, and collect the resulting values.//
while(iterator.hasNext()) {
Object value = iterator.next();
if(handler.evaluate(value).booleanValue()) {
results.add(value);
}//if//
}//while//
return results;
}//select()//
/**
* Converts the list to an object array.
* @return Object[] An array of the values in the collection.
*/
public Object[] toArray() {
Object[] result = new Object[getSize()];
toArray(result);
return result;
}//toArray()//
/* (Non-Javadoc)
* @see ICollection.toArray(Object)
*/
public abstract int toArray(Object array);
/**
* Verifies that the collection may be modified.
* @throws IllegalOperationException If the isImmutable flag is set.
*/
protected void verifyIsChangeable() {
if(!isChangeable) {
throw new IllegalOperationException("The collection is immutable which prevents the collection from being modified.");
}//if//
}//verifyIsChangeable()//
/**
* Writes the collection to the stream.
* @param out java.io.ObjectOutput The stream that the object data can be written to.
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
}//writeExternal()//
/**
* Calculates the diffences between the old array and new array.
* @param oldArray The old array.
* @param newArray The new array.
* @param comparator The optional comparator used to determine equality. If null then exact equality will be used (==).
* @param added The optional set of items that are new in the new array (that don't exist in the old array).
* @param removed The optional set of items that are old in the old array (that don't exist in the new array).
* @param unchanged The optional set of items that have not changed and are in both arrays.
*/
public static void calculateDifferences(Object[] oldArray, Object[] newArray, IComparator comparator, ICollection added, ICollection removed, ICollection unchanged) {
boolean[] newMatched = new boolean[newArray.length];
Arrays.fill(newMatched, false);
if(comparator == null) {
comparator = Comparator.getIdentityComparator();
}//if//
//For each old item, see if it exists in the new items and add to the appropriate collections. Mark matched items so we can easily see which items are new.//
for(int oldIndex = 0; oldIndex < oldArray.length; oldIndex++) {
boolean found = false;
//Search for a match in the new collection.//
for(int newIndex = 0; (!found) && (newIndex < newArray.length); newIndex++) {
if((!newMatched[newIndex]) && (Comparator.isEqual(comparator.compare(oldArray[oldIndex], newArray[newIndex])))) {
found = true;
newMatched[newIndex] = true;
if(unchanged != null) {
unchanged.add(oldArray[oldIndex]);
}//if//
}//if//
}//for//
if((!found) && (removed != null)) {
removed.add(oldArray[oldIndex]);
}//if//
}//for//
//If we need to collect added items then iterate over the new items and add those that are not marked as matched.//
if(added != null) {
for(int newIndex = 0; newIndex < newArray.length; newIndex++) {
if(!newMatched[newIndex]) {
added.add(newArray[newIndex]);
}//if//
}//for//
}//if//
}//calculateDifferences()//
}//LiteCollection//