Ranides Atterwim %!s(int64=10) %!d(string=hai) anos
pai
achega
e6783c3b64

+ 169 - 165
assira/src/main/java/net/ranides/assira/collection/arrays/ArrayAllocator.java

@@ -1,165 +1,169 @@
-/*
- * @author Ranides Atterwim <ranides@gmail.com>
- * @copyright Ranides Atterwim
- * @license WTFPL
- * @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.collection.arrays;
-
-public final class ArrayAllocator {
-   
-    private ArrayAllocator() {
-        // utility class
-    }
-    
-    public static <A> A forComponent(Class<?> component, int size) {
-        return NativeArray.allocate(component, size).$array();
-    }
-    
-    /**
-     * Creates a new array using a the given one as prototype.
-     *
-     * <P>This method returns a new array of the given length whose element are
-     * of the same class as of those of <code>prototype</code>. 
-     * In case of an empty array, it tries to return {@link #EMPTY_ARRAY}, if possible.
-     *
-     * @param prototype an array that will be used to type the new one.
-     * @param length the length of the new array.
-     * @return a new array of given type and length.
-     */
-    public static <A> A forPrototype(A prototype, int length) {
-        return NativeArray.wrap(prototype).allocate(length).$array();
-    }
-
-    /**
-     * 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 NativeArrayAllocator.ensureCapacity(NativeArray.wrap(array), length).$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>.
-     */
-    public static <A> A ensureCapacity(A array, int length, int preserve) {
-        return NativeArrayAllocator.ensureCapacity(NativeArray.wrap(array), length, preserve).$array();
-    }
-
-    /**
-     * 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 <A> void ensureOffsetLength(A array, int offset, int length) {
-        NativeArrayAllocator.ensureOffsetLength(NativeArray.wrap(array), offset, length);
-    }
-    
-    /**
-     * 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 <A> void ensureFromTo(A array, int begin, int end) {
-        NativeArrayAllocator.ensureFromTo(NativeArray.wrap(array), begin, end);
-    }
-    
-    /**
-     * 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 NativeArrayAllocator.grow(NativeArray.wrap(array), length).$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>.
-     *
-     */
-    public static <A> A grow(A array, int length, int preserve) {
-        return NativeArrayAllocator.grow(NativeArray.wrap(array), length, preserve).$array();
-    }
-    
-    /**
-     * 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>.
-     *
-     */
-    public static <A> A trim(A array, int length) {
-        return NativeArrayAllocator.trim(NativeArray.wrap(array), length).$array();
-    }
-    
-}
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.collection.arrays;
+
+public final class ArrayAllocator {
+   
+    private ArrayAllocator() {
+        // utility class
+    }
+    
+    public static <A> A forComponent(Class<?> component, int size) {
+        return NativeArray.allocate(component, size).$array();
+    }
+    
+    /**
+     * Creates a new array using a the given one as prototype.
+     *
+     * <P>This method returns a new array of the given length whose element are
+     * of the same class as of those of <code>prototype</code>. 
+     * In case of an empty array, it tries to return {@link #EMPTY_ARRAY}, if possible.
+     *
+     * @param prototype an array that will be used to type the new one.
+     * @param length the length of the new array.
+     * @return a new array of given type and length.
+     */
+    public static <A> A forPrototype(A prototype, int length) {
+        return NativeArray.wrap(prototype).allocate(length).$array();
+    }
+
+    /**
+     * 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 NativeArrayAllocator.ensureCapacity(NativeArray.wrap(array), length).$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>.
+     */
+    public static <A> A ensureCapacity(A array, int length, int preserve) {
+        return NativeArrayAllocator.ensureCapacity(NativeArray.wrap(array), length, preserve).$array();
+    }
+
+    /**
+     * 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 <A> void ensureOffsetLength(A array, int offset, int length) {
+        NativeArrayAllocator.ensureOffsetLength(NativeArray.wrap(array), offset, length);
+    }
+    
+    /**
+     * 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 <A> void ensureFromTo(A array, int begin, int end) {
+        NativeArrayAllocator.ensureFromTo(NativeArray.wrap(array), begin, end);
+    }
+    
+    public static <A> A resize(A array, int size) {
+        return NativeArrayAllocator.resize(NativeArray.wrap(array), size).$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.
+     *
+     * <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 NativeArrayAllocator.grow(NativeArray.wrap(array), length).$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>.
+     *
+     */
+    public static <A> A grow(A array, int length, int preserve) {
+        return NativeArrayAllocator.grow(NativeArray.wrap(array), length, preserve).$array();
+    }
+    
+    /**
+     * 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>.
+     *
+     */
+    public static <A> A trim(A array, int length) {
+        return NativeArrayAllocator.trim(NativeArray.wrap(array), length).$array();
+    }
+    
+}

+ 204 - 170
assira/src/main/java/net/ranides/assira/collection/arrays/ArrayUtils.java

@@ -1,170 +1,204 @@
-/*
- *  @author Ranides Atterwim <ranides@gmail.com>
- *  @copyright Ranides Atterwim
- *  @license WTFPL
- *  @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.collection.arrays;
-
-import java.lang.reflect.Array;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Random;
-import net.ranides.assira.collection.iterators.IntIterator;
-
-@SuppressWarnings({
-    "PMD.AvoidReassigningParameters"
-})
-public final class ArrayUtils {
-
-    private ArrayUtils() {
-        // utility class
-    }
-    
-    /**
-     * Unwraps an iterator into an array starting at a given offset for a given
-     * number of elements.
-     *
-     * <P>This method iterates over the given type-specific iterator and stores
-     * the elements returned, up to a maximum of
-     * <code>length</code>, in the given array starting at
-     * <code>offset</code>. The number of actually unwrapped elements is
-     * returned (it may be less than
-     * <code>max</code> if the iterator emits less than
-     * <code>max</code> elements).
-     *
-     * @param iterator a type-specific iterator.
-     * @param target an array to contain the output of the iterator.
-     * @param begin the first element of the array to be returned.
-     * @param end the maximum number of elements to collect.
-     * @return the number of elements unwrapped.
-     */
-    public static <A,T> int collect(Iterator<T> iterator, A target, int begin, int end) {
-        if($isint(target)) {
-            return $collect(IntIterator.$wrap(iterator), (int[])target, begin, end);
-        } else {
-            return NativeArrayUtils.collect(iterator, NativeArray.wrap(target), begin, end);
-        }
-    }
-
-    private static <A> boolean $isint(A array) {
-        return null!=array && int[].class.equals(array.getClass());
-    }
-    
-    /**
-     * Unwraps an iterator into an array.
-     *
-     * <P>This method iterates over the given type-specific iterator and stores
-     * the elements returned in the given array. The iteration will stop when
-     * the iterator has no more elements or when the end of the array has been
-     * reached.
-     *
-     * @param iterator a type-specific iterator.
-     * @param target an array to contain the output of the iterator.
-     * @return the number of elements unwrapped.
-     */
-    public static <A,T> int collect(Iterator<T> iterator, A target) {
-        if($isint(target)) {
-            int[] array = (int[])target;
-            return $collect(IntIterator.$wrap(iterator), array, 0, array.length);
-        } else {
-            return NativeArrayUtils.collect(iterator, NativeArray.wrap(target));
-        }
-    }
-    
-    static int $collect(IntIterator iterator, int target[], int begin, int end) {
-        NativeArrayAllocator.ensureFromTo(target.length, begin, end);
-        int j = end;
-        while (j-- != 0 && iterator.hasNext()) {
-            target[begin++] = iterator.nextInt();
-        }
-        return end - j - 1;
-    }
-        
-    /**
-     * Fills the given array with the given value.
-     *
-     * <P>This method uses a backward loop. It is significantly faster than the
-     * corresponding method in {@link java.util.Arrays}.
-     *
-     * @param array an array.
-     * @param value the new value for all elements of the array.
-     */
-    public static <A,T> void fill(A array, T value) {
-        NativeArrayUtils.fill(NativeArray.wrap(array), value);
-    }
-
-    /**
-     * Fills a portion of the given array with the given value.
-     *
-     * <P>If possible (i.e.,
-     * <code>from</code> is 0) this method uses a backward loop. In this case,
-     * it is significantly faster than the corresponding method in
-     * {@link java.util.Arrays}.
-     *
-     * @param array an array.
-     * @param begin the starting index of the portion to fill (inclusive).
-     * @param end the end index of the portion to fill (exclusive).
-     * @param value the new value for all elements of the specified portion of
-     * the array.
-     */
-    public static <A,T> void fill(A array, int begin, int end, T value) {
-        NativeArrayUtils.fill(NativeArray.wrap(array), begin, end, value);
-    }
-
-    /**
-     * Reverses the order of the elements in the specified array.
-     *
-     * @param array the array to be reversed.
-     * @return <code>a</code>.
-     */
-    public static <A> A reverse(A array) {
-        NativeArrayUtils.reverse(NativeArray.wrap(array));
-        return array;
-    }
-    
-    /**
-     * Returns true if the two arrays are elementwise equal.
-     *
-     * <P>This method uses a backward loop. It is significantly faster than the
-     * corresponding method in {@link java.util.Arrays}.
-     *
-     * @param array1 an array.
-     * @param array2 another array.
-     * @return true if the two arrays are of the same length, and their elements
-     * are equal.
-     */
-    public static <A> boolean equals(A array1, A array2) {
-        return NativeArrayUtils.equals(NativeArray.wrap(array1), NativeArray.wrap(array2));
-    }
-
-    public static <A,T> A head(A array, T value, Comparator<? super T> cmp) {
-        return NativeArrayUtils.head(NativeArray.wrap(array), value, cmp).$array();
-    }
-    
-    public static <A,T> A tail(A array, T value, Comparator<? super T> cmp) {
-        return NativeArrayUtils.tail(NativeArray.wrap(array), value, cmp).$array();
-    }
-   
-    public static <A,T> A slice(A values, T begin, T end, Comparator<? super T> cmp) {
-        return NativeArrayUtils.slice(NativeArray.wrap(values), begin, end, cmp).$array();
-    }
-    
-    public static <A> A slice(A array, int begin, int end) {
-        return NativeArrayUtils.slice(NativeArray.wrap(array), begin, end).$array();
-    }
-    
-    public static <A> void shuffle(Random random, A array) {
-        NativeArrayUtils.shuffle(random, NativeArray.wrap(array));
-    }
-    
-    public static <A> int size(A array) {
-        return null == array ? 0 : Array.getLength(array);
-    }
-    
-    @SuppressWarnings("SuspiciousSystemArraycopy")
-    public static <A> void copy(A src, int srcpos, A dst, int dstpos, int size) {
-        System.arraycopy(src, srcpos, dst, dstpos, size);
-    }
-    
-}
+/*
+ *  @author Ranides Atterwim <ranides@gmail.com>
+ *  @copyright Ranides Atterwim
+ *  @license WTFPL
+ *  @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.collection.arrays;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Random;
+import net.ranides.assira.collection.iterators.IntIterator;
+
+@SuppressWarnings({
+    "PMD.AvoidReassigningParameters"
+})
+public final class ArrayUtils {
+
+    private ArrayUtils() {
+        // utility class
+    }
+    
+    /**
+     * Unwraps an iterator into an array starting at a given offset for a given
+     * number of elements.
+     *
+     * <P>This method iterates over the given type-specific iterator and stores
+     * the elements returned, up to a maximum of
+     * <code>length</code>, in the given array starting at
+     * <code>offset</code>. The number of actually unwrapped elements is
+     * returned (it may be less than
+     * <code>max</code> if the iterator emits less than
+     * <code>max</code> elements).
+     *
+     * @param iterator a type-specific iterator.
+     * @param target an array to contain the output of the iterator.
+     * @param begin the first element of the array to be returned.
+     * @param end the maximum number of elements to collect.
+     * @return the number of elements unwrapped.
+     */
+    public static <A,T> int collect(Iterator<T> iterator, A target, int begin, int end) {
+        if($isint(target)) {
+            return $collect(IntIterator.$wrap(iterator), (int[])target, begin, end);
+        } else {
+            return NativeArrayUtils.collect(iterator, NativeArray.wrap(target), begin, end);
+        }
+    }
+
+    private static <A> boolean $isint(A array) {
+        return null!=array && int[].class.equals(array.getClass());
+    }
+    
+    /**
+     * Unwraps an iterator into an array.
+     *
+     * <P>This method iterates over the given type-specific iterator and stores
+     * the elements returned in the given array. The iteration will stop when
+     * the iterator has no more elements or when the end of the array has been
+     * reached.
+     *
+     * @param iterator a type-specific iterator.
+     * @param target an array to contain the output of the iterator.
+     * @return the number of elements unwrapped.
+     */
+    public static <A,T> int collect(Iterator<T> iterator, A target) {
+        if($isint(target)) {
+            int[] array = (int[])target;
+            return $collect(IntIterator.$wrap(iterator), array, 0, array.length);
+        } else {
+            return NativeArrayUtils.collect(iterator, NativeArray.wrap(target));
+        }
+    }
+    
+    static int $collect(IntIterator iterator, int target[], int begin, int end) {
+        NativeArrayAllocator.ensureFromTo(target.length, begin, end);
+        int j = end;
+        while (j-- != 0 && iterator.hasNext()) {
+            target[begin++] = iterator.nextInt();
+        }
+        return end - j - 1;
+    }
+        
+    /**
+     * Fills the given array with the given value.
+     *
+     * <P>This method uses a backward loop. It is significantly faster than the
+     * corresponding method in {@link java.util.Arrays}.
+     *
+     * @param array an array.
+     * @param value the new value for all elements of the array.
+     */
+    public static <A,T> void fill(A array, T value) {
+        NativeArrayUtils.fill(NativeArray.wrap(array), value);
+    }
+
+    /**
+     * Fills a portion of the given array with the given value.
+     *
+     * <P>If possible (i.e.,
+     * <code>from</code> is 0) this method uses a backward loop. In this case,
+     * it is significantly faster than the corresponding method in
+     * {@link java.util.Arrays}.
+     *
+     * @param array an array.
+     * @param begin the starting index of the portion to fill (inclusive).
+     * @param end the end index of the portion to fill (exclusive).
+     * @param value the new value for all elements of the specified portion of
+     * the array.
+     */
+    public static <A,T> void fill(A array, int begin, int end, T value) {
+        NativeArrayUtils.fill(NativeArray.wrap(array), begin, end, value);
+    }
+
+    /**
+     * Reverses the order of the elements in the specified array.
+     *
+     * @param array the array to be reversed.
+     * @return <code>a</code>.
+     */
+    public static <A> A reverse(A array) {
+        NativeArrayUtils.reverse(NativeArray.wrap(array));
+        return array;
+    }
+    
+    /**
+     * Returns true if the two arrays are elementwise equal.
+     *
+     * <P>This method uses a backward loop. It is significantly faster than the
+     * corresponding method in {@link java.util.Arrays}.
+     *
+     * @param array1 an array.
+     * @param array2 another array.
+     * @return true if the two arrays are of the same length, and their elements
+     * are equal.
+     */
+    public static <A> boolean equals(A array1, A array2) {
+        return NativeArrayUtils.equals(NativeArray.wrap(array1), NativeArray.wrap(array2));
+    }
+    
+     public static <A,T> A head(A array, int index) {
+        return NativeArrayUtils.head(NativeArray.wrap(array), index).$array();
+    }
+
+    public static <A,T> A head(A array, T value, Comparator<? super T> cmp) {
+        return NativeArrayUtils.head(NativeArray.wrap(array), value, cmp).$array();
+    }
+    
+    public static <A,T> A tail(A array, int index) {
+        return NativeArrayUtils.tail(NativeArray.wrap(array), index).$array();
+    }
+    
+    public static <A,T> A tail(A array, T value, Comparator<? super T> cmp) {
+        return NativeArrayUtils.tail(NativeArray.wrap(array), value, cmp).$array();
+    }
+   
+    public static <A,T> A slice(A values, T begin, T end, Comparator<? super T> cmp) {
+        return NativeArrayUtils.slice(NativeArray.wrap(values), begin, end, cmp).$array();
+    }
+    
+    public static <A> A slice(A array, int begin, int end) {
+        return NativeArrayUtils.slice(NativeArray.wrap(array), begin, end).$array();
+    }
+    
+    public static <A> A shift(A array, int offset) {
+        return NativeArrayUtils.shift(NativeArray.wrap(array), offset).$array();
+    }
+    
+    public static <A> void shuffle(Random random, A array) {
+        NativeArrayUtils.shuffle(random, NativeArray.wrap(array));
+    }
+    
+    public static <A> int size(A array) {
+        return null == array ? 0 : Array.getLength(array);
+    }
+    
+    public static <A> boolean isEmpty(A array) {
+        return 0 == size(array);
+    }
+    
+    @SuppressWarnings("SuspiciousSystemArraycopy")
+    public static <A> A copy(A src, int srcpos, A dst, int dstpos, int size) {
+        System.arraycopy(src, srcpos, dst, dstpos, size);
+        return dst;
+    }
+    
+    public static <A> A copy(A array) {
+        int n = Array.getLength(array);
+        return copy(array, 0, ArrayAllocator.forPrototype(array, n), 0, n);
+    }
+    
+    public static <A> A concat(A a, A b) {
+        return NativeArrayUtils.concat(NativeArray.wrap(a), NativeArray.wrap(b)).$array();
+    }
+
+    public static <A> Iterator<Object> iterator(A array) {
+        return NativeArrayUtils.iterator(NativeArray.wrap(array));
+    }
+
+    public static <A> Iterator<Object> iterator(A array, int begin, int end) {
+        return NativeArrayUtils.iterator(NativeArray.wrap(array), begin, end);
+    }
+}

+ 13 - 13
assira/src/main/java/net/ranides/assira/collection/arrays/NativeArray.java

@@ -106,17 +106,17 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         return (a,b)-> cmp.compare(get(a), get(b));
     }
     
-    protected abstract int ihash(int index);
-    
     @Override
     public int hashCode() {
-        return hashCode(0, size());
+        return NativeArray.this.hashCode(0, size());
     }
     
+    public abstract int hashCode(int index);
+    
     public int hashCode(int begin, int end) {
         int result = 1;
         for(int i=begin; i<end; i++) {
-            result = 31 * result + ihash(i);
+            result = 31 * result + hashCode(i);
         }
         return result;
     }
@@ -376,7 +376,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
 
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return array[index];
         }
 
@@ -481,7 +481,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return array[index];
         }
         
@@ -626,7 +626,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return array[index];
         }
         
@@ -731,7 +731,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return (int)(array[index] ^ (array[index] >>> 32));
         }
         
@@ -836,7 +836,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return Float.floatToIntBits(array[index]);
         }
         
@@ -941,7 +941,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             long bits = Double.doubleToLongBits(array[index]);
             return (int)(bits ^ (bits >>> 32));
         }
@@ -1047,7 +1047,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return array[index];
         }
         
@@ -1152,7 +1152,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return array[index] ? 1231 : 1237;
         }
         
