// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.util; /** * This is a simplified hash pool that does not support removal or * numbering of elements. */ @SuppressWarnings("unchecked") public class SimplePool<E> { static final double MAX_LOAD = 0.7; static final int DEFAULT_POW = 10; Object[] table; int count; int pow; int mask; int nextRehash; /** * Creates a SimplePool that holds about 716 elements before first * rehash. */ public SimplePool() { this(DEFAULT_POW); } /** * Creates a SimplePool that holds about 0.7 * 2**pow elements before * first rehash. */ public SimplePool(int pow) { table = new Object[1 << pow]; count = 0; this.pow = pow; mask = table.length - 1; nextRehash = (int)(MAX_LOAD * mask); } // ********************** API as simple hash pool ******************* // /** * Asks whether a particular element is already pooled. NOT A TYPICAL * OPERATION. */ public boolean isPooled(E e) { return e == null || query(e) != null; } /** * Returns the matching element if there is one, null if not. */ public E query(E e) { if (e == null) return null; int code = e.hashCode(); int idx = code & mask; int delta = (code >> (pow - 1)) | 1; // must be odd! int oidx = idx; for(;;) { Object o = table[idx]; if (o == null) break; if (e.equals(o)) { return (E) o; // seen before! } idx = (idx + delta) & mask; assert (idx != oidx); // should never wrap around } return null; } /** * Returns a pooled element matching e, which will be e if no match * has been previously pooled. */ public E pool(E e) { if (e == null) return null; int code = e.hashCode(); int idx = code & mask; int delta = (code >> (pow - 1)) | 1; // must be odd! int oidx = idx; for(;;) { Object o = table[idx]; if (o == null) break; if (e.equals(o)) { return (E) o; // seen before! } idx = (idx + delta) & mask; assert (idx != oidx); // should never wrap around } assert (table[idx] == null); // should never fill up // not seen before; add it count++; if (count >= nextRehash) { // too full Object[] oldTable = table; pow++; table = new Object[1 << pow]; mask = table.length - 1; nextRehash = (int)(MAX_LOAD * mask); int oldLen = oldTable.length; for (int i = 0; i < oldLen; i++) { Object o = oldTable[i]; if (o != null) { code = o.hashCode(); idx = code & mask; delta = (code >> (pow - 1)) | 1; // must be odd! while (table[idx] != null) { // we know enough slots exist idx = (idx + delta) & mask; } table[idx] = o; } } // done with rehash; now get idx to empty slot code = e.hashCode(); idx = code & mask; delta = (code >> (pow - 1)) | 1; // must be odd! while (table[idx] != null) { // we know enough slots exist & new element idx = (idx + delta) & mask; } } else { // idx already pointing to empty slot } table[idx] = e; return e; } // ******************* API as add-only hash set *************** // public boolean isMember(E e) { return query(e) != null; } public void add(E e) { /*(void)*/ pool(e); } // ************************** Test main ************************ // /** * Test main. */ public static void main(String[] args) { SimplePool<Integer> pool = new SimplePool<Integer>(4); for (int i = 0; i < 1000000; i += 42) { Integer o = new Integer(i); Integer p = pool.pool(o); if (o != p) throw new RuntimeException(); Integer q = pool.pool(p); if (q != p) throw new RuntimeException(); } for (int i = 0; i < 1000000; i += 42) { Integer o = new Integer(i); Integer p = pool.pool(o); if (o == p) throw new RuntimeException(); if (!o.equals(p)) throw new RuntimeException(); } for (int i = 1; i < 1000000; i += 42) { Integer o = new Integer(i); Integer p = pool.pool(o); if (o != p) throw new RuntimeException(); } } }