瀏覽代碼

test (59)

Ranides Atterwim 10 年之前
父節點
當前提交
a5271c70d1

+ 168 - 3
assira/src/main/java/net/ranides/assira/collection/arrays/ArrayAllocator.java

@@ -6,6 +6,8 @@
  */
 package net.ranides.assira.collection.arrays;
 
+import java.lang.reflect.Array;
+
 public final class ArrayAllocator {
     
     /**
@@ -51,8 +53,7 @@ public final class ArrayAllocator {
      * @return a new array of given type and length.
      */
     public static <Auto> Auto forPrototype(Object prototype, int length) {
-        Class<?> component = prototype.getClass().getComponentType();
-        return forComponent(component, length);
+        return forComponent(prototype.getClass().getComponentType(), length);
     }
     
     /**
@@ -73,7 +74,7 @@ public final class ArrayAllocator {
         if (length == 0 && component == Object.class) {
             return (Auto)EMPTY_ARRAY;
         }
-        return (Auto)java.lang.reflect.Array.newInstance(component, length);
+        return (Auto)Array.newInstance(component, length);
     }
     
     /**
@@ -93,6 +94,24 @@ public final class ArrayAllocator {
     public static <K> K[] ensureCapacity(K[] array, int length) {
         return ensureCapacity(array, length, array.length);
     }
+    
+    /**
+     * Ensures that an array can contain the given number of entries.
+     *
+     * <P>If you cannot foresee whether this array will need again to be
+     * enlarged, you should probably use
+     * <code>grow()</code> instead.
+     *
+     * @param array an array.
+     * @param length the new minimum length for this array.
+     * @return <code>array</code>, if it contains <code>length</code> entries or
+     * more; otherwise, an array with <code>length</code> entries whose * *
+     * first <code>array.length</code> entries are the same as those * *
+     * of <code>array</code>.
+     */
+    public static <A> A ensureCapacity(A array, int length) {
+        return ensureCapacity(array, length, -1);
+    }
 
     /**
      * Ensures that an array can contain the given number of entries, preserving
@@ -115,6 +134,35 @@ public final class ArrayAllocator {
         }
         return array;
     }
+    
+    /**
+     * Ensures that an array can contain the given number of entries, preserving
+     * just a part of the array.
+     *
+     * @param array an array.
+     * @param length the new minimum length for this array.
+     * @param preserve the number of elements of the array that must be
+     * preserved in case a new allocation is necessary.
+     * @return <code>array</code>, if it can contain <code>length</code> entries
+     * or more; otherwise, an array with <code>length</code> entries whose *
+     * first <code>preserve</code> entries are the same as those * *
+     * of <code>array</code>.
+     */
+    @SuppressWarnings({
+        "SuspiciousSystemArraycopy"
+    })
+    public static <A> A ensureCapacity(A array, int length, int preserve) {
+        int n = Array.getLength(array);
+        if(preserve < 0) {
+            preserve = n;
+        }
+        if (length > n) {
+            A target = forPrototype(array, length);
+            System.arraycopy(array, 0, target, 0, preserve);
+            return target;
+        }
+        return array;
+    }
 
     /**
      * Ensures that a range given by an offset and a length fits an array.
@@ -132,6 +180,23 @@ public final class ArrayAllocator {
     public static <K> void ensureOffsetLength(K[] array, int offset, int length) {
         ensureOffsetLength(array.length, offset, length);
     }
+    
+    /**
+     * Ensures that a range given by an offset and a length fits an array.
+     *
+     * <P>This method may be used whenever an array range check is needed.
+     *
+     * @param array an array.
+     * @param offset a start index.
+     * @param length a length (the number of elements in the range).
+     * @throws IllegalArgumentException if <code>length</code> is negative.
+     * @throws ArrayIndexOutOfBoundsException if <code>offset</code> is negative
+     * or <code>offset</code>+<code>length</code> is greater than the array
+     * length.
+     */
+    public static void ensureOffsetLength(Object array, int offset, int length) {
+        ArrayAllocator.ensureOffsetLength(Array.getLength(array), offset, length);
+    }
 
     /**
      * Ensures that a range given by an offset and a length fits an array of
@@ -176,6 +241,24 @@ public final class ArrayAllocator {
         ensureFromTo(array.length, begin, end);
     }
     
+    /**
+     * Ensures that a range given by its first (inclusive) and last (exclusive)
+     * elements fits an array.
+     *
+     * <P>This method may be used whenever an array range check is needed.
+     *
+     * @param array an array.
+     * @param begin a start index (inclusive).
+     * @param end an end index (exclusive).
+     * @throws IllegalArgumentException if <code>from</code> is greater * *
+     * than <code>to</code>.
+     * @throws ArrayIndexOutOfBoundsException if <code>from</code> * *
+     * or <code>to</code> are greater than the array length or negative.
+     */
+    public static void ensureFromTo(Object array, int begin, int end) {
+        ArrayAllocator.ensureFromTo(Array.getLength(array), begin, end);
+    }
+    
     /**
      * Ensures that a range given by its first (inclusive) and last (exclusive)
      * elements fits an array of given length.
@@ -223,6 +306,28 @@ public final class ArrayAllocator {
     public static <K> K[] grow(K[] array, int length) {
         return grow(array, length, array.length);
     }
+    
+    /**
+     * Grows the given array to the maximum between the given length and the
+     * current length multiplied by two, provided that the given length is
+     * larger than the current length.
+     *
+     * <P>If you want complete control on the array growth, you should probably
+     * use
+     * <code>ensureCapacity()</code> instead.
+     *
+     * @param array an array.
+     * @param length the new minimum length for this array.
+     * @return <code>array</code>, if it can contain <code>length</code>
+     * entries; otherwise, an array with
+     * max(<code>length</code>,<code>array.length</code>/&phi;) entries whose
+     * first <code>array.length</code> entries are the same as those * *
+     * of <code>array</code>.
+     *
+     */
+    public static <A> A grow(A array, int length) {
+        return grow(array, length, -1);
+    }
 
     /**
      * Grows the given array to the maximum between the given length and the
@@ -253,6 +358,43 @@ public final class ArrayAllocator {
         }
         return array;
     }
+    
+    /**
+     * Grows the given array to the maximum between the given length and the
+     * current length multiplied by two, provided that the given length is
+     * larger than the current length, preserving just a part of the array.
+     *
+     * <P>If you want complete control on the array growth, you should probably
+     * use
+     * <code>ensureCapacity()</code> instead.
+     *
+     * @param array an array.
+     * @param length the new minimum length for this array.
+     * @param preserve the number of elements of the array that must be
+     * preserved in case a new allocation is necessary.
+     * @return <code>array</code>, if it can contain <code>length</code>
+     * entries; otherwise, an array with
+     * max(<code>length</code>,<code>array.length</code>/&phi;) entries whose
+     * first <code>preserve</code> entries are the same as those
+     * of <code>array</code>.
+     *
+     */
+    @SuppressWarnings({
+        "SuspiciousSystemArraycopy"
+    })
+    public static <A> A grow(A array, int length, int preserve) {
+        int n = Array.getLength(array);
+        if(preserve < 0) {
+            preserve = n;
+        }
+        if (length > n) {
+            int newLength = (int) Math.min(Math.max(2L * n, length), ArrayAllocator.MAX_SIZE);
+            A target = forPrototype(array, newLength);
+            System.arraycopy(array, 0, target, 0, preserve);
+            return target;
+        }
+        return array;
+    }
 
     /**
      * Trims the given array to the given length.
@@ -273,4 +415,27 @@ public final class ArrayAllocator {
         System.arraycopy(array, 0, target, 0, length);
         return target;
     }
+    
+    /**
+     * Trims the given array to the given length.
+     *
+     * @param array an array.
+     * @param length the new maximum length for the array.
+     * @return <code>array</code>, if it contains <code>length</code> entries or
+     * less; otherwise, an array with <code>length</code> entries whose entries
+     * are the same as the first <code>length</code> entries * *
+     * of <code>array</code>.
+     *
+     */
+    @SuppressWarnings({
+        "SuspiciousSystemArraycopy"
+    })
+    public static <A> A trim(A array, int length) {
+        if (length >= Array.getLength(array)) {
+            return array;
+        }
+        A target = forPrototype(array, length);
+        System.arraycopy(array, 0, target, 0, length);
+        return target;
+    }
 }