@@ -1255,7 +1255,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray>, C
         }
         
         @Override
-        protected int ihash(int index) {
+        public int hashCode(int index) {
             return null == array[index] ? 0 : array[index].hashCode();
         }
         

+ 252 - 229
assira/src/main/java/net/ranides/assira/collection/arrays/NativeArrayAllocator.java

@@ -1,229 +1,252 @@
-/*
- * @author Ranides Atterwim <ranides@gmail.com>
- * @copyright Ranides Atterwim
- * @license WTFPL
- * @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.collection.arrays;
-
-import java.util.ArrayList;
-
-public final class NativeArrayAllocator {
-    
-    /**
-     * This is a safe value used by {@link ArrayList} (as of Java 7) to avoid
-     * throwing {@link OutOfMemoryError} on some JVMs. We adopt the same value.
-     */
-    private static final int MAX_SIZE = Integer.MAX_VALUE - 8;
-    
-    private NativeArrayAllocator() {
-        // utility class
-    }
-    
-    /**
-     * 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 NativeArray ensureCapacity(NativeArray array, int length) {
-        return ensureCapacity(array, length, -1);
-    }
-    
-    /**
-     * 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>.
-     */
-    public static NativeArray ensureCapacity(NativeArray array, int length, int preserve) {
-        int n = array.size();
-        if(preserve < 0) {
-            preserve = n;
-        }
-        if (length > n) {
-            NativeArray target = array.allocate(length);
-            NativeArrayUtils.copy(array, 0, target, 0, preserve);
-            return target;
-        }
-        return array;
-    }
-    
-    /**
-     * 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(NativeArray array, int offset, int length) {
-        ensureOffsetLength(array.size(), offset, length);
-    }
-    
-    /**
-     * Ensures that a range given by an offset and a length fits an array of
-     * given length.
-     *
-     * <P>This method may be used whenever an array range check is needed.
-     *
-     * @param arrayLength an array length.
-     * @param offset a start index for the fragment
-     * @param length a length (the number of elements in the fragment).
-     * @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 <code>arrayLength</code>.
-     */
-    public static void ensureOffsetLength(int arrayLength, int offset, int length) {
-        if (offset < 0) {
-            throw new ArrayIndexOutOfBoundsException("Offset (" + offset + ") is negative");
-        }
-        if (length < 0) {
-            throw new IllegalArgumentException("Length (" + length + ") is negative");
-        }
-        if (offset + length > arrayLength) {
-            throw new ArrayIndexOutOfBoundsException("Last index (" + (offset + length) + ") is greater than array length (" + arrayLength + ")");
-        }
-    }
-
-    /**
-     * 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(NativeArray array, int begin, int end) {
-        ensureFromTo(array.size(), begin, end);
-    }
-    
-    /**
-     * Ensures that a range given by its first (inclusive) and last (exclusive)
-     * elements fits an array of given length.
-     *
-     * <P>This method may be used whenever an array range check is needed.
-     *
-     * @param arrayLength an array length.
-     * @param begin a start index (inclusive).
-     * @param end an end index (inclusive).
-     * @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 <code>arrayLength</code> or
-     * negative.
-     */
-    public static void ensureFromTo(int arrayLength, int begin, int end) {
-        if (begin < 0) {
-            throw new ArrayIndexOutOfBoundsException("Start index (" + begin + ") is negative");
-        }
-        if (begin > end) {
-            throw new IllegalArgumentException("Start index (" + begin + ") is greater than end index (" + end + ")");
-        }
-        if (end > arrayLength) {
-            throw new ArrayIndexOutOfBoundsException("End index (" + end + ") is greater than array length (" + arrayLength + ")");
-        }
-    }
- 
-    /**
-     * 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 NativeArray grow(NativeArray array, int length) {
-        return grow(array, length, -1);
-    }
-    
-    /**
-     * 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>.
-     *
-     */
-    public static NativeArray grow(NativeArray array, int length, int preserve) {
-        int n = array.size();
-        if(preserve < 0) {
-            preserve = n;
-        }
-        if (length > n) {
-            int newLength = (int) Math.min(Math.max(2L * n, length), MAX_SIZE);
-            NativeArray target = array.allocate(newLength);
-            NativeArrayUtils.copy(array, 0, target, 0, preserve);
-            return target;
-        }
-        return array;
-    }
-
-    /**
-     * 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>.
-     *
-     */
-    public static NativeArray trim(NativeArray array, int length) {
-        if (length >= array.size()) {
-            return array;
-        }
-        NativeArray target = array.allocate(length);
-        NativeArrayUtils.copy(array, 0, target, 0, length);
-        return target;
-    }
-
-    
-}
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.collection.arrays;
+
+import java.util.ArrayList;
+
+public final class NativeArrayAllocator {
+    
+    /**
+     * This is a safe value used by {@link ArrayList} (as of Java 7) to avoid
+     * throwing {@link OutOfMemoryError} on some JVMs. We adopt the same value.
+     */
+    private static final int MAX_SIZE = Integer.MAX_VALUE - 8;
+    
+    private NativeArrayAllocator() {
+        // utility class
+    }
+    
+    public static NativeArray forComponent(Class<?> component, int size) {
+        return NativeArray.allocate(component, size);
+    }
+    
+    /**
+     * Creates a new array using a the given one as prototype.
+     *
+     * <P>This method returns a new array of the given length whose element are
+     * of the same class as of those of <code>prototype</code>. 
+     * In case of an empty array, it tries to return {@link #EMPTY_ARRAY}, if possible.
+     *
+     * @param prototype an array that will be used to type the new one.
+     * @param length the length of the new array.
+     * @return a new array of given type and length.
+     */
+    public static NativeArray forPrototype(NativeArray prototype, int length) {
+        return prototype.allocate(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 NativeArray ensureCapacity(NativeArray array, int length) {
+        return ensureCapacity(array, length, -1);
+    }
+    
+    /**
+     * 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>.
+     */
+    public static NativeArray ensureCapacity(NativeArray array, int length, int preserve) {
+        int n = array.size();
+        if(preserve < 0) {
+            preserve = n;
+        }
+        if (length > n) {
+            NativeArray target = array.allocate(length);
+            NativeArrayUtils.copy(array, 0, target, 0, preserve);
+            return target;
+        }
+        return array;
+    }
+    
+    /**
+     * 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(NativeArray array, int offset, int length) {
+        ensureOffsetLength(array.size(), offset, length);
+    }
+    
+    /**
+     * Ensures that a range given by an offset and a length fits an array of
+     * given length.
+     *
+     * <P>This method may be used whenever an array range check is needed.
+     *
+     * @param arrayLength an array length.
+     * @param offset a start index for the fragment
+     * @param length a length (the number of elements in the fragment).
+     * @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 <code>arrayLength</code>.
+     */
+    public static void ensureOffsetLength(int arrayLength, int offset, int length) {
+        if (offset < 0) {
+            throw new ArrayIndexOutOfBoundsException("Offset (" + offset + ") is negative");
+        }
+        if (length < 0) {
+            throw new IllegalArgumentException("Length (" + length + ") is negative");
+        }
+        if (offset + length > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException("Last index (" + (offset + length) + ") is greater than array length (" + arrayLength + ")");
+        }
+    }
+
+    /**
+     * 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(NativeArray array, int begin, int end) {
+        ensureFromTo(array.size(), begin, end);
+    }
+    
+    /**
+     * Ensures that a range given by its first (inclusive) and last (exclusive)
+     * elements fits an array of given length.
+     *
+     * <P>This method may be used whenever an array range check is needed.
+     *
+     * @param arrayLength an array length.
+     * @param begin a start index (inclusive).
+     * @param end an end index (inclusive).
+     * @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 <code>arrayLength</code> or
+     * negative.
+     */
+    public static void ensureFromTo(int arrayLength, int begin, int end) {
+        if (begin < 0) {
+            throw new ArrayIndexOutOfBoundsException("Start index (" + begin + ") is negative");
+        }
+        if (begin > end) {
+            throw new IllegalArgumentException("Start index (" + begin + ") is greater than end index (" + end + ")");
+        }
+        if (end > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException("End index (" + end + ") is greater than array length (" + arrayLength + ")");
+        }
+    }
+    
+    public static NativeArray resize(NativeArray array, int size) {
+        return NativeArrayUtils.copy(array, 0, array.allocate(size), 0, Math.min(size, array.size()));
+    }
+ 
+    /**
+     * 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 NativeArray grow(NativeArray array, int length) {
+        return grow(array, length, -1);
+    }
+    
+    /**
+     * 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>.
+     *
+     */
+    public static NativeArray grow(NativeArray array, int length, int preserve) {
+        int n = array.size();
+        if(preserve < 0) {
+            preserve = n;
+        }
+        if (length > n) {
+            int newLength = (int) Math.min(Math.max(2L * n, length), MAX_SIZE);
+            NativeArray target = array.allocate(newLength);
+            NativeArrayUtils.copy(array, 0, target, 0, preserve);
+            return target;
+        }
+        return array;
+    }
+
+    /**
+     * 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>.
+     *
+     */
+    public static NativeArray trim(NativeArray array, int length) {
+        if (length >= array.size()) {
+            return array;
+        }
+        NativeArray target = array.allocate(length);
+        NativeArrayUtils.copy(array, 0, target, 0, length);
+        return target;
+    }
+
+    
+}

+ 190 - 119
assira/src/main/java/net/ranides/assira/collection/arrays/NativeArrayUtils.java

@@ -1,119 +1,190 @@
-/*
- *  @author Ranides Atterwim <ranides@gmail.com>
- *  @copyright Ranides Atterwim
- *  @license WTFPL
- *  @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.collection.arrays;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Random;
-import net.ranides.assira.collection.Swapper;
-import net.ranides.assira.collection.arrays.NativeArray.NativeComparator;
-
-@SuppressWarnings({
-    "PMD.AvoidReassigningParameters"
-})
-public final class NativeArrayUtils {
-
-    private NativeArrayUtils() {
-        // utility class
-    }
-    
-    public static <T> int collect(Iterator<? extends T> iterator, NativeArray target, int begin, int end) {
-        NativeArrayAllocator.ensureFromTo(target, begin, end);
-        int j = end;
-        while (j-- != 0 && iterator.hasNext()) {
-            target.set(begin++, iterator.next());
-        }
-        return end - j - 1;
-    }
-
-    public static <T> int collect(Iterator<? extends T> iterator, NativeArray target) {
-        return collect(iterator, target, 0, target.size());
-    }
-
-    /**
-     * Fills the given array with the given value.
-     *
-     * <P>This method uses a backward loop. It is significantly faster than the
-     * corresponding method in {@link java.util.Arrays}.
-     *
-     * @param array an array.
-     * @param value the new value for all elements of the array.
-     */
-    public static <T> void fill(NativeArray array, T value) {
-        array.set(0, array.size(), value);
-    }
-
-    public static <T> void fill(NativeArray array, int begin, int end, T value) {
-        NativeArrayAllocator.ensureFromTo(array, begin, end);
-        array.set(begin, end, value);
-    }
-
-    public static void reverse(int size, Swapper swapper) {
-        for (int i = size / 2; i-- != 0;) {
-            swapper.swap(size - i - 1, i);
-        }
-    }
-    
-    public static NativeArray reverse(NativeArray array) {
-        reverse(array.size(), array);
-        return array;
-    }
-    
-    public static boolean equals(NativeArray array1, NativeArray array2) {
-        return array1.equals(array2);
-    }
-
-    public static <T> NativeArray head(NativeArray values, T value, Comparator<? super T> cmp) {
-        return slice(values, 0, ifind(values, value, 0, cmp));
-    }
-    
-    public static <T> NativeArray tail(NativeArray values, T value, Comparator<? super T> cmp) {
-        return slice(values, ifind(values, value, 0, cmp), values.size());
-    }
-    
-    public static <T> NativeArray slice(NativeArray values, T begin, T end, Comparator<? super T> cmp) {
-        int bi = ifind(values, begin, 0, cmp);
-        int ei = ifind(values, end, bi, cmp);
-        return slice(values, bi, ei);
-    }
-
-    public static NativeArray slice(NativeArray values, int begin, int end) {
-        int size = end - begin;
-        NativeArray result = values.allocate(size);
-        NativeArrayUtils.copy(values, begin, result, 0, size);
-        return result;
-    }
-    
-    private static <T> int ifind(NativeArray values, T value, int begin, Comparator<? super T> cmp) {
-        NativeComparator icmp = values.rcmp(value, cmp);
-        int i = begin, n = values.size();
-        while(i<n && icmp.compare(i) < 0) {
-            i++;
-        }
-        return i;
-    }
-    
-    public static void shuffle(Random random, NativeArray array) {
-        shuffle(random, array.size(), array);
-    }
-    
-    public static void shuffle(Random random, int size, Swapper swapper) {
-        for(int i=0; i<size; i++) {
-            swapper.swap(random.nextInt(size), random.nextInt(size));
-        }
-    }
-    
-    public static int size(NativeArray array) {
-        return array.size();
-    }
-    
-    @SuppressWarnings("SuspiciousSystemArraycopy")
-    public static <T> void copy(NativeArray src, int srcpos, NativeArray dst, int dstpos, int size) {
-        System.arraycopy(src.array(), srcpos, dst.array(), dstpos, size);
-    }
-    
-}
+/*
+ *  @author Ranides Atterwim <ranides@gmail.com>
+ *  @copyright Ranides Atterwim
+ *  @license WTFPL
+ *  @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.collection.arrays;
+
+import java.lang.reflect.Array;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Random;
+import net.ranides.assira.collection.Swapper;
+import static net.ranides.assira.collection.arrays.ArrayUtils.copy;
+import static net.ranides.assira.collection.arrays.ArrayUtils.size;
+import net.ranides.assira.collection.arrays.NativeArray.NativeComparator;
+import net.ranides.assira.collection.iterators.AListIterator;
+import net.ranides.assira.collection.iterators.RandomAccessIterator;
+
+@SuppressWarnings({
+    "PMD.AvoidReassigningParameters"
+})
+public final class NativeArrayUtils {
+
+    private NativeArrayUtils() {
+        // utility class
+    }
+    
+    public static <T> int collect(Iterator<? extends T> iterator, NativeArray target, int begin, int end) {
+        NativeArrayAllocator.ensureFromTo(target, begin, end);
+        int j = end;
+        while (j-- != 0 && iterator.hasNext()) {
+            target.set(begin++, iterator.next());
+        }
+        return end - j - 1;
+    }
+
+    public static <T> int collect(Iterator<? extends T> iterator, NativeArray target) {
+        return collect(iterator, target, 0, target.size());
+    }
+
+    /**
+     * Fills the given array with the given value.
+     *
+     * <P>This method uses a backward loop. It is significantly faster than the
+     * corresponding method in {@link java.util.Arrays}.
+     *
+     * @param array an array.
+     * @param value the new value for all elements of the array.
+     */
+    public static <T> void fill(NativeArray array, T value) {
+        array.set(0, array.size(), value);
+    }
+
+    public static <T> void fill(NativeArray array, int begin, int end, T value) {
+        NativeArrayAllocator.ensureFromTo(array, begin, end);
+        array.set(begin, end, value);
+    }
+
+    public static void reverse(int size, Swapper swapper) {
+        for (int i = size / 2; i-- != 0;) {
+            swapper.swap(size - i - 1, i);
+        }
+    }
+    
+    public static NativeArray reverse(NativeArray array) {
+        reverse(array.size(), array);
+        return array;
+    }
+    
+    public static boolean equals(NativeArray array1, NativeArray array2) {
+        return array1.equals(array2);
+    }
+    
+    public static <T> NativeArray head(NativeArray values, int index) {
+        return slice(values, 0, index);
+    }
+
+    public static <T> NativeArray head(NativeArray values, T value, Comparator<? super T> cmp) {
+        return slice(values, 0, ifind(values, value, 0, cmp));
+    }
+    
+    public static <T> NativeArray tail(NativeArray values, int index) {
+        return slice(values, index, values.size());
+    }
+    
+    public static <T> NativeArray tail(NativeArray values, T value, Comparator<? super T> cmp) {
+        return slice(values, ifind(values, value, 0, cmp), values.size());
+    }
+    
+    public static <T> NativeArray slice(NativeArray values, T begin, T end, Comparator<? super T> cmp) {
+        int bi = ifind(values, begin, 0, cmp);
+        int ei = ifind(values, end, bi, cmp);
+        return slice(values, bi, ei);
+    }
+
+    public static NativeArray slice(NativeArray values, int begin, int end) {
+        int size = end - begin;
+        NativeArray result = values.allocate(size);
+        NativeArrayUtils.copy(values, begin, result, 0, size);
+        return result;
+    }
+    
+    public static <A> NativeArray shift(NativeArray array, int offset) {
+        int n = array.size();
+        if(offset > 0) {
+            for(int i=n-1; i>=0; i--) {
+                array.move(i, (i+offset)%n);
+            }
+        } else {
+            offset += n;
+            for(int i=0; i<n; i++) {
+                array.move(i, (i-offset)%n);
+            }
+        }
+        return array;
+    }
+    
+    private static <T> int ifind(NativeArray values, T value, int begin, Comparator<? super T> cmp) {
+        NativeComparator icmp = values.rcmp(value, cmp);
+        int i = begin, n = values.size();
+        while(i<n && icmp.compare(i) < 0) {
+            i++;
+        }
+        return i;
+    }
+    
+    public static void shuffle(Random random, NativeArray array) {
+        shuffle(random, array.size(), array);
+    }
+    
+    public static void shuffle(Random random, int size, Swapper swapper) {
+        for(int i=0; i<size; i++) {
+            swapper.swap(random.nextInt(size), random.nextInt(size));
+        }
+    }
+    
+    public static int size(NativeArray array) {
+        return array.size();
+    }
+    
+    public static <A> boolean isEmpty(NativeArray array) {
+        return 0 == array.size();
+    }
+    
+    @SuppressWarnings("SuspiciousSystemArraycopy")
+    public static <T> NativeArray copy(NativeArray src, int srcpos, NativeArray dst, int dstpos, int size) {
+        System.arraycopy(src.array(), srcpos, dst.array(), dstpos, size);
+        return dst;
+    }
+    
+    public static NativeArray copy(NativeArray array) {
+        int n = array.size();
+        return copy(array, 0, NativeArrayAllocator.forPrototype(array, n), 0, n);
+    }
+    
+    public static NativeArray concat(NativeArray a, NativeArray b) {
+        int as = a.size();
+        int bs = b.size();
+        NativeArray result = a.allocate(as+bs);
+        copy(a, 0, result, 0, as);
+        copy(b, 0, result, as, bs);
+        return result;
+    }
+    
+    public static Iterator<Object> iterator(NativeArray array) {
+        return iterator(array, 0, array.size());
+    }
+
+    public static Iterator<Object> iterator(NativeArray array, int begin, int end) {
+        return new RandomAccessIterator<Object>() {
+            @Override
+            protected int size() {
+                return end-begin;
+            }
+
+            @Override
+            protected Object get(int index) {
+                return array.get(begin+index);
+            }
+
+            @Override
+            protected void set(int index, Object value) {
+                array.set(begin+index, value);
+            }
+            
+        };
+    }
+    
+}

+ 110 - 0
assira/src/main/java/net/ranides/assira/collection/iterators/RandomAccessIterator.java

@@ -0,0 +1,110 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.collection.iterators;
+
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public abstract class RandomAccessIterator<T> implements ListIterator<T> {
+    
+    private int index;
+    
+    private int cursor;
+
+    protected abstract int size();
+    
+    protected abstract T get(int index);
+    
+    protected void remove(int index) {
+        throw new UnsupportedOperationException();
+    }
+    
+    protected void add(int index, T value) {
+        throw new UnsupportedOperationException();
+    }
+    
+    protected void set(int index, T value) {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Tworzy iterator wskazujący na pierwszą pozycję w liście
+     */
+    public RandomAccessIterator() {
+        this(0);
+    }
+
+    /**
+     * Tworzy iterator wskazujący na podaną pozycję w liście
+     * @param index
+     */
+    public RandomAccessIterator(int index) {
+        this.index = index;
+        this.cursor = index;
+    }
+
+    @Override
+    public final void set(T value) {
+        if (index == -1) {
+            throw new IllegalStateException("set must be called after next or previous");
+        }
+        set(index, value);
+    }
+
+    @Override
+    public final void add(T value) {
+        add(index, value);
+        index++;
+        cursor++;
+    }
+
+    @Override
+    public final void remove() {
+        remove(index);
+        index = - 1;
+    }
+
+    @Override
+    public final boolean hasNext() {
+        return cursor < size();
+    }
+
+    @Override
+    public final T next() {
+        if( cursor >= size() ) { 
+            throw new NoSuchElementException(); 
+        }
+        index = cursor++;
+        return get(index);
+    }
+
+    @Override
+    public final boolean hasPrevious() {
+        return cursor > 0;
+    }
+
+    @Override
+    public final T previous() {
+        if( cursor < 1 ) { 
+            throw new NoSuchElementException(); 
+        }
+        index = --cursor;
+        return get(index);
+    }
+
+    @Override
+    public final int nextIndex() {
+        return cursor;
+    }
+
+    @Override
+    public final int previousIndex() {
+        return cursor - 1;
+    }
+    
+    
+}