Double2ObjectOpenHashMap.java :  » Natural-Language-Processing » Stanford-CoreNLP » it » unimi » dsi » fastutil » doubles » Java Open Source

Java Open Source » Natural Language Processing » Stanford CoreNLP 
Stanford CoreNLP » it » unimi » dsi » fastutil » doubles » Double2ObjectOpenHashMap.java


/* Generic definitions */




/* Assertions (useful to generate conditional code) */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/* Methods that have special names depending on keys (but the special names depend on values) */
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/*     
 * fastutil: Fast & compact type-specific collections for Java
 *
 * Copyright (C) 2002-2008 Sebastiano Vigna 
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
package it.unimi.dsi.fastutil.doubles;
import java.util.Arrays;
import java.util.Map;
import java.util.NoSuchElementException;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.bytes.ByteArrays;
import it.unimi.dsi.fastutil.objects.ObjectCollection;
import it.unimi.dsi.fastutil.objects.AbstractObjectCollection;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectArrays;
import it.unimi.dsi.fastutil.objects.AbstractObjectSet;
/** A type-specific hash map with a fast, small-footprint implementation.
 *
 * <P>Instances of this class use a hash table to represent a map. The table is
 * enlarged as needed when new entries are created, but it is <em>never</em> made
 * smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming
 * methods} lets you control the size of the table; this is particularly useful
 * if you reuse instances of this class.
 *
 * <P>The enlargement speed is controlled by the <em>growth factor</em>, a
 * positive number. If the growth factor is <var>p</var>, then the table is
 * enlarged each time roughly by a factor 2<sup>p/16</sup>. By default, <var>p</var> is
 * {@link Hash#DEFAULT_GROWTH_FACTOR}, which means that the table is doubled at
 * each enlargement, but one can easily set more or less aggressive policies by
 * calling {@link #growthFactor(int)} (note that the growth factor is <em>not</em> serialized:
 * deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
 *
 * @see Hash
 * @see HashCommon
 */