+ 16 - 0
assira/src/main/java/net/ranides/assira/collection/iterators/IntIterator.java

@@ -7,6 +7,7 @@
 package net.ranides.assira.collection.iterators;
 
 import java.util.Iterator;
+import net.ranides.assira.collection.IntCollection;
 
 public interface IntIterator extends Iterator<Integer> {
 
@@ -62,5 +63,20 @@ public interface IntIterator extends Iterator<Integer> {
             }
         };
     }
+    
+    static String toString(IntIterator iterator) {
+        if ( !iterator.hasNext() ) {
+            return "[]";
+        }
+        StringBuilder builder = new StringBuilder();
+        builder.append('[');
+        for (;;) {
+            builder.append(iterator.nextInt());
+            if ( !iterator.hasNext() ) {
+                return builder.append(']').toString();
+            }
+            builder.append(", ");
+        }
+    }
 
 }

+ 126 - 4
assira/src/test/java/net/ranides/assira/collection/arrays/ArrayAllocatorTest.java

@@ -28,12 +28,15 @@ public class ArrayAllocatorTest {
         
         assertArray(Object[].class, 0, ArrayAllocator.forPrototype(new Object[0], 0));
         assertSame(ArrayAllocator.EMPTY_ARRAY, ArrayAllocator.forPrototype(new Object[0], 0));
-        
+    }
+    
+    @Test
+    public void testForPrototype_A() {
         assertArray(float[].class, 4, ArrayAllocator.forPrototype(new float[0], 4));
         assertArray(int[].class, 4, ArrayAllocator.forPrototype(new int[0], 4));
         assertArray(float[].class, 0, ArrayAllocator.forPrototype(new float[0], 0));
     }
