Example #1
0
  /**
   * Allocate internal buffers for a given capacity.
   *
   * @param capacity New capacity (must be a power of two).
   */
  @SuppressWarnings("boxing")
  private void allocateBuffers(final int capacity) {
    try {

      final KType[] keys = Intrinsics.<KType>newArray(capacity);

      /*! #if ($RH) !*/
      final int[] allocated = new int[capacity];
      /*! #end !*/

      this.keys = keys;

      /*! #if ($RH) !*/
      this.hash_cache = allocated;
      /*! #end !*/

      // allocate so that there is at least one slot that remains allocated = false
      // this is compulsory to guarantee proper stop in searching loops
      this.resizeAt = HashContainers.expandAtCount(capacity, this.loadFactor);
    } catch (final OutOfMemoryError e) {

      throw new BufferAllocationException(
          "Not enough memory to allocate buffers to grow from %d -> %d elements",
          e, (this.keys == null) ? 0 : this.keys.length, capacity);
    }
  }
Example #2
0
  /**
   * Expand the internal storage buffers (capacity) or rehash current keys and values if there are a
   * lot of deleted slots.
   */
  private void expandAndAdd(final KType pendingKey, final int freeSlot) {
    assert this.assigned == this.resizeAt;

    // default sentinel value is never in the keys[] array, so never trigger reallocs
    assert (!Intrinsics.<KType>isEmpty(pendingKey));

    // Try to allocate new buffers first. If we OOM, it'll be now without
    // leaving the data structure in an inconsistent state.
    final KType[] oldKeys = Intrinsics.<KType[]>cast(this.keys);

    allocateBuffers(
        HashContainers.nextBufferSize(this.keys.length, this.assigned, this.loadFactor));

    // We have succeeded at allocating new data so insert the pending key/value at
    // the free slot in the old arrays before rehashing.

    this.assigned++;

    oldKeys[freeSlot] = pendingKey;

    // Variables for adding
    final int mask = this.keys.length - 1;

    KType key = Intrinsics.<KType>empty();
    // adding phase
    int slot = -1;

    final KType[] keys = Intrinsics.<KType[]>cast(this.keys);

    /*! #if ($RH) !*/
    final int[] cached = this.hash_cache;
    /*! #end !*/

    /*! #if ($RH) !*/
    KType tmpKey = Intrinsics.<KType>empty();
    int tmpAllocated = -1;
    int initial_slot = -1;
    int dist = -1;
    int existing_distance = -1;
    /*! #end !*/

    // iterate all the old arrays to add in the newly allocated buffers
    // It is important to iterate backwards to minimize the conflict chain length !
    final int perturb = this.perturbation;

    for (int i = oldKeys.length; --i >= 0; ) {

      // only consider non-empty slots, of course
      if (!Intrinsics.<KType>isEmpty(key = oldKeys[i])) {

        slot = REHASH2(key, perturb) & mask;

        /*! #if ($RH) !*/
        initial_slot = slot;
        dist = 0;
        /*! #end !*/

        // similar to add(), except all inserted keys are known to be unique.
        while (is_allocated(slot, keys)) {
          /*! #if ($RH) !*/
          // re-shuffle keys to minimize variance
          existing_distance = probe_distance(slot, cached);

          if (dist > existing_distance) {
            // swap current (key, value, initial_slot) with slot places
            tmpKey = keys[slot];
            keys[slot] = key;
            key = tmpKey;

            tmpAllocated = cached[slot];
            cached[slot] = initial_slot;
            initial_slot = tmpAllocated;

            /*! #if($DEBUG) !*/
            // Check invariants
            assert cached[slot] == (REHASH(keys[slot]) & mask);
            assert initial_slot == (REHASH(key) & mask);
            /*! #end !*/

            dist = existing_distance;
          } // endif
          /*! #end !*/

          slot = (slot + 1) & mask;

          /*! #if ($RH) !*/
          dist++;
          /*! #end !*/
        } // end while

        // place it at that position
        /*! #if ($RH) !*/
        cached[slot] = initial_slot;
        /*! #end !*/

        keys[slot] = key;

        /*! #if ($RH) !*/
        /*! #if($DEBUG) !*/
        // Check invariants
        assert cached[slot] == (REHASH(keys[slot]) & mask);
        /*! #end !*/
        /*! #end !*/
      }
    }
  }
Example #3
0
 /** Creates a hash set with the given capacity and load factor. */
 public KTypeHashSet(final int initialCapacity, final double loadFactor) {
   this.loadFactor = loadFactor;
   // take into account of the load factor to guarantee no reallocations before reaching
   // initialCapacity.
   allocateBuffers(HashContainers.minBufferSize(initialCapacity, loadFactor));
 }