Exemple #1
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 !*/
      }
    }
  }