-
+    
     @Test
     public void testForComponent() {
         assertArray(Float[].class, 4, ArrayAllocator.forComponent(Float.class, 4));
@@ -45,7 +48,10 @@ public class ArrayAllocatorTest {
         
         assertArray(Object[].class, 0, ArrayAllocator.forComponent(Object.class, 0));
         assertSame(ArrayAllocator.EMPTY_ARRAY, ArrayAllocator.forComponent(Object.class, 0));
-        
+    }
+    
+    @Test
+    public void testForComponent_A() {
         assertArray(float[].class, 4, ArrayAllocator.forComponent(float.class, 4));
         assertArray(int[].class, 4, ArrayAllocator.forComponent(int.class, 4));
         assertArray(float[].class, 0, ArrayAllocator.forComponent(float.class, 0));
@@ -63,6 +69,19 @@ public class ArrayAllocatorTest {
         assertNotSame(array1, array2);
         assertArrayEquals(new Integer[]{1,2,3,4,5,6,null,null}, array2);
     }
+    
+    @Test
+    public void testEnsureCapacity_A() {
+        byte[] array1 = new byte[]{ 1,2,3,4,5,6 };
+        
+        assertSame(array1, ArrayAllocator.ensureCapacity(array1, 0));
+        assertSame(array1, ArrayAllocator.ensureCapacity(array1, 3));
+        assertSame(array1, ArrayAllocator.ensureCapacity(array1, 6));
+        
+        byte[] array2 = ArrayAllocator.ensureCapacity(array1, 8);
+        assertNotSame(array1, array2);
+        assertArrayEquals(new byte[]{1,2,3,4,5,6,0,0}, array2);
+    }
 
     @Test
     public void testEnsureCapacity_Preserve() {
@@ -84,6 +103,27 @@ public class ArrayAllocatorTest {
             ArrayAllocator.ensureCapacity(array1, 8, 7);
         });
     }
+    
+    @Test
+    public void testEnsureCapacity_Preserve_A() {
+        byte[] array1 = new byte[]{ 1,2,3,4,5,6 };
+        
+        assertSame(array1, ArrayAllocator.ensureCapacity(array1, 0, 0));
+        assertSame(array1, ArrayAllocator.ensureCapacity(array1, 3, 0));
+        assertSame(array1, ArrayAllocator.ensureCapacity(array1, 6, 0));
+        
+        byte[] array2 = ArrayAllocator.ensureCapacity(array1, 8, 6);
+        assertNotSame(array1, array2);
+        assertArrayEquals(new byte[]{1,2,3,4,5,6,0,0}, array2);
+        
+        byte[] array3 = ArrayAllocator.ensureCapacity(array1, 8, 4);
+        assertNotSame(array1, array3);
+        assertArrayEquals(new byte[]{1,2,3,4,0,0,0,0}, array3);
+        
+        QAssert.assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
+            ArrayAllocator.ensureCapacity(array1, 8, 7);
+        });
+    }
 
     @Test
     public void testEnsureOffsetLength() {
@@ -109,6 +149,31 @@ public class ArrayAllocatorTest {
             ArrayAllocator.ensureOffsetLength(array1, 3, 10);
         });
     }
+    
+    @Test
+    public void testEnsureOffsetLength_A() {
+        byte[] array1 = new byte[4];
+        ArrayAllocator.ensureOffsetLength(array1, 1, 2);
+        ArrayAllocator.ensureOffsetLength(array1, 0, 4);
+        ArrayAllocator.ensureOffsetLength(array1, 1, 3);
+        
+        QAssert.assertThrows(IllegalArgumentException.class, ()-> {
+            ArrayAllocator.ensureOffsetLength(array1, 1, -1);
+        });
+        QAssert.assertThrows(IllegalArgumentException.class, ()-> {
+            ArrayAllocator.ensureOffsetLength(array1, 8, -1);
+        });
+        
+        QAssert.assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
+            ArrayAllocator.ensureOffsetLength(array1, -1, 1);
+        });
+        QAssert.assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
+            ArrayAllocator.ensureOffsetLength(array1, 8, 1);
+        });
+        QAssert.assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
+            ArrayAllocator.ensureOffsetLength(array1, 3, 10);
+        });
+    }
 
     @Test
     public void testEnsureOffsetLength_N() {
@@ -133,7 +198,7 @@ public class ArrayAllocatorTest {
             ArrayAllocator.ensureOffsetLength(4, 3, 10);
         });
     }
-
+    
     @Test
     public void testEnsureFromTo() {
         Integer[] array1 = new Integer[4];
@@ -155,6 +220,28 @@ public class ArrayAllocatorTest {
             ArrayAllocator.ensureFromTo(array1, 5, 6);
         });
     }
