/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.geode.internal.concurrent;

/*
 * CompactConcurrentHashSet2 is derived from the JSR 166 ConcurrentHashMap class version 1.43
 * (current as of 27 March 2015). The modifications made for GemFire turn it into a Set instead of a
 * Map by removing the map's storage for values and removing the methods that are associated with
 * values.
 *
 * JSR 166 interest web site: http://gee.cs.oswego.edu/dl/concurrency-interest/
 *
 * File download location:
 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jdk7/java/util/concurrent/
 * CompactConcurrentHashSet2.java?revision=1.43
 *
 * Original licensing notice: Written by Doug Lea with assistance from members of JCP JSR-166 Expert
 * Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */


import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.geode.annotations.Immutable;
import org.apache.geode.annotations.internal.MakeNotStatic;
import org.apache.geode.unsafe.internal.sun.misc.Unsafe;

/**
 * <p>
 * This is the original javadoc describing ConcurrentHashMap. This class is actually a Set based on
 * Doug Lea's CHM implementation (see the source file for full attribution).
 * <p>
 * A hash map supporting full concurrency of retrievals and high expected concurrency for updates.
 * This class obeys the same functional specification as {@link java.util.HashMap}, and includes
 * versions of methods corresponding to each method of {@code HashMap}. However, even though all
 * operations are thread-safe, retrieval operations do <em>not</em> entail locking, and there is
 * <em>not</em> any support for locking the entire set in a way that prevents all access. This class
 * is fully interoperable with {@code HashMap} in programs that rely on its thread safety but not on
 * its synchronization details.
 *
 *
 * @since Geode 1.0
 * @author Originally Doug Lea
 * @param <V> the type of values held in the set
 */
public class CompactConcurrentHashSet2<V> extends AbstractSet<V> implements Set<V>, Serializable {
  private static final long serialVersionUID = 7249069246763182397L;

  /*
   * Overview:
   *
   * The primary design goal of this hash table is to maintain concurrent readability (typically
   * method get(), but also iterators and related methods) while minimizing update contention.
   * Secondary goals are to keep space consumption about the same or better than java.util.HashMap,
   * and to support high initial insertion rates on an empty table by many threads.
   *
   * This map usually acts as a binned (bucketed) hash table. Each key-value mapping is held in a
   * Node. Most nodes are instances of the basic Node class with hash, key, value, and next fields.
   * However, various subclasses exist: TreeNodes are arranged in balanced trees, not lists.
   * TreeBins hold the roots of sets of TreeNodes. ForwardingNodes are placed at the heads of bins
   * during resizing. ReservationNodes are used as placeholders while establishing values in
   * computeIfAbsent and related methods. The types TreeBin, ForwardingNode, and ReservationNode do
   * not hold normal user keys, values, or hashes, and are readily distinguishable during search etc
   * because they have negative hash fields and null key and value fields. (These special nodes are
   * either uncommon or transient, so the impact of carrying around some unused fields is
   * insignificant.)
   *
   * The table is lazily initialized to a power-of-two size upon the first insertion. Each bin in
   * the table normally contains a list of Nodes (most often, the list has only zero or one Node).
   * Table accesses require volatile/atomic reads, writes, and CASes. Because there is no other way
   * to arrange this without adding further indirections, we use intrinsics (sun.misc.Unsafe)
   * operations.
   *
   * We use the top (sign) bit of Node hash fields for control purposes -- it is available anyway
   * because of addressing constraints. Nodes with negative hash fields are specially handled or
   * ignored in map methods.
   *
   * Insertion (via put or its variants) of the first node in an empty bin is performed by just
   * CASing it to the bin. This is by far the most common case for put operations under most
   * key/hash distributions. Other update operations (insert, delete, and replace) require locks. We
   * do not want to waste the space required to associate a distinct lock object with each bin, so
   * instead use the first node of a bin list itself as a lock. Locking support for these locks
   * relies on builtin "synchronized" monitors.
   *
   * Using the first node of a list as a lock does not by itself suffice though: When a node is
   * locked, any update must first validate that it is still the first node after locking it, and
   * retry if not. Because new nodes are always appended to lists, once a node is first in a bin, it
   * remains first until deleted or the bin becomes invalidated (upon resizing).
   *
   * The main disadvantage of per-bin locks is that other update operations on other nodes in a bin
   * list protected by the same lock can stall, for example when user equals() or mapping functions
   * take a long time. However, statistically, under random hash codes, this is not a common
   * problem. Ideally, the frequency of nodes in bins follows a Poisson distribution
   * (http://en.wikipedia.org/wiki/Poisson_distribution) with a parameter of about 0.5 on average,
   * given the resizing threshold of 0.75, although with a large variance because of resizing
   * granularity. Ignoring variance, the expected occurrences of list size k are (exp(-0.5) *
   * pow(0.5, k) / factorial(k)). The first values are:
   *
   * 0: 0.60653066 1: 0.30326533 2: 0.07581633 3: 0.01263606 4: 0.00157952 5: 0.00015795 6:
   * 0.00001316 7: 0.00000094 8: 0.00000006 more: less than 1 in ten million
   *
   * Lock contention probability for two threads accessing distinct elements is roughly 1 / (8 *
   * #elements) under random hashes.
   *
   * Actual hash code distributions encountered in practice sometimes deviate significantly from
   * uniform randomness. This includes the case when N > (1<<30), so some keys MUST collide.
   * Similarly for dumb or hostile usages in which multiple keys are designed to have identical hash
   * codes or ones that differs only in masked-out high bits. So we use a secondary strategy that
   * applies when the number of nodes in a bin exceeds a threshold. These TreeBins use a balanced
   * tree to hold nodes (a specialized form of red-black trees), bounding search time to O(log N).
   * Each search step in a TreeBin is at least twice as slow as in a regular list, but given that N
   * cannot exceed (1<<64) (before running out of addresses) this bounds search steps, lock hold
   * times, etc, to reasonable constants (roughly 100 nodes inspected per operation worst case) so
   * long as keys are Comparable (which is very common -- String, Long, etc). TreeBin nodes
   * (TreeNodes) also maintain the same "next" traversal pointers as regular nodes, so can be
   * traversed in iterators in the same way.
   *
   * The table is resized when occupancy exceeds a percentage threshold (nominally, 0.75, but see
   * below). Any thread noticing an overfull bin may assist in resizing after the initiating thread
   * allocates and sets up the replacement array. However, rather than stalling, these other threads
   * may proceed with insertions etc. The use of TreeBins shields us from the worst case effects of
   * overfilling while resizes are in progress. Resizing proceeds by transferring bins, one by one,
   * from the table to the next table. However, threads claim small blocks of indices to transfer
   * (via field transferIndex) before doing so, reducing contention. A generation stamp in field
   * sizeCtl ensures that resizings do not overlap. Because we are using power-of-two expansion, the
   * elements from each bin must either stay at same index, or move with a power of two offset. We
   * eliminate unnecessary node creation by catching cases where old nodes can be reused because
   * their next fields won't change. On average, only about one-sixth of them need cloning when a
   * table doubles. The nodes they replace will be garbage collectable as soon as they are no longer
   * referenced by any reader thread that may be in the midst of concurrently traversing table. Upon
   * transfer, the old table bin contains only a special forwarding node (with hash field "MOVED")
   * that contains the next table as its key. On encountering a forwarding node, access and update
   * operations restart, using the new table.
   *
   * Each bin transfer requires its bin lock, which can stall waiting for locks while resizing.
   * However, because other threads can join in and help resize rather than contend for locks,
   * average aggregate waits become shorter as resizing progresses. The transfer operation must also
   * ensure that all accessible bins in both the old and new table are usable by any traversal. This
   * is arranged in part by proceeding from the last bin (table.length - 1) up towards the first.
   * Upon seeing a forwarding node, traversals (see class Traverser) arrange to move to the new
   * table without revisiting nodes. To ensure that no intervening nodes are skipped even when moved
   * out of order, a stack (see class TableStack) is created on first encounter of a forwarding node
   * during a traversal, to maintain its place if later processing the current table. The need for
   * these save/restore mechanics is relatively rare, but when one forwarding node is encountered,
   * typically many more will be. So Traversers use a simple caching scheme to avoid creating so
   * many new TableStack nodes. (Thanks to Peter Levart for suggesting use of a stack here.)
   *
   * The traversal scheme also applies to partial traversals of ranges of bins (via an alternate
   * Traverser constructor) to support partitioned aggregate operations. Also, read-only operations
   * give up if ever forwarded to a null table, which provides support for shutdown-style clearing,
   * which is also not currently implemented.
   *
   * Lazy table initialization minimizes footprint until first use, and also avoids resizings when
   * the first operation is from a putAll, constructor with map argument, or deserialization. These
   * cases attempt to override the initial capacity settings, but harmlessly fail to take effect in
   * cases of races.
   *
   * The element count is maintained using a specialization of LongAdder. We need to incorporate a
   * specialization rather than just use a LongAdder in order to access implicit contention-sensing
   * that leads to creation of multiple CounterCells. The counter mechanics avoid contention on
   * updates but can encounter cache thrashing if read too frequently during concurrent access. To
   * avoid reading so often, resizing under contention is attempted only upon adding to a bin
   * already holding two or more nodes. Under uniform hash distributions, the probability of this
   * occurring at threshold is around 13%, meaning that only about 1 in 8 puts check threshold (and
   * after resizing, many fewer do so).
   *
   * TreeBins use a special form of comparison for search and related operations (which is the main
   * reason we cannot use existing collections such as TreeMaps). TreeBins contain Comparable
   * elements, but may contain others, as well as elements that are Comparable but not necessarily
   * Comparable for the same T, so we cannot invoke compareTo among them. To handle this, the tree
   * is ordered primarily by hash value, then by Comparable.compareTo order if applicable. On lookup
   * at a node, if elements are not comparable or compare as 0 then both left and right children may
   * need to be searched in the case of tied hash values. (This corresponds to the full list search
   * that would be necessary if all elements were non-Comparable and had tied hashes.) On insertion,
   * to keep a total ordering (or as close as is required here) across rebalancings, we compare
   * classes and identityHashCodes as tie-breakers. The red-black balancing code is updated from
   * pre-jdk-collections (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) based in turn
   * on Cormen, Leiserson, and Rivest "Introduction to Algorithms" (CLR).
   *
   * TreeBins also require an additional locking mechanism. While list traversal is always possible
   * by readers even during updates, tree traversal is not, mainly because of tree-rotations that
   * may change the root node and/or its linkages. TreeBins include a simple read-write lock
   * mechanism parasitic on the main bin-synchronization strategy: Structural adjustments associated
   * with an insertion or removal are already bin-locked (and so cannot conflict with other writers)
   * but must wait for ongoing readers to finish. Since there can be only one such waiter, we use a
   * simple scheme using a single "waiter" field to block writers. However, readers need never
   * block. If the root lock is held, they proceed along the slow traversal path (via next-pointers)
   * until the lock becomes available or the list is exhausted, whichever comes first. These cases
   * are not fast, but maximize aggregate expected throughput.
   *
   * Maintaining API and serialization compatibility with previous versions of this class introduces
   * several oddities. Mainly: We leave untouched but unused constructor arguments refering to
   * concurrencyLevel. We accept a loadFactor constructor argument, but apply it only to initial
   * table capacity (which is the only time that we can guarantee to honor it.) We also declare an
   * unused "Segment" class that is instantiated in minimal form only when serializing.
   *
   * Also, solely for compatibility with previous versions of this class, it extends AbstractMap,
   * even though all of its methods are overridden, so it is just useless baggage.
   *
   * This file is organized to make things a little easier to follow while reading than they might
   * otherwise: First the main static declarations and utilities, then fields, then main public
   * methods (with a few factorings of multiple public methods into internal ones), then sizing
   * methods, trees, traversers, and bulk operations.
   */


  /* ---------------- Constants -------------- */

  /**
   * The largest possible table capacity. This value must be exactly 1<<30 to stay within Java array
   * allocation and indexing bounds for power of two table sizes, and is further required because
   * the top two bits of 32bit hash fields are used for control purposes.
   */
  private static final int MAXIMUM_CAPACITY = 1 << 30;

  /**
   * The default initial table capacity. Must be a power of 2 (i.e., at least 1) and at most
   * MAXIMUM_CAPACITY.
   */
  private static final int DEFAULT_CAPACITY = 16;

  /**
   * The largest possible (non-power of two) array size. Needed by toArray and related methods.
   */
  static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

  /**
   * The default concurrency level for this table. Unused but defined for compatibility with
   * previous versions of this class.
   */
  private static final int DEFAULT_CONCURRENCY_LEVEL = 16;

  /**
   * The load factor for this table. Overrides of this value in constructors affect only the initial
   * table capacity. The actual floating point value isn't normally used -- it is simpler to use
   * expressions such as {@code n - (n >>> 2)} for the associated resizing threshold.
   */
  private static final float LOAD_FACTOR = 0.75f;

  /**
   * The bin count threshold for using a tree rather than list for a bin. Bins are converted to
   * trees when adding an element to a bin with at least this many nodes. The value must be greater
   * than 2, and should be at least 8 to mesh with assumptions in tree removal about conversion back
   * to plain bins upon shrinkage.
   */
  static final int TREEIFY_THRESHOLD = 8;

