Beispiel #1
0
  /** {@inheritDoc} */
  @Override
  public int removeAll(final KTypePredicate<? super KType> predicate) {
    final int before = this.size();

    if (this.allocatedDefaultKey) {

      if (predicate.apply(Intrinsics.<KType>empty())) {
        this.allocatedDefaultKey = false;
      }
    }

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

    for (int i = 0; i < keys.length; ) {
      KType existing;
      if (!Intrinsics.<KType>isEmpty(existing = keys[i]) && predicate.apply(existing)) {

        shiftConflictingKeys(i);
        // Shift, do not increment slot.
      } else {
        i++;
      }
    }

    return before - this.size();
  }
Beispiel #2
0
  /** {@inheritDoc} */
  @Override
  public <T extends KTypePredicate<? super KType>> T forEach(final T predicate) {
    if (this.allocatedDefaultKey) {

      if (!predicate.apply(Intrinsics.<KType>empty())) {

        return predicate;
      }
    }

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

    // Iterate in reverse for side-stepping the longest conflict chain
    // in another hash, in case apply() is actually used to fill another hash container.
    for (int i = keys.length - 1; i >= 0; i--) {
      KType existing;
      if (!Intrinsics.<KType>isEmpty(existing = keys[i])) {
        if (!predicate.apply(existing)) {
          break;
        }
      }
    }

    return predicate;
  }
Beispiel #3
0
    /**
     * Iterate backwards w.r.t the buffer, to minimize collision chains when filling another hash
     * container (ex. with putAll())
     */
    @Override
    protected KTypeCursor<KType> fetch() {
      if (this.cursor.index == KTypeHashSet.this.keys.length + 1) {

        if (KTypeHashSet.this.allocatedDefaultKey) {

          this.cursor.index = KTypeHashSet.this.keys.length;
          this.cursor.value = Intrinsics.<KType>empty();

          return this.cursor;
        }
        // no value associated with the default key, continue iteration...
        this.cursor.index = KTypeHashSet.this.keys.length;
      }

      int i = this.cursor.index - 1;

      while (i >= 0 && !is_allocated(i, Intrinsics.<KType[]>cast(KTypeHashSet.this.keys))) {
        i--;
      }

      if (i == -1) {
        return done();
      }

      this.cursor.index = i;
      this.cursor.value = Intrinsics.<KType>cast(KTypeHashSet.this.keys[i]);
      return this.cursor;
    }
Beispiel #4
0
  /** {@inheritDoc} */
  @Override
  public KType[] toArray(final KType[] target) {
    int count = 0;

    if (this.allocatedDefaultKey) {

      target[count++] = Intrinsics.<KType>empty();
    }

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

    for (int i = 0; i < keys.length; i++) {
      KType existing;
      if (!Intrinsics.<KType>isEmpty(existing = keys[i])) {
        target[count++] = existing;
      }
    }

    assert count == this.size();

    return target;
  }
Beispiel #5
0
  /** Shift all the slot-conflicting keys allocated to (and including) <code>slot</code>. */
  private void shiftConflictingKeys(int gapSlot) {

    final int mask = this.keys.length - 1;

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

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

    // Perform shifts of conflicting keys to fill in the gap.
    int distance = 0;

    while (true) {

      final int slot = (gapSlot + (++distance)) & mask;

      final KType existing = keys[slot];

      if (Intrinsics.<KType>isEmpty(existing)) {
        break;
      }

      /*! #if ($RH) !*/
      // use the cached value, no need to recompute
      final int idealSlotModMask = cached[slot];
      /*! #if($DEBUG) !*/
      // Check invariants
      assert idealSlotModMask == (REHASH(existing) & mask);
      /*! #end !*/
      /*! #else
      final int idealSlotModMask = REHASH2(existing, perturb) & mask;
      #end !*/

      // original HPPC code: shift = (slot - idealSlot) & mask;
      // equivalent to shift = (slot & mask - idealSlot & mask) & mask;
      // since slot and idealSlotModMask are already folded, we have :
      final int shift = (slot - idealSlotModMask) & mask;

      if (shift >= distance) {
        // Entry at this position was originally at or before the gap slot.
        // Move the conflict-shifted entry to the gap's position and repeat the procedure
        // for any entries to the right of the current position, treating it
        // as the new gap.
        keys[gapSlot] = existing;

        /*! #if ($RH) !*/
        cached[gapSlot] = idealSlotModMask;
        /*! #if($DEBUG) !*/
        assert cached[gapSlot] == (REHASH(existing) & mask);
        /*! #end !*/
        /*! #end !*/

        gapSlot = slot;
        distance = 0;
      }
    } // end while

    // Mark the last found gap slot without a conflict as empty.
    keys[gapSlot] = Intrinsics.<KType>empty();

    this.assigned--;
  }
Beispiel #6
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 !*/
      }
    }
  }