public class Double2ObjectOpenHashMap <V> extends AbstractDouble2ObjectMap <V> implements java.io.Serializable, Cloneable, Hash {
 /** The array of keys. */
 protected transient double key[];
 /** The array of values. */
 protected transient V value[];
 /** The array of occupancy states. */
 protected transient byte state[];
 /** The acceptable load factor. */
 protected final float f;
 /** Index into the prime list, giving the current table size. */
 protected transient int p;
 /** Threshold after which we rehash. It must be the table size times {@link #f}. */
 protected transient int maxFill;
 /** Number of free entries in the table (may be less than the table size - {@link #count} because of deleted entries). */
 protected transient int free;
 /** Number of entries in the map. */
 protected int count;
 /** Cached set of entries. */
 protected transient volatile FastEntrySet <V> entries;
 /** Cached set of keys. */
 protected transient volatile DoubleSet keys;
 /** Cached collection of values. */
 protected transient volatile ObjectCollection <V> values;
 /** The growth factor of the table. The next table size will be <code>{@link Hash#PRIMES}[{@link #p}+growthFactor</code>. */
 protected transient int growthFactor = Hash.DEFAULT_GROWTH_FACTOR;
 public static final long serialVersionUID = -7046029254386353129L;
 private static final boolean ASSERTS = false;
 /** Creates a new hash map.
   *
   * The actual table size is the least available prime greater than <code>n</code>/<code>f</code>.
   *
   * @param n the expected number of elements in the hash map.
   * @param f the load factor.
   * @see Hash#PRIMES
   */
 @SuppressWarnings("unchecked")
 public Double2ObjectOpenHashMap( final int n, final float f ) {
  if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" );
  if ( n < 0 ) throw new IllegalArgumentException( "Hash table size must be nonnegative" );
  int l = Arrays.binarySearch( PRIMES, (int)( n / f ) + 1 );
  if ( l < 0 ) l = -l - 1;
  free = PRIMES[ p = l ];
  this.f = f;
  this.maxFill = (int)( free * f );
  key = new double[ free ];
  value = (V[]) new Object[ free ];
  state = new byte[ free ];
 }
 /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
   *
   * @param n the expected number of elements in the hash map.
   */
 public Double2ObjectOpenHashMap( final int n ) {
  this( n, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash map with {@link Hash#DEFAULT_INITIAL_SIZE} entries
   * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
   */
 public Double2ObjectOpenHashMap() {
  this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash map copying a given one.
   *
   * @param m a {@link Map} to be copied into the new hash map. 
   * @param f the load factor.
   */
 public Double2ObjectOpenHashMap( final Map<? extends Double, ? extends V> m, final float f ) {
  this( m.size(), f );
  putAll( m );
 }
 /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one.
   *
   * @param m a {@link Map} to be copied into the new hash map. 
   */
 public Double2ObjectOpenHashMap( final Map<? extends Double, ? extends V> m ) {
  this( m, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash map copying a given type-specific one.
   *
   * @param m a type-specific map to be copied into the new hash map. 
   * @param f the load factor.
   */
 public Double2ObjectOpenHashMap( final Double2ObjectMap <V> m, final float f ) {
  this( m.size(), f );
  putAll( m );
 }
 /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one.
   *
   * @param m a type-specific map to be copied into the new hash map. 
   */
 public Double2ObjectOpenHashMap( final Double2ObjectMap <V> m ) {
  this( m, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash map using the elements of two parallel arrays.
   *
   * @param k the array of keys of the new hash map.
   * @param v the array of corresponding values in the new hash map.
   * @param f the load factor.
   * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths.
   */
 public Double2ObjectOpenHashMap( final double[] k, final V v[], final float f ) {
  this( k.length, f );
  if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" );
  for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] );
 }
 /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays.
   *
   * @param k the array of keys of the new hash map.
   * @param v the array of corresponding values in the new hash map.
   * @throws IllegalArgumentException if <code>k</code> and <code>v</code> have different lengths.
   */
 public Double2ObjectOpenHashMap( final double[] k, final V v[] ) {
  this( k, v, DEFAULT_LOAD_FACTOR );
 }
 /** Sets the growth factor. Subsequent enlargements will increase the table
   * size roughly by a multiplicative factor of 2<sup>p/16</sup>.
   * 
   * @param growthFactor the new growth factor; it must be positive.
   */
 public void growthFactor( int growthFactor ) {
  if ( growthFactor <= 0 ) throw new IllegalArgumentException( "Illegal growth factor " + growthFactor );
  this.growthFactor = growthFactor;
 }
 /** Gets the growth factor.
   *
   * @return the growth factor of this set.
   * @see #growthFactor(int)
   */
 public int growthFactor() {
  return growthFactor;
 }
 /*
   * The following methods implements some basic building blocks used by
   * all accessors.  They are (and should be maintained) identical to those used in HashSet.drv.
   */
 /** Searches for a key, keeping track of a possible insertion point.
   *
   * @param k the key.
   * @return the index of the correct insertion point, if the key is not found; otherwise,
   * <var>-i</var>-1, where <var>i</var> is the index of the entry containing the key.
   */
 protected final int findInsertionPoint( final double k ) {
  final double key[] = this.key;
  final byte state[] = this.state;
  final int n = key.length;
  // First of all, we make the key into a positive integer.
  final int k2i = it.unimi.dsi.fastutil.HashCommon.double2int(k) & 0x7FFFFFFF;
  // The primary hash, a.k.a. starting point.
  int h1 = k2i % n;
  if ( state[ h1 ] == OCCUPIED && ! ( (k) == (key[ h1 ]) ) ) {
   // The secondary hash.
   final int h2 = ( k2i % ( n - 2 ) ) + 1;
   do {
    h1 += h2;
    if ( h1 >= n || h1 < 0 ) h1 -= n;
   } while( state[ h1 ] == OCCUPIED && ! ( (k) == (key[ h1 ]) ) ); // There's always a FREE entry.
  }
  if (state[ h1 ] == FREE) return h1;
  if (state[ h1 ] == OCCUPIED) return -h1-1; // Necessarily, KEY_EQUALS_HASH( k, h, key[ h1 ] ).
  /* Tables without deletions will never use code beyond this point. */
  final int i = h1; // Remember first available bucket for later.
  /** See the comments in the documentation of the interface Hash. */
  if ( ASSERTS ) assert state[ h1 ] == REMOVED;
  if ( ! ( (k) == (key[ h1 ]) ) ) {
   // The secondary hash.
   final int h2 = ( k2i % ( n - 2 ) ) + 1;
   do {
    h1 += h2;
    if ( h1 >= n || h1 < 0 ) h1 -= n;
   } while( state[ h1 ] != FREE && ! ( (k) == (key[ h1 ]) ) );
  }
  return state[ h1 ] == OCCUPIED ? -h1-1 : i; // In the first case, necessarily, KEY_EQUALS_HASH( k, h, key[ h1 ] ).
 }
 /** Searches for a key.
   *
   * @param k the key.
   * @return the index of the entry containing the key, or -1 if the key wasn't found.
   */
 protected final int findKey( final double k ) {
  final double key[] = this.key;
  final byte state[] = this.state;
  final int n = key.length;
  // First of all, we make the key into a positive integer.
  final int k2i = it.unimi.dsi.fastutil.HashCommon.double2int(k) & 0x7FFFFFFF;
  // The primary hash, a.k.a. starting point.
  int h1 = k2i % n;
  /** See the comments in the documentation of the interface Hash. */
  if ( state[ h1 ] != FREE && ! ( (k) == (key[ h1 ]) ) ) {
   // The secondary hash.
   final int h2 = ( k2i % ( n - 2 ) ) + 1;
   do {
    h1 += h2;
    if ( h1 >= n || h1 < 0 ) h1 -= n;
   } while( state[ h1 ] != FREE && ! ( (k) == (key[ h1 ]) ) ); // There's always a FREE entry.
  }
  return state[ h1 ] == OCCUPIED ? h1 : -1; // In the first case, necessarily, KEY_EQUALS_HASH( k, h, key[ h1 ] ).
 }
 public V put(final double k, final V v) {
  final int i = findInsertionPoint( k );
  if (i < 0) {
   final V oldValue = value[-i-1];
   value[-i-1] = v;
   return oldValue;
  }
  if ( state[i] == FREE ) free--;
  state[i] = OCCUPIED;
  key[i] = k;
  value[i] = v;
  if ( ++count >= maxFill ) {
   int newP = Math.min( p + growthFactor, PRIMES.length - 1 );
   // Just to be sure that size changes when p is very small.
   while( PRIMES[ newP ] == PRIMES[ p ] ) newP++;
   rehash( newP ); // Table too filled, let's rehash
  }
  if ( free == 0 ) rehash( p );
  if ( ASSERTS ) checkTable();
  return defRetValue;
 }
 public V put(final Double ok, final V ov) {
  final V v = (ov);
  final double k = ((ok).doubleValue());
  final int i = findInsertionPoint( k );
  if (i < 0) {
   final V oldValue = value[-i-1];
   value[-i-1] = v;
   return (oldValue);
  }
  if ( state[i] == FREE ) free--;
  state[i] = OCCUPIED;
  key[i] = k;
  value[i] = v;
  if ( ++count >= maxFill ) rehash( Math.min(p+16, PRIMES.length-1) ); // Table too filled, let's rehash
  if ( free == 0 ) rehash( p );
  if ( ASSERTS ) checkTable();
  return (this.defRetValue);
 }
 public boolean containsValue( final Object v ) {
  final V value[] = this.value;
  final byte state[] = this.state;
  int i = 0, j = count;
  while(j-- != 0) {
   while(state[ i ] != OCCUPIED ) i++;
   if ( ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true;
   i++;
  }
  return false;
 }
 /* Removes all elements from this map.
   *
   * <P>To increase object reuse, this method does not change the table size.
   * If you want to reduce the table size, you must use {@link #trim()}.
   *
   */
 public void clear() {
  if ( free == state.length ) return;
  free = state.length;
  count = 0;
  ByteArrays.fill( state, FREE );
  // We null all object entries so that the garbage collector can do its work.
  ObjectArrays.fill( value, null );
 }
 /** The entry class for a hash map does not record key and value, but
   * rather the position in the hash table of the corresponding entry. This
   * is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in
   * the map */
 private final class MapEntry implements Double2ObjectMap.Entry <V>, Map.Entry<Double, V> {
  private int index;
  MapEntry( final int index ) {
   this.index = index;
  }
  public Double getKey() {
   return (Double.valueOf(key[ index ]));
  }
  public double getDoubleKey() {
      return key[ index ];
  }
  public V getValue() {
   return (value[ index ]);
  }
  public V setValue( final V v ) {
   final V oldValue = value[ index ];
   value[ index ] = v;
   return oldValue;
  }
  @SuppressWarnings("unchecked")
  public boolean equals( final Object o ) {
   if (!(o instanceof Map.Entry)) return false;
   Map.Entry<Double, V> e = (Map.Entry<Double, V>)o;
   return ( (key[ index ]) == (((e.getKey()).doubleValue())) ) && ( (value[ index ]) == null ? ((e.getValue())) == null : (value[ index ]).equals((e.getValue())) );
  }
  public int hashCode() {
   return it.unimi.dsi.fastutil.HashCommon.double2int(key[ index ]) ^ ( (value[ index ]) == null ? 0 : (value[ index ]).hashCode() );
  }
  public String toString() {
   return key[ index ] + "->" + value[ index ];
  }
 }
 /** An iterator over a hash map. */
 private class MapIterator {
  /** The index of the next entry to be returned. */
  int pos = 0;
  /** The index of the last entry that has been returned. */
  int last = -1;
  /** A downward counter measuring how many entries have been returned. */
  int c = count;
  {
   final byte state[] = Double2ObjectOpenHashMap.this.state;
   final int n = state.length;
   if ( c != 0 ) while( pos < n && state[ pos ] != OCCUPIED ) pos++;
  }
  public boolean hasNext() {
   return c != 0 && pos < Double2ObjectOpenHashMap.this.state.length;
  }
  public int nextEntry() {
   final byte state[] = Double2ObjectOpenHashMap.this.state;
   final int n = state.length;
   if ( ! hasNext() ) throw new NoSuchElementException();
   last = pos;
   if ( --c != 0 ) do pos++; while( pos < n && state[ pos ] != OCCUPIED );
   return last;
  }
  @SuppressWarnings("unchecked")
  public void remove() {
   if (last == -1) throw new IllegalStateException();
   state[last] = REMOVED;
   value[last] = null;
   count--;
  }
  public int skip( final int n ) {
   int i = n;
   while( i-- != 0 && hasNext() ) nextEntry();
   return n - i - 1;
  }
 }
 private class EntryIterator extends MapIterator implements ObjectIterator<Double2ObjectMap.Entry <V> > {
  public Double2ObjectMap.Entry <V> next() {
   return new MapEntry( nextEntry() );
  }
 }
 private class FastEntryIterator extends MapIterator implements ObjectIterator<Double2ObjectMap.Entry <V> > {
  final BasicEntry <V> entry = new BasicEntry <V> ( (0), (null) );
  public BasicEntry <V> next() {
   final int e = nextEntry();
   entry.key = key[ e ];
   entry.value = value[ e ];
   return entry;
  }
 }
 @SuppressWarnings("unchecked")
 public boolean containsKey( double k ) {
  return findKey( k ) >= 0;
 }
 public int size() {
  return count;
 }
 public boolean isEmpty() {
  return count == 0;
 }
 @SuppressWarnings("unchecked")
 public V get(final double k) {
  final int i = findKey( k);
  return i < 0 ? defRetValue : value[i];
 }
 @SuppressWarnings("unchecked")
 public V remove(final double k) {
  final int i = findKey( k );
  if (i < 0) return defRetValue;
  state[i] = REMOVED;
  count--;
  final V v = value[i];
  value[i] = null;
  return v;
 }
 public V get(final Double ok) {
  final int i = findKey(((ok).doubleValue()));
  return i < 0 ? (this.defRetValue) : (V)(value[i]);
 }
 @SuppressWarnings("unchecked")
 public V remove( final Object ok ) {
  final int i = findKey( ((((Double)(ok)).doubleValue())) );
  if (i < 0) return (this.defRetValue);
  state[i] = REMOVED;
  count--;
  final V v = value[i];
  value[i] = null;
  if ( ASSERTS ) checkTable();
  return v;
 }
 private final class MapEntrySet extends AbstractObjectSet<Double2ObjectMap.Entry <V> > implements FastEntrySet <V> {
  public ObjectIterator<Double2ObjectMap.Entry <V> > iterator() {
   return new EntryIterator();
  }
  public ObjectIterator<Double2ObjectMap.Entry <V> > fastIterator() {
   return new FastEntryIterator();
  }
  @SuppressWarnings("unchecked")
  public boolean contains( final Object o ) {
   if (!(o instanceof Map.Entry)) return false;
   final Map.Entry<Double, V> e = (Map.Entry<Double, V>)o;
   final int i = findKey( ((e.getKey()).doubleValue()) );
   return i >= 0 && ( (value[ i ]) == null ? ((e.getValue())) == null : (value[ i ]).equals((e.getValue())) );
  }
  @SuppressWarnings("unchecked")
  public boolean remove( final Object o ) {
   if (!(o instanceof Map.Entry)) return false;
   final Map.Entry<Double, V> e = (Map.Entry<Double, V>)o;
   final int i = findKey( ((e.getKey()).doubleValue()) );
   if ( i >= 0 ) Double2ObjectOpenHashMap.this.remove( e.getKey() );
   return i >= 0;
  }
  public int size() {
   return count;
  }
  public void clear() {
   Double2ObjectOpenHashMap.this.clear();
  }
 }
 public FastEntrySet <V> double2ObjectEntrySet() {
  if ( entries == null ) entries = new MapEntrySet();
  return entries;
 }
 /** An iterator on keys.
   *
   * <P>We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods
   * (and possibly their type-specific counterparts) so that they return keys
   * instead of entries.
   */
 private final class KeyIterator extends MapIterator implements DoubleIterator {
  public KeyIterator() { super(); }
  public double nextDouble() { return key[ nextEntry() ]; }
  public Double next() { return (Double.valueOf(key[ nextEntry() ])); }
 }
 private final class KeySet extends AbstractDoubleSet {
  public DoubleIterator iterator() {
   return new KeyIterator();
  }
  public int size() {
   return count;
  }
  public boolean contains( double k ) {
   return containsKey( k );
  }
  public boolean remove( double k ) {
   int oldCount = count;
   Double2ObjectOpenHashMap.this.remove( k );
   return count != oldCount;
  }
  public void clear() {
   Double2ObjectOpenHashMap.this.clear();
  }
 }
 public DoubleSet keySet() {
  if ( keys == null ) keys = new KeySet();
  return keys;
 }
 /** An iterator on values.
   *
   * <P>We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods
   * (and possibly their type-specific counterparts) so that they return values
   * instead of entries.
   */
 private final class ValueIterator extends MapIterator implements ObjectIterator <V> {
  public ValueIterator() { super(); }
  public V next() { return value[ nextEntry() ]; }
 }
 public ObjectCollection <V> values() {
  if ( values == null ) values = new AbstractObjectCollection <V>() {
    public ObjectIterator <V> iterator() {
     return new ValueIterator();
    }
    public int size() {
     return count;
    }
    public boolean contains( Object v ) {
     return containsValue( v );
    }
    public void clear() {
     Double2ObjectOpenHashMap.this.clear();
    }
   };
  return values;
 }
 /** Rehashes this map without changing the table size.
   * <P>This method should be called when the map underwent numerous deletions and insertions.
   * In this case, free entries become rare, and unsuccessful searches
   * require probing <em>all</em> entries. For reasonable load factors this method is linear in the number of entries.
   * You will need as much additional free memory as
   * that occupied by the table.
   *
   * <P>If you need to reduce the table siza to fit exactly
   * this map, you must use {@link #trim()}.
   *
   * @return <code>true</code> if there was enough memory to rehash the map, <code>false</code> otherwise.
   * @see #trim()
   */
 public boolean rehash() {
  try {
   rehash(p);
  }
  catch(OutOfMemoryError cantDoIt) { return false; }
  return true;
 }
 /** Rehashes the map, making the table as small as possible.
   * 
   * <P>This method rehashes to the smallest size satisfying
   * the load factor. It can be used when the map will not be
   * changed anymore, so to optimize access speed (by collecting
   * deleted entries) and size.
   *
   * <P>If the table size is already the minimum possible, this method
   * does nothing. If you want to guarantee rehashing, use {@link #rehash()}.
   *
   * @return true if there was enough memory to trim the map.
   * @see #trim(int)
   * @see #rehash()
   */
 public boolean trim() {
  int l = Arrays.binarySearch( PRIMES, (int)( count / f ) + 1 );
  if ( l < 0 ) l = -l - 1;
  if ( l >= p ) return true;
  try {
   rehash( l );
  }
  catch(OutOfMemoryError cantDoIt) { return false; }
  return true;
 }
 /** Rehashes this map if the table is too large.
   * 
   * <P>Let <var>N</var> be the smallest table size that can hold
   * <code>max(n,{@link #size()})</code> entries, still satisfying the load factor. If the current
   * table size is smaller than or equal to <var>N</var>, this method does
   * nothing. Otherwise, it rehashes this map in a table of size
   * <var>N</var>.
   *
   * <P>This method is useful when reusing maps.  {@linkplain #clear() Clearing a
   * map} leaves the table size untouched. If you are reusing a map
   * many times, you can call this method with a typical
   * size to avoid keeping around a very large table just
   * because of a few large transient maps.
   *
   * @param n the threshold for the trimming.
   * @return true if there was enough memory to trim the map.
   * @see #trim()
   * @see #rehash()
   */
 public boolean trim( final int n ) {
  int l = Arrays.binarySearch( PRIMES, (int)( Math.min( Integer.MAX_VALUE - 1, Math.max( n, count ) / f ) ) + 1 );
  if ( l < 0 ) l = -l - 1;
  if ( p <= l ) return true;
  try {
   rehash( l );
  }
  catch( OutOfMemoryError cantDoIt ) { return false; }
  return true;
 }
 /** Resizes the map.
   *
   * <P>This method implements the basic rehashing strategy, and may be
   * overriden by subclasses implementing different rehashing strategies (e.g.,
   * disk-based rehashing). However, you should not override this method
   * unless you understand the internal workings of this class.
   *
   * @param newP the new size as an index in {@link Hash#PRIMES}.
   */
 @SuppressWarnings("unchecked")
 protected void rehash( final int newP ) {
  int i = 0, j = count, k2i, h1, h2;
  final byte state[] = this.state;
  double k;
  V v;
  final int newN = PRIMES[newP];
  final double key[] = this.key, newKey[] = new double[newN];
  final V value[] = this.value, newValue[] = (V[]) new Object[newN];
  final byte newState[] = new byte[newN];
  while(j-- != 0) {
   while(state[i] != OCCUPIED ) i++;
   k = key[i];
   v = value[i];
   k2i = it.unimi.dsi.fastutil.HashCommon.double2int(k) & 0x7FFFFFFF;
   h1 = k2i % newN;
   h2 = (k2i % (newN - 2)) + 1;
   if ( newState[h1] != FREE ) {
    h2 = (k2i % (newN - 2)) + 1;
    do {
     h1 += h2;
     if ( h1 >= newN || h1 < 0 ) h1 -= newN;
    } while( newState[h1] != FREE );
   }
   newState[h1] = OCCUPIED;
   newKey[h1] = k;
   newValue[h1] = v;
   i++;
  }
  p = newP;
  free = newN - count;
  maxFill = (int)( newN * f );
  this.key = newKey;
  this.value = newValue;
  this.state = newState;
 }
 /** Returns a deep copy of this map. 
   *
   * <P>This method performs a deep copy of this hash map; the data stored in the
   * map, however, is not cloned. Note that this makes a difference only for object keys.
   *
   *  @return a deep copy of this map.
   */
 @SuppressWarnings("unchecked")
 public Object clone() {
  Double2ObjectOpenHashMap c;
  try {
   c = (Double2ObjectOpenHashMap)super.clone();
  }
  catch(CloneNotSupportedException cantHappen) {
   throw new InternalError();
  }
  c.keys = null;
  c.values = null;
  c.entries = null;
  c.key = key.clone();
  c.value = value.clone();
  c.state = state.clone();
  return c;
 }
 /** Returns a hash code for this map.
   *
   * This method overrides the generic method provided by the superclass. 
   * Since <code>equals()</code> is not overriden, it is important
   * that the value returned by this method is the same value as
   * the one returned by the overriden method.
   *
   * @return a hash code for this map.
   */
 public int hashCode() {
  int h = 0, t, i = 0, j = count;
  while( j-- != 0 ) {
   while( state[ i ] != OCCUPIED ) i++;
   t = 0;
    t = it.unimi.dsi.fastutil.HashCommon.double2int(key[ i ]);
   if ( this != value[ i ] )
    t ^= ( (value[ i ]) == null ? 0 : (value[ i ]).hashCode() );
   h += t;
   i++;
  }
  return h;
 }
 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
  final double key[] = this.key;
  final V value[] = this.value;
  final MapIterator i = new MapIterator();
  int e, j = count;
  s.defaultWriteObject();
  while( j-- != 0 ) {
   e = i.nextEntry();
   s.writeDouble( key[ e ] );
   s.writeObject( value[ e ] );
  }
 }
 @SuppressWarnings("unchecked")
 private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
  s.defaultReadObject();
  // We restore the default growth factor.
  growthFactor = Hash.DEFAULT_GROWTH_FACTOR;
  // Note that we DO NOT USE the stored p. See CHANGES.
  p = Arrays.binarySearch( PRIMES, (int)( count / f ) + 1 );
  if ( p < 0 ) p = -p - 1;
  final int n = PRIMES[ p ];
  maxFill = (int)( n * f );
  free = n - count;;
  final double key[] = this.key = new double[ n ];
  final V value[] = this.value = (V[]) new Object[ n ];
  final byte state[] = this.state = new byte[ n ];
  int i, k2i, h1, h2;
  double k;
  V v;
  i = count;
  while( i-- != 0 ) {
   k = s.readDouble();
   v = (V) s.readObject();
   k2i = it.unimi.dsi.fastutil.HashCommon.double2int(k) & 0x7FFFFFFF;
   h1 = k2i % n;
   if ( state[ h1 ] != FREE ) {
    h2 = ( k2i % ( n - 2 ) ) + 1;
    do {
     h1 += h2;
     if ( h1 >= n || h1 < 0 ) h1 -= n;
    } while( state[ h1 ] != FREE );
   }
   state[ h1 ] = OCCUPIED;
   key[ h1 ] = k;
   value[ h1 ] = v;
  }
  if ( ASSERTS ) checkTable();
 }
 private void checkTable() {}
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.