  /**
   * The bin count threshold for untreeifying a (split) bin during a resize operation. Should be
   * less than TREEIFY_THRESHOLD, and at most 6 to mesh with shrinkage detection under removal.
   */
  static final int UNTREEIFY_THRESHOLD = 6;

  /**
   * The smallest table capacity for which bins may be treeified. (Otherwise the table is resized if
   * too many nodes in a bin.) The value should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
   * between resizing and treeification thresholds.
   */
  static final int MIN_TREEIFY_CAPACITY = 64;

  /**
   * Minimum number of rebinnings per transfer step. Ranges are subdivided to allow multiple resizer
   * threads. This value serves as a lower bound to avoid resizers encountering excessive memory
   * contention. The value should be at least DEFAULT_CAPACITY.
   */
  private static final int MIN_TRANSFER_STRIDE = 16;

  /**
   * The number of bits used for generation stamp in sizeCtl. Must be at least 6 for 32bit arrays.
   */
  private static final int RESIZE_STAMP_BITS = 16;

  /**
   * The maximum number of threads that can help resize. Must fit in 32 - RESIZE_STAMP_BITS bits.
   */
  private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;

  /**
   * The bit shift for recording size stamp in sizeCtl.
   */
  private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;

  /*
   * Encodings for Node hash fields. See above for explanation.
   */
  static final int MOVED = 0x8fffffff; // (-1) hash for forwarding nodes
  static final int TREEBIN = 0x80000000; // hash for roots of trees
  static final int RESERVED = 0x80000001; // hash for transient reservations
  static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash

  /** Number of CPUS, to place bounds on some sizings */
  static final int NCPU = Runtime.getRuntime().availableProcessors();

  /** For serialization compatibility. */
  @Immutable
  private static final ObjectStreamField[] serialPersistentFields =
      {new ObjectStreamField("segments", Segment[].class),
          new ObjectStreamField("segmentMask", Integer.TYPE),
          new ObjectStreamField("segmentShift", Integer.TYPE)};

