Revision: 4527 http://sourceforge.net/p/vexi/code/4527 Author: mkpg2 Date: 2013-05-26 10:16:43 +0000 (Sun, 26 May 2013) Log Message: ----------- Resurrect ibex map as org.ibex.js.util.Hash - Fixed. There was a logic bug in rehash. That meant it would lose track of its size. - Fixed/Changed probing algorithm - It was not using primes of size 4n+3 as the size of the elements list. It started with 4n+3 number (pseudo prime) and then just multiplied that by the number of slots (for some reason) i.e. 2/3 when resizing. - New probing algorithm requires basket size 2^n instead, so avoids this issue. - Removed multiple slots (a better way to achieve this is to use keys of a different type in a single map). - Made as small as possible by hardcoding load factor ... etc. It is no longer tunable at runtime, so for this reason it is essentially JS specific.
Added Paths: ----------- branches/vexi4/org.vexi-library.js/src/main/java/org/ibex/js/util/ branches/vexi4/org.vexi-library.js/src/main/java/org/ibex/js/util/Hash.java Added: branches/vexi4/org.vexi-library.js/src/main/java/org/ibex/js/util/Hash.java =================================================================== --- branches/vexi4/org.vexi-library.js/src/main/java/org/ibex/js/util/Hash.java (rev 0) +++ branches/vexi4/org.vexi-library.js/src/main/java/org/ibex/js/util/Hash.java 2013-05-26 10:16:43 UTC (rev 4527) @@ -0,0 +1,200 @@ + +package org.ibex.js.util; + +import org.ibex.util.Basket; +import org.ibex.util.Basket.Map; + +/** + * + * <P>Copyright 2013 the Contributors, as shown in the revision logs. + * Licensed under the Apache Public Source License 2.0 ("the License"). + * You may not use this file except in compliance with the License.</p> + * + * <p>Based on the original implementation by a...@ibex.org, craws...@ibex.org. + * Originally Hash used the standard form of Radke's quadratic residue linear probing.</p> + * + * <p> + * Now hash uses a variant probing strategy by F R A Hopgood and J. Davenport, which supports + * full table scans when the table size is a power of 2. + * </p> + * + * <p>Not thread safe</p> + * + * @author mike.good...@cantab.net + */ +public class Hash implements Basket, Map { + /** When <tt>loadFactor * usedslots > num_slots</tt>, call + * <tt>rehash()</tt>. */ + static final float LOAD_FACTOR = 0.75f; + static final Object PLACE_HOLDER = new Object(); + static final int SLOTS = 2; // 2 slots, one for the key, one for the value + + private int size = 0; // bookkeeping - the nmuber of active entries + private int placeholders = 0; // bookkeeping - the number of placeholders (used when removing entries - until next rehash) + private Object[] entries = null; + + public Hash() { this(4); } + public Hash(int sizePowerOf2) { + if(sizePowerOf2>=1){ + int size = 1<<sizePowerOf2; + // 2 entries, key + value + this.entries = new Object[size*SLOTS]; + } + } + + // Returns the array position of the key, if it exists. + // + // If the key is not found, this function returns + // (-1 * indexPosition) - 1, where indexPosition + // is the array position where the mapping should be stored. + private int _indexOf(Object k) { + if(entries==null) return Integer.MIN_VALUE; + + final int capacity = _capacity(); + final int orig = Math.abs(k.hashCode()) % capacity; + int dest = orig * SLOTS; + int increment = 1; + while (entries[dest] != null) { + if (equals(k, entries[dest])) return dest; + + dest = Math.abs((dest + increment) % capacity) * SLOTS; + + if(increment>capacity) return Integer.MIN_VALUE; + increment = increment +1; + } + return _convertKey(dest); + } + + // encode/decodes index as a negative value + private int _convertKey(int dest){ + return -1 * dest - 1; + } + + private int _capacity(){ return entries==null?0:entries.length/SLOTS; } + private boolean _notKey(Object k){ return k==null || k==PLACE_HOLDER; } + + public int size() { return size; } + public void clear() { + if(entries==null) return; + for (int i = 0; i<entries.length; i++) entries[i] = null; + size = 0; placeholders=0; + } + + private boolean areEqual(Object a, Object b){ + if(a==null && b==null) return true; + if(a!=null && b!=null) return a.equals(b); + return false; + } + + public boolean containsKey(Object k) { return _indexOf(k) >= 0; } + public boolean containsValue(Object value) { + for(int i=0; i<entries.length; i+=SLOTS){ + Object k = entries[i]; + if(_notKey(k)) continue; + Object v = entries[i+1]; + if(areEqual(value, v)) return true; + } + return false; + } + + public Object[] listKeys() { + Object[] arr = new Object[size]; + listKeys(arr); + return arr; + } + public void listKeys(Object[] arr) { + int pos = 0; + if(entries!=null) for(int i=0; i<entries.length; i+=SLOTS){ + Object k = entries[i]; + if(_notKey(k)) continue; + arr[pos++] = entries[i]; + } + } + + public Object remove(Object k) { return remove(_indexOf(k)); } + public Object remove(int dest) { + if (dest < 0) return null; + // instead of removing, insert a placeholder + Object r = entries[dest+1]; + entries[dest] = PLACE_HOLDER; + entries[dest + 1] = null; + size--; + placeholders++; + return r; + } + + public Object get(Object key) { + int i = _indexOf(key); + return i >= 0 ? entries[i + 1] : null; + } + + public Object put(Object key, Object value) { + if (size + placeholders >= (float)(_capacity() * LOAD_FACTOR)) rehash(); + int dest = _indexOf(key); + Object old = null; + if (dest < 0) { + dest = _convertKey(dest); + if (entries[dest] != PLACE_HOLDER) size++; + entries[dest] = key; + entries[dest+1] = null; + } else { + old = entries[dest + 1]; + } + entries[dest + 1] = value; + return old; + } + + /* + public boolean containsKey(Object k) { return super.containsValue(k); } + public boolean containsValue(Object v) { + for (int i=0; i < entries.length/indexmultiple; i++) + if ((i == 0 || entries[i * indexmultiple] != null) && // exception for null key + !equals(placeholder, entries[i * indexmultiple]) && + v == null ? entries[i + 1] == null : v.equals(entries[i + 1])) + return true; + return false; + } + */ + + /** Compares two keys for equality. <tt>userKey</tt> is the key + * passed to the map, <tt>storedKey</tt> is from the map. + * + * <p>Default implementation provides standard Java equality + * testing, <tt>k1 == null ? k2 == null : k1.equals(k2)</tt>.</p> + */ + protected boolean equals(Object userKey, Object storedKey) { + return userKey == null ? storedKey == null : userKey.equals(storedKey); + } + + /** Doubles the available entry space, first by packing the data + * set (removes <tt>placeholder</tt> references) and if necessary + * by increasing the size of the <tt>entries</tt> array. + */ + private void rehash() { + // we may rehash if we have too many + boolean expand = size > (float)(_capacity() * LOAD_FACTOR); + rehash(expand); + } + private void rehash(boolean expand) { + Object[] oldentries = entries; + if(oldentries==null){ + entries = new Object[4]; + return; + } + + entries = new Object[oldentries.length * (expand?2:1)]; + + for (int pos=0; pos < oldentries.length; pos+=2) { + Object k = oldentries[pos]; + if (_notKey(k)) continue; + + // dont adjust any of the support entries + int dest = _indexOf(k); + // dest is negative (new entry) so we + dest = _convertKey(dest); + entries[dest] = oldentries[pos]; + entries[dest + 1] = oldentries[pos + 1]; + } + placeholders = 0; + } +} \ No newline at end of file Property changes on: branches/vexi4/org.vexi-library.js/src/main/java/org/ibex/js/util/Hash.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Try New Relic Now & We'll Send You this Cool Shirt New Relic is the only SaaS-based application performance monitoring service that delivers powerful full stack analytics. Optimize and monitor your browser, app, & servers with just a few lines of code. Try New Relic and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn