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

Java Open Source » Natural Language Processing » Stanford CoreNLP 
Stanford CoreNLP » it » unimi » dsi » fastutil » ints » IntLinkedOpenHashSet.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.ints;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.bytes.ByteArrays;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**  A type-specific linked hash set with with a fast, small-footprint implementation.
 *
 * <P>Instances of this class use a hash table to represent a set. 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}).
 *
 * <P>This class implements the interface of a sorted set, so to allow easy
 * access of the iteration order: for instance, you can get the first element
 * in iteration order with {@link #first()} without having to create an
 * iterator; however, this class partially violates the {@link java.util.SortedSet}
 * contract because all subset methods throw an exception and {@link
 * #comparator()} returns always <code>null</code>.
 *
 * <P>The iterators provided by this class are type-specific {@linkplain
 * java.util.ListIterator list iterators}.  However, creation of an iterator
 * using a starting point is going to be very expensive, as the chosen starting
 * point must be linearly searched for, unless it is {@link #last()}, in which
 * case the iterator is created in constant time.
 *
 * <P>Note that deletions in a linked table require scanning the list until the
 * element to be removed is found. The only exceptions are the first element, the last element,
 * and deletions performed using an iterator.
 *
 * @see Hash
 * @see HashCommon
 */
public class IntLinkedOpenHashSet extends AbstractIntSortedSet implements java.io.Serializable, Cloneable, Hash {
 /** The array of keys. */
 protected transient int key[];
 /** 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 set. */
 protected int count;
 /** 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;
 /** The index of the first entry in iteration order. It is valid iff {@link #count} is nonzero; otherwise, it contains -1. */
 protected transient int first = -1;
 /** The index of the last entry in iteration order. It is valid iff {@link #count} is nonzero; otherwise, it contains -1. */
 protected transient int last = -1;
 /** For each entry, the next and the previous entry in iteration order
  exclusive-or'd together. It is valid only on {@link Hash#OCCUPIED}
  entries. The first and the last entry contain the actual successor and
  predecessor, respectively, exclusived-or'd with -1. */
 protected transient int link[];
    public static final long serialVersionUID = -7046029254386353129L;
 private static final boolean ASSERTS = false;
 /** Creates a new hash set.
   *
   * 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 set. 
   * @param f the load factor.
   * @see Hash#PRIMES
   */
 @SuppressWarnings("unchecked")
 public IntLinkedOpenHashSet( 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 int[ free ];
  state = new byte[ free ];
  link = new int[ free ];
 }
 /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
   *
   * @param n the expected number of elements in the hash set. 
   */
 public IntLinkedOpenHashSet( final int n ) {
  this( n, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash set with {@link Hash#DEFAULT_INITIAL_SIZE} elements
   * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
   */
 public IntLinkedOpenHashSet() {
  this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash set copying a given collection.
   *
   * @param c a {@link Collection} to be copied into the new hash set. 
   * @param f the load factor.
   */
 public IntLinkedOpenHashSet( final Collection<? extends Integer> c, final float f ) {
  this( c.size(), f );
  addAll( c );
 }
 /** Creates a new hash set  with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
   * copying a given collection.
   *
   * @param c a {@link Collection} to be copied into the new hash set. 
   */
 public IntLinkedOpenHashSet( final Collection<? extends Integer> c ) {
  this( c, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash set copying a given type-specific collection.
   *
   * @param c a type-specific collection to be copied into the new hash set. 
   * @param f the load factor.
   */
 public IntLinkedOpenHashSet( final IntCollection c, final float f ) {
  this( c.size(), f );
  addAll( c );
 }
 /** Creates a new hash set  with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
   * copying a given type-specific collection.
   *
   * @param c a type-specific collection to be copied into the new hash set. 
   */
 public IntLinkedOpenHashSet( final IntCollection c ) {
  this( c, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash set using elements provided by a type-specific iterator.
   *
   * @param i a type-specific iterator whose elements will fill the set.
   * @param f the load factor.
   */
 public IntLinkedOpenHashSet( final IntIterator i, final float f ) {
  this( DEFAULT_INITIAL_SIZE, f );
  while( i.hasNext() ) add( i.nextInt() );
 }
 /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by a type-specific iterator.
   *
   * @param i a type-specific iterator whose elements will fill the set.
   */
 public IntLinkedOpenHashSet( final IntIterator i ) {
  this( i, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash set using elements provided by an iterator.
   *
   * @param i an iterator whose elements will fill the set.
   * @param f the load factor.
   */
 public IntLinkedOpenHashSet( final Iterator<?> i, final float f ) {
  this( IntIterators.asIntIterator( i ), f );
 }
 /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by an iterator.
   *
   * @param i an iterator whose elements will fill the set.
   */
 public IntLinkedOpenHashSet( final Iterator<?> i ) {
  this( IntIterators.asIntIterator( i ) );
 }
 /** Creates a new hash set and fills it with the elements of a given array.
   *
   * @param a an array whose elements will be used to fill the set.
   * @param offset the first element to use.
   * @param length the number of elements to use.
   * @param f the load factor.
   */
 public IntLinkedOpenHashSet( final int[] a, final int offset, final int length, final float f ) {
  this( length < 0 ? 0 : length, f );
  IntArrays.ensureOffsetLength( a, offset, length );
  for( int i = 0; i < length; i++ ) add( a[ offset + i ] );
 }
 /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor and fills it with the elements of a given array.
   *
   * @param a an array whose elements will be used to fill the set.
   * @param offset the first element to use.
   * @param length the number of elements to use.
   */
 public IntLinkedOpenHashSet( final int[] a, final int offset, final int length ) {
  this( a, offset, length, DEFAULT_LOAD_FACTOR );
 }
 /** Creates a new hash set copying the elements of an array.
   *
   * @param a an array to be copied into the new hash set. 
   * @param f the load factor.
   */
 public IntLinkedOpenHashSet( final int[] a, final float f ) {
  this( a, 0, a.length, f );
 }
 /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
   * copying the elements of an array.
   *
   * @param a an array to be copied into the new hash set. 
   */
 public IntLinkedOpenHashSet( final int[] a ) {
  this( a, 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 HashMap.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 int k ) {
  final int 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 = (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 int k ) {
  final int 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 = (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 boolean add( final int k ) {
  final int i = findInsertionPoint( k );
  if ( i < 0 ) return false;
  if ( state[ i ] == FREE ) free--;
  state[ i ] = OCCUPIED;
  key[ i ] = k;
  if ( count == 0 ) {
   first = last = i;
   link[ i ] = 0;
  }
  else {
   link[ last ] ^= i ^ -1;
   link[ i ] = last ^ -1;
   last = i;
  }
  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 true;
 }
 @SuppressWarnings("unchecked")
 public boolean remove( final int k ) {
  final int i = findKey( k );
  if ( i < 0 ) return false;
  state[ i ] = REMOVED;
  count--;
  fixPointers( i );
  if ( ASSERTS ) checkTable();
  return true;
 }
 @SuppressWarnings("unchecked")
 public boolean contains( final int k ) {
  return findKey( k ) >= 0;
 }
 /* Removes all elements from this set.
   *
   * <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 );
  first = last = -1;
 }
 /** Modifies the {@link #link} vector so that the given entry is removed.
   *
   * <P>If the given entry is the first or the last one, this method will complete
   * in constant time; otherwise, it will have to search for the given entry.
   *
   * @param i the index of an entry. 
   */
 private void fixPointers( int i ) {
  if ( count == 0 ) {
   first = last = -1;
   return;
  }
  if ( first == i ) {
   first = link[ i ] ^ -1;
   link[ first ] ^= i ^ -1;
   return;
  }
  if ( last == i ) {
   last = link[ i ] ^ -1;
   link[ last ] ^= i ^ -1;
   return;
  }
  int j = first, prev = -1, next;
  while( ( next = link[ j ] ^ prev ) != i ) {
   prev = j;
   j = next;
  }
  link[ j ] ^= link[ i ] ^ i ^ j;
  link[ link[ i ] ^ j ] ^= i ^ j;
 }
 /** Returns the first element of this set in iteration order.
   *
   * @return the first element in iteration order.
   */
 public int firstInt() {
  if ( count == 0 ) throw new NoSuchElementException();
  return key[ first ];
 }
 /** Returns the last element of this set in iteration order.
   *
   * @return the last element in iteration order.
   */
 public int lastInt() {
  if ( count == 0 ) throw new NoSuchElementException();
  return key[ last ];
 }
 public IntSortedSet tailSet( int from ) { throw new UnsupportedOperationException(); }
 public IntSortedSet headSet( int to ) { throw new UnsupportedOperationException(); }
 public IntSortedSet subSet( int from, int to ) { throw new UnsupportedOperationException(); }
 public IntComparator comparator() { return null; }
 /** A list iterator over a linked set.
   *
   * <P>This class provides a list iterator over a linked hash set. The empty constructor runs in 
   * constant time. The one-argoument constructor needs to search for the given element, but it is 
   * optimized for the case of {@link java.util.SortedSet#last()}, in which case runs in constant time, too.
   */
 private class SetIterator extends AbstractIntListIterator {
  /** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or <code>null</code> if no previous entry exists). */
  int prev = -1;
  /** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or <code>null</code> if no next entry exists). */
  int next = -1;
  /** The last entry that was returned (or -1 if we did not iterate or used {@link #remove()}). */
  int curr = -1;
  /** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this {@link SetIterator} has been created using the nonempty constructor.*/
  int index = 0;
  SetIterator() {
   next = first;
  }
  SetIterator( int from ) {
   if ( ( (key[ last ]) == (from) ) ) {
    prev = last;
    index = count;
   }
   else {
    if ( ! contains( from ) ) throw new IllegalArgumentException( "The key " + from + " does not belong to this set." );
    next = first;
    int k;
    do k = nextInt(); while( ! ( (k) == (from) ) );
    curr = -1;
   }
  }
  public boolean hasNext() { return next != -1; }
  public boolean hasPrevious() { return prev != -1; }
  public int nextInt() {
   if ( ! hasNext() ) throw new NoSuchElementException();
   curr = next;
   next = link[ curr ] ^ prev;
   prev = curr;
   index++;
   return key[ curr ];
  }
  public int previousInt() {
   if ( ! hasPrevious() ) throw new NoSuchElementException();
   curr = prev;
   prev = link[ curr ] ^ next;
   next = curr;
   index--;
   return key[ curr ];
  }
  public int nextIndex() {
   return index;
  }
  public int previousIndex() {
   return index - 1;
  }
  @SuppressWarnings("unchecked")
  public void remove() {
   if ( curr == -1 ) throw new IllegalStateException();
   state[ curr ] = REMOVED;
   if ( curr == prev ) {
    /* If the last operation was a next(), we are removing an entry that preceeds
           the current index, and thus we must decrement it. */
    index--;
    prev = link[ curr ] ^ next;
   }
   else next = link[ curr ] ^ prev; // curr == next
   count--;
   /* Now we manually fix the pointers. Because of our knowledge of next
         and prev, this is going to be faster than calling fixPointers(). */
   if ( prev == -1 ) first = next;
   else link[ prev ] ^= curr ^ next;
   if ( next == -1 ) last = prev;
   else link[ next ] ^= curr ^ prev;
   curr = -1;
  }
 }
 /** Returns a type-specific list iterator on the elements in this set, starting from a given element of the set.
   *
   * <P>This method provides an iterator positioned immediately after the
   * given element. That is, the next call to <code>previous()</code> will
   * return <code>from</code>, whereas the next call to <code>next()</code>
   * will return the element immediately after <code>from</code>. This
   * allows to call <code>iterator(last())</code> and obtain an iterator starting
   * from the end of the iteration order.
   *
   * <P>Because of the way linking is implemented, generating an iterator using this method
   * requires constant time only if the argument is <code>last()</code>. In all other cases,
   * a linear search for the given element will be necessary.
   *
   * <P>Note that this method returns a bidirectional iterator, which, however, can be safely cast to 
   * a type-specific list iterator.
   *
   * @param from an element to start from.
   * @return a type-specific list iterator starting at the given element.
   * @throws IllegalArgumentException if <code>from</code> does not belong to the set.
   */
 public IntBidirectionalIterator iterator( int from ) {
  return new SetIterator( from );
 }
 public IntBidirectionalIterator iterator() {
  return new SetIterator();
 }
 /** Rehashes this set without changing the table size.
   *
   * <P>This method should be called when the set 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 set, you must use {@link #trim()}.
   *
   * @return true if there was enough memory to rehash the set, false otherwise.
   * @see #trim()
   */
 public boolean rehash() {
  try {
   rehash( p );
  }
  catch( OutOfMemoryError cantDoIt ) { return false; }
  return true;
 }
 /** Rehashes this set, making the table as small as possible.
   * 
   * <P>This method rehashes the table to the smallest size satisfying the
   * load factor. It can be used when the set 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 set.
   * @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 set 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 set in a table of size
   * <var>N</var>.
   *
   * <P>This method is useful when reusing sets.  {@linkplain #clear() Clearing a
   * set} leaves the table size untouched. If you are reusing a set
   * 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 sets.
   *
   * @param n the threshold for the trimming.
   * @return true if there was enough memory to trim the set.
   * @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 set.
   *
   * <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 = first, j = count, prev = -1, newPrev = -1, t, k2i, h1, h2;
  //System.err.println("Rehashing to size " +  PRIMES[newP] + "...");
  int k;
  final int newN = PRIMES[ newP ];
  final int key[] = this.key, newKey[] = new int[ newN ];
  final byte newState[] = new byte[ newN ];
  final int link[] = this.link, newLink[] = new int[ newN ];
  first = -1;
  while( j-- != 0 ) {
   k = key[ i ];
   k2i = (k) & 0x7FFFFFFF;
   h1 = k2i % newN;
   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;
   t = i;
   i = link[ i ] ^ prev;
   prev = t;
   if ( first != -1 ) {
    newLink[ newPrev ] ^= h1;
    newLink[ h1 ] = newPrev;
    newPrev = h1;
   }
   else {
    newPrev = first = h1;
    newLink[ h1 ] = -1;
   }
  }
  p = newP;
  free = newN - count;
  maxFill = (int)( newN * f );
  this.key = newKey;
  this.state = newState;
  this.link = newLink;
  this.last = newPrev;
  if ( newPrev != -1 ) newLink[ newPrev ] ^= -1;
 }
 public int size() {
  return count;
 }
 public boolean isEmpty() {
  return count == 0;
 }
 /** Returns a deep copy of this set. 
   *
   * <P>This method performs a deep copy of this hash set; the data stored in the
   * set, however, is not cloned. Note that this makes a difference only for object keys.
   *
   *  @return a deep copy of this set.
   */
 @SuppressWarnings("unchecked")
 public Object clone() {
  IntLinkedOpenHashSet c;
  try {
   c = (IntLinkedOpenHashSet )super.clone();
  }
  catch(CloneNotSupportedException cantHappen) {
   throw new InternalError();
  }
  c.key = key.clone();
  c.state = state.clone();
  c.link = link.clone();
  return c;
 }
 /** Returns a hash code for this set.
   *
   * 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 set.
   */
 public int hashCode() {
  int h = 0, i = 0, j = count;
  while( j-- != 0 ) {
   while( state[ i ] != OCCUPIED ) i++;
    h += (key[ i ]);
   i++;
  }
  return h;
 }
 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
  final IntIterator i = iterator();
  int j = count;
  s.defaultWriteObject();
  while( j-- != 0 ) s.writeInt( i.nextInt() );
 }
 @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 int key[] = this.key = new int[ n ];
  final byte state[] = this.state = new byte[ n ];
  final int link[] = this.link = new int[ n ];
  int prev = -1;
  first = last = -1;
  int i, k2i, h1, h2;
  int k;
  i = count;
  while( i-- != 0 ) {
   k = s.readInt();
   k2i = (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;
   if ( first != -1 ) {
    link[ prev ] ^= h1;
    link[ h1 ] = prev;
    prev = h1;
   }
   else {
    prev = first = h1;
    link[ h1 ] = -1;
   }
  }
  last = prev;
  if ( prev != -1 ) link[ prev ] ^= -1;
  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.