Просмотр исходного кода

new: BlockCollection, BlockMap

Ranides Atterwim 10 лет назад
Родитель
Сommit
8582fd0cb0

+ 53 - 0
assira/src/main/java/net/ranides/assira/collection/BlockCollection.java

@@ -0,0 +1,53 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/???
+ */
+package net.ranides.assira.collection;
+
+import java.util.Collection;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public interface BlockCollection<T> extends Collection<T> {
+    
+    int capacity();
+
+    /**
+     * Reallocates this collection, making the capacity as small as possible.
+     *
+     * <P>This method reallocates the internal table to the smallest possible size. 
+     * It can be used when the collection will not be changed anymore, so
+     * to optimize access speed and size.
+     *
+     * <P>If the table size is already the minimum possible, this method does nothing.
+     *
+     * @return true if there was enough memory to trim the collection.
+     * @see #trim(int)
+     */
+    boolean trim();
+
+    /**
+     * Reallocates this collection if the table is too large.
+     *
+     * <P>Let <var>N</var> be the smallest capacity that can hold
+     * <code>max(n,{@link #size()})</code> entries, still satisfying internal constraints. 
+     * If the current table size is smaller than or equal to
+     * <var>N</var>, this method does nothing. Otherwise, it resizes this set
+     * in a table of size <var>N</var>.
+     *
+     * <P>This method is useful when reusing collections. {@linkplain #clear() Clearing a
+     * set} leaves in most situations the collection capacity untouched. If you are reusing a collection many
+     * times, you can call this method with a typical size to avoid keeping
+     * around a very large memory usage just because of a few large transient sets.
+     *
+     * @param n the threshold for the trimming.
+     * @return true if there was enough memory to trim the set.
+     * @see #trim()
+     */
+    boolean trim(int n);
+    
+}

+ 23 - 9
assira/src/main/java/net/ranides/assira/collection/lists/IntArrayList.java

@@ -16,6 +16,7 @@ import net.ranides.assira.collection.IntCollection;
 import net.ranides.assira.collection.arrays.ArrayAllocator;
 import net.ranides.assira.collection.arrays.IntArrayAllocator;
 import net.ranides.assira.collection.iterators.IntIterator;
+import net.ranides.assira.collection.BlockCollection;
 
 /**
  * A type-specific array-based list; provides some additional methods that use
@@ -41,7 +42,7 @@ import net.ranides.assira.collection.iterators.IntIterator;
  * @see java.util.ArrayList
  * 
  */
