Coverage Report - net.wotonomy.foundation.NSArray
 
Classes in this File Line Coverage Branch Coverage Complexity
NSArray
93% 
100% 
1.622
 
 1  4
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Blacksmith, Inc.
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.foundation;
 20  
 
 21  
 import java.io.Serializable;
 22  
 import java.util.ArrayList;
 23  
 import java.util.Collection;
 24  
 import java.util.Collections;
 25  
 import java.util.Enumeration;
 26  
 import java.util.Iterator;
 27  
 import java.util.LinkedList;
 28  
 import java.util.List;
 29  
 import java.util.ListIterator;
 30  
 
 31  
 /**
 32  
 * NSArray is an unmodifiable List.  
 33  
 * Calling the mutator methods of the List interface (add, addAll, 
 34  
 * set, etc.) on an instance of NSArray will throw an Unsupported
 35  
 * Operation exception: use a NSMutableArray instead.  This is to
 36  
 * simulate Objective-C's pattern of exposing mutator methods only
 37  
 * on mutable subinterface, which is wonderful for communicating
 38  
 * via interface the contract on returned collections (whether you
 39  
 * may modify return values) as well as implementing array faults.
 40  
 *
 41  
 * @author michael@mpowers.net
 42  
 * @author $Author: cgruber $
 43  
 * @version $Revision: 929 $
 44  
 */
 45  1
 public class NSArray implements List, Serializable
 46  
 {
 47  
     /**
 48  
     * Actual list that backs this instance.
 49  
     */
 50  
     List list;
 51  
     
 52  
         /**
 53  
         * Return value when array index is not found.
 54  
         */
 55  
     public static final int NotFound = -1;
 56  
 
 57  
         /**
 58  
         * A constant representing an empty array.
 59  
         */
 60  9
     public static final NSArray EmptyArray = new NSArray();
 61  
 
 62  
     /**
 63  
     * Returns an NSArray backed by the specified List.
 64  
     * This is useful to "protect" an internal representation
 65  
     * that is returned by a method of return type NSArray.
 66  
     */
 67  
     public static NSArray arrayBackedByList( List aList )
 68  
     {
 69  9
         return new NSArray( aList, null );
 70  
     }
 71  
     
 72  
     /**
 73  
      * A constructor that uses the provided list as the backing 
 74  
      * list object.  This is unlike ArrayList and other 
 75  
      * java.util.Collection types insofar as that API requires
 76  
      * that the provided Collection be copied into the newly constructed
 77  
      * Collection.
 78  
      * 
 79  
      * TODO: See if this signature can be reasonably changed, as having a no-op parameter is a little counter-intuitive.
 80  
      * @param aList A list that the caller wishes to become the backing list for the NSArray.
 81  
      * @param ignored This parameter is entirely ignored, and is only there to distinguish the API.
 82  
      */
 83  2
     NSArray( List aList, Object ignored ) // differentiates
 84  16
     {
 85  18
         list = aList;
 86  18
     }
 87  
     
 88  
     /**
 89  
     * Constructor with a size hint, used by NSMutableArray.
 90  
     */
 91  4
     NSArray( int aSize )
 92  32
     {
 93  36
         list = new ArrayList( aSize );
 94  27
     }
 95  
     
 96  
         /**
 97  
         * Default constructor returns an empty array.
 98  
         */
 99  59
     public NSArray ()
 100  472
     {
 101  531
             list = new ArrayList();
 102  531
     }        
 103  
 
 104  
         /**
 105  
         * Produces an array containing only the specified object.
 106  
         */
 107  
     public NSArray (Object anObject)
 108  
     {
 109  99
             this();
 110  99
             list.add( anObject );
 111  99
     }
 112  
 
 113  
         /**
 114  
         * Produces an array containing the specified objects.
 115  
         */
 116  
     public NSArray (Object[] anArray)
 117  
     {
 118  369
             this();
 119  1530
             for ( int i = 0; i < anArray.length; i++ )
 120  
             {
 121  1161
                     list.add( anArray[i] );
 122  
             }
 123  369
     }
 124  
 
 125  
         /**
 126  
         * Produces an array containing the objects in the specified collection.
 127  
         */
 128  
     public NSArray (Collection aCollection)
 129  
     {
 130  27
         this();
 131  27
             Iterator i = aCollection.iterator();
 132  67
         while ( i.hasNext() ) list.add( i.next() );
 133  27
     }
 134  
 
 135  
         /**
 136  
         * Returns the number of items in this array.
 137  
         */
 138  
     public int count ()
 139  
     {
 140  189
             return list.size();
 141  
     }
 142  
 
 143  
         /**
 144  
         * Returns an array containing all objects in this array 
 145  
         * plus the specified object.
 146  
         */
 147  
     public NSArray arrayByAddingObject (Object anObject)
 148  
     {
 149  9
             NSArray result = new NSArray( this );
 150  9
             result.protectedAdd( anObject );
 151  9
             return result;
 152  
     }
 153  
 
 154  
         /**
 155  
         * Returns an array containing all objects in this array
 156  
         * plus all objects in the specified list.
 157  
         */
 158  
     public NSArray arrayByAddingObjectsFromArray (Collection aCollection)
 159  
     {
 160  9
             NSArray result = new NSArray( this );
 161  9
             result.protectedAddAll( aCollection );
 162  9
             return result;
 163  
     }
 164  
 
 165  
         /**
 166  
         * Returns a string containing the string representations of
 167  
         * each element in this array, with each element separated from
 168  
         * each neighboring element by the specified string.
 169  
         */
 170  
     public String componentsJoinedByString (String separator)
 171  
     {
 172  9
             StringBuffer buf = new StringBuffer();
 173  9
             Iterator it = list.iterator();
 174  9
             if ( it.hasNext() )
 175  
             {
 176  9
                     buf.append( it.next().toString() );
 177  
             }
 178  28
             while ( it.hasNext() )
 179  
             {
 180  18
                     buf.append( separator );
 181  18
                     buf.append( String.valueOf(it.next()) );
 182  16
             }
 183  9
             return buf.toString();
 184  
     }
 185  
 
 186  
         /**
 187  
         * Returns whether an equivalent object is contained in this array.
 188  
         */
 189  
     public boolean containsObject (Object anObject)
 190  
     {
 191  0
             return list.contains( anObject );
 192  
     }
 193  
 
 194  
         /**
 195  
         * Returns the first object in this array that is equivalent to
 196  
         * an object in the specified list, or null if no objects are
 197  
         * in common.
 198  
         */
 199  
     public Object firstObjectCommonWithArray (Collection aCollection)
 200  
     {
 201  9
             if ( aCollection == null ) return null;
 202  
             
 203  
             Object o;
 204  9
             Iterator it = list.iterator();
 205  19
             while ( it.hasNext() )
 206  
             {
 207  18
                     o = it.next();
 208  18
                     if ( aCollection.contains( o ) ) return o;
 209  
             }
 210  0
             return null;
 211  
     }
 212  
 
 213  
         /**
 214  
         * Returns whether the specified list contains elements equivalent
 215  
         * to those in this array in the same order.
 216  
         */
 217  
     public boolean isEqualToArray (List aList)
 218  
     {
 219  18
             return list.equals( aList );
 220  
     }
 221  
 
 222  
         /**
 223  
         * Returns the last object in this array, or null if the array is empty.
 224  
         */
 225  
     public Object lastObject ()
 226  
     {
 227  
             int i;
 228  18
             if ( (i = list.size()) == 0 ) return null;
 229  9
             return list.get( i - 1 );
 230  
     }
 231  
 
 232  
         /**
 233  
         * 
 234  
         */
 235  
 /*
 236  
     public NSArray sortedArrayUsingSelector (NSSelector);
 237  
 */
 238  
 
 239  
         /**
 240  
         * Returns an array comprised of only those elements whose
 241  
         * indices fall within the specified range.
 242  
         */
 243  
     public NSArray subarrayWithRange (NSRange aRange)
 244  
     {
 245  
             //TODO: Test this logic.
 246  9
             NSArray result = new NSArray();
 247  9
             if ( aRange == null ) return result;
 248  
             
 249  9
             int loc = aRange.location();
 250  9
             int max = aRange.maxRange();
 251  9
         int count = count();
 252  27
             for ( int i = loc; i <= max && i < count; i++ )
 253  
             {
 254  18
                     result.protectedAdd( list.get( i ) );
 255  
             }
 256  9
             return result;
 257  
     }
 258  
 
 259  
         /**
 260  
         * Returns an enumeration over the the elements of the array.
 261  
         */
 262  
     public Enumeration objectEnumerator ()
 263  
     {
 264  
             //TODO: Test this logic.
 265  9
             return new Enumeration()
 266  
                 {
 267  9
                     Iterator it = NSArray.this.iterator(); 
 268  
                     public boolean hasMoreElements()
 269  
                     {
 270  9
                                 return it.hasNext();
 271  
                     }
 272  8
                     public Object nextElement()
 273  
                     {
 274  36
                             return it.next();
 275  
                     }
 276  
             };
 277  
         }
 278  
 
 279  
         /**
 280  
         * Returns an enumeration over the elements of the array in reverse order.
 281  
         */
 282  
     public java.util.Enumeration reverseObjectEnumerator ()
 283  
     {
 284  9
             return new java.util.Enumeration()
 285  
             {
 286  9
                     ListIterator it = null;
 287  
                     public ListIterator getIterator()
 288  
                     {
 289  45
                             if ( it == null )
 290  
                             {
 291  9
                     it = NSArray.this.listIterator();
 292  
                     // zoom to end
 293  41
                     while ( it.hasNext() ) it.next();
 294  
                                 }
 295  45
                                 return it;
 296  
                     }
 297  
                     public boolean hasMoreElements()
 298  
                     {
 299  9
                                 return getIterator().hasPrevious();
 300  
                     }
 301  8
                     public Object nextElement()
 302  
                     {
 303  36
                             return getIterator().previous();
 304  
                     }
 305  
             };
 306  
         }
 307  
 
 308  
         /**
 309  
         * Copies the elements of this array into the specified object array
 310  
         * as the array's capacity permits.
 311  
         */
 312  
     public void getObjects (Object[] anArray)
 313  
     {
 314  27
             getObjects(anArray,null);
 315  27
     }
 316  
 
 317  
         /**
 318  
         * Copies the elements of this array that fall within the specified range
 319  
         * into the specified object array as the array's capacity permits. This
 320  
         * method must not overflow, even in the face of a null range, an over or
 321  
         * under-sized array, or a bad range.  It may underflow and fail to 
 322  
         * entirely populate the array, if the array is larger than the data to 
 323  
         * be copied.
 324  
         * 
 325  
         * TODO: Check whether in WebObjects the range supposed to be measured against the parameter or the NSArray itself??? -ceg
 326  
         * 
 327  
         * @param anArray An object array to be filled by this method.
 328  
         * @param range An NSRange object representing the range of data in the NSArray to be copied.
 329  
         */
 330  
     public void getObjects (Object[] array, NSRange range)
 331  
     {
 332  45
             if ( array == null ) return;
 333  45
             if ( range == null) range = new NSRange(0,array.length);
 334  45
             int limit = Math.min(Math.min(array.length,range.length()),(count()-range.location()));
 335  180
             for ( int i = 0; i < limit ; i++ ) {
 336  
                     //anArray[ i-aRange.location() ] = objectAtIndex( i );
 337  135
                     array[ i ] = objectAtIndex( range.location() + i );
 338  
             }
 339  45
     }
 340  
 
 341  
         /**
 342  
         * Returns the index of the first object in the array equivalent
 343  
         * to the specified object.  Returns NotFound if the item is not found.
 344  
         */
 345  
     public int indexOfObject (Object anObject)
 346  
     {
 347  207
             int result = list.indexOf( anObject );
 348  207
             if ( result == -1 ) return NotFound; // in case this changes
 349  189
             return result;
 350  
     }
 351  
 
 352  
         /**
 353  
         * Returns the index of the first object in the array 
 354  
         * within the specified range equivalent to the specified object.
 355  
         * Returns NotFound if the item is not found.
 356  
         */
 357  
     public int indexOfObject (Object anObject, NSRange aRange)
 358  
     {
 359  54
             if ( ( anObject == null ) || ( aRange == null ) ) return NotFound;
 360  
             
 361  45
             int loc = aRange.location();
 362  45
             int max = aRange.maxRange();
 363  72
             for ( int i = loc; i < max; i++ )
 364  
             {
 365  45
                     if ( anObject.equals( list.get(i) ) )
 366  
                     {
 367  18
                             return i;
 368  
                     }
 369  
             }
 370  27
             return NotFound;
 371  
     }
 372  
 
 373  
         /**
 374  
         * Returns the index of the specified object if it exists
 375  
         * in the array, comparing by reference.
 376  
         * Returns NotFound if the item is not found.
 377  
         */
 378  
     public int indexOfIdenticalObject (Object anObject)
 379  
     {
 380  18
         int size = list.size();
 381  63
             for ( int i = 0; i < size; i++ )
 382  
             {
 383  54
                     if ( anObject == list.get(i) )
 384  
                     {
 385  9
                             return i;
 386  
                     }
 387  
             }
 388  9
             return NotFound;
 389  
     }
 390  
 
 391  
         /**
 392  
         * Returns the index of the first object in the array 
 393  
         * within the specified range equivalent to the specified object.
 394  
         */
 395  
     public int indexOfIdenticalObject (Object anObject, NSRange aRange)
 396  
     {
 397  36
             if ( aRange == null ) return NotFound;
 398  
             
 399  36
             int loc = aRange.location();
 400  36
             int max = aRange.maxRange();
 401  63
             for ( int i = loc; i < max; i++ )
 402  
             {
 403  36
                     if ( anObject == list.get(i) )
 404  
                     {
 405  9
                             return i;
 406  
                     }
 407  
             }
 408  27
             return NotFound;
 409  
     }
 410  
 
 411  
         /**
 412  
         * Returns the object at the specified index.  Throws an
 413  
         * IndexOutOfRange exception if the index is out of range.
 414  
         */
 415  
     public Object objectAtIndex (int anIndex)
 416  
     {
 417  297
             return list.get( anIndex );
 418  
     }
 419  
 
 420  
         /**
 421  
         * Returns an array consisting of strings within the specified string
 422  
         * as delimited by the specified separator characters. 
 423  
         */
 424  
     public static NSArray componentsSeparatedByString 
 425  
             (String aString, String aSeparator)
 426  
     {
 427  9
             NSArray result = new NSArray();
 428  9
             if ( aString == null ) return result;
 429  9
             if ( aSeparator == null ) return new NSArray( aString );
 430  
             
 431  
         //FIXME: The spec probably considers the whole
 432  
         // string as a separator, unlike string tokenizer.
 433  9
             java.util.StringTokenizer tokens = 
 434  1
                     new java.util.StringTokenizer( aString, aSeparator );
 435  46
             while ( tokens.hasMoreTokens() )
 436  
             {
 437  36
                     result.protectedAdd( tokens.nextToken() );
 438  32
             }
 439  
             
 440  9
             return result;
 441  
     }
 442  
     
 443  
     public Object clone()
 444  
     {
 445  0
         return new NSArray( list );
 446  
     }
 447  
     
 448  
     public NSArray immutableClone()
 449  
     {
 450  0
         return this;
 451  
     }
 452  
         
 453  
     public NSMutableArray mutableClone()
 454  
     {
 455  0
         return new NSMutableArray( this );
 456  
     }
 457  
     
 458  
     public String toString() {
 459  9
         StringBuffer buf = new StringBuffer();
 460  9
         buf.append(NSPropertyListSerialization.TOKEN_BEGIN[NSPropertyListSerialization.PLIST_ARRAY]);
 461  36
         for (int i = 0; i < count(); i++) {
 462  27
             Object x = objectAtIndex(i);
 463  27
             buf.append(NSPropertyListSerialization.stringForPropertyList(x));
 464  27
             if (i < count() - 1)
 465  18
                 buf.append(", ");
 466  
         }
 467  9
         buf.append(NSPropertyListSerialization.TOKEN_END[NSPropertyListSerialization.PLIST_ARRAY]);
 468  9
         return buf.toString();
 469  
     }
 470  
     
 471  
     // interface List: accessors
 472  
     
 473  54
     public boolean contains(Object o) { return list.contains(o); }
 474  18
     public boolean containsAll(Collection c) { return list.containsAll(c); }
 475  18
     public boolean equals(Object o) { return list.equals(o); }
 476  171
     public Object get(int index) { return list.get(index); }
 477  
     public int hashCode() { 
 478  36
             int code = 19;
 479  36
             code *= getClass().hashCode();
 480  36
             code *= list.hashCode();
 481  36
             return code;
 482  
     }
 483  36
     public int indexOf(Object o) { return list.indexOf(o); }
 484  18
     public boolean isEmpty() { return list.isEmpty(); }
 485  36
     public int lastIndexOf(Object o) { return list.lastIndexOf(o); }
 486  45
         public int size() { return list.size(); }
 487  9
     public Object[] toArray() { return list.toArray(); }
 488  9
     public Object[] toArray(Object[] a) { return list.toArray(a); }
 489  
     
 490  
     // interface List: mutators
 491  
 
 492  
 
 493  
         public void add(int index, Object element) 
 494  
     {
 495  9
                 this.list.add(index,element);
 496  9
     }
 497  
     
 498  
         public boolean add(Object o)
 499  
     {
 500  9
                 return this.list.add(o);
 501  
     }
 502  
 
 503  
         public boolean addAll(Collection coll) 
 504  
     {
 505  9
             return this.list.addAll(coll);
 506  
     }
 507  
 
 508  
         public boolean addAll(int index, Collection c) 
 509  
     {
 510  9
                 return this.list.addAll(index,c);
 511  
     }
 512  
     
 513  
         public void clear() 
 514  
     {
 515  9
                 this.list.clear();
 516  9
     }
 517  
 
 518  
         public Iterator iterator() 
 519  
     {
 520  
         // make a copy to avoid ConcurrentModificationExceptions
 521  36
         final Iterator i = new LinkedList( list ).iterator();
 522  4
             return new Iterator() 
 523  
         {
 524  54
             public boolean hasNext() {return i.hasNext();}
 525  72
             public Object next()          {return i.next();}
 526  32
             public void remove() { throw new UnsupportedOperationException(); }
 527  
         };
 528  
     }
 529  
 
 530  54
         public ListIterator listIterator() { return listIterator(0); }
 531  
 
 532  
         public ListIterator listIterator(final int index) 
 533  
     {
 534  
         // make a copy to avoid ConcurrentModificationExceptions
 535  63
         final ListIterator i = new LinkedList( list ).listIterator(index);
 536  63
             return new ListIterator() 
 537  
         {
 538  117
             public boolean hasNext()     {return i.hasNext();}
 539  171
             public Object next()         {return i.next();}
 540  9
             public boolean hasPrevious() {return i.hasPrevious();}
 541  72
             public Object previous()     {return i.previous();}
 542  0
             public int nextIndex()       {return i.nextIndex();}
 543  0
             public int previousIndex()   {return i.previousIndex();}
 544  0
             public void remove() { throw new UnsupportedOperationException(); }
 545  0
             public void set(Object o) { throw new UnsupportedOperationException(); }
 546  56
             public void add(Object o) { throw new UnsupportedOperationException(); }
 547  
             };
 548  
         }
 549  
 
 550  
         public Object remove(int index) 
 551  
     {
 552  18
                 return this.list.remove(index);
 553  
     }
 554  
     
 555  
         public boolean remove(Object o) 
 556  
     {
 557  27
                 return this.list.remove(o);
 558  
     }
 559  
 
 560  
         public boolean removeAll(Collection coll) 
 561  
     {
 562  9
                 return this.list.removeAll(coll);
 563  
     }
 564  
 
 565  
         public boolean retainAll(Collection coll) 
 566  
     {
 567  0
                 return this.list.retainAll(coll);
 568  
     }
 569  
 
 570  
     public Object set(int index, Object element) 
 571  
     {
 572  0
             return this.list.set(index,element);
 573  
     }
 574  
     
 575  
     public List subList(int fromIndex, int toIndex) 
 576  
     {
 577  0
         return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
 578  
     }
 579  
     
 580  
     /**
 581  
     * Provided for the use of subclasses like ArrayFault.
 582  
     */
 583  
     protected boolean protectedAdd( Object o )
 584  
     {
 585  63
         return list.add( o );
 586  
     }
 587  
     
 588  
     /**
 589  
     * Provided for the use of subclasses like ArrayFault.
 590  
     */
 591  
     protected boolean protectedAddAll( Collection coll )
 592  
     {
 593  9
         return list.addAll( coll );
 594  
     }
 595  
 }
 596  
 
 597  
 /*
 598  
  * $Log$
 599  
  * Revision 1.2  2006/03/10 00:52:27  cgruber
 600  
  * Add tests for NSArray and fix some problems that became obvious as a result.
 601  
  *
 602  
  * Revision 1.1  2006/02/16 12:47:16  cgruber
 603  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 604  
  *
 605  
  * Revision 1.16  2005/07/13 14:12:44  cgruber
 606  
  * Add mutableClone() and immutableClone()  per. WebObjects 5.3 conformance.
 607  
  *
 608  
  * Revision 1.15  2003/08/06 23:07:52  chochos
 609  
  * general code cleanup (mostly, removing unused imports)
 610  
  *
 611  
  * Revision 1.14  2003/08/05 00:48:56  chochos
 612  
  * use NSPropertyListSerialization to get the opening and closing tokens for the string representation
 613  
  *
 614  
  * Revision 1.13  2003/08/04 20:26:10  chochos
 615  
  * use NSPropertyListSerialization inside toString()
 616  
  *
 617  
  * Revision 1.12  2003/08/04 18:18:43  chochos
 618  
  * toString() yields strings in the same format as Apple's NSArray
 619  
  *
 620  
  * Revision 1.11  2003/01/28 19:44:20  mpowers
 621  
  * Fixed reverse enumerator.
 622  
  *
 623  
  * Revision 1.10  2003/01/18 23:49:55  mpowers
 624  
  * Added mutableClone().
 625  
  *
 626  
  * Revision 1.9  2003/01/18 23:30:42  mpowers
 627  
  * WODisplayGroup now compiles.
 628  
  *
 629  
  * Revision 1.8  2003/01/16 22:47:30  mpowers
 630  
  * Compatibility changes to support compiling woextensions source.
 631  
  * (34 out of 56 classes compile!)
 632  
  *
 633  
  * Revision 1.7  2003/01/10 19:16:40  mpowers
 634  
  * Implemented support for page caching.
 635  
  *
 636  
  * Revision 1.6  2002/10/24 21:15:36  mpowers
 637  
  * New implementations of NSArray and subclasses.
 638  
  *
 639  
  * Revision 1.5  2002/10/24 18:16:30  mpowers
 640  
  * Now enforcing NSArray's immutable nature.
 641  
  *
 642  
  * Revision 1.4  2002/03/08 19:02:54  mpowers
 643  
  * Long-overdue speed optimization of indexOfIdenticalObject.
 644  
  *
 645  
  * Revision 1.3  2002/02/13 22:02:56  mpowers
 646  
  * Fixed: bug in componentsSeparatedByString when separator is null
 647  
  * (thanks to Cedrik LIME).
 648  
  *
 649  
  * Revision 1.2  2001/01/11 20:34:26  mpowers
 650  
  * Implemented EOSortOrdering and added support in framework.
 651  
  * Added header-click to sort table columns.
 652  
  *
 653  
  * Revision 1.1.1.1  2000/12/21 15:47:26  mpowers
 654  
  * Contributing wotonomy.
 655  
  *
 656  
  * Revision 1.3  2000/12/20 16:25:37  michael
 657  
  * Added log to all files.
 658  
  *
 659  
  *
 660  
  */
 661