  /* ---------------- Nodes -------------- */

  /**
   * Key-value entry. This class is never exported out as a user-mutable Map.Entry (i.e., one
   * supporting setValue; see MapEntry below), but can be used for read-only traversals used in bulk
   * tasks. Subclasses of Node with a negative hash field are special, and contain null keys and
   * values (but are never exported). Otherwise, keys and vals are never null.
   */
  static class Node<K> {
    final int hash;
    final K key;
    Node<K> next;

    Node(int hash, K key, Node<K> next) {
      this.hash = hash;
      this.key = key;
      this.next = next;
    }

    public K getKey() {
      return key;
    }

    public int hashCode() {
      return key.hashCode();
    }

    public String toString() {
      return key.toString();
    }

    public boolean equals(Object o) {
      return ((o instanceof Node)
          && (o == key || o.equals(key)));
    }

    /**
     * Virtualized support for map.get(); overridden in subclasses.
     */
    Node<K> find(int h, Object k) {
      Node<K> e = this;
      if (k != null) {
        do {
          K ek;
          if (e.hash == h && ((ek = e.key) == k || (ek != null && k.equals(ek)))) {
            return e;
          }
        } while ((e = e.next) != null);
      }
      return null;
    }
  }

  /* ---------------- Static utilities -------------- */

  /**
   * Spreads (XORs) higher bits of hash to lower and also forces top bit to 0. Because the table
   * uses power-of-two masking, sets of hashes that vary only in bits above the current mask will
   * always collide. (Among known examples are sets of Float keys holding consecutive whole numbers
   * in small tables.) So we apply a transform that spreads the impact of higher bits downward.
   * There is a tradeoff between speed, utility, and quality of bit-spreading. Because many common
   * sets of hashes are already reasonably distributed (so don't benefit from spreading), and
   * because we use trees to handle large sets of collisions in bins, we just XOR some shifted bits
   * in the cheapest possible way to reduce systematic lossage, as well as to incorporate impact of
   * the highest bits that would otherwise never be used in index calculations because of table
   * bounds.
   */
  static int spread(int h) {
    return (h ^ (h >>> 16)) & HASH_BITS;
  }

  /**
   * Returns a power of two table size for the given desired capacity. See Hackers Delight, sec 3.2
   */
  private static int tableSizeFor(int c) {
    int n = c - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
  }