-public class IntArrayList extends AIntList implements RandomAccess {
+public class IntArrayList extends AIntList implements BlockCollection<Integer>, RandomAccess {
 
     private static final long serialVersionUID = 2;
     
@@ -208,6 +209,7 @@ public class IntArrayList extends AIntList implements RandomAccess {
      * without resizing.
      *
      * @param capacity the new minimum capacity for this array list.
+     * @todo (assira # 2) move #ensureCapacity to BlockCollection
      */
     public void ensureCapacity(int capacity) {
         data = IntArrayAllocator.ensureCapacity(data, capacity, size);
@@ -317,13 +319,19 @@ public class IntArrayList extends AIntList implements RandomAccess {
         this.size = size;
     }
 
+    @Override
+    public int capacity() {
+        return data.length;
+    }
+
     /**
      * Trims this array list so that the capacity is equal to the size.
      *
      * @see java.util.ArrayList#trimToSize()
      */
-    public void trim() {
-        trim(0);
+    @Override
+    public boolean trim() {
+        return trim(0);
     }
     
     /**
@@ -341,14 +349,20 @@ public class IntArrayList extends AIntList implements RandomAccess {
      *
      * @param n the threshold for the trimming.
      */
-    public void trim(int n) {
+    @Override
+    public boolean trim(int n) {
         if (n >= data.length || size == data.length) {
-            return;
+            return true;
         }
-        int t[] = new int[Math.max(n, size)];
-        System.arraycopy(data, 0, t, 0, size);
-        data = t;
-        assert size <= data.length;
+        try {
+            int t[] = new int[Math.max(n, size)];
+            System.arraycopy(data, 0, t, 0, size);
+            data = t;
+            return true;
+        } catch(OutOfMemoryError e) {
+            return false;
+        }
+        
     }
 
     /**

+ 9 - 1
assira/src/main/java/net/ranides/assira/collection/lookups/AHashLookup.java

@@ -17,6 +17,7 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import net.ranides.assira.collection.IntCollection;
+import net.ranides.assira.collection.maps.BlockMap;
 import net.ranides.assira.collection.utils.HashCollection;
 import net.ranides.assira.generic.CompareUtils;
 import net.ranides.assira.math.MathUtils;
@@ -24,7 +25,7 @@ import net.ranides.assira.math.MathUtils;
 /**
  * A type-specific hash map with primitive int values.
  */
-public abstract class AHashLookup<K> extends ALookup<K> implements java.io.Serializable {
+public abstract class AHashLookup<K> extends ALookup<K> implements BlockMap<K, Integer>, java.io.Serializable {
 
     private static final long serialVersionUID = 4L;
     /**
@@ -208,6 +209,11 @@ public abstract class AHashLookup<K> extends ALookup<K> implements java.io.Seria
         return mvalues;
     }
 
+    @Override
+    public int capacity() {
+        return capacity;
+    }
+    
     /**
      * Rehashes the map, making the table as small as possible.
      *
@@ -221,6 +227,7 @@ public abstract class AHashLookup<K> extends ALookup<K> implements java.io.Seria
      * @return true if there was enough memory to trim the map.
      * @see #trim(int)
      */
+    @Override
     public final boolean trim() {
         int l = HashCollection.arraysize(size, factor);
         if (l >= n) {
@@ -253,6 +260,7 @@ public abstract class AHashLookup<K> extends ALookup<K> implements java.io.Seria
      * @return true if there was enough memory to trim the map.
      * @see #trim()
      */
+    @Override
     public final boolean trim(int n) {
         int l = MathUtils.pow2next((int) Math.ceil(n / factor));
         if (this.n <= l) {

+ 8 - 1
assira/src/main/java/net/ranides/assira/collection/maps/AHashMap.java

@@ -24,7 +24,7 @@ import net.ranides.assira.math.MathUtils;
  *
  * @author Ranides Atterwim <ranides@gmail.com>
  */
-public abstract class AHashMap<K,V> extends AMap<K, V> implements java.io.Serializable {
+public abstract class AHashMap<K,V> extends AMap<K, V> implements BlockMap<K, V>, java.io.Serializable {
    
     private static final long serialVersionUID = 4L;
     
@@ -182,6 +182,11 @@ public abstract class AHashMap<K,V> extends AMap<K, V> implements java.io.Serial
         return mvalues;
     }
 
+    @Override
+    public int capacity() {
+        return capacity;
+    }
+
     /**
      * Rehashes the map, making the table as small as possible.
      *
@@ -195,6 +200,7 @@ public abstract class AHashMap<K,V> extends AMap<K, V> implements java.io.Serial
      * @return true if there was enough memory to trim the map.
      * @see #trim(int)
      */
+    @Override
     public final boolean trim() {
         final int l = HashCollection.arraysize(size, factor);
         if (l >= n) {
@@ -227,6 +233,7 @@ public abstract class AHashMap<K,V> extends AMap<K, V> implements java.io.Serial
      * @return true if there was enough memory to trim the map.
      * @see #trim()
      */
+    @Override
     public final boolean trim(int n) {
         int l = MathUtils.pow2next((int) Math.ceil(n / factor));
         if (this.n <= l) {

+ 53 - 0
assira/src/main/java/net/ranides/assira/collection/maps/BlockMap.java

@@ -0,0 +1,53 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/???
+ */
+package net.ranides.assira.collection.maps;
+
+import java.util.Map;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public interface BlockMap<K,V> extends Map<K,V> {
+    
+    int capacity();
+
+    /**
+     * Reallocates this collection, making the capacity as small as possible.
+     *
+     * <P>This method reallocates the internal table to the smallest possible size. 
+     * It can be used when the collection will not be changed anymore, so
+     * to optimize access speed and size.
+     *
+     * <P>If the table size is already the minimum possible, this method does nothing.
+     *
+     * @return true if there was enough memory to trim the collection.
+     * @see #trim(int)
+     */
+    boolean trim();
+
+    /**
+     * Reallocates this collection if the table is too large.
+     *
+     * <P>Let <var>N</var> be the smallest capacity that can hold
+     * <code>max(n,{@link #size()})</code> entries, still satisfying internal constraints. 
+     * If the current table size is smaller than or equal to
+     * <var>N</var>, this method does nothing. Otherwise, it resizes this set
+     * in a table of size <var>N</var>.
+     *
+     * <P>This method is useful when reusing collections. {@linkplain #clear() Clearing a
+     * set} leaves in most situations the collection capacity untouched. If you are reusing a collection many
+     * times, you can call this method with a typical size to avoid keeping
+     * around a very large memory usage just because of a few large transient sets.
+     *
+     * @param n the threshold for the trimming.
+     * @return true if there was enough memory to trim the set.
+     * @see #trim()
+     */
+    boolean trim(int n);
+    
+}

+ 8 - 1
assira/src/main/java/net/ranides/assira/collection/maps/IntHashMap.java

@@ -31,7 +31,7 @@ import net.ranides.assira.math.MathUtils;
     "PMD.AvoidReassigningParameters",
     "EqualsAndHashcode"
 })
-public class IntHashMap<V> extends AIntMap<V> implements java.io.Serializable {
+public class IntHashMap<V> extends AIntMap<V> implements BlockMap<Integer, V>, java.io.Serializable {
 
     private static final long serialVersionUID = 5L;
 
@@ -317,6 +317,11 @@ public class IntHashMap<V> extends AIntMap<V> implements java.io.Serializable {
         return mvalues;
     }
 
+    @Override
+    public int capacity() {
+        return capacity;
+    }
+
     /**
      * Rehashes the map, making the table as small as possible.
      *
@@ -330,6 +335,7 @@ public class IntHashMap<V> extends AIntMap<V> implements java.io.Serializable {
      * @return true if there was enough memory to trim the map.
      * @see #trim(int)
      */
+    @Override
     public boolean trim() {
         final int l = HashCollection.arraysize(size, factor);
         if (l >= n) {
@@ -361,6 +367,7 @@ public class IntHashMap<V> extends AIntMap<V> implements java.io.Serializable {
      * @return true if there was enough memory to trim the map.
      * @see #trim()
      */
+    @Override
     public final boolean trim(int n) {
         int l = MathUtils.pow2next((int) Math.ceil(n / factor));
         if (this.n <= l) {

+ 10 - 1
assira/src/main/java/net/ranides/assira/collection/sets/AHashSet.java

@@ -6,6 +6,7 @@
  */
 package net.ranides.assira.collection.sets;
 
+import net.ranides.assira.collection.BlockCollection;
 import net.ranides.assira.collection.arrays.ArrayUtils;
 import net.ranides.assira.generic.HashUtils;
 import java.util.ArrayList;
@@ -17,7 +18,7 @@ import net.ranides.assira.math.MathUtils;
 /**
  * A generic set map implementation
  */
-public abstract class AHashSet<K> extends ASet<K> implements java.io.Serializable {
+public abstract class AHashSet<K> extends ASet<K> implements BlockCollection<K>, java.io.Serializable {
 
     private static final long serialVersionUID = 4L;
 
@@ -132,6 +133,12 @@ public abstract class AHashSet<K> extends ASet<K> implements java.io.Serializabl
         return new SetIterator();
     }
 
+    @Override
+    public int capacity() {
+        return capacity;
+    }
+
+    
     /**
      * Rehashes this set, making the table as small as possible.
      *
@@ -145,6 +152,7 @@ public abstract class AHashSet<K> extends ASet<K> implements java.io.Serializabl
      * @return true if there was enough memory to trim the set.
      * @see #trim(int)
      */
+    @Override
     public final boolean trim() {
         final int l = HashCollection.arraysize(size, factor);
         if (l >= n) {
@@ -177,6 +185,7 @@ public abstract class AHashSet<K> extends ASet<K> implements java.io.Serializabl
      * @return true if there was enough memory to trim the set.
      * @see #trim()
      */
+    @Override
     public final boolean trim(int n) {
         final int l = MathUtils.pow2next((int) Math.ceil(n / factor));
         if (this.n <= l) {

+ 9 - 1
assira/src/main/java/net/ranides/assira/collection/sets/IntHashSet.java

@@ -6,6 +6,7 @@
  */
 package net.ranides.assira.collection.sets;
 
+import net.ranides.assira.collection.BlockCollection;
 import net.ranides.assira.collection.iterators.IntIterator;
 import net.ranides.assira.collection.arrays.ArrayUtils;
 import net.ranides.assira.generic.HashUtils;
@@ -22,7 +23,7 @@ import net.ranides.assira.math.MathUtils;
 /**
  * A type-specific set implementation with primitive int values
  */
-public final class IntHashSet extends AIntSet implements java.io.Serializable {
+public final class IntHashSet extends AIntSet implements java.io.Serializable, BlockCollection<Integer> {
 
     private static final long serialVersionUID = 4L;
 
@@ -278,6 +279,11 @@ public final class IntHashSet extends AIntSet implements java.io.Serializable {
         return new SetIterator();
     }
 
+    @Override
+    public int capacity() {
+        return capacity;
+    }
+
     /**
      * Rehashes this set, making the table as small as possible.
      *
@@ -291,6 +297,7 @@ public final class IntHashSet extends AIntSet implements java.io.Serializable {
      * @return true if there was enough memory to trim the set.
      * @see #trim(int)
      */
+    @Override
     public boolean trim() {
         final int l = HashCollection.arraysize(size, factor);
         if (l >= n) {
@@ -323,6 +330,7 @@ public final class IntHashSet extends AIntSet implements java.io.Serializable {
      * @return true if there was enough memory to trim the set.
      * @see #trim()
      */
+    @Override
     public boolean trim(int n) {
         final int l = MathUtils.pow2next((int) Math.ceil(n / factor));
         if (this.n <= l) {

+ 4 - 6
assira/src/test/java/net/ranides/assira/collection/mockup/CollectionSuite.java

@@ -6,6 +6,8 @@
  */
 package net.ranides.assira.collection.mockup;
 
+import net.ranides.assira.collection.suite.BlockCollectionTester;
+import net.ranides.assira.collection.suite.maps.BlockMapTester;
 import net.ranides.assira.collection.suite.maps.AHashMapTester;
 import net.ranides.assira.collection.suite.maps.ASortedMapTester;
 import net.ranides.assira.collection.suite.maps.IntHashMapTester;
@@ -13,12 +15,9 @@ import net.ranides.assira.collection.suite.maps.IntMapTester;
 import net.ranides.assira.collection.suite.maps.IntSortedMapTester;
 import net.ranides.assira.collection.suite.maps.MapTester;
 import net.ranides.assira.collection.suite.maps.SortedMapTester;
-import net.ranides.assira.collection.suite.lookups.AHashLookupTester;
 import net.ranides.assira.collection.suite.lookups.LookupTester;
 import net.ranides.assira.collection.suite.lookups.SortedLookupTester;
-import net.ranides.assira.collection.suite.sets.AHashSetTester;
 import net.ranides.assira.collection.suite.sets.ASortedSetTester;
-import net.ranides.assira.collection.suite.sets.IntHashSetTester;
 import net.ranides.assira.collection.suite.sets.IntSortedSetTester;
 import net.ranides.assira.collection.suite.sets.SetTester;
 import net.ranides.assira.collection.suite.sets.SortedSetTester;
@@ -34,7 +33,6 @@ public final class CollectionSuite {
     
     public static final QTesterSuite SUITE = new QTesterSuite(System.err)
         .append(new LookupTester())
-        .append(new AHashLookupTester())
         .append(new SortedLookupTester())
         .append(new MapTester())
         .append(new AHashMapTester())
@@ -47,8 +45,8 @@ public final class CollectionSuite {
         .append(new ASortedSetTester())
         .append(new IntSortedSetTester())
         .append(new SortedSetTester())
-        .append(new AHashSetTester())
-        .append(new IntHashSetTester())
+        .append(new BlockMapTester())
+        .append(new BlockCollectionTester())
 		;
    
 }

+ 8 - 6
assira/src/test/java/net/ranides/assira/collection/suite/sets/AHashSetTester.java

@@ -4,9 +4,11 @@
  * @license WTFPL
  * @url http://ranides.net/projects/???
  */
-package net.ranides.assira.collection.suite.sets;
+package net.ranides.assira.collection.suite;
 
+import net.ranides.assira.collection.suite.sets.*;
 import javax.annotation.Resource;
+import net.ranides.assira.collection.BlockCollection;
 import net.ranides.assira.collection.sets.AHashSet;
 import net.ranides.assira.test.TCollection;
 import net.ranides.assira.junit.QAssert;
@@ -16,13 +18,13 @@ import org.junit.Test;
  *
  * @author Ranides Atterwim <ranides@gmail.com>
  */
-public final class AHashSetTester<K> {
+public final class BlockCollectionTester<K> {
 
     @Resource(name = "set!")
     private TCollection<K> $set;
     
     @Test
-    public void basicTrim(AHashSet<K> target) {
+    public void basicTrim(BlockCollection<K> target) {
         $set.range(1024).into(target);
         target.clear();
         $set.range(128).into(target);
@@ -30,18 +32,18 @@ public final class AHashSetTester<K> {
     }
     
     @Test
-    public void basicTrimN1(AHashSet<K> target) {
+    public void basicTrimN1(BlockCollection<K> target) {
         basicTrim(target, 5*32, 32, 1024);
     }
     
     @Test
-    public void basicTrimN2(AHashSet<K> target) {
+    public void basicTrimN2(BlockCollection<K> target) {
         QAssert.assertThrows(IllegalArgumentException.class, () -> 
             basicTrim(target, 5*32, 32, 1)
         );
     }
     
-    private void basicTrim(AHashSet<K> target, int put1st, int put2nd, int n) {
+    private void basicTrim(BlockCollection<K> target, int put1st, int put2nd, int n) {
         $set.range(put1st).into(target);
         target.clear();
         $set.range(put2nd).into(target);

+ 0 - 27
assira/src/test/java/net/ranides/assira/collection/suite/maps/AHashMapTester.java

@@ -45,31 +45,4 @@ public final class AHashMapTester<K,V> {
         QAssert.assertThrows(NoSuchElementException.class, ()-> iterator.next());
     }
     
-    @Test
-    public void basicTrim(AHashMap<K, V> target) {
-        $map.range(1024).into(target);
-        target.clear();
-        $map.range(128).into(target);
-        target.trim();
-    }
-    
-    @Test
-    public void basicTrimN1(AHashMap<K, V> target) {
-        basicTrim(target, 5*32, 32, 1024);
-    }
-    
-    @Test
-    public void basicTrimN2(AHashMap<K, V> target) {
-        QAssert.assertThrows(IllegalArgumentException.class, () -> 
-            basicTrim(target, 5*32, 32, 1)
-        );
-    }
-    
-    private void basicTrim(AHashMap<K, V> target, int put1st, int put2nd, int n) {
-        $map.range(put1st).into(target);
-        target.clear();
-        $map.range(put2nd).into(target);
-        target.trim(n);
-    }
-    
 }

+ 8 - 8
assira/src/test/java/net/ranides/assira/collection/suite/lookups/AHashLookupTester.java

@@ -4,10 +4,10 @@
  * @license WTFPL
  * @url http://ranides.net/projects/???
  */
-package net.ranides.assira.collection.suite.lookups;
+package net.ranides.assira.collection.suite.maps;
 
 import javax.annotation.Resource;
-import net.ranides.assira.collection.lookups.AHashLookup;
+import net.ranides.assira.collection.maps.BlockMap;
 import net.ranides.assira.test.TMap;
 import net.ranides.assira.junit.QAssert;
 import org.junit.Test;
@@ -16,13 +16,13 @@ import org.junit.Test;
  *
  * @author Ranides Atterwim <ranides@gmail.com>
  */
-public final class AHashLookupTester<K> {
+public final class BlockMapTester<K,V> {
     
     @Resource(name = "map!")
-    private TMap<K,Integer> $map;
+    private TMap<K,V> $map;
 
     @Test
-    public void basicTrim(AHashLookup<K> target) {
+    public void basicTrim(BlockMap<K,V> target) {
         $map.range(1024).into(target);
         target.clear();
         $map.range(128).into(target);
@@ -30,18 +30,18 @@ public final class AHashLookupTester<K> {
     }
     
     @Test
-    public void basicTrimN1(AHashLookup<K> target) {
+    public void basicTrimN1(BlockMap<K,V> target) {
         basicTrim(target, 5*32, 32, 1024);
     }
     
     @Test
-    public void basicTrimN2(AHashLookup<K> target) {
+    public void basicTrimN2(BlockMap<K,V> target) {
         QAssert.assertThrows(IllegalArgumentException.class, () -> 
             basicTrim(target, 5*32, 32, 1)
         );
     }
     
-    private void basicTrim(AHashLookup<K> target, int put1st, int put2nd, int n) {
+    private void basicTrim(BlockMap<K,V> target, int put1st, int put2nd, int n) {
         $map.range(put1st).into(target);
         target.clear();
         $map.range(put2nd).into(target);

+ 0 - 27
assira/src/test/java/net/ranides/assira/collection/suite/maps/IntHashMapTester.java

@@ -45,31 +45,4 @@ public final class IntHashMapTester<K,V> {
         QAssert.assertThrows(NoSuchElementException.class, ()-> iterator.next());
     }
     
-    @Test
-    public void basicTrim(IntHashMap<V> target) {
-        $map.range(1024).into(target);
-        target.clear();
-        $map.range(128).into(target);
-        target.trim();
-    }
-    
-    @Test
-    public void basicTrimN1(IntHashMap<V> target) {
-        basicTrim(target, 5*32, 32, 1024);
-    }
-    
-    @Test
-    public void basicTrimN2(IntHashMap<V> target) {
-        QAssert.assertThrows(IllegalArgumentException.class, () -> 
-            basicTrim(target, 5*32, 32, 1)
-        );
-    }
-    
-    private void basicTrim(IntHashMap<V> target, int put1st, int put2nd, int n) {
-        $map.range(put1st).into(target);
-        target.clear();
-        $map.range(put2nd).into(target);
-        target.trim(n);
-    }
-    
 }

+ 0 - 51
assira/src/test/java/net/ranides/assira/collection/suite/sets/IntHashSetTester.java

@@ -1,51 +0,0 @@
-/*
- * @author Ranides Atterwim <ranides@gmail.com>
- * @copyright Ranides Atterwim
- * @license WTFPL
- * @url http://ranides.net/projects/???
- */
-package net.ranides.assira.collection.suite.sets;
-
-import javax.annotation.Resource;
-import net.ranides.assira.collection.sets.IntHashSet;
-import net.ranides.assira.junit.QAssert;
-import net.ranides.assira.test.TCollection;
-import org.junit.Test;
-
-/**
- *
- * @author Ranides Atterwim <ranides@gmail.com>
- */
-public final class IntHashSetTester<K> {
-
-    @Resource(name = "set!")
-    private TCollection<Integer> $set;
-    
-    @Test
-    public void basicTrim(IntHashSet target) {
-        $set.range(1024).into(target);
-        target.clear();
-        $set.range(128).into(target);
-        target.trim();
-    }
-    
-    @Test
-    public void basicTrimN1(IntHashSet target) {
-        basicTrim(target, 5*32, 32, 1024);
-    }
-    
-    @Test
-    public void basicTrimN2(IntHashSet target) {
-        QAssert.assertThrows(IllegalArgumentException.class, () -> 
-            basicTrim(target, 5*32, 32, 1)
-        );
-    }
-    
-    private void basicTrim(IntHashSet target, int put1st, int put2nd, int n) {
-        $set.range(put1st).into(target);
-        target.clear();
-        $set.range(put2nd).into(target);
-        target.trim(n);
-    }
-    
-}