Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/util/WeakPool.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
line wrap: on
line source
/* * Copyright (C) 2014, United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. * * The Java Pathfinder core (jpf-core) platform is licensed under the * Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gov.nasa.jpf.util; import java.lang.ref.WeakReference; /** * This is a simplified hash pool that does not support removal or * numbering of elements. */ public class WeakPool<E> { private static final boolean DEBUG = false; static final double MAX_LOAD_WIPE = 0.6; static final double MAX_LOAD_REHASH = 0.4; static final int DEFAULT_POW = 10; WeakReference<E>[] table; int count; int pow; int mask; int nextWipe; int nextRehash; /** * Creates a SimplePool that holds about 716 elements before first * rehash. */ public WeakPool() { this(DEFAULT_POW); } /** * Creates a SimplePool that holds about 0.7 * 2**pow elements before * first rehash. */ public WeakPool(int pow) { this.pow = pow; newTable(); count = 0; mask = table.length - 1; nextWipe = (int)(MAX_LOAD_WIPE * mask); nextRehash = (int)(MAX_LOAD_REHASH * mask); } @SuppressWarnings("unchecked") protected void newTable() { table = new WeakReference[1 << pow]; } // ********************** 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(;;) { WeakReference<E> r = table[idx]; if (r == null) break; E o = r.get(); if (o != null && e.equals(o)) { return 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(;;) { WeakReference<E> r = table[idx]; if (r == null) break; E o = r.get(); if (o != null && e.equals(o)) { return 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 >= nextWipe) { // too full // determine if size needs to be increased or just wipe unused weak refs int oldCount = count; count = 0; for (int i = 0; i < table.length; i++) { if (table[i] != null && table[i].get() != null) { count++; } } if (DEBUG && oldCount > count) { System.out.println("Weak references collected: " + (oldCount - count)); } if (count >= nextRehash) { pow++; // needs to be increased in size } WeakReference<E>[] oldTable = table; newTable(); mask = table.length - 1; nextWipe = (int)(MAX_LOAD_WIPE * mask); nextRehash = (int)(MAX_LOAD_REHASH * mask); int oldLen = oldTable.length; for (int i = 0; i < oldLen; i++) { WeakReference<E> r = oldTable[i]; if (r == null) continue; E o = r.get(); if (o == null) continue; // otherwise: 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] = r; } // 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] = new WeakReference<E>(e); return e; } // ******************* API as add-only weak hash set *************** // public boolean isMember(E e) { return query(e) != null; } public void add(E e) { /*(void)*/ pool(e); } // ************************** Test main ************************ // /** * BROKEN Test main. */ public static void main(String[] args) { WeakPool<Integer> pool = new WeakPool<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(); } } }