  /**
   * Returns x's Class if it is of the form "class C implements Comparable<C>", else null.
   */
  static Class<?> comparableClassFor(Object x) {
    if (x instanceof Comparable) {
      Class<?> c;
      Type[] ts, as;
      Type t;
      ParameterizedType p;
      if ((c = x.getClass()) == String.class) // bypass checks
      {
        return c;
      }
      if ((ts = c.getGenericInterfaces()) != null) {
        for (final Type type : ts) {
          if (((t = type) instanceof ParameterizedType)
              && ((p = (ParameterizedType) t).getRawType() == Comparable.class)
              && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type
          // arg
          // is c
          {
            return c;
          }
        }
      }
    }
    return null;
  }

  /**
   * Returns k.compareTo(x) if x matches kc (k's screened comparable class), else 0.
   */
  @SuppressWarnings({"rawtypes", "unchecked"}) // for cast to Comparable
  static int compareComparables(Class<?> kc, Object k, Object x) {
    return (x == null || x.getClass() != kc ? 0 : ((Comparable) k).compareTo(x));
  }

  /* ---------------- Table element access -------------- */

  /*
   * Volatile access methods are used for table elements as well as elements of in-progress next
   * table while resizing. All uses of the tab arguments must be null checked by callers. All
   * callers also paranoically precheck that tab's length is not zero (or an equivalent check), thus
   * ensuring that any index argument taking the form of a hash value anded with (length - 1) is a
   * valid index. Note that, to be correct wrt arbitrary concurrency errors by users, these checks
   * must operate on local variables, which accounts for some odd-looking inline assignments below.
   * Note that calls to setTabAt always occur within locked regions, and so do not need full
   * volatile semantics, but still require ordering to maintain concurrent readability.
   */

  @SuppressWarnings("unchecked")
  static <K> Node<K> tabAt(Node<K>[] tab, int i) {
    return (Node<K>) U.getObjectVolatile(tab, ((long) i << ASHIFT) + ABASE);
  }

  static <K> boolean casTabAt(Node<K>[] tab, int i, Node<K> c, Node<K> v) {
    return U.compareAndSwapObject(tab, ((long) i << ASHIFT) + ABASE, c, v);
  }

  static <K> void setTabAt(Node<K>[] tab, int i, Node<K> v) {
    U.putOrderedObject(tab, ((long) i << ASHIFT) + ABASE, v);
  }

  /* ---------------- Fields -------------- */

  /**
   * The array of bins. Lazily initialized upon first insertion. Size is always a power of two.
   * Accessed directly by iterators.
   */
  transient volatile Node<V>[] table;

  /**
   * The next table to use; non-null only while resizing.
   */
  private transient volatile Node<V>[] nextTable;

  /**
   * Base counter value, used mainly when there is no contention, but also as a fallback during
   * table initialization races. Updated via CAS.
   */
  private transient volatile long baseCount;

  /**
   * Table initialization and resizing control. When negative, the table is being initialized or
   * resized: -1 for initialization, else -(1 + the number of active resizing threads). Otherwise,
   * when table is null, holds the initial table size to use upon creation, or 0 for default. After
   * initialization, holds the next element count value upon which to resize the table.
   */
  private transient volatile int sizeCtl;

  /**
   * The next table index (plus one) to split while resizing.
   */
  private transient volatile int transferIndex;

  /**
   * Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
   */
  private transient volatile int cellsBusy;

  /**
   * Table of counter cells. When non-null, size is a power of 2.
   */
  private transient volatile CounterCell[] counterCells;


  /* ---------------- Public operations -------------- */

  /**
   * Creates a new, empty map with the default initial table size (16).
   */
  public CompactConcurrentHashSet2() {}

  /**
   * Creates a new, empty map with an initial table size accommodating the specified number of
   * elements without the need to dynamically resize.
   *
   * @param initialCapacity The implementation performs internal sizing to accommodate this many
   *        elements.
   * @throws IllegalArgumentException if the initial capacity of elements is negative
   */
  public CompactConcurrentHashSet2(int initialCapacity) {
    if (initialCapacity < 0) {
      throw new IllegalArgumentException();
    }
    int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY
        : tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
    sizeCtl = cap;
  }

  /**
   * Creates a new map with the same mappings as the given map.
   *
   * @param m the map
   */
  public CompactConcurrentHashSet2(Collection<? extends V> m) {
    sizeCtl = DEFAULT_CAPACITY;
    addAll(m);
  }

  /**
   * Creates a new, empty map with an initial table size based on the given number of elements
   * ({@code initialCapacity}) and initial table density ({@code loadFactor}).
   *
   * @param initialCapacity the initial capacity. The implementation performs internal sizing to
   *        accommodate this many elements, given the specified load factor.
   * @param loadFactor the load factor (table density) for establishing the initial table size
   * @throws IllegalArgumentException if the initial capacity of elements is negative or the load
   *         factor is nonpositive
   *
   * @since Geode 1.0
   */
  public CompactConcurrentHashSet2(int initialCapacity, float loadFactor) {
    this(initialCapacity, loadFactor, 1);
  }

  /**
   * Creates a new, empty map with an initial table size based on the given number of elements
   * ({@code initialCapacity}), table density ({@code loadFactor}), and number of concurrently
   * updating threads ({@code concurrencyLevel}).
   *
   * @param initialCapacity the initial capacity. The implementation performs internal sizing to
   *        accommodate this many elements, given the specified load factor.
   * @param loadFactor the load factor (table density) for establishing the initial table size
   * @param concurrencyLevel the estimated number of concurrently updating threads. The
   *        implementation may use this value as a sizing hint.
   * @throws IllegalArgumentException if the initial capacity is negative or the load factor or
   *         concurrencyLevel are nonpositive
   */
  public CompactConcurrentHashSet2(int initialCapacity, float loadFactor, int concurrencyLevel) {
    if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) {
      throw new IllegalArgumentException();
    }
    if (initialCapacity < concurrencyLevel) // Use at least as many bins
    {
      initialCapacity = concurrencyLevel; // as estimated threads
    }
    long size = (long) (1.0 + (long) initialCapacity / loadFactor);
    int cap = (size >= (long) MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int) size);
    sizeCtl = cap;
  }

  // Original (since JDK1.2) Map methods

  /**
   * {@inheritDoc}
   */
  @Override
  public int size() {
    long n = sumCount();
    return ((n < 0L) ? 0 : (n > (long) Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) n);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isEmpty() {
    return sumCount() <= 0L; // ignore transient negative values
  }

  boolean _contains(Object key) {
    Node<V>[] tab;
    Node<V> e, p;
    int n, eh;
    V ek;
    if (key == null) {
      return false;
    }
    int h = spread(key.hashCode());
    if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) {
      if ((eh = e.hash) == h) {
        if ((ek = e.key) == key || (ek != null && key.equals(ek))) {
          return true;
        }
      } else if (eh < 0) {
        return ((p = e.find(h, key)) != null);
      }
      while ((e = e.next) != null) {
        if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
          return true;
        }
      }
    }
    return false;
  }

  @Override
  public boolean add(V value) {
    return putKey(value, false);
  }

  /** Implementation for add */
  boolean putKey(V key, boolean onlyIfAbsent) {
    if (key == null) {
      throw new NullPointerException();
    }
    int hash = spread(key.hashCode());
    int binCount = 0;
    for (Node<V>[] tab = table;;) {
      Node<V> f;
      int n, i, fh;
      if (tab == null || (n = tab.length) == 0) {
        tab = initTable();
      } else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
        if (casTabAt(tab, i, null, new Node<>(hash, key, null))) {
          break; // no lock when adding to empty bin
        }
      } else if ((fh = f.hash) == MOVED) {
        tab = helpTransfer(tab, f);
      } else {
        boolean wasPresent = false;
        synchronized (f) {
          if (tabAt(tab, i) == f) {
            if (fh >= 0) {
              binCount = 1;
              for (Node<V> e = f;; ++binCount) {
                V ek;
                if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
                  wasPresent = true;
                  break;
                }
                Node<V> pred = e;
                if ((e = e.next) == null) {
                  pred.next = new Node<>(hash, key, null);
                  break;
                }
              }
            } else if (f instanceof TreeBin) {
              Node<V> p;
              binCount = 2;
              if ((p = ((TreeBin<V>) f).putTreeVal(hash, key)) != null) {
                wasPresent = true;
              }
            }
          }
        }
        if (binCount != 0) {
          if (binCount >= TREEIFY_THRESHOLD) {
            treeifyBin(tab, i);
          }
          if (wasPresent) {
            return true;
          }
          break;
        }
      }
    }
    addCount(1L, binCount);
    return false;
  }

  /**
   * Copies all of the mappings from the specified map to this one. These mappings replace any
   * mappings that this map had for any of the keys currently in the specified map.
   *
   * @param m mappings to be stored in this map
   */
  public void addAll(Set<? extends V> m) {
    tryPresize(m.size());
    for (final V v : m) {
      putKey(v, false);
    }
  }

  @Override
  public boolean remove(Object key) {
    return removeNode(key);
  }

  boolean removeNode(Object key) {
    int hash = spread(key.hashCode());
    for (Node<V>[] tab = table;;) {