+    
+    @Test
+    public void testEnsureFromTo_A() {
+        byte[] array1 = new byte[4];
+        ArrayAllocator.ensureFromTo(array1, 1, 3);
+        ArrayAllocator.ensureFromTo(array1, 0, 4);
+        ArrayAllocator.ensureFromTo(array1, 1, 4);
+        
+        QAssert.assertThrows(IllegalArgumentException.class, ()-> {
+            ArrayAllocator.ensureFromTo(array1, 3, 1);
+        });
+        
+        QAssert.assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
+            ArrayAllocator.ensureFromTo(array1, -1, 8);
+        });
+        QAssert.assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
+            ArrayAllocator.ensureFromTo(array1, 2, 8);
+        });
+        QAssert.assertThrows(ArrayIndexOutOfBoundsException.class, ()-> {
+            ArrayAllocator.ensureFromTo(array1, 5, 6);
+        });
+    }
 
     @Test
     public void testEnsureFromTo_N() {
@@ -189,6 +276,18 @@ public class ArrayAllocatorTest {
         assertArrayEquals(new Integer[]{1,2,3,null,null,null,null,null,null}, ArrayAllocator.grow(array1, 9));
     }
     
+    @Test
+    public void testGrow_A() {
+        byte[] array1 = new byte[]{1,2,3};
+        assertSame(array1, ArrayAllocator.grow(array1, 2));
+        assertSame(array1, ArrayAllocator.grow(array1, 3));
+        assertArrayEquals(new byte[]{1,2,3,0,0,0}, ArrayAllocator.grow(array1, 4));
+        assertArrayEquals(new byte[]{1,2,3,0,0,0}, ArrayAllocator.grow(array1, 5));
+        assertArrayEquals(new byte[]{1,2,3,0,0,0}, ArrayAllocator.grow(array1, 6));
+        assertArrayEquals(new byte[]{1,2,3,0,0,0,0}, ArrayAllocator.grow(array1, 7));
+        assertArrayEquals(new byte[]{1,2,3,0,0,0,0,0,0}, ArrayAllocator.grow(array1, 9));
+    }
+    
     @Test
     public void testGrow_preserve() {
         Integer[] array1 = new Integer[]{1,2,3};
@@ -201,6 +300,18 @@ public class ArrayAllocatorTest {
         assertArrayEquals(new Integer[]{1,2,null,null,null,null,null,null,null}, ArrayAllocator.grow(array1, 9, 2));
     }
     
+    @Test
+    public void testGrow_preserve_A() {
+        byte[] array1 = new byte[]{1,2,3};
+        assertSame(array1, ArrayAllocator.grow(array1, 2, 2));
+        assertSame(array1, ArrayAllocator.grow(array1, 3, 2));
+        assertArrayEquals(new byte[]{1,2,0,0,0,0}, ArrayAllocator.grow(array1, 4, 2));
+        assertArrayEquals(new byte[]{1,2,0,0,0,0}, ArrayAllocator.grow(array1, 5, 2));
+        assertArrayEquals(new byte[]{1,2,0,0,0,0}, ArrayAllocator.grow(array1, 6, 2));
+        assertArrayEquals(new byte[]{1,2,0,0,0,0,0}, ArrayAllocator.grow(array1, 7, 2));
+        assertArrayEquals(new byte[]{1,2,0,0,0,0,0,0,0}, ArrayAllocator.grow(array1, 9, 2));
+    }
+    
     @Test
     public void testTrim() {
         Integer[] array1 = new Integer[]{1,2,3};
@@ -211,6 +322,17 @@ public class ArrayAllocatorTest {
         assertArrayEquals(new Integer[]{1}, ArrayAllocator.trim(array1, 1));
         assertArrayEquals(new Integer[]{}, ArrayAllocator.trim(array1, 0));
     }
+    
+    @Test
+    public void testTrim_A() {
+        byte[] array1 = new byte[]{1,2,3};
+        
+        assertSame(array1, ArrayAllocator.trim(array1, 5));
+        assertSame(array1, ArrayAllocator.trim(array1, 3));
+        assertArrayEquals(new byte[]{1,2}, ArrayAllocator.trim(array1, 2));
+        assertArrayEquals(new byte[]{1}, ArrayAllocator.trim(array1, 1));
+        assertArrayEquals(new byte[]{}, ArrayAllocator.trim(array1, 0));
+    }
         
     private void assertArray(Class<?> type, int size, Object array) {
         assertEquals(type, array.getClass());