Explorar o código

new: NativeArray#clone
new: NativeArray#box / #unbox

fix: NativeArray#compareTo
fix: NativeArray#toString

new: reflect.ClassTraits
new: reflect.ClassUtils

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

+ 3 - 0
assira/pom.xml

@@ -143,6 +143,9 @@
                                 <exclude>net/ranides/assira/collection/arrays/NativeArraySearch.class</exclude>
                                 <exclude>net/ranides/assira/collection/arrays/NativeArraySort.class</exclude>
                                 
+                                <exclude>net/ranides/assira/collection/arrays/NativeArray.class</exclude>
+                                <exclude>net/ranides/assira/collection/arrays/NativeArray$*</exclude>
+                                
                                 <!--                                
                                 <exclude>net/ranides/assira/collection/arrays/ArrayUtils.class</exclude>
                                 <exclude>net/ranides/assira/collection/arrays/ArrayUtils$*</exclude>

+ 2 - 8
assira/src/main/java/net/ranides/assira/collection/arrays/ArraySort.java

@@ -202,7 +202,7 @@ public final class ArraySort {
      * @param end the index of the last element (exclusive) to be sorted.
      */
     public static void mergeSort(NativeArray array, int begin, int end) {
-        mergeSort(array, begin, end, clone(array));
+        mergeSort(array, begin, end, array.clone());
     }
     
     public static <K> void mergeSort(K[] array, int begin, int end) {
@@ -263,7 +263,7 @@ public final class ArraySort {
      * @param comp the comparator to determine the sorting order.
      */
     public static void mergeSort(NativeArray array, int begin, int end, Comparator comp) {
-        NativeArray supp = clone(array);
+        NativeArray supp = array.clone();
         MergeArray a = new MergeArray(array, supp, comp);
         MergeArray s = new MergeArray(supp, array, comp);
         mergeSort(begin, end, comp, a, s);
@@ -524,12 +524,6 @@ public final class ArraySort {
         }
     }
     
-    private static NativeArray clone(NativeArray array) {
-        NativeArray ret = array.allocate(array.size());
-        ArrayUtils.copy(array, 0, ret, 0, array.size());
-        return ret;
-    }
-    
     private static final class MergeArray {
         public final NativeArray array;
         public final IntComparator icmp;

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

@@ -7,18 +7,19 @@
 package net.ranides.assira.collection.arrays;
 
 import java.lang.reflect.Array;
+import java.util.Arrays;
 import java.util.Comparator;
 import net.ranides.assira.collection.IntComparator;
 import net.ranides.assira.collection.Swapper;
 import net.ranides.assira.generic.CompareUtils;
+import net.ranides.assira.reflection.util.ClassTraits;
+import net.ranides.assira.reflection.util.ClassUtils;
 
 /**
  *
  * @author Ranides Atterwim <ranides@gmail.com>
  */
-public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
-
-    private static final NativeArray NULL = new NULLArray();
+public abstract class NativeArray implements Swapper, Comparable<NativeArray>, Cloneable {
     
     public abstract NativeArray allocate(int size);
     
@@ -44,6 +45,41 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
     public abstract NativeMove move(NativeArray source);
     
     public abstract void move(int index, int source);
+    
+    @Override
+    @SuppressWarnings({
+        "PMD",
+        "CloneDoesntCallSuperClone", 
+        "CloneDeclaresCloneNotSupported", 
+        "SuspiciousSystemArraycopy"
+    })
+    public NativeArray clone() {
+        NativeArray ret = allocate(size());
+        System.arraycopy(array(), 0, ret.array(), 0, size());
+        return ret;
+    }
+    
+    public NativeArray box() {
+        if(ClassTraits.isBoxed(component())) {
+            return this;
+        }
+        NativeArray ret = allocate(ClassUtils.box(component()), size());
+        for(int i=0, n=size(); i<n; i++) {
+            ret.set(i, get(i));
+        }
+        return ret;
+    }
+    
+    public NativeArray unbox() {
+        if(!ClassTraits.isBoxed(component())) {
+            return this;
+        }
+        NativeArray ret = allocate(ClassUtils.unbox(component()), size());
+        for(int i=0, n=size(); i<n; i++) {
+            ret.set(i, get(i));
+        }
+        return ret;
+    }
 
     public abstract NativeComparator lcmp(Object value);
     
@@ -100,8 +136,17 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
         
     @Override
     public int compareTo(NativeArray object) {
-        int c = compareTo(object, 0, 0, size());
-        return 0 != c ? c : Integer.compare(size(), object.size());
+        int a = size();
+        int b = object.size();
+        int c = compareTo(object, 0, 0, Math.min(a,b));
+        return 0 != c ? c : Integer.compare(a, b);
+    }
+    
+    public int compareTo(NativeArray object, Comparator comp) {
+        int a = size();
+        int b = object.size();
+        int c = compareTo(object, 0, 0, Math.min(a,b), comp);
+        return 0 != c ? c : Integer.compare(a, b);
     }
     
     public int compareTo(NativeArray object, int src, int dst, int size) {
@@ -138,6 +183,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
         return 0;
     }
     
+    
     public interface NativeComparator {
 
         int compare(int index);
@@ -190,9 +236,6 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
         "PMD.CyclomaticComplexity"
     })
 	public static NativeArray wrap(Object array) {
-		if(null == array) {
-			return NULL;
-		}
         Class<?> c = array.getClass().getComponentType();
         if(!c.isPrimitive()) {
             return new ObjectArray(array);
@@ -236,110 +279,6 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
 		return new BooleanArray(array);
     }
     
-    private static final class NULLArray extends NativeArray {
-
-        @Override
-        public NativeArray allocate(int size) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public Object array() {
-            throw new UnsupportedOperationException();
-        }
-        
-        @Override
-        public int size() {
-            return 0;
-        }
-
-        @Override
-        public void set(int index, Object value) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        @Override
-        public void set(int begin, int end, Object value) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        @Override
-        public Object get(int index) {
-            throw new IndexOutOfBoundsException();
-        }
-        
-        @Override
-        public NativeMove move(NativeArray source) {
-            return (a,b)->{ throw new IndexOutOfBoundsException(); };
-        }
-        
-        @Override
-        public void move(int index, int source) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        @Override
-        public NativeComparator lcmp(Object value) {
-            return (v)->{ throw new IndexOutOfBoundsException(); };
-        }
-
-        @Override
-        public NativeComparator lcmp(Object value, Comparator cmp) {
-            return (v)->{ throw new IndexOutOfBoundsException(); };
-        }
-        
-        @Override
-        public NativeComparator rcmp(Object value) {
-            return (v)->{ throw new IndexOutOfBoundsException(); };
-        }
-
-        @Override
-        public NativeComparator rcmp(Object value, Comparator cmp) {
-            return (v)->{ throw new IndexOutOfBoundsException(); };
-        }
-
-        @Override
-        public IntComparator comparator() {
-            return (a,b)->{ throw new IndexOutOfBoundsException(); };
-        }
-
-        @Override
-        public IntComparator comparator(Comparator cmp) {
-            return (a,b)->{ throw new IndexOutOfBoundsException(); };
-        }
-
-        @Override
-        public void swap(int index1, int index2) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        @Override
-        public boolean equals(NativeArray object, int src, int dst, int size) {
-            return size==0;
-        }
-
-        @Override
-        public int compareTo(NativeArray array, int src, int dst, int size) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public IntComparator comparator(NativeArray values) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public IntComparator comparator(NativeArray values, Comparator cmp) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        protected int ihash(int index) {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-    
     private static final class ByteArray extends NativeArray {
         
         private static final byte[] EMPTY = new byte[0];
@@ -439,6 +378,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
         protected int ihash(int index) {
             return array[index];
         }
+
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
         
     }
     
@@ -542,6 +486,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return array[index];
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
     private static final class IntegerArray extends NativeArray {
@@ -684,6 +633,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return array[index];
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
     private static final class LongArray extends NativeArray {
@@ -786,6 +740,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return (int)(array[index] ^ (array[index] >>> 32));
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
     private static final class FloatArray extends NativeArray {
@@ -888,6 +847,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return Float.floatToIntBits(array[index]);
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
     private static final class DoubleArray extends NativeArray {
@@ -991,6 +955,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return (int)(bits ^ (bits >>> 32));
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
     private static final class CharacterArray extends NativeArray {
@@ -1093,6 +1062,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return array[index];
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
     private static final class BooleanArray extends NativeArray {
@@ -1195,6 +1169,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return array[index] ? 1231 : 1237;
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
     private static final class ObjectArray extends NativeArray {
@@ -1286,7 +1265,7 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
         @Override
         public IntComparator comparator(NativeArray values, Comparator cmp) {
             ObjectArray that = (ObjectArray)values;
-            return (a,b) -> CompareUtils.cmp(this.array[a], that.array[b]);
+            return (a,b) -> cmp.compare(this.array[a], that.array[b]);
         }
         
         @Override
@@ -1294,6 +1273,11 @@ public abstract class NativeArray implements Swapper, Comparable<NativeArray> {
             return null == array[index] ? 0 : array[index].hashCode();
         }
         
+        @Override
+        public String toString() {
+            return Arrays.toString(array);
+        }
+        
     }
     
 }

+ 77 - 0
assira/src/main/java/net/ranides/assira/reflection/util/ClassTraits.java

@@ -0,0 +1,77 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.util;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class ClassTraits {
+    
+    private ClassTraits() {
+        // utility class
+    }
+
+    // @todo (assira #2) benchmark: ClassTraits#isPrimitive 
+    public static boolean isPrimitive(Class<?> clazz) {
+        if(null == clazz) {
+            return false;
+        }
+        return
+            byte.class.equals(clazz) ||
+            short.class.equals(clazz) ||
+            int.class.equals(clazz) ||
+            long.class.equals(clazz) ||
+            char.class.equals(clazz) ||
+            float.class.equals(clazz) ||
+            double.class.equals(clazz) ||
+            boolean.class.equals(clazz) ||
+            void.class.equals(clazz);
+    }
+    
+    public static boolean isPrimitiveArray(Class<?> clazz) {
+        return clazz.isArray() && isPrimitive(clazz.getComponentType());
+    }
+
+    // @todo (assira #2) benchmark: ClassTraits#isBoxed
+    public static boolean isBoxed(Class<?> clazz) {
+        
+        // może inaczej: !clazz.isPrimitive && Object.class.isAssignableFrom(clazz)
+        
+        return
+            Byte.class.equals(clazz) ||
+            Short.class.equals(clazz) ||
+            Integer.class.equals(clazz) ||
+            Long.class.equals(clazz) ||
+            Character.class.equals(clazz) ||
+            Float.class.equals(clazz) ||
+            Double.class.equals(clazz) ||
+            Boolean.class.equals(clazz) ||
+            Void.class.equals(clazz);
+    }
+    
+    public static boolean isBool(Class<?> clazz) {
+        return boolean.class.equals(clazz) || Boolean.class.equals(clazz);
+    }
+
+    public static boolean isNumber(Class<?> clazz) {
+        return
+            byte.class.equals(clazz) ||
+            short.class.equals(clazz) ||
+            int.class.equals(clazz) ||
+            long.class.equals(clazz) ||
+            float.class.equals(clazz) ||
+            double.class.equals(clazz) ||
+            Byte.class.equals(clazz) ||
+            Short.class.equals(clazz) ||
+            Integer.class.equals(clazz) ||
+            Long.class.equals(clazz) ||
+            Float.class.equals(clazz) ||
+            Double.class.equals(clazz) ||
+            Number.class.isAssignableFrom(clazz);
+    }
+}

+ 178 - 0
assira/src/main/java/net/ranides/assira/reflection/util/ClassUtils.java

@@ -0,0 +1,178 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.util;
+
+import java.lang.reflect.Modifier;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class ClassUtils {
+    
+    private ClassUtils() {
+        // utility class
+    }
+    
+    @SuppressWarnings("PMD")
+    public static Class<?> box(Class<?> clazz) {
+        if (byte.class.equals(clazz)) {
+            return Byte.class;
+        } else if (short.class.equals(clazz)) {
+            return Short.class;
+        } else if (int.class.equals(clazz)) {
+            return Integer.class;
+        } else if (long.class.equals(clazz)) {
+            return Long.class;
+        } else if (char.class.equals(clazz)) {
+            return Character.class;
+        } else if (float.class.equals(clazz)) {
+            return Float.class;
+        } else if (double.class.equals(clazz)) {
+            return Double.class;
+        } else if (boolean.class.equals(clazz)) {
+            return Boolean.class;
+        } else if (void.class.equals(clazz)) {
+            return Void.class;
+        } else {
+            return clazz;
+        }
+    }
+
+    @SuppressWarnings("PMD")
+    public static Class<?> unbox(Class<?> clazz) {
+        if (Byte.class.equals(clazz)) {
+            return byte.class;
+        } else if (Short.class.equals(clazz)) {
+            return short.class;
+        } else if (Integer.class.equals(clazz)) {
+            return int.class;
+        } else if (Long.class.equals(clazz)) {
+            return long.class;
+        } else if (Character.class.equals(clazz)) {
+            return char.class;
+        } else if (Float.class.equals(clazz)) {
+            return float.class;
+        } else if (Double.class.equals(clazz)) {
+            return double.class;
+        } else if (Boolean.class.equals(clazz)) {
+            return boolean.class;
+        } else if (Void.class.equals(clazz)) {
+            return void.class;
+        } else {
+            return clazz;
+        }
+    }
+
+    
+    public static boolean isStatic(Class<?> clazz) {
+        return Modifier.isStatic(clazz.getModifiers());
+    }
+
+    public static boolean isPublic(Class<?> clazz) {
+        return Modifier.isPublic(clazz.getModifiers());
+    }
+
+    public static boolean isProtected(Class<?> clazz) {
+        return Modifier.isProtected(clazz.getModifiers());
+    }
+
+    public static boolean isPrivate(Class<?> clazz) {
+        return Modifier.isPrivate(clazz.getModifiers());
+    }
+
+    public static boolean isInterface(Class<?> clazz) {
+        return Modifier.isInterface(clazz.getModifiers());
+    }
+
+    public static boolean isFinal(Class<?> clazz) {
+        return Modifier.isFinal(clazz.getModifiers());
+    }
+
+    public static boolean isAbstract(Class<?> clazz) {
+        return Modifier.isAbstract(clazz.getModifiers());
+    }
+    
+    /**
+     * Rozszerzenie standardowej metody {@code Class.isAssignableFrom}.
+     * Uwzględnia autoboxing argumentów.
+     * @param ssuper
+     * @param value
+     * @return
+     */
+    @SuppressWarnings("PMD.CyclomaticComplexity")
+    public static boolean isAssignableFrom(Class<?> ssuper, Class<?> value) {
+        if (ssuper.equals(boolean.class) || ssuper.equals(Boolean.class)) {
+            return value.equals(boolean.class) || value.equals(Boolean.class);
+        } else if (ssuper.equals(char.class) || ssuper.equals(Character.class)) {
+            return value.equals(char.class) || value.equals(Character.class);
+        } else if (ssuper.equals(byte.class) || ssuper.equals(Byte.class)) {
+            return value.equals(byte.class) || value.equals(Byte.class);
+        } else if (ssuper.equals(short.class) || ssuper.equals(Short.class)) {
+            return value.equals(short.class) || value.equals(Short.class);
+        } else if (ssuper.equals(int.class) || ssuper.equals(Integer.class)) {
+            return value.equals(int.class) || value.equals(Integer.class);
+        } else if (ssuper.equals(long.class) || ssuper.equals(Long.class)) {
+            return value.equals(long.class) || value.equals(Long.class);
+        } else if (ssuper.equals(float.class) || ssuper.equals(Float.class)) {
+            return value.equals(float.class) || value.equals(Float.class);
+        } else if (ssuper.equals(double.class) || ssuper.equals(Double.class)) {
+            return value.equals(double.class) || value.equals(Double.class);
+        } else {
+            return ssuper.isAssignableFrom(value);
+        }
+    }
+    
+    /**
+     * Grupowa wersja funkcji {@code Class.isAssignableFrom} - sprawdza, czy odpowiednie
+     * elementy z tablicy {@code supers} są assignable względem odpowiednich
+     * elementów {@code values}, czyli czy <br>
+     * {@code for(i) supers[i].isAssignableFrom( values[i] ) }
+     * Uwzględnia autoboxing argumentów.
+     * @param supers
+     * @param values
+     * @return
+     */
+    public static boolean isAssignableFrom(Class<?>[] supers, Class<?>[] values) {
+        if(supers.length != values.length) {
+            return false;
+        }
+        for(int i=0; i<supers.length; i++) {
+            if( !isAssignableFrom(supers[i], values[i]) ) { return false; }
+        }
+        return true;
+    }
+
+    /**
+     * Sprawdza, czy podany obiekt {@code get} jest instancją klasy {@code ssuper}.
+     * Uwzględnia autoboxing argumentów.
+     * @param ssuper
+     * @param value
+     * @return
+     */
+    public static boolean isInstance(Class<?> ssuper, Object value) {
+        return value==null || ssuper.isInstance(value) || box(ssuper).isInstance(value);
+    }
+
+    /**
+     * Sprawdza, czy odpowiednie obiekty z tablicy {@code values} są istancjami
+     * odpowiednich klas z tablicy {@code supers}. Uwzględnia autoboxing argumentów.
+     * @param supers
+     * @param values
+     * @return
+     */
+    public static boolean isInstance(Class<?>[] supers, Object[] values) {
+        if(supers.length != values.length) {
+            return false;
+        }
+        for(int i=0; i<supers.length; i++) {
+            if( !isInstance(supers[i], values[i]) ) { return false; }
+        }
+        return true;
+    }
+    
+}

+ 36 - 4
assira/src/test/java/net/ranides/assira/collection/arrays/NativeArrayTest.java

@@ -6,6 +6,7 @@
  */
 package net.ranides.assira.collection.arrays;
 
+import java.util.Random;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
@@ -16,9 +17,40 @@ import static org.junit.Assert.*;
 public class NativeArrayTest {
 
     @Test
-    public void testSomeMethod() {
-        // @todo (assira #1) test: NativeArray
-        assertTrue(true);
+    public void testSuite() {
+        NativeArrayTester.SUITE.debug(true);
+        NativeArrayTester.run( (index)->(byte)index );
+        NativeArrayTester.run( (index)->(int)index );
+        NativeArrayTester.run( (index)->(short)index );
+        NativeArrayTester.run( (index)->(long)index );
+        NativeArrayTester.run( (index)->(float)0.75*index );
+        NativeArrayTester.run( (index)->(double)0.75*index );
+        NativeArrayTester.run( (index)->(char)('a'+index) );
+        NativeArrayTester.run( (index)->String.format("%02d", index) );
+        
+        NativeArrayTester.SUITE
+            .ignore("NativeArrayTester.basicCompare")
+            .ignore("NativeArrayTester.basicCompare_cmp");
+        NativeArrayTester.run( (index)->new Random(1027*index).nextBoolean() );
     }
-   
+    
+    @Test
+    public void testBoxing() {
+        final NativeArray na1i = NativeArray.wrap(new int[]{1,2});
+        final NativeArray na2i = na1i.box();
+        final NativeArray na3i = na2i.unbox();
+        assertArrayEquals(new Integer[]{1,2}, na1i.box().$array());
+        assertSame(na2i, na2i.box());
+        assertArrayEquals(new int[]{1,2}, na3i.$array());
+        assertSame(na3i, na3i.unbox());
+        
+        final NativeArray na1c = NativeArray.wrap(new char[]{'a','b'});
+        final NativeArray na2c = na1c.box();
+        final NativeArray na3c = na2c.unbox();
+        assertArrayEquals(new Character[]{'a','b'}, na1c.box().$array());
+        assertSame(na2c, na2c.box());
+        assertArrayEquals(new char[]{'a','b'}, na3c.$array());
+        assertSame(na3c, na3c.unbox());
+    }
+	
 }

+ 314 - 0
assira/src/test/java/net/ranides/assira/collection/arrays/NativeArrayTester.java

@@ -0,0 +1,314 @@
+/*
+ * @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;
+import java.util.Comparator;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import javax.annotation.Resource;
+import net.ranides.assira.collection.IntComparator;
+import net.ranides.assira.collection.arrays.NativeArray.NativeComparator;
+import net.ranides.assira.collection.arrays.NativeArray.NativeMove;
+import net.ranides.assira.generic.CompareUtils;
+import net.ranides.assira.generic.HashUtils;
+import net.ranides.assira.junit.InterfaceSuite;
+import net.ranides.assira.junit.InterfaceTest;
+import net.ranides.assira.test.TCollection;
+import static net.ranides.assira.junit.NewAssert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class NativeArrayTester<K> {
+    
+    @Resource(name = "collection!")
+    private TCollection<K> $var;
+    
+    public static final InterfaceSuite SUITE = new InterfaceSuite(System.err)
+        .append(new NativeArrayTester());
+    
+    
+    public static <T> boolean run(InterfaceSuite suite, IntFunction<T> function) {
+        TValues<T> var = new TValues<>(function);
+        return suite
+            .param("collection!", var)
+            .run((int[] array)-> NativeArray.wrap(var.list(array).values()).unbox() );
+    }
+    
+    public static <T> boolean run(IntFunction<T> function) {
+        return run(SUITE, function);
+    }
+   
+    @InterfaceTest
+    public void basicCompare(Function<int[], NativeArray> f) {
+        NativeArray a = f.apply(new int[]{1,3,5,7});
+        NativeArray b = f.apply(new int[]{1,3,5,7});
+        NativeArray c = f.apply(new int[]{1,3,5});
+        NativeArray d = f.apply(new int[]{1,2,5,7});
+        NativeArray e = f.apply(new int[]{1,4,5,7});
+        
+        assertTrue("a==a", a.compareTo(a) == 0 );
+        assertTrue("a==b", a.compareTo(b) == 0 );
+        
+        assertTrue("a>c", a.compareTo(c) > 0 );
+        assertTrue("c<a", c.compareTo(a) < 0 );
+        
+        assertTrue("a==c (3)", a.compareTo(c,0,0,3) == 0 );
+        assertTrue("c==a (3)", c.compareTo(a,0,0,3) == 0 );
+        
+        assertTrue("a==c (0)", a.compareTo(c,0,0,0) == 0 );
+        assertTrue("c==a (0)", c.compareTo(a,1,0,0) == 0 );
+        
+        assertTrue("a>d", a.compareTo(d) > 0 );
+        assertTrue("d<a", d.compareTo(a) < 0 );
+        
+        assertTrue("a<e", a.compareTo(e) < 0 );
+        assertTrue("e>a", e.compareTo(a) > 0 );
+    }
+    
+    @InterfaceTest
+    public void basicCompare_cmp(Function<int[], NativeArray> f) {
+        Comparator cmp = CompareUtils.comparator().reversed();
+            
+        NativeArray a = f.apply(new int[]{1,3,5,7});
+        NativeArray b = f.apply(new int[]{1,3,5,7});
+        NativeArray c = f.apply(new int[]{1,3,5});
+        NativeArray d = f.apply(new int[]{1,2,5,7});
+        NativeArray e = f.apply(new int[]{1,4,5,7});
+        
+        assertTrue("a==a", a.compareTo(a, cmp) == 0 );
+        assertTrue("a==b", a.compareTo(b, cmp) == 0 );
+        
+        assertTrue("a>c", a.compareTo(c, cmp) > 0 );
+        assertTrue("c<a", c.compareTo(a, cmp) < 0 );
+        
+        assertTrue("a==c (3)", a.compareTo(c,0,0,3, cmp) == 0 );
+        assertTrue("c==a (3)", c.compareTo(a,0,0,3, cmp) == 0 );
+        
+        assertTrue("a==c (0)", a.compareTo(c,0,0,0, cmp) == 0 );
+        assertTrue("c==a (0)", c.compareTo(a,1,0,0, cmp) == 0 );
+        
+        assertTrue("a<d", a.compareTo(d, cmp) < 0 );
+        assertTrue("d>a", d.compareTo(a, cmp) > 0 );
+        
+        assertTrue("a>e", a.compareTo(e, cmp) > 0 );
+        assertTrue("e<a", e.compareTo(a, cmp) < 0 );
+    }
+    
+    @InterfaceTest
+    public void basicEquals(Function<int[], NativeArray> f) {
+        NativeArray a = f.apply(new int[]{1,3,5,7});
+        NativeArray b = f.apply(new int[]{1,3,5,7});
+        NativeArray c = f.apply(new int[]{1,3,5});
+        NativeArray d = f.apply(new int[]{1,4,5,7});
+        
+        System.out.printf("%s%n", a);
+        assertTrue("a==a", a.equals(a));
+        assertTrue("a==b", a.equals(b));
+        assertFalse("a!=c", a.equals(c));
+        assertFalse("a!=d", a.equals(d));
+    }
+
+    @InterfaceTest
+    public void basicSet(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7});
+        target.set(0, $var.item(4).value());
+        target.set(1, $var.item(6).value());
+        target.set(3, $var.item(8).value());
+        
+        assertEquals(f.apply(new int[]{4,6,5,8}), target);
+        
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            target.set(4, $var.item(9).value());
+        });
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            target.set(9, $var.item(9).value());
+        });
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            target.set(-1, $var.item(9).value());
+        });
+        
+        target.set(1,3, $var.item(2).value());
+        assertEquals(f.apply(new int[]{4,2,2,8}), target);
+    }
+    
+    @InterfaceTest
+    public void basicMove(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7});
+        
+        target.move(0,1);
+        target.move(1,3);
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            target.move(0,5);
+        });
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            target.move(5,0);
+        });
+        
+        assertEquals(f.apply(new int[]{3,7,5,7}), target);
+        
+        NativeMove imov = target.move(f.apply(new int[]{11,12,13,14}));
+        imov.move(0, 2);
+        imov.move(1, 1);
+        imov.move(3, 0);
+        assertEquals(f.apply(new int[]{13,12,5,11}), target);
+    }
+    
+    @InterfaceTest
+    public void basicSwap(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7,2,4});
+        
+        target.swap(0,1);
+        target.swap(1,3);
+        target.swap(2,5);
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            target.move(0,6);
+        });
+        assertThrows(ArrayIndexOutOfBoundsException.class, ()->{
+            target.move(6,0);
+        });
+        
+        assertEquals(f.apply(new int[]{3,7,4,1,2,5}), target);
+        
+    }
+    
+    @InterfaceTest
+    public void basicLRCompare(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7});
+        
+        NativeComparator lcmp = target.lcmp($var.item(4).value());
+        NativeComparator rcmp = target.rcmp($var.item(4).value());
+        
+        assertEquals($cmp(4,1), lcmp.compare(0));
+        assertEquals($cmp(4,3), lcmp.compare(1));
+        assertEquals($cmp(4,5), lcmp.compare(2));
+        assertEquals($cmp(4,7), lcmp.compare(3));
+        
+        assertEquals($cmp(1,4), rcmp.compare(0));
+        assertEquals($cmp(3,4), rcmp.compare(1));
+        assertEquals($cmp(5,4), rcmp.compare(2));
+        assertEquals($cmp(7,4), rcmp.compare(3));
+    }
+    
+    @InterfaceTest
+    public void basicLRCompare_cmp(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7});
+        
+        NativeComparator lcmp = target.lcmp($var.item(4).value(), CompareUtils.comparator().reversed());
+        NativeComparator rcmp = target.rcmp($var.item(4).value(), CompareUtils.comparator().reversed());
+        
+        assertEquals($cmp(1,4), lcmp.compare(0));
+        assertEquals($cmp(3,4), lcmp.compare(1));
+        assertEquals($cmp(5,4), lcmp.compare(2));
+        assertEquals($cmp(7,4), lcmp.compare(3));
+        
+        assertEquals($cmp(4,1), rcmp.compare(0));
+        assertEquals($cmp(4,3), rcmp.compare(1));
+        assertEquals($cmp(4,5), rcmp.compare(2));
+        assertEquals($cmp(4,7), rcmp.compare(3));
+    }
+    
+    @InterfaceTest
+    public void basicComparator(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7,2});
+        IntComparator icmp = target.comparator();
+        
+        assertEquals($cmp(1,3), icmp.compare(0,1));
+        assertEquals($cmp(3,5), icmp.compare(1,2));
+        assertEquals($cmp(1,7), icmp.compare(0,3));
+        assertEquals($cmp(7,1), icmp.compare(3,0));
+        assertEquals($cmp(5,5), icmp.compare(2,2));
+        assertEquals($cmp(3,2), icmp.compare(1,4));
+        
+        NativeArray array = f.apply(new int[]{4,5,9,3,1});
+        IntComparator acmp = target.comparator(array);
+        
+        assertEquals($cmp(1,5), acmp.compare(0,1));
+        assertEquals($cmp(3,9), acmp.compare(1,2));
+        assertEquals($cmp(1,3), acmp.compare(0,3));
+        assertEquals($cmp(7,4), acmp.compare(3,0));
+        assertEquals($cmp(5,9), acmp.compare(2,2));
+        assertEquals($cmp(3,1), acmp.compare(1,4));
+    }
+    
+    @InterfaceTest
+    public void basicComparator_cmp(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7,2});
+        IntComparator icmp = target.comparator(CompareUtils.comparator().reversed());
+        
+        assertEquals($cmp(3,1), icmp.compare(0,1));
+        assertEquals($cmp(5,3), icmp.compare(1,2));
+        assertEquals($cmp(7,1), icmp.compare(0,3));
+        assertEquals($cmp(1,7), icmp.compare(3,0));
+        assertEquals($cmp(5,5), icmp.compare(2,2));
+        assertEquals($cmp(2,3), icmp.compare(1,4));
+        
+        NativeArray array = f.apply(new int[]{4,5,9,3,1});
+        IntComparator acmp = target.comparator(array, CompareUtils.comparator().reversed());
+        
+        assertEquals($cmp(5,1), acmp.compare(0,1));
+        assertEquals($cmp(9,3), acmp.compare(1,2));
+        assertEquals($cmp(3,1), acmp.compare(0,3));
+        assertEquals($cmp(4,7), acmp.compare(3,0));
+        assertEquals($cmp(9,5), acmp.compare(2,2));
+        assertEquals($cmp(1,3), acmp.compare(1,4));
+    }
+    
+    @InterfaceTest
+    public void basicToString(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5,7,2});
+        String exp = $var.list(1,3,5,7,2).into(new ArrayList<>()).toString();
+        assertEquals(exp, target.toString());
+    }
+    
+    @InterfaceTest
+    public void basicAllocate(Function<int[], NativeArray> f) {
+        NativeArray target = f.apply(new int[]{1,3,5});
+        NativeArray z = target.allocate(0);
+        assertEquals(0, z.size());
+        assertEquals(target.component(), z.component());
+        
+        NativeArray c = target.allocate(5);
+        assertEquals(5, c.size());
+        assertEquals(target.component(), c.component());
+    }
+    
+    private int $cmp(int a, int b) {
+        return CompareUtils.cmp($var.item(a).value(), $var.item(b).value());
+    }
+    
+    private static class TValues<T> extends TCollection<T> {
+
+        private final IntFunction<T> function;
+        
+        public TValues(IntFunction<T> function) {
+            this.function = function;
+        }
+
+        @Override
+        protected T value(int index, int n) {
+            if(n!=0) {
+                throw new UnsupportedOperationException("NO TEST");
+            }
+            return function.apply(index);
+        }
+
+        @Override
+        protected int cmp(Object a, Object b) {
+            return CompareUtils.cmp(a, b);
+        }
+
+        @Override
+        protected int hash(Object value) {
+            return HashUtils.hash(value);
+        }
+        
+    }
+    
+}

+ 42 - 0
assira/src/test/java/net/ranides/assira/reflection/mockup/ForMemberUtils.java

@@ -0,0 +1,42 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.mockup;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+@SuppressWarnings("PMD")
+public class ForMemberUtils {
+    
+    public static final Class<?> ABSTRACT   = CAbstract.class;
+    public static final Class<?> FINAL      = CFinal.class;
+    public static final Class<?> INTERFACE  = CInterface.class;
+    public static final Class<?> PRIVATE    = CPrivate.class;
+    public static final Class<?> PROTECTED  = CProtected.class;
+    public static final Class<?> PUBLIC     = CPublic.class;
+    public static final Class<?> STATIC     = CStatic.class;
+    public static final Class<?> NOTHING    = CNothing.class;
+    
+    
+    public class CPublic { }
+    
+    protected class CProtected { }
+    
+    private class CPrivate { }
+    
+    interface CInterface { }
+    
+    abstract class CAbstract { }
+    
+    final class CFinal { }
+    
+    static class CStatic { }
+    
+    class CNothing { }
+    
+}

+ 105 - 0
assira/src/test/java/net/ranides/assira/reflection/util/ClassTraitsTest.java

@@ -0,0 +1,105 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.util;
+
+import java.math.BigDecimal;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class ClassTraitsTest {
+    
+    @Test
+    public void testIsPrimitive() {
+        assertTrue( ClassTraits.isPrimitive(byte.class));
+        assertTrue( ClassTraits.isPrimitive(short.class));
+        assertTrue( ClassTraits.isPrimitive(int.class));
+        assertTrue( ClassTraits.isPrimitive(long.class));
+        assertTrue( ClassTraits.isPrimitive(char.class));
+        assertTrue( ClassTraits.isPrimitive(float.class));
+        assertTrue( ClassTraits.isPrimitive(double.class));
+        assertTrue( ClassTraits.isPrimitive(boolean.class));
+        assertTrue( ClassTraits.isPrimitive(void.class));
+        
+        assertFalse( ClassTraits.isPrimitive(Byte.class));
+        assertFalse( ClassTraits.isPrimitive(Integer.class));
+        assertFalse( ClassTraits.isPrimitive(Number.class));
+    }
+    
+    @Test
+    public void testIsPrimitiveArray() {
+        assertTrue( ClassTraits.isPrimitiveArray(byte[].class));
+        assertTrue( ClassTraits.isPrimitiveArray(short[].class));
+        assertTrue( ClassTraits.isPrimitiveArray(int[].class));
+        
+        assertFalse( ClassTraits.isPrimitiveArray(byte.class));
+        
+        assertFalse( ClassTraits.isPrimitiveArray(Byte[].class));
+        assertFalse( ClassTraits.isPrimitiveArray(Integer[].class));
+        assertFalse( ClassTraits.isPrimitiveArray(Number[].class));
+    }
+    
+    @Test
+    public void testIsBoxed() {
+        assertTrue( ClassTraits.isBoxed(Byte.class));
+        assertTrue( ClassTraits.isBoxed(Short.class));
+        assertTrue( ClassTraits.isBoxed(Integer.class));
+        assertTrue( ClassTraits.isBoxed(Long.class));
+        assertTrue( ClassTraits.isBoxed(Character.class));
+        assertTrue( ClassTraits.isBoxed(Float.class));
+        assertTrue( ClassTraits.isBoxed(Double.class));
+        assertTrue( ClassTraits.isBoxed(Boolean.class));
+        assertTrue( ClassTraits.isBoxed(Void.class));
+        
+        assertFalse( ClassTraits.isBoxed(byte.class));
+        assertFalse( ClassTraits.isBoxed(int.class));
+        assertFalse( ClassTraits.isBoxed(Number.class));
+    }
+    
+    @Test
+    public void testIsBool() {
+        
+        assertTrue( ClassTraits.isBool(Boolean.class));
+        assertTrue( ClassTraits.isBool(boolean.class));
+        
+        assertFalse( ClassTraits.isBool(Number.class));
+    }
+    
+    @Test
+    public void testIsNumber() {
+        assertTrue( ClassTraits.isNumber(Byte.class));
+        assertTrue( ClassTraits.isNumber(Short.class));
+        assertTrue( ClassTraits.isNumber(Integer.class));
+        assertTrue( ClassTraits.isNumber(Long.class));
+        assertTrue( ClassTraits.isNumber(Float.class));
+        assertTrue( ClassTraits.isNumber(Double.class));
+        
+        assertTrue( ClassTraits.isNumber(byte.class));
+        assertTrue( ClassTraits.isNumber(short.class));
+        assertTrue( ClassTraits.isNumber(int.class));
+        assertTrue( ClassTraits.isNumber(long.class));
+        assertTrue( ClassTraits.isNumber(float.class));
+        assertTrue( ClassTraits.isNumber(double.class));
+        
+        assertTrue( ClassTraits.isNumber(Number.class));
+        assertTrue( ClassTraits.isNumber(BigDecimal.class));
+
+        // char isn't number, if you use it as unsigned short, that's a hack
+        assertFalse( ClassTraits.isNumber(Character.class));
+        assertFalse( ClassTraits.isNumber(char.class));
+        
+        assertFalse( ClassTraits.isNumber(Boolean.class));
+        assertFalse( ClassTraits.isNumber(Void.class));
+        assertFalse( ClassTraits.isNumber(boolean.class));
+        assertFalse( ClassTraits.isNumber(void.class));
+
+    }
+    
+}

+ 71 - 0
assira/src/test/java/net/ranides/assira/reflection/util/ClassUtilsTest.java

@@ -0,0 +1,71 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.util;
+
+import net.ranides.assira.collection.mockup.TPoint;
+import net.ranides.assira.reflection.mockup.ForMemberUtils;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class ClassUtilsTest {
+    
+    @Test
+    public void testModifiers() throws Exception {
+        
+        assertTrue( ClassUtils.isAbstract(ForMemberUtils.ABSTRACT) );
+        assertTrue( ClassUtils.isFinal(ForMemberUtils.FINAL) );
+        assertTrue( ClassUtils.isInterface(ForMemberUtils.INTERFACE) );
+        assertTrue( ClassUtils.isPrivate(ForMemberUtils.PRIVATE) );
+        assertTrue( ClassUtils.isProtected(ForMemberUtils.PROTECTED) );
+        assertTrue( ClassUtils.isPublic(ForMemberUtils.PUBLIC) );
+        assertTrue( ClassUtils.isStatic(ForMemberUtils.STATIC) );
+        
+        assertFalse( ClassUtils.isAbstract(ForMemberUtils.NOTHING) );
+        assertFalse( ClassUtils.isFinal(ForMemberUtils.NOTHING) );
+        assertFalse( ClassUtils.isInterface(ForMemberUtils.NOTHING) );
+        assertFalse( ClassUtils.isPrivate(ForMemberUtils.NOTHING) );
+        assertFalse( ClassUtils.isProtected(ForMemberUtils.NOTHING) );
+        assertFalse( ClassUtils.isPublic(ForMemberUtils.NOTHING) );
+        assertFalse( ClassUtils.isStatic(ForMemberUtils.NOTHING) );
+        
+    }
+    
+    @Test
+    public void testBox() throws Exception {
+        assertEquals(Byte.class, ClassUtils.box(byte.class));
+        assertEquals(Short.class, ClassUtils.box(short.class));
+        assertEquals(Integer.class, ClassUtils.box(int.class));
+        assertEquals(Long.class, ClassUtils.box(long.class));
+        assertEquals(Float.class, ClassUtils.box(float.class));
+        assertEquals(Double.class, ClassUtils.box(double.class));
+        assertEquals(Character.class, ClassUtils.box(char.class));
+        assertEquals(Boolean.class, ClassUtils.box(boolean.class));
+        assertEquals(Void.class, ClassUtils.box(void.class));
+        assertEquals(Object.class, ClassUtils.box(Object.class));
+        assertEquals(TPoint.class, ClassUtils.box(TPoint.class));
+    }
+    
+    @Test
+    public void testUnbox() throws Exception {
+        assertEquals(byte.class, ClassUtils.unbox(Byte.class));
+        assertEquals(short.class, ClassUtils.unbox(Short.class));
+        assertEquals(int.class, ClassUtils.unbox(Integer.class));
+        assertEquals(long.class, ClassUtils.unbox(Long.class));
+        assertEquals(float.class, ClassUtils.unbox(Float.class));
+        assertEquals(double.class, ClassUtils.unbox(Double.class));
+        assertEquals(char.class, ClassUtils.unbox(Character.class));
+        assertEquals(boolean.class, ClassUtils.unbox(Boolean.class));
+        assertEquals(void.class, ClassUtils.unbox(Void.class));
+        assertEquals(Object.class, ClassUtils.unbox(Object.class));
+        assertEquals(TPoint.class, ClassUtils.unbox(TPoint.class));
+    }
+    
+}