summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java
diff options
context:
space:
mode:
authorBenjamin Culkin <scorpress@gmail.com>2024-05-19 17:56:33 -0400
committerBenjamin Culkin <scorpress@gmail.com>2024-05-19 17:56:33 -0400
commitaedc34d55462a75e329bbf342251ff6504cd117e (patch)
treebcc8f1f2352582717b484df302aeea6696b8f000 /projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java
Initial import from SVN
Diffstat (limited to 'projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java')
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java661
1 files changed, 661 insertions, 0 deletions
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java
new file mode 100644
index 0000000..491722c
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSArray.java
@@ -0,0 +1,661 @@
+/*
+Wotonomy: OpenStep design patterns for pure Java applications.
+Copyright (C) 2000 Blacksmith, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, see http://www.gnu.org
+*/
+
+package net.wotonomy.foundation;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+* NSArray is an unmodifiable List.
+* Calling the mutator methods of the List interface (add, addAll,
+* set, etc.) on an instance of NSArray will throw an Unsupported
+* Operation exception: use a NSMutableArray instead. This is to
+* simulate Objective-C's pattern of exposing mutator methods only
+* on mutable subinterface, which is wonderful for communicating
+* via interface the contract on returned collections (whether you
+* may modify return values) as well as implementing array faults.
+*
+* @author michael@mpowers.net
+* @author $Author: cgruber $
+* @version $Revision: 929 $
+*/
+public class NSArray implements List, Serializable
+{
+ /**
+ * Actual list that backs this instance.
+ */
+ List list;
+
+ /**
+ * Return value when array index is not found.
+ */
+ public static final int NotFound = -1;
+
+ /**
+ * A constant representing an empty array.
+ */
+ public static final NSArray EmptyArray = new NSArray();
+
+ /**
+ * Returns an NSArray backed by the specified List.
+ * This is useful to "protect" an internal representation
+ * that is returned by a method of return type NSArray.
+ */
+ public static NSArray arrayBackedByList( List aList )
+ {
+ return new NSArray( aList, null );
+ }
+
+ /**
+ * A constructor that uses the provided list as the backing
+ * list object. This is unlike ArrayList and other
+ * java.util.Collection types insofar as that API requires
+ * that the provided Collection be copied into the newly constructed
+ * Collection.
+ *
+ * TODO: See if this signature can be reasonably changed, as having a no-op parameter is a little counter-intuitive.
+ * @param aList A list that the caller wishes to become the backing list for the NSArray.
+ * @param ignored This parameter is entirely ignored, and is only there to distinguish the API.
+ */
+ NSArray( List aList, Object ignored ) // differentiates
+ {
+ list = aList;
+ }
+
+ /**
+ * Constructor with a size hint, used by NSMutableArray.
+ */
+ NSArray( int aSize )
+ {
+ list = new ArrayList( aSize );
+ }
+
+ /**
+ * Default constructor returns an empty array.
+ */
+ public NSArray ()
+ {
+ list = new ArrayList();
+ }
+
+ /**
+ * Produces an array containing only the specified object.
+ */
+ public NSArray (Object anObject)
+ {
+ this();
+ list.add( anObject );
+ }
+
+ /**
+ * Produces an array containing the specified objects.
+ */
+ public NSArray (Object[] anArray)
+ {
+ this();
+ for ( int i = 0; i < anArray.length; i++ )
+ {
+ list.add( anArray[i] );
+ }
+ }
+
+ /**
+ * Produces an array containing the objects in the specified collection.
+ */
+ public NSArray (Collection aCollection)
+ {
+ this();
+ Iterator i = aCollection.iterator();
+ while ( i.hasNext() ) list.add( i.next() );
+ }
+
+ /**
+ * Returns the number of items in this array.
+ */
+ public int count ()
+ {
+ return list.size();
+ }
+
+ /**
+ * Returns an array containing all objects in this array
+ * plus the specified object.
+ */
+ public NSArray arrayByAddingObject (Object anObject)
+ {
+ NSArray result = new NSArray( this );
+ result.protectedAdd( anObject );
+ return result;
+ }
+
+ /**
+ * Returns an array containing all objects in this array
+ * plus all objects in the specified list.
+ */
+ public NSArray arrayByAddingObjectsFromArray (Collection aCollection)
+ {
+ NSArray result = new NSArray( this );
+ result.protectedAddAll( aCollection );
+ return result;
+ }
+
+ /**
+ * Returns a string containing the string representations of
+ * each element in this array, with each element separated from
+ * each neighboring element by the specified string.
+ */
+ public String componentsJoinedByString (String separator)
+ {
+ StringBuffer buf = new StringBuffer();
+ Iterator it = list.iterator();
+ if ( it.hasNext() )
+ {
+ buf.append( it.next().toString() );
+ }
+ while ( it.hasNext() )
+ {
+ buf.append( separator );
+ buf.append( String.valueOf(it.next()) );
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns whether an equivalent object is contained in this array.
+ */
+ public boolean containsObject (Object anObject)
+ {
+ return list.contains( anObject );
+ }
+
+ /**
+ * Returns the first object in this array that is equivalent to
+ * an object in the specified list, or null if no objects are
+ * in common.
+ */
+ public Object firstObjectCommonWithArray (Collection aCollection)
+ {
+ if ( aCollection == null ) return null;
+
+ Object o;
+ Iterator it = list.iterator();
+ while ( it.hasNext() )
+ {
+ o = it.next();
+ if ( aCollection.contains( o ) ) return o;
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether the specified list contains elements equivalent
+ * to those in this array in the same order.
+ */
+ public boolean isEqualToArray (List aList)
+ {
+ return list.equals( aList );
+ }
+
+ /**
+ * Returns the last object in this array, or null if the array is empty.
+ */
+ public Object lastObject ()
+ {
+ int i;
+ if ( (i = list.size()) == 0 ) return null;
+ return list.get( i - 1 );
+ }
+
+ /**
+ *
+ */
+/*
+ public NSArray sortedArrayUsingSelector (NSSelector);
+*/
+
+ /**
+ * Returns an array comprised of only those elements whose
+ * indices fall within the specified range.
+ */
+ public NSArray subarrayWithRange (NSRange aRange)
+ {
+ //TODO: Test this logic.
+ NSArray result = new NSArray();
+ if ( aRange == null ) return result;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ int count = count();
+ for ( int i = loc; i <= max && i < count; i++ )
+ {
+ result.protectedAdd( list.get( i ) );
+ }
+ return result;
+ }
+
+ /**
+ * Returns an enumeration over the the elements of the array.
+ */
+ public Enumeration objectEnumerator ()
+ {
+ //TODO: Test this logic.
+ return new Enumeration()
+ {
+ Iterator it = NSArray.this.iterator();
+ public boolean hasMoreElements()
+ {
+ return it.hasNext();
+ }
+ public Object nextElement()
+ {
+ return it.next();
+ }
+ };
+ }
+
+ /**
+ * Returns an enumeration over the elements of the array in reverse order.
+ */
+ public java.util.Enumeration reverseObjectEnumerator ()
+ {
+ return new java.util.Enumeration()
+ {
+ ListIterator it = null;
+ public ListIterator getIterator()
+ {
+ if ( it == null )
+ {
+ it = NSArray.this.listIterator();
+ // zoom to end
+ while ( it.hasNext() ) it.next();
+ }
+ return it;
+ }
+ public boolean hasMoreElements()
+ {
+ return getIterator().hasPrevious();
+ }
+ public Object nextElement()
+ {
+ return getIterator().previous();
+ }
+ };
+ }
+
+ /**
+ * Copies the elements of this array into the specified object array
+ * as the array's capacity permits.
+ */
+ public void getObjects (Object[] anArray)
+ {
+ getObjects(anArray,null);
+ }
+
+ /**
+ * Copies the elements of this array that fall within the specified range
+ * into the specified object array as the array's capacity permits. This
+ * method must not overflow, even in the face of a null range, an over or
+ * under-sized array, or a bad range. It may underflow and fail to
+ * entirely populate the array, if the array is larger than the data to
+ * be copied.
+ *
+ * TODO: Check whether in WebObjects the range supposed to be measured against the parameter or the NSArray itself??? -ceg
+ *
+ * @param anArray An object array to be filled by this method.
+ * @param range An NSRange object representing the range of data in the NSArray to be copied.
+ */
+ public void getObjects (Object[] array, NSRange range)
+ {
+ if ( array == null ) return;
+ if ( range == null) range = new NSRange(0,array.length);
+ int limit = Math.min(Math.min(array.length,range.length()),(count()-range.location()));
+ for ( int i = 0; i < limit ; i++ ) {
+ //anArray[ i-aRange.location() ] = objectAtIndex( i );
+ array[ i ] = objectAtIndex( range.location() + i );
+ }
+ }
+
+ /**
+ * Returns the index of the first object in the array equivalent
+ * to the specified object. Returns NotFound if the item is not found.
+ */
+ public int indexOfObject (Object anObject)
+ {
+ int result = list.indexOf( anObject );
+ if ( result == -1 ) return NotFound; // in case this changes
+ return result;
+ }
+
+ /**
+ * Returns the index of the first object in the array
+ * within the specified range equivalent to the specified object.
+ * Returns NotFound if the item is not found.
+ */
+ public int indexOfObject (Object anObject, NSRange aRange)
+ {
+ if ( ( anObject == null ) || ( aRange == null ) ) return NotFound;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for ( int i = loc; i < max; i++ )
+ {
+ if ( anObject.equals( list.get(i) ) )
+ {
+ return i;
+ }
+ }
+ return NotFound;
+ }
+
+ /**
+ * Returns the index of the specified object if it exists
+ * in the array, comparing by reference.
+ * Returns NotFound if the item is not found.
+ */
+ public int indexOfIdenticalObject (Object anObject)
+ {
+ int size = list.size();
+ for ( int i = 0; i < size; i++ )
+ {
+ if ( anObject == list.get(i) )
+ {
+ return i;
+ }
+ }
+ return NotFound;
+ }
+
+ /**
+ * Returns the index of the first object in the array
+ * within the specified range equivalent to the specified object.
+ */
+ public int indexOfIdenticalObject (Object anObject, NSRange aRange)
+ {
+ if ( aRange == null ) return NotFound;
+
+ int loc = aRange.location();
+ int max = aRange.maxRange();
+ for ( int i = loc; i < max; i++ )
+ {
+ if ( anObject == list.get(i) )
+ {
+ return i;
+ }
+ }
+ return NotFound;
+ }
+
+ /**
+ * Returns the object at the specified index. Throws an
+ * IndexOutOfRange exception if the index is out of range.
+ */
+ public Object objectAtIndex (int anIndex)
+ {
+ return list.get( anIndex );
+ }
+
+ /**
+ * Returns an array consisting of strings within the specified string
+ * as delimited by the specified separator characters.
+ */
+ public static NSArray componentsSeparatedByString
+ (String aString, String aSeparator)
+ {
+ NSArray result = new NSArray();
+ if ( aString == null ) return result;
+ if ( aSeparator == null ) return new NSArray( aString );
+
+ //FIXME: The spec probably considers the whole
+ // string as a separator, unlike string tokenizer.
+ java.util.StringTokenizer tokens =
+ new java.util.StringTokenizer( aString, aSeparator );
+ while ( tokens.hasMoreTokens() )
+ {
+ result.protectedAdd( tokens.nextToken() );
+ }
+
+ return result;
+ }
+
+ public Object clone()
+ {
+ return new NSArray( list );
+ }
+
+ public NSArray immutableClone()
+ {
+ return this;
+ }
+
+ public NSMutableArray mutableClone()
+ {
+ return new NSMutableArray( this );
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_ARRAY]);
+ for (int i = 0; i < count(); i++) {
+ Object x = objectAtIndex(i);
+ buf.append(NSPropertyListSerialization.stringForPropertyList(x));
+ if (i < count() - 1)
+ buf.append(", ");
+ }
+ buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_ARRAY]);
+ return buf.toString();
+ }
+
+ // interface List: accessors
+
+ public boolean contains(Object o) { return list.contains(o); }
+ public boolean containsAll(Collection c) { return list.containsAll(c); }
+ public boolean equals(Object o) { return list.equals(o); }
+ public Object get(int index) { return list.get(index); }
+ public int hashCode() {
+ int code = 19;
+ code *= getClass().hashCode();
+ code *= list.hashCode();
+ return code;
+ }
+ public int indexOf(Object o) { return list.indexOf(o); }
+ public boolean isEmpty() { return list.isEmpty(); }
+ public int lastIndexOf(Object o) { return list.lastIndexOf(o); }
+ public int size() { return list.size(); }
+ public Object[] toArray() { return list.toArray(); }
+ public Object[] toArray(Object[] a) { return list.toArray(a); }
+
+ // interface List: mutators
+
+
+ public void add(int index, Object element)
+ {
+ this.list.add(index,element);
+ }
+
+ public boolean add(Object o)
+ {
+ return this.list.add(o);
+ }
+
+ public boolean addAll(Collection coll)
+ {
+ return this.list.addAll(coll);
+ }
+
+ public boolean addAll(int index, Collection c)
+ {
+ return this.list.addAll(index,c);
+ }
+
+ public void clear()
+ {
+ this.list.clear();
+ }
+
+ public Iterator iterator()
+ {
+ // make a copy to avoid ConcurrentModificationExceptions
+ final Iterator i = new LinkedList( list ).iterator();
+ return new Iterator()
+ {
+ public boolean hasNext() {return i.hasNext();}
+ public Object next() {return i.next();}
+ public void remove() { throw new UnsupportedOperationException(); }
+ };
+ }
+
+ public ListIterator listIterator() { return listIterator(0); }
+
+ public ListIterator listIterator(final int index)
+ {
+ // make a copy to avoid ConcurrentModificationExceptions
+ final ListIterator i = new LinkedList( list ).listIterator(index);
+ return new ListIterator()
+ {
+ public boolean hasNext() {return i.hasNext();}
+ public Object next() {return i.next();}
+ public boolean hasPrevious() {return i.hasPrevious();}
+ public Object previous() {return i.previous();}
+ public int nextIndex() {return i.nextIndex();}
+ public int previousIndex() {return i.previousIndex();}
+ public void remove() { throw new UnsupportedOperationException(); }
+ public void set(Object o) { throw new UnsupportedOperationException(); }
+ public void add(Object o) { throw new UnsupportedOperationException(); }
+ };
+ }
+
+ public Object remove(int index)
+ {
+ return this.list.remove(index);
+ }
+
+ public boolean remove(Object o)
+ {
+ return this.list.remove(o);
+ }
+
+ public boolean removeAll(Collection coll)
+ {
+ return this.list.removeAll(coll);
+ }
+
+ public boolean retainAll(Collection coll)
+ {
+ return this.list.retainAll(coll);
+ }
+
+ public Object set(int index, Object element)
+ {
+ return this.list.set(index,element);
+ }
+
+ public List subList(int fromIndex, int toIndex)
+ {
+ return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
+ }
+
+ /**
+ * Provided for the use of subclasses like ArrayFault.
+ */
+ protected boolean protectedAdd( Object o )
+ {
+ return list.add( o );
+ }
+
+ /**
+ * Provided for the use of subclasses like ArrayFault.
+ */
+ protected boolean protectedAddAll( Collection coll )
+ {
+ return list.addAll( coll );
+ }
+}
+
+/*
+ * $Log$
+ * Revision 1.2 2006/03/10 00:52:27 cgruber
+ * Add tests for NSArray and fix some problems that became obvious as a result.
+ *
+ * Revision 1.1 2006/02/16 12:47:16 cgruber
+ * Check in all sources in eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.16 2005/07/13 14:12:44 cgruber
+ * Add mutableClone() and immutableClone() per. WebObjects 5.3 conformance.
+ *
+ * Revision 1.15 2003/08/06 23:07:52 chochos
+ * general code cleanup (mostly, removing unused imports)
+ *
+ * Revision 1.14 2003/08/05 00:48:56 chochos
+ * use NSPropertyListSerialization to get the opening and closing tokens for the string representation
+ *
+ * Revision 1.13 2003/08/04 20:26:10 chochos
+ * use NSPropertyListSerialization inside toString()
+ *
+ * Revision 1.12 2003/08/04 18:18:43 chochos
+ * toString() yields strings in the same format as Apple's NSArray
+ *
+ * Revision 1.11 2003/01/28 19:44:20 mpowers
+ * Fixed reverse enumerator.
+ *
+ * Revision 1.10 2003/01/18 23:49:55 mpowers
+ * Added mutableClone().
+ *
+ * Revision 1.9 2003/01/18 23:30:42 mpowers
+ * WODisplayGroup now compiles.
+ *
+ * Revision 1.8 2003/01/16 22:47:30 mpowers
+ * Compatibility changes to support compiling woextensions source.
+ * (34 out of 56 classes compile!)
+ *
+ * Revision 1.7 2003/01/10 19:16:40 mpowers
+ * Implemented support for page caching.
+ *
+ * Revision 1.6 2002/10/24 21:15:36 mpowers
+ * New implementations of NSArray and subclasses.
+ *
+ * Revision 1.5 2002/10/24 18:16:30 mpowers
+ * Now enforcing NSArray's immutable nature.
+ *
+ * Revision 1.4 2002/03/08 19:02:54 mpowers
+ * Long-overdue speed optimization of indexOfIdenticalObject.
+ *
+ * Revision 1.3 2002/02/13 22:02:56 mpowers
+ * Fixed: bug in componentsSeparatedByString when separator is null
+ * (thanks to Cedrik LIME).
+ *
+ * Revision 1.2 2001/01/11 20:34:26 mpowers
+ * Implemented EOSortOrdering and added support in framework.
+ * Added header-click to sort table columns.
+ *
+ * Revision 1.1.1.1 2000/12/21 15:47:26 mpowers
+ * Contributing wotonomy.
+ *
+ * Revision 1.3 2000/12/20 16:25:37 michael
+ * Added log to all files.
+ *
+ *
+ */
+