Jelajahi Sumber

#51 mutable IntArrayMap, new ArrayLookup

Ranides Atterwim 4 tahun lalu
induk
melakukan
30fa371918

+ 506 - 0
assira.commons/src/main/java/net/ranides/assira/collection/lookups/ArrayLookup.java

@@ -0,0 +1,506 @@
+/*
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+
+package net.ranides.assira.collection.lookups;
+
+import net.ranides.assira.collection.IntCollection;
+import net.ranides.assira.collection.arrays.ArrayAllocator;
+import net.ranides.assira.collection.arrays.NativeArraySort;
+import net.ranides.assira.collection.iterators.IntListIterator;
+import net.ranides.assira.collection.iterators.RandomAccessIntIterator;
+import net.ranides.assira.collection.iterators.RandomAccessIterator;
+import net.ranides.assira.collection.lists.AIntList;
+import net.ranides.assira.generic.CompareUtils;
+
+import java.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+
+/**
+ * Container stores elements inside sorted array and uses binary search for access.
+ *
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ */
+public class ArrayLookup<K> extends ALookup<K> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final Object[] EMPTY = new Object[0];
+    private static final int[] EMPTY_INT = new int[0];
+
+    private final Class<?> type;
+    private K[] keys;
+    private int[] vars;
+    private int size;
+
+    private final Comparator<? super K> cmp;
+
+    public ArrayLookup() {
+        this(CompareUtils.comparator());
+    }
+
+    public ArrayLookup(Comparator<? super K> cmp) {
+        this.type = Object.class;
+        this.keys = (K[]) EMPTY;
+        this.vars = EMPTY_INT;
+        this.size = 0;
+        this.cmp = cmp;
+    }
+
+    /**
+     * Creates new map with provided keys and values.
+     * Please note, that keys must be comparable.
+     * Please note, that map does not preserve order of keys.
+     *
+     * @param keys keys
+     * @param vars values
+     */
+    public ArrayLookup(K[] keys, int[] vars) {
+        this(keys, vars, CompareUtils.comparator());
+    }
+
+    /**
+     * Creates new map with provided keys and values.
+     * It uses comparator function for sorting keys.
+     * Please note, that map does not preserve order of keys.
+     *
+     * @param keys keys
+     * @param vars values
+     * @param comparator comparator
+     */
+    public ArrayLookup(K[] keys, int[] vars, Comparator<? super K> comparator) {
+        this.type = keys.getClass().getComponentType();
+        this.keys = keys.clone();
+        this.vars = vars.clone();
+        this.size = vars.length;
+        this.cmp = comparator;
+        sort();
+    }
+
+    @SuppressWarnings("unchecked")
+    public ArrayLookup(Map<? extends K, ? extends Integer> values) {
+        int n = values.size();
+        Object[] k = new Object[n];
+        int[] v = new int[n];
+
+        int i = 0;
+        for(Entry<? extends K, ? extends Integer> e : values.entrySet()) {
+            k[i] = e.getKey();
+            v[i] = e.getValue();
+            i++;
+        }
+
+        this.type = Object.class;
+        this.keys = (K[])k;
+        this.vars = v;
+        this.size = vars.length;
+        this.cmp = CompareUtils.comparator();
+    }
+
+    @SuppressWarnings("unchecked")
+    public ArrayLookup(SortedMap<K, Integer> map) {
+        int n = map.size();
+        Object[] k = new Object[n];
+        int[] v = new int[n];
+
+        int i = 0;
+        for(Entry<K, Integer> e : map.entrySet()) {
+            k[i] = e.getKey();
+            v[i] = e.getValue();
+            i++;
+        }
+
+        this.type = Object.class;
+        this.keys = (K[])k;
+        this.vars = v;
+        this.size = vars.length;
+        this.cmp = map.comparator();
+    }
+
+    /**
+     * Creates new map with content from source map.
+     * Created ArrayMap uses the same comparator as source map.
+     *
+     * @param map map
+     */
+    @SuppressWarnings("unchecked")
+    public ArrayLookup(SortedLookup<K> map) {
+        int n = map.size();
+        Object[] k = new Object[n];
+        int[] v = new int[n];
+
+        int i = 0;
+        for(LookupEntry<K> e : map.fastEntrySet()) {
+            k[i] = e.getKey();
+            v[i] = e.getIntValue();
+            i++;
+        }
+
+        this.type = Object.class;
+        this.keys = (K[])k;
+        this.vars = v;
+        this.size = vars.length;
+        this.cmp = map.comparator();
+    }
+    
+    private void sort() {
+        NativeArraySort.quickSort(0, size, (a,b) -> cmp.compare(keys[a],keys[b]), (a,b) -> {
+            swap(keys, a, b);
+            swap(vars, a, b);
+        });
+    }
+
+    private static <T> void swap(int[] array, int a, int b) {
+        int t = array[a];
+        array[a] = array[b];
+        array[b] = t;
+    }
+
+    private static <T> void swap(T[] array, int a, int b) {
+        T t = array[a];
+        array[a] = array[b];
+        array[b] = t;
+    }
+
+    @Override
+    public Set<LookupEntry<K>> fastEntrySet() {
+        return new AbstractSet<LookupEntry<K>>() {
+            @Override
+            public Iterator<LookupEntry<K>> iterator() {
+                return new EntryIterator(0);
+            }
+
+            @Override
+            public int size() {
+                return size;
+            }
+
+            @Override
+            public boolean remove(Object object) {
+                if (object instanceof Map.Entry) {
+                    Entry<?, ?> entry = (Entry<?,?>) object;
+                    return ArrayLookup.this.remove(entry.getKey(), entry.getValue());
+                }
+                return false;
+            }
+
+            @Override
+            public void clear() {
+                ArrayLookup.this.clear();
+            }
+        };
+    }
+
+    @Override
+    public IntCollection values() {
+        return new AIntList() {
+            @Override
+            public IntListIterator iterator() {
+                return new ValueIterator(0);
+            }
+
+            @Override
+            public IntListIterator listIterator(int index) {
+                return new ValueIterator(index);
+            }
+
+            @Override
+            public int size() {
+                return size;
+            }
+
+            @Override
+            public int getInt(int index) {
+                if(index <0 || index>=size) {
+                    throw new IndexOutOfBoundsException(index + " out of bound " + size);
+                }
+                return vars[index];
+            }
+
+            @Override
+            public void add(int index, int k) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public int removeInt(int index) {
+                if(index <0 || index>=size) {
+                    throw new IndexOutOfBoundsException(index + " out of bound " + size);
+                }
+                int prev = vars[index];
+                $remove(index);
+                return prev;
+            }
+
+            @Override
+            public int set(int index, int k) {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Override
+    public Set<K> keySet() {
+        return new AbstractSet<K>() {
+            @Override
+            public Iterator<K> iterator() {
+                return new KeyIterator(0);
+            }
+
+            @Override
+            public int size() {
+                return size;
+            }
+
+            @Override
+            public boolean contains(Object o) {
+                return containsKey(o);
+            }
+
+            @Override
+            public boolean remove(Object o) {
+                int prev = size;
+                ArrayLookup.this.remove(o);
+                return prev != size;
+            }
+
+            @Override
+            public void clear() {
+                ArrayLookup.this.clear();
+            }
+        };
+    }
+
+    @Override
+    public int getInt(Object key) {
+        if(!type.isInstance(key)) {
+            return defaultReturnValue();
+        }
+        @SuppressWarnings("unchecked")
+        int i = Arrays.binarySearch(keys, 0, size, (K)key, cmp);
+        return i<0 ? defaultReturnValue() : vars[i];
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean containsKey(Object key) {
+        if(!type.isInstance(key)) {
+            return false;
+        }
+        @SuppressWarnings("unchecked")
+        int i = Arrays.binarySearch(keys, 0, size, (K)key, cmp);
+        return i >= 0;
+    }
+
+    @Override
+    public boolean containsValue(int value) {
+        for(int i=0; i<size; i++) {
+            if (value == vars[i]) { return true; }
+        }
+        return false;
+    }
+    
+    @Override
+    public int size() {
+        return size;
+    }
+
+    @Override
+    public int removeInt(Object key) {
+        if(!type.isInstance(key)) {
+            return defaultReturnValue();
+        }
+
+        @SuppressWarnings("unchecked")
+        int pos = Arrays.binarySearch(keys, 0, size, (K)key, cmp);
+        if(pos<0) {
+            return defaultReturnValue();
+        }
+        int prev = vars[pos];
+        $remove(pos);
+        return prev;
+    }
+
+    @Override
+    public boolean remove(Object key, Object value) {
+        if(!type.isInstance(key)) {
+            return false;
+        }
+
+        @SuppressWarnings("unchecked")
+        int pos = Arrays.binarySearch(keys, 0, size, (K)key, cmp);
+        if(pos<0) {
+            return false;
+        }
+        if(CompareUtils.equals(value, vars[pos])) {
+            $remove(pos);
+            return true;
+        }
+
+        for(int s = pos-1; s>0 && keys[s].equals(key); s--) {
+            if(CompareUtils.equals(value, vars[s])) {
+                $remove(s);
+                return true;
+            }
+        }
+
+        for(int s = pos+1; s<size && keys[s].equals(key); s++) {
+            if(CompareUtils.equals(value, vars[s])) {
+                $remove(s);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int put(K key, int value) {
+        int pos = Arrays.binarySearch(keys, 0, size, key, cmp);
+        if(pos >=0) {
+            int prev = vars[pos];
+            vars[pos] = value;
+            return prev;
+        } else {
+            $add(-pos - 1, key, value);
+            return defaultReturnValue();
+        }
+    }
+
+    @Override
+    public void clear() {
+        size = 0;
+        Arrays.fill(keys, null);
+        Arrays.fill(vars, defaultReturnValue());
+    }
+
+    private void $remove(int index) {
+        int shift = size - index - 1;
+        if (shift > 0) {
+            System.arraycopy(keys, index + 1, keys, index, shift);
+            System.arraycopy(vars, index + 1, vars, index, shift);
+        }
+
+        size--;
+        keys[size] = null;
+        vars[size] = defaultReturnValue();
+    }
+
+    private void $add(int index, K key, int value) {
+        keys = ArrayAllocator.grow(keys, size+1);
+        vars = ArrayAllocator.grow(vars, size+1);
+
+        int shift = size - index;
+        if (shift > 0) {
+            System.arraycopy(keys, index, keys, index + 1, shift);
+            System.arraycopy(vars, index, vars, index + 1, shift);
+        }
+        keys[index] = key;
+        vars[index] = value;
+        size++;
+    }
+
+    private class EntryIterator extends RandomAccessIterator<LookupEntry<K>> {
+
+        public EntryIterator(int index) {
+            super(index);
+        }
+
+        @Override
+        protected int size() {
+            return size;
+        }
+
+        @Override
+        protected LookupEntry<K> get(int index) {
+            return new AMEntry(index);
+        }
+
+        @Override
+        protected void remove(int index) {
+            $remove(index);
+        }
+
+    }
+
+    private class KeyIterator extends RandomAccessIterator<K> {
+
+        public KeyIterator(int index) {
+            super(index);
+        }
+
+        @Override
+        protected int size() {
+            return size;
+        }
+
+        @Override
+        protected K get(int index) {
+            return keys[index];
+        }
+
+        @Override
+        protected void remove(int index) {
+            $remove(index);
+        }
+
+    }
+
+    private class ValueIterator extends RandomAccessIntIterator {
+
+        public ValueIterator(int index) {
+            super(index);
+        }
+
+        @Override
+        protected int size() {
+            return size;
+        }
+
+        @Override
+        protected int get(int index) {
+            return vars[index];
+        }
+
+        @Override
+        protected void remove(int index) {
+            $remove(index);
+        }
+
+    }
+
+    private class AMEntry extends ALookupEntry<K> {
+
+        private final int index;
+
+        public AMEntry(int index) {
+            this.index = index;
+        }
+
+        @Override
+        public K getKey() {
+            return keys[index];
+        }
+
+        @Override
+        public int getIntValue() {
+            return vars[index];
+        }
+
+        @Override
+        public int setValue(int value) {
+            int prev = vars[index];
+            vars[index] = value;
+            return prev;
+        }
+
+    }
+
+}

+ 241 - 52
assira.commons/src/main/java/net/ranides/assira/collection/maps/IntArrayMap.java

@@ -7,19 +7,25 @@
 
 package net.ranides.assira.collection.maps;
 
-import java.util.AbstractSet;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Set;
 import net.ranides.assira.collection.IntComparator;
+import net.ranides.assira.collection.arrays.ArrayAllocator;
 import net.ranides.assira.collection.arrays.ArraySearch;
-import net.ranides.assira.collection.arrays.IntArrays;
 import net.ranides.assira.collection.arrays.NativeArraySort;
 import net.ranides.assira.collection.iterators.IntIterator;
+import net.ranides.assira.collection.iterators.RandomAccessIntIterator;
 import net.ranides.assira.collection.iterators.RandomAccessIterator;
 import net.ranides.assira.collection.sets.AIntSet;
 import net.ranides.assira.collection.sets.IntSet;
+import net.ranides.assira.generic.CompareUtils;
+
+import java.util.AbstractList;
+import java.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
 
 /**
  *
@@ -29,9 +35,10 @@ public class IntArrayMap<V> extends AIntMap<V> {
 
     private static final long serialVersionUID = 1L;
 
-    private final int[] keys;
-    private final V[] vars;
-    
+    private int[] keys;
+    private V[] vars;
+    private int size;
+
     private final IntComparator cmp;
     
     public IntArrayMap(int[] keys, V[] vars) {
@@ -41,12 +48,13 @@ public class IntArrayMap<V> extends AIntMap<V> {
     public IntArrayMap(int[] keys, V[] vars, IntComparator comparator) {
         this.keys = keys.clone();
         this.vars = vars.clone();
+        this.size = vars.length;
         this.cmp = comparator;
         sort();
     }
     
     private void sort() {
-        NativeArraySort.quickSort(0, keys.length, (a,b) -> cmp.compare(keys[a],keys[b]), (a,b) -> {
+        NativeArraySort.quickSort(0, size, (a,b) -> cmp.compare(keys[a],keys[b]), (a,b) -> {
             swap(keys, a, b);
             swap(vars, a, b);
         });
@@ -69,49 +77,113 @@ public class IntArrayMap<V> extends AIntMap<V> {
         return new AbstractSet<IntEntry<V>>() {
             @Override
             public Iterator<IntEntry<V>> iterator() {
-                return new AIterator(0);
+                return new EntryIterator(0);
             }
 
             @Override
             public int size() {
-                return keys.length;
+                return size;
+            }
+
+            @Override
+            public boolean remove(Object object) {
+                if (object instanceof Map.Entry) {
+                    Map.Entry<?, ?> entry = (Map.Entry<?,?>) object;
+                    return IntArrayMap.this.remove(entry.getKey(), entry.getValue());
+                }
+                return false;
+            }
+
+            @Override
+            public void clear() {
+                IntArrayMap.this.clear();
             }
 
         };
     }
-    
-    
-    
+
     @Override
     public Collection<V> values() {
-        return Arrays.asList(vars);
+        return new AbstractList<V>() {
+            @Override
+            public Iterator<V> iterator() {
+                return new ValueIterator(0);
+            }
+
+            @Override
+            public ListIterator<V> listIterator(int index) {
+                return new ValueIterator(index);
+            }
+
+            @Override
+            public int size() {
+                return size;
+            }
+
+            @Override
+            public V get(int index) {
+                if(index <0 || index>=size) {
+                    throw new IndexOutOfBoundsException(index + " out of bound " + size);
+                }
+                return vars[index];
+            }
+        };
     }
 
     @Override
     public IntSet keySet() {
-        return new AKeys();
+        return new AIntSet() {
+
+
+            @Override
+            public IntIterator iterator() {
+                return new KeyIterator(0);
+            }
+
+            @Override
+            public int size() {
+                return size;
+            }
+
+            @Override
+            public boolean contains(Object o) {
+                return containsKey(o);
+            }
+
+            @Override
+            public boolean remove(Object o) {
+                int prev = size;
+                IntArrayMap.this.remove(o);
+                return prev != size;
+            }
+
+            @Override
+            public void clear() {
+                IntArrayMap.this.clear();
+            }
+        };
     }
 
     @Override
     public V get(int key) {
-        int i = ArraySearch.binarySearch(keys, key, cmp);
+        int i = ArraySearch.binarySearch(keys, 0, size, key, cmp);
         return i<0 ? null : vars[i];
     }
 
     @Override
     public boolean containsKey(int key) {
-        int i = ArraySearch.binarySearch(keys, key, cmp);
+        int i = ArraySearch.binarySearch(keys, 0, size, key, cmp);
         return i >= 0;
     }
 
     @Override
     public boolean containsValue(Object value) {
         if (value==null) {
-            for (int i=0; i<vars.length; i++) {
+            for (int i=0; i<size; i++) {
                 if (vars[i]==null) { return true; }
             }
         } else {
-            for(int i=0; i<vars.length; i++) {
+            for(int i=0; i<size; i++) {
                 if( value.equals(vars[i]) ) { return true; }
             }
         }
@@ -120,45 +192,104 @@ public class IntArrayMap<V> extends AIntMap<V> {
     
     @Override
     public int size() {
-        return keys.length;
+        return size;
     }
-    
-    private class PEntry extends AIntEntry<V> {
-    
-        private final int index;
 
-        public PEntry(int index) {
-            this.index = index;
+
+
+    @Override
+    public V remove(int key) {
+        int pos = ArraySearch.binarySearch(keys, 0, size, key, cmp);
+        if(pos<0) {
+            return null;
         }
+        V prev = vars[pos];
+        $remove(pos);
+        return prev;
+    }
 
-        @Override
-        public int getIntKey() {
-            return keys[index];
+    @Override
+    public boolean remove(int key, Object value) {
+        int pos = ArraySearch.binarySearch(keys, 0, size, key, cmp);
+        if(pos<0) {
+            return false;
+        }
+        if(CompareUtils.equals(value, vars[pos])) {
+            $remove(pos);
+            return true;
         }
 
-        @Override
-        public V getValue() {
-            return vars[index];
+        for(int s = pos-1; s>0 && keys[s] == key; s--) {
+            if(CompareUtils.equals(value, vars[s])) {
+                $remove(s);
+                return true;
+            }
         }
 
-        @Override
-        public V setValue(V value) {
-            V prev = vars[index];
-            vars[index] = value;
+        for(int s = pos+1; s<size && keys[s] == key; s++) {
+            if(CompareUtils.equals(value, vars[s])) {
+                $remove(s);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public V put(int key, V value) {
+        int pos = ArraySearch.binarySearch(keys, 0, size, key, cmp);
+        if(pos >=0) {
+            V prev = vars[pos];
+            vars[pos] = value;
             return prev;
+        } else {
+            $add(-pos - 1, key, value);
+            return null;
         }
-        
     }
-    
-    private class AIterator extends RandomAccessIterator<IntEntry<V>> {
 
-        public AIterator(int index) {
+    @Override
+    public void clear() {
+        size = 0;
+        Arrays.fill(keys, 0);
+        Arrays.fill(vars, null);
+    }
+
+    private void $remove(int index) {
+        int shift = size - index - 1;
+        if (shift > 0) {
+            System.arraycopy(keys, index + 1, keys, index, shift);
+            System.arraycopy(vars, index + 1, vars, index, shift);
+        }
+
+        size--;
+        keys[size] = 0;
+        vars[size] = null;
+    }
+
+    private void $add(int index, int key, V value) {
+        keys = ArrayAllocator.grow(keys, size+1);
+        vars = ArrayAllocator.grow(vars, size+1);
+
+        int shift = size - index;
+        if (shift > 0) {
+            System.arraycopy(keys, index, keys, index + 1, shift);
+            System.arraycopy(vars, index, vars, index + 1, shift);
+        }
+        keys[index] = key;
+        vars[index] = value;
+        size++;
+    }
+
+    private class EntryIterator extends RandomAccessIterator<IntEntry<V>> {
+
+        public EntryIterator(int index) {
             super(index);
         }
 
         @Override
         protected int size() {
-            return keys.length;
+            return size;
         }
 
         @Override
@@ -166,26 +297,84 @@ public class IntArrayMap<V> extends AIntMap<V> {
             return new PEntry(index);
         }
 
+        @Override
+        protected void remove(int index) {
+            $remove(index);
+        }
+
     }
 
-    private class AKeys extends AIntSet {
-        
-        private static final long serialVersionUID = 1L;
+    private class KeyIterator extends RandomAccessIntIterator {
+
+        public KeyIterator(int index) {
+            super(index);
+        }
+
+        @Override
+        protected int size() {
+            return size;
+        }
+
+        @Override
+        protected int get(int index) {
+            return keys[index];
+        }
+
+        @Override
+        protected void remove(int index) {
+            $remove(index);
+        }
+
+    }
+
+    private class ValueIterator extends RandomAccessIterator<V> {
+
+        public ValueIterator(int index) {
+            super(index);
+        }
+
+        @Override
+        protected int size() {
+            return size;
+        }
+
+        @Override
+        protected V get(int index) {
+            return vars[index];
+        }
+
+        @Override
+        protected void remove(int index) {
+            $remove(index);
+        }
+
+    }
+    
+    private class PEntry extends AIntEntry<V> {
+    
+        private final int index;
+
+        public PEntry(int index) {
+            this.index = index;
+        }
 
         @Override
-        public IntIterator iterator() {
-            return IntArrays.iterator(keys);
+        public int getIntKey() {
+            return keys[index];
         }
 
         @Override
-        public int size() {
-            return keys.length;
+        public V getValue() {
+            return vars[index];
         }
 
         @Override
-        public boolean contains(Object o) {
-            return containsKey(o);
+        public V setValue(V value) {
+            V prev = vars[index];
+            vars[index] = value;
+            return prev;
         }
+        
     }
 
 }

+ 67 - 0
assira.commons/src/test/java/net/ranides/assira/collection/lookups/ArrayLookupTest.java

@@ -0,0 +1,67 @@
+/*
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.collection.lookups;
+
+import net.ranides.test.ContractTesters;
+import net.ranides.test.data.TComparator;
+import net.ranides.test.data.TMap;
+import net.ranides.test.data.TMapItems;
+import net.ranides.test.data.TMaps;
+import net.ranides.test.data.TPoint;
+import org.junit.Test;
+
+import net.ranides.assira.collection.maps.IntArrayMap;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import static net.ranides.assira.junit.NewAssert.*;
+
+public class ArrayLookupTest {
+    
+    private final TMap<TPoint, Integer> $map = TMaps.MAP_PI;
+    
+    @Test
+    public void testSuite() {
+
+        ContractTesters.runner()
+            .param("map!", $map)
+            .function(new int[0], array -> new ArrayLookup<>($map.keys().list(array).values(), $map.values().list(array).valuesInt(), $map.comparator()))
+            .ignore(Pattern.compile(".*_HC"))
+            .run();
+    }
+
+
+    @Test
+    public void counter() {
+        Lookup<String> map = new ArrayLookup<>();
+        map.inc("a");
+        map.inc("a");
+        map.inc("a");
+        map.inc("b");
+        map.inc("b");
+        map.inc("c");
+
+        assertEquals(Arrays.asList("a", "b", "c"), new ArrayList<>(map.keySet()));
+
+        map.dec("a");
+        map.dec("b");
+        map.dec("c");
+
+        assertEquals(Arrays.asList("a", "b"), new ArrayList<>(map.keySet()));
+
+        map.dec("a");
+        map.dec("b");
+
+        assertEquals(Arrays.asList("a"), new ArrayList<>(map.keySet()));
+    }
+
+}

+ 0 - 10
assira.commons/src/test/java/net/ranides/assira/collection/maps/IntArrayMapTest.java

@@ -44,16 +44,6 @@ public class IntArrayMapTest {
         ContractTesters.runner()
                 .param("map!", $map)
                 .function(new int[0], array -> new IntArrayMap<>($map.keys().list(array).valuesInt(), $map.values().list(array).values()))
-                .ignore("MapTester.basicEntrySet_Iterator_RemoveAll")
-                .ignore("MapTester.basicEntrySet_Iterator_SetValue")
-                .ignore("IntMapTester.basicEntrySet_Iterator_Remove")
-                .ignore("IntMapTester.basicEntrySet_Iterator_RemoveAll")
-                .ignore("IntMapTester.basicEntrySet_Iterator_SetValue")
-                .ignore("IntMapTester.basicEntrySet_Remove")
-                .ignore(Pattern.compile("MapTester\\..*Remove"))
-                .ignore(Pattern.compile("MapTester\\.basicPut.*"))
-                .ignore(Pattern.compile("MapTester\\.basicRemove.*"))
-                .ignore(Pattern.compile("MapTester\\.basicClear.*"))
                 .ignore(Pattern.compile(".*_HC"))
                 .run();
     }

+ 9 - 0
assira.core/src/main/java/net/ranides/assira/collection/lists/AIntList.java

@@ -228,6 +228,9 @@ public abstract class AIntList extends AIntCollection implements IntList, Compar
 
     @Override
     public boolean remove(Object value) {
+        if(!(value instanceof Integer)) {
+            return false;
+        }
         return rem(((Integer) value).intValue());
     }
 
@@ -264,11 +267,17 @@ public abstract class AIntList extends AIntCollection implements IntList, Compar
 
     @Override
     public int indexOf(Object value) {
+        if(!(value instanceof Integer)) {
+            return -1;
+        }
         return indexOf( ((Integer) value).intValue() );
     }
 
     @Override
     public int lastIndexOf(Object value) {
+        if(!(value instanceof Integer)) {
+            return -1;
+        }
         return lastIndexOf( ((Integer)value).intValue() );
     }
 

+ 3 - 0
assira.core/src/main/java/net/ranides/assira/collection/lookups/ALookup.java

@@ -32,6 +32,9 @@ public abstract class ALookup<K> implements Lookup<K> {
 	
     @Override
     public boolean containsValue(Object value) {
+        if(!(value instanceof Integer)) {
+            return false;
+        }
         return containsValue(((Integer) value).intValue());
     }