001         package com.croftsoft.core.util;
002    
003         import java.lang.reflect.Array;
004         import java.util.Enumeration;
005         import java.util.Hashtable;
006    
007         import com.croftsoft.core.lang.NullArgumentException;
008         import com.croftsoft.core.lang.ObjectLib;
009    
010         /*********************************************************************
011         * Array manipulation for Java 1.1+.
012         *
013         * <p>
014         * Java 1.1 compatible.
015         * </p>
016         *
017         * @see
018         *   ArrayLib2
019         *
020         * @version
021         *   2003-04-07
022         * @since
023         *   2001-04-06
024         * @author
025         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
026         *********************************************************************/
027    
028         public final class  ArrayLib
029         //////////////////////////////////////////////////////////////////////
030         //////////////////////////////////////////////////////////////////////
031         {
032    
033         public static void  main ( String [ ]  args )
034         //////////////////////////////////////////////////////////////////////
035         {
036           System.out.println ( test ( args ) );
037         }
038    
039         public static boolean  test ( String [ ]  args )
040         //////////////////////////////////////////////////////////////////////
041         {
042           try
043           {
044             insert ( new int [ ] { }, 0, 0 );
045    
046             String [ ]  stringArray
047               = ( String [ ] ) append ( new String [ ] { }, "" );
048    
049             stringArray
050               = ( String [ ] ) insert ( new String [ ] { }, "", 0 );
051    
052             stringArray
053               = ( String [ ] ) remove ( new String [ ] { "" }, 0 );
054    
055             return true;
056           }
057           catch ( Exception  ex )
058           {
059             ex.printStackTrace ( );
060    
061             return false;
062           }
063         }
064    
065         //////////////////////////////////////////////////////////////////////
066         //////////////////////////////////////////////////////////////////////
067    
068         /*********************************************************************
069         * Appends an Object to an Object array.
070         *
071         * <p>
072         * Example:
073         * <code>
074         * <pre>
075         * String [ ]  stringArray
076         *   = ( String [ ] ) ArrayLib.append ( new String [ ] { }, "" );
077         * </pre>
078         * </code>
079         * </p>
080         *
081         * @throws NullArgumentException
082         *
083         *   If either argument is null.
084         *
085         * @return
086         *
087         *   Returns a new array with the same component type as the old array.
088         *********************************************************************/
089         public static Object [ ]  append ( Object [ ]  oldArray, Object  o )
090         //////////////////////////////////////////////////////////////////////
091         {
092           NullArgumentException.check ( oldArray );
093    
094           NullArgumentException.check ( o );
095    
096           Object [ ]  newArray = ( Object [ ] ) Array.newInstance (
097             oldArray.getClass ( ).getComponentType ( ), oldArray.length + 1 );
098    
099           System.arraycopy ( oldArray, 0, newArray, 0, oldArray.length );
100    
101           newArray [ oldArray.length ] = o;
102    
103           return newArray;
104         }
105    
106         /*********************************************************************
107         * Appends an integer to an integer array.
108         *
109         * @param  intArray
110         *
111         *   May be null.
112         *********************************************************************/
113         public static int [ ]  append ( int [ ]  intArray, int  i )
114         //////////////////////////////////////////////////////////////////////
115         {
116           if ( intArray == null )
117           {
118             return new int [ ] { i };
119           }
120    
121           int  intArrayLength = intArray.length;
122    
123           int [ ]  newIntArray = new int [ intArrayLength + 1 ];
124    
125           System.arraycopy ( intArray, 0, newIntArray, 0, intArrayLength );
126    
127           newIntArray [ intArrayLength ] = i;
128    
129           return newIntArray;
130         }
131    
132         /*********************************************************************
133         * Determines if an array contains an equivalent object.
134         *
135         * @param  objectArray
136         *
137         *   May not be null.
138         *
139         * @param  o
140         *
141         *   If null, function will return true if an array element is null.
142         *********************************************************************/
143         public static boolean  contains (
144           Object [ ]  objectArray,
145           Object      o )
146         //////////////////////////////////////////////////////////////////////
147         {
148           NullArgumentException.check ( objectArray );
149    
150           for ( int  i = 0; i < objectArray.length; i++ )
151           {
152             if ( ObjectLib.equivalent ( objectArray [ i ], o ) )
153             {
154               return true;
155             }
156           }
157    
158           return false;
159         }
160    
161         /*********************************************************************
162         * Compares two object arrays for equivalency.
163         *
164         * <p>
165         * A Java 1.1 version of the Java 1.2 method java.util.Arrays.equals().
166         * </p>
167         *********************************************************************/
168         public static boolean  equals (
169           Object [ ]  objectArray1,
170           Object [ ]  objectArray2 )
171         //////////////////////////////////////////////////////////////////////
172         {
173           if ( objectArray1 == null )
174           {
175             return objectArray2 == null;
176           }
177           else if ( objectArray2 == null )
178           {
179             return false;
180           }
181    
182           if ( objectArray1.length != objectArray2.length )
183           {
184             return false;
185           }
186    
187           for ( int  i = 0; i < objectArray1.length; i++ )
188           {
189             Object  element1 = objectArray1 [ i ];
190    
191             Object  element2 = objectArray2 [ i ];
192    
193             if ( element1 == null )
194             {
195               if ( element2 != null )
196               {
197                 return false;
198               }
199             }
200             else if ( !element1.equals ( element2 ) )
201             {
202               return false;         
203             }
204           }
205    
206           return true;
207         }
208    
209         /*********************************************************************
210         * Inserts an integer into an integer array at the index position.
211         *********************************************************************/
212         public static int [ ]  insert (
213           int [ ]  intArray,
214           int      i,
215           int      index )
216         //////////////////////////////////////////////////////////////////////
217         {
218           NullArgumentException.check ( intArray );
219    
220           if ( ( index < 0               )
221             || ( index > intArray.length ) )
222           {
223             throw new IllegalArgumentException (
224               "index out of range:  " + index );
225           }
226    
227           int  intArrayLength = intArray.length;
228    
229           int [ ]  newIntArray = new int [ intArrayLength + 1 ];
230    
231           System.arraycopy ( intArray, 0, newIntArray, 0, index );
232    
233           newIntArray [ index ] = i;
234    
235           System.arraycopy (
236             intArray, index, newIntArray, index + 1, intArrayLength - index );
237    
238           return newIntArray;
239         }
240    
241         /*********************************************************************
242         * Inserts an Object into an Object array at the index position.
243         *
244         * <p>
245         * Example:
246         * <code>
247         * <pre>
248         * String [ ]  stringArray
249         *   = ( String [ ] ) ArrayLib.insert ( new String [ ] { }, "", 0 );
250         * </pre>
251         * </code>
252         * </p>
253         *
254         * @throws NullArgumentException
255         *
256         *   If objectArray or o is null.
257         *
258         * @throws IndexOutOfBoundsException
259         *
260         *   If index < 0 or index > objectArray.length.
261         *
262         * @return
263         *
264         *   Returns a new array with the same component type as the old array.
265         *********************************************************************/
266         public static Object [ ]  insert (
267           Object [ ]  objectArray,
268           Object      o,
269           int         index )
270         //////////////////////////////////////////////////////////////////////
271         {
272           NullArgumentException.check ( objectArray );
273    
274           NullArgumentException.check ( o );
275    
276           if ( ( index < 0                  )
277             || ( index > objectArray.length ) )
278           {
279             throw new IndexOutOfBoundsException (
280               "index out of range:  " + index );
281           }
282    
283           Object [ ]  newObjectArray = ( Object [ ] ) Array.newInstance (
284             objectArray.getClass ( ).getComponentType ( ),
285             objectArray.length + 1 );
286    
287    
288           System.arraycopy ( objectArray, 0, newObjectArray, 0, index );
289    
290           newObjectArray [ index ] = o;
291    
292           System.arraycopy ( objectArray, index, newObjectArray, index + 1,
293             objectArray.length - index );
294    
295           return newObjectArray;
296         }
297    
298         /*********************************************************************
299         * Prepends an Object to an Object array.
300         *
301         * <p>
302         * Example:
303         * <code>
304         * <pre>
305         * String [ ]  stringArray
306         *   = ( String [ ] ) ArrayLib.prepend ( new String [ ] { }, "" );
307         * </pre>
308         * </code>
309         * </p>
310         *
311         * @throws NullArgumentException
312         *
313         *   If either argument is null.
314         *
315         * @return
316         *
317         *   Returns a new array with the same component type as the old array.
318         *********************************************************************/
319         public static Object [ ]  prepend ( Object [ ]  oldArray, Object  o )
320         //////////////////////////////////////////////////////////////////////
321         {
322           NullArgumentException.check ( oldArray );
323    
324           NullArgumentException.check ( o );
325    
326           Object [ ]  newArray = ( Object [ ] ) Array.newInstance (
327             oldArray.getClass ( ).getComponentType ( ), oldArray.length + 1 );
328    
329           System.arraycopy ( oldArray, 0, newArray, 1, oldArray.length );
330    
331           newArray [ 0 ] = o;
332    
333           return newArray;
334         }
335    
336         /*********************************************************************
337         * Prints each array element to the standard output.
338         *********************************************************************/
339         public static void  println ( Object [ ]  objectArray )
340         //////////////////////////////////////////////////////////////////////
341         {
342           for ( int  i = 0; i < objectArray.length; i++ )
343           {
344             System.out.println ( objectArray [ i ] );
345           }
346         }
347    
348         /*********************************************************************
349         * Removes an Object from an Object array.
350         *
351         * <p>
352         * Example:
353         * <code>
354         * <pre>
355         * String [ ]  stringArray
356         *   = ( String [ ] ) remove ( new String [ ] { "" }, 0 );
357         * </pre>
358         * </code>
359         * </p>
360         *
361         * @throws NullArgumentException
362         *
363         *   If oldArray is null.
364         *
365         * @throws ArrayIndexOutOfBoundsException
366         *
367         *   If index < 0 or index >= oldArray.length.
368         *
369         * @return
370         *
371         *   Returns a new array with the same component type as the old array.
372         *********************************************************************/
373         public static Object [ ]  remove ( Object [ ]  oldArray, int  index )
374         //////////////////////////////////////////////////////////////////////
375         {
376           NullArgumentException.check ( oldArray );
377    
378           if ( ( index < 0 )
379             || ( index >= oldArray.length ) )
380           {
381             throw new ArrayIndexOutOfBoundsException ( index );
382           }
383    
384           Object [ ]  newArray = ( Object [ ] ) Array.newInstance (
385             oldArray.getClass ( ).getComponentType ( ), oldArray.length - 1 );
386    
387           System.arraycopy ( oldArray, 0, newArray, 0, index );
388    
389           System.arraycopy (
390             oldArray, index + 1, newArray, index, newArray.length - index );
391    
392           return newArray;
393         }
394    
395         public static Object [ ]  remove ( Object [ ]  oldArray, Object  o )
396         //////////////////////////////////////////////////////////////////////
397         {
398           NullArgumentException.check ( oldArray );
399    
400           int  index = -1;
401    
402           for ( int  i = 0; i < oldArray.length; i++ )
403           {
404             if ( oldArray [ i ] == o )
405             {
406               index = i;
407    
408               break;
409             }
410           }
411    
412           if ( index > -1 )
413           {
414             return remove ( oldArray, index );
415           }
416    
417           return oldArray;
418         }
419    
420         /*********************************************************************
421         * Removes duplicate elements from the array.
422         *********************************************************************/
423         public static Object [ ]  removeDuplicates ( Object [ ]  array )
424         //////////////////////////////////////////////////////////////////////
425         {
426           NullArgumentException.check ( array );
427    
428           Hashtable  hashtable = new Hashtable ( );
429    
430           for ( int  i = 0; i < array.length; i++ )
431           {
432             hashtable.put ( array [ i ], array [ i ] );
433           }
434    
435           Object [ ]  newArray = ( Object [ ] ) Array.newInstance (
436             array.getClass ( ).getComponentType ( ), hashtable.size ( ) );
437    
438           int  index = 0;
439    
440           Enumeration  enumeration = hashtable.elements ( );
441    
442           while ( enumeration.hasMoreElements ( ) )
443           {
444             newArray [ index++ ] = enumeration.nextElement ( );
445           }
446    
447           return newArray;
448         }
449    
450         /*********************************************************************
451         * Creates a new subarray from a larger array.
452         *
453         * <p>
454         * To avoid unnecessary object creation, this method returns the
455         * original array argument if the requested subarray length is the same
456         * and the startIndex is 0.  That is to say, if the method arguments
457         * are such that the algorithm would have created a shallow clone, the
458         * original array is returned instead.
459         * </p>
460         *
461         * @throws NullArgumentException
462         *
463         *   If objectArray is null.
464         *
465         * @throws ArrayIndexOutOfBoundsException
466         *
467         *   If startIndex, length, or startIndex + length are out of range.
468         *
469         * @return
470         *
471         *   Returns an array with the same component type as the old array.
472         *********************************************************************/
473         public static Object [ ]  subArray (
474           Object [ ]  objectArray,
475           int         startIndex,
476           int         length )
477         //////////////////////////////////////////////////////////////////////
478         {
479           NullArgumentException.check ( objectArray );
480    
481           if ( ( startIndex == 0 )
482             && ( length == objectArray.length ) )
483           {
484             return objectArray;
485           }
486    
487           Object [ ]  newArray = ( Object [ ] ) Array.newInstance (
488             objectArray.getClass ( ).getComponentType ( ), length );
489    
490           System.arraycopy ( objectArray, startIndex, newArray, 0, length );
491    
492           return newArray;
493         }
494    
495         /*********************************************************************
496         * Creates a new subarray from a larger array.
497         *
498         * <p>
499         * <code>
500         * <pre>
501         * return subArray (
502         *   objectArray, startIndex, objectArray.length - startIndex );
503         * </pre>
504         * </code>
505         * </p>
506         *********************************************************************/
507         public static Object [ ]  subArray (
508           Object [ ]  objectArray,
509           int         startIndex )
510         //////////////////////////////////////////////////////////////////////
511         {
512           return subArray (
513             objectArray, startIndex, objectArray.length - startIndex );
514         }
515    
516         /*********************************************************************
517         * Returns the union of the arrays, discarding duplicates.
518         *********************************************************************/
519         public static Object [ ]  union (
520           Object [ ]  array1,
521           Object [ ]  array2 )
522         //////////////////////////////////////////////////////////////////////
523         {
524           if ( array1 == null )
525           {
526             if ( array2 == null )
527             {
528               return null;
529             }
530             else
531             {
532               return removeDuplicates ( array2 );
533             }
534           }
535           else if ( array2 == null )
536           {
537             return removeDuplicates ( array1 );
538           }
539    
540           Class  componentType1 = array1.getClass ( ).getComponentType ( );
541    
542           Class  componentType2 = array2.getClass ( ).getComponentType ( );
543    
544           if ( componentType1 != componentType2 )
545           {
546             throw new IllegalArgumentException (
547               "arrays of different component types" );
548           }
549    
550           Hashtable  hashtable = new Hashtable ( );
551    
552           for ( int  i = 0; i < array1.length; i++ )
553           {
554             hashtable.put ( array1 [ i ], array1 [ i ] );
555           }
556    
557           for ( int  i = 0; i < array2.length; i++ )
558           {
559             hashtable.put ( array2 [ i ], array2 [ i ] );
560           }
561    
562           Object [ ]  array = ( Object [ ] )
563             Array.newInstance ( componentType1, hashtable.size ( ) );
564    
565           int  index = 0;
566    
567           Enumeration  enumeration = hashtable.elements ( );
568    
569           while ( enumeration.hasMoreElements ( ) )
570           {
571             array [ index++ ] = enumeration.nextElement ( );
572           }
573    
574           return array;
575         }
576    
577         //////////////////////////////////////////////////////////////////////
578         //////////////////////////////////////////////////////////////////////
579    
580         private  ArrayLib ( ) { }
581    
582         //////////////////////////////////////////////////////////////////////
583         //////////////////////////////////////////////////////////////////////
584         }