All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.internal.cache.TStatelessLongHash Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
/*
 * Contains code from GNU Trove having the license below.
 *
 * Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package com.gemstone.gemfire.internal.cache;

import com.gemstone.gnu.trove.*;
import java.util.Arrays;

/**
 * An open addressed hashing implementation for long primitives.
 *
 * @author darrel
 */

abstract public class TStatelessLongHash extends TStatelessPrimitiveHash
  implements TLongHashingStrategy {
  /** the set of longs */
  protected transient long[] _set;

  protected /*final*/ long _FREE;
  
  /** strategy used to hash values in this collection */
  protected TLongHashingStrategy _hashingStrategy;

  /**
   * Creates a new TStatelessLongHash instance with the default
   * capacity and load factor.
   */
  public TStatelessLongHash(long freeValue) {
    super();
    this._hashingStrategy = this;
    this._FREE = freeValue;
  }

  /**
   * Creates a new TStatelessLongHash instance whose capacity
   * is the next highest prime above initialCapacity + 1
   * unless that value is already prime.
   *
   * @param initialCapacity an int value
   */
  public TStatelessLongHash(long freeValue, int initialCapacity) {
    super(initialCapacity);
    this._hashingStrategy = this;
    this._FREE = freeValue;
  }

  /**
   * Creates a new TStatelessLongHash instance with a prime
   * value at or near the specified capacity and load factor.
   *
   * @param initialCapacity used to find a prime capacity for the table.
   * @param loadFactor used to calculate the threshold over which
   * rehashing takes place.
   */
  public TStatelessLongHash(long freeValue, int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor);
    this._hashingStrategy = this;
    this._FREE = freeValue;
  }

  /**
   * Creates a new TStatelessLongHash instance with the default
   * capacity and load factor.
   * @param strategy used to compute hash codes and to compare keys.
   */
  public TStatelessLongHash(long freeValue, TLongHashingStrategy strategy) {
    super();
    this._hashingStrategy = strategy;
    this._FREE = freeValue;
  }

  /**
   * Creates a new TStatelessLongHash instance whose capacity
   * is the next highest prime above initialCapacity + 1
   * unless that value is already prime.
   *
   * @param initialCapacity an int value
   * @param strategy used to compute hash codes and to compare keys.
   */
  public TStatelessLongHash(long freeValue, int initialCapacity, TLongHashingStrategy strategy) {
    super(initialCapacity);
    this._hashingStrategy = strategy;
    this._FREE = freeValue;
  }

  /**
   * Creates a new TStatelessLongHash instance with a prime
   * value at or near the specified capacity and load factor.
   *
   * @param initialCapacity used to find a prime capacity for the table.
   * @param loadFactor used to calculate the threshold over which
   * rehashing takes place.
   * @param strategy used to compute hash codes and to compare keys.
   */
  public TStatelessLongHash(long freeValue, int initialCapacity, float loadFactor, TLongHashingStrategy strategy) {
    super(initialCapacity, loadFactor);
    this._hashingStrategy = strategy;
    this._FREE = freeValue;
  }

  public long getFreeValue() {
    return this._FREE;
  }
  
  /**
   * @return a deep clone of this collection
   */
  @Override 
    public Object clone() {
    TStatelessLongHash h = (TStatelessLongHash)super.clone();
    h._set = this._set.clone();
    h._FREE = this._FREE;
    return h;
  }

  /**
   * Returns the capacity of the hash table.  This is the true
   * physical capacity, without adjusting for the load factor.
   *
   * @return the physical capacity of the hash table.
   */
  @Override 
    protected int capacity() {
    return _set.length;
  }

  /**
   * initializes the hashtable to a prime capacity which is at least
   * initialCapacity + 1.  
   *
   * @param initialCapacity an int value
   * @return the actual capacity chosen
   */
  @Override 
    protected int setUp(int initialCapacity) {
    int capacity;

    capacity = super.setUp(initialCapacity);
    _set = new long[capacity];
    if (this._FREE != 0) {
      Arrays.fill(_set, this._FREE);
    }
    return capacity;
  }
    
  /**
   * Searches the set for val
   *
   * @param val an long value
   * @return a boolean value
   */
  public boolean contains(long val) {
    return index(val) >= 0;
  }

  /**
   * Executes procedure for each element in the set.
   *
   * @param procedure a TObjectProcedure value
   * @return false if the loop over the set terminated because
   * the procedure returned false for some value.
   */
  public boolean forEach(TLongProcedure procedure) {
    long[] set = _set;
    for (int i = set.length; i-- > 0;) {
      if (set[i] != this._FREE && ! procedure.execute(set[i])) {
        return false;
      }
    }
    return true;
  }

//   /**
//    * Releases the element currently stored at index.
//    *
//    * @param index an int value
//    */
//   @Override 
//     protected void removeAt(int index) {
//     super.removeAt(index);
//     _set[index] = this._FREE;
//   }

  /**
   * Locates the index of val.
   *
   * @param val an long value
   * @return the index of val or -1 if it isn't in the set.
   */
  protected int index(long val) {
    int hash, probe, index, length;
    long[] set;

    if (val == this._FREE) {
      return -1;
    }
    set = _set;
    length = set.length;
    hash = _hashingStrategy.computeHashCode(val) & 0x7fffffff;
    index = hash % length;

    if (set[index] != this._FREE && set[index] != val) {
      // see Knuth, p. 529
      probe = 1 + (hash % (length - 2));

      do {
        index -= probe;
        if (index < 0) {
          index += length;
        }
      } while (set[index] != this._FREE && set[index] != val);
    }

    return set[index] == this._FREE ? -1 : index;
  }

  /**
   * Locates the index at which val can be inserted.  if
   * there is already a value equal()ing val in the set,
   * returns that value as a negative integer.
   *
   * @param val an long value
   * @return an int value
   */
  protected int insertionIndex(long val) {
    int hash, probe, index, length;
    long[] set;

    if (val == this._FREE) {
      throw new IllegalArgumentException("can not add the value " + val);
    }
    set = _set;
    length = set.length;
    hash = _hashingStrategy.computeHashCode(val) & 0x7fffffff;
    index = hash % length;

    if (set[index] == this._FREE) {
      return index;       // empty, all done
    } else if (set[index] == val) {
      return -index -1;   // already stored
    } else {                // already FULL or REMOVED, must probe
      // compute the double hash
      probe = 1 + (hash % (length - 2));

      // if the slot we landed on is not FREE, probe
      // until we find an empty slot or an element
      // equal to the one we are trying to insert.       
      // finding an empty slot means that the value is not present
      // and that we should use that slot as the insertion point;
      // finding a matching value means that we've found that our desired
      // key is already in the table

      // starting at the natural offset, probe until we find an
      // offset that isn't full.
      do {
        index -= probe;
        if (index < 0) {
          index += length;
        }
      } while (set[index] != this._FREE && set[index] != val);

      // if it's not free, the key is already stored
      return set[index] != this._FREE ? -index -1 : index;
    }
  }

  /**
   * Default implementation of TLongHashingStrategy:
   * delegates hashing to HashFunctions.hash(long).
   *
   * @param val the value to hash
   * @return the hashcode.
   */
  public final int computeHashCode(long val) {
    return HashFunctions.hash(val);
  }
} // TStatelessLongHash




© 2015 - 2024 Weber Informatics LLC | Privacy Policy