1 /*
   2  * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package org.openjdk.bench.valhalla.sandbox.corelibs.corelibs.mapprotos;
  27 
  28 import java.io.IOException;
  29 import java.io.InvalidObjectException;
  30 import java.io.PrintStream;
  31 import java.io.Serializable;
  32 import java.lang.Boolean;
  33 import java.lang.reflect.Field;
  34 import java.lang.reflect.InvocationTargetException;
  35 import java.lang.reflect.Method;
  36 import java.util.AbstractCollection;
  37 import java.util.AbstractMap;
  38 import java.util.AbstractSet;
  39 import java.util.Arrays;
  40 import java.util.Collection;
  41 import java.util.Collections;
  42 import java.util.ConcurrentModificationException;
  43 import java.util.Hashtable;
  44 import java.util.Iterator;
  45 import java.util.Map;
  46 import java.util.Objects;
  47 import java.util.Optional;
  48 import java.util.TreeMap;
  49 import java.util.NoSuchElementException;
  50 import java.util.Set;
  51 import java.util.Spliterator;
  52 import java.util.function.BiConsumer;
  53 import java.util.function.BiFunction;
  54 import java.util.function.Consumer;
  55 import java.util.function.Function;
  56 
  57 /**
  58  * HashMap using hashing and "open addressing".
  59  * Hash entries are inline class instances.
  60  * As described in <em>Introduction to Algorithms, 3rd Edition (The MIT Press)</em>,
  61  * Section 11 Hash tables and Section 11.4 Open addressing.
  62  *
  63  * Open addressing is used to locate other entries for keys with the same hash.
  64  * If multiple keys have the same hashcode, a rehashing mechanism
  65  * is used to place the 2nd and subsequent
  66  * key/value pairs at a non-optimal index in the table. Therefore,
  67  * finding the entry for a desired key must rehash and examine subsequent
  68  * entries until the value is value or it encounters an empty entry.
  69  * When an entry is removed, the entry is marked as deleted, (not empty)
  70  * to allow the search algorithm to keep looking; otherwise it would terminate
  71  * the scan on the deleted entry, when it might be the case for some (other) key
  72  * would have that same entry as part of its chain of possible locations for its hash.
  73  * The default load factor (.75) should be re-evaluated in light of the open addressing
  74  * computations.  A higher number would reduce unused (wasted) space at the cost of
  75  * increased search times, a lower number would increase unused (wasted) space but
  76  * improve search times (assuming even hashcode distributions).
  77  * Badly distributed hash values will result in incremental table growth and
  78  * linear search performance.
  79  * <p>
  80  * During insertion the Robin Hood hash algorithm does a small optimization
  81  * to reduce worst case rehash lengths.
  82  * Removal of entries, does a compaction of the following entries to fill
  83  * in free entries and reduce entry rehashling lengths based on
  84  * "On Deletions in Open Addressing Hashing", by Rosa M. Jimenez and Conrado Martinz.
  85  *
  86  * <p>
  87  * The only allocation that occurs during put operations is for the resizing of the entry table.
  88  *
  89  * <P>
  90  * Hash table based implementation of the {@code Map} interface.  This
  91  * implementation provides all of the optional map operations, and permits
  92  * {@code null} values and the {@code null} key.  (The {@code HashMap}
  93  * class is roughly equivalent to {@code Hashtable}, except that it is
  94  * unsynchronized and permits nulls.)  This class makes no guarantees as to
  95  * the order of the map; in particular, it does not guarantee that the order
  96  * will remain constant over time.
  97  *
  98  * <p>This implementation provides constant-time performance for the basic
  99  * operations ({@code get} and {@code put}), assuming the hash function
 100  * disperses the elements properly among the buckets.  Iteration over
 101  * collection views requires time proportional to the "capacity" of the
 102  * {@code HashMap} instance (the number of buckets) plus its size (the number
 103  * of key-value mappings).  Thus, it's very important not to set the initial
 104  * capacity too high (or the load factor too low) if iteration performance is
 105  * important.
 106  *
 107  * <p>An instance of {@code HashMap} has two parameters that affect its
 108  * performance: <i>initial capacity</i> and <i>load factor</i>.  The
 109  * <i>capacity</i> is the number of buckets in the hash table, and the initial
 110  * capacity is simply the capacity at the time the hash table is created.  The
 111  * <i>load factor</i> is a measure of how full the hash table is allowed to
 112  * get before its capacity is automatically increased.  When the number of
 113  * entries in the hash table exceeds the product of the load factor and the
 114  * current capacity, the hash table is <i>rehashed</i> (that is, internal data
 115  * structures are rebuilt) so that the hash table has approximately twice the
 116  * number of buckets.
 117  *
 118  * <p>As a general rule, the default load factor (.75) offers a good
 119  * tradeoff between time and space costs.  Higher values decrease the
 120  * space overhead but increase the lookup cost (reflected in most of
 121  * the operations of the {@code HashMap} class, including
 122  * {@code get} and {@code put}).  The expected number of entries in
 123  * the map and its load factor should be taken into account when
 124  * setting its initial capacity, so as to minimize the number of
 125  * rehash operations.  If the initial capacity is greater than the
 126  * maximum number of entries divided by the load factor, no rehash
 127  * operations will ever occur.
 128  *
 129  * <p>If many mappings are to be stored in a {@code HashMap}
 130  * instance, creating it with a sufficiently large capacity will allow
 131  * the mappings to be stored more efficiently than letting it perform
 132  * automatic rehashing as needed to grow the table.  Note that using
 133  * many keys with the same {@code hashCode()} is a sure way to slow
 134  * down performance of any hash table.
 135  * TBD: To ameliorate impact, when keys
 136  * are {@link Comparable}, this class may use comparison order among
 137  * keys to help break ties.
 138  *
 139  * <p><strong>Note that this implementation is not synchronized.</strong>
 140  * If multiple threads access a hash map concurrently, and at least one of
 141  * the threads modifies the map structurally, it <i>must</i> be
 142  * synchronized externally.  (A structural modification is any operation
 143  * that adds or deletes one or more mappings; merely changing the value
 144  * associated with a key that an instance already contains is not a
 145  * structural modification.)  This is typically accomplished by
 146  * synchronizing on some object that naturally encapsulates the map.
 147  *
 148  * If no such object exists, the map should be "wrapped" using the
 149  * {@link Collections#synchronizedMap Collections.synchronizedMap}
 150  * method.  This is best done at creation time, to prevent accidental
 151  * unsynchronized access to the map:<pre>
 152  *   Map m = Collections.synchronizedMap(new HashMap(...));</pre>
 153  *
 154  * <p>The iterators returned by all of this class's "collection view methods"
 155  * are <i>fail-fast</i>: if the map is structurally modified at any time after
 156  * the iterator is created, in any way except through the iterator's own
 157  * {@code remove} method, the iterator will throw a
 158  * {@link ConcurrentModificationException}.  Thus, in the face of concurrent
 159  * modification, the iterator fails quickly and cleanly, rather than risking
 160  * arbitrary, non-deterministic behavior at an undetermined time in the
 161  * future.
 162  *
 163  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 164  * as it is, generally speaking, impossible to make any hard guarantees in the
 165  * presence of unsynchronized concurrent modification.  Fail-fast iterators
 166  * throw {@code ConcurrentModificationException} on a best-effort basis.
 167  * Therefore, it would be wrong to write a program that depended on this
 168  * exception for its correctness: <i>the fail-fast behavior of iterators
 169  * should be used only to detect bugs.</i>
 170  *
 171  * <p>This class is a member of the
 172  * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
 173  * Java Collections Framework</a>.
 174  *
 175  * @param <K> the type of keys maintained by this map
 176  * @param <V> the type of mapped values
 177  *
 178  * @author  Doug Lea
 179  * @author  Josh Bloch
 180  * @author  Arthur van Hoff
 181  * @author  Neal Gafter
 182  * @see     Object#hashCode()
 183  * @see     Collection
 184  * @see     Map
 185  * @see     TreeMap
 186  * @see     Hashtable
 187  * @since   1.2
 188  */
 189 public class HashMap<K,V> extends XAbstractMap<K,V>
 190         implements Map<K,V>, Cloneable, Serializable {
 191 
 192     private static final long serialVersionUID = 362498820763181265L;
 193 
 194     private static final boolean DEBUG = Boolean.getBoolean("DEBUG");
 195     private static final boolean VERIFYTABLEOK = Boolean.getBoolean("VERIFYTABLEOK");
 196 
 197     /*
 198      * Implementation notes.
 199      *
 200      * This map usually acts as a binned (bucketed) hash table.
 201      * The concurrent-programming-like SSA-based coding style helps
 202      * avoid aliasing errors amid all of the twisty pointer operations.
 203      */
 204 
 205     /**
 206      * The default initial capacity - MUST be a power of two.
 207      */
 208     static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
 209 
 210     /**
 211      * The maximum capacity, used if a higher value is implicitly specified
 212      * by either of the constructors with arguments.
 213      * MUST be a power of two <= 1<<30.
 214      */
 215     static final int MAXIMUM_CAPACITY = 1 << 30;
 216 
 217     /**
 218      * The load factor used when none specified in constructor.
 219      */
 220     static final float DEFAULT_LOAD_FACTOR = 0.75f;
 221 
 222     private final int REHASH_HASH = 2003; // Odd and small (a medium-small prime)
 223 
 224     /**
 225      * Basic hash bin node, used for most entries.
 226      */
 227     static value class YNode<K,V> implements Map.Entry<K,V> {
 228         final int hash;
 229         final short probes; // maybe only a byte
 230         final K key;
 231         final V value;
 232 
 233         YNode() {
 234             this.hash = 0;
 235             this.probes = 0;
 236             this.key = null;
 237             this.value = null;
 238         }
 239 
 240         YNode(int hash, K key, V value, int probes) {
 241             this.hash = hash;
 242             this.key = key;
 243             this.value = value;
 244             this.probes = (short)probes;
 245         }
 246 
 247         boolean isEmpty() {
 248             return probes == 0;
 249         }
 250 
 251         boolean isValue() {
 252             return probes > 0;
 253         }
 254 
 255         public final K getKey()        { return key; }
 256         public final V getValue()      { return value; }
 257         public final String toString() { return key + "=" + value + ", probes: " + probes
 258                 + ", hash: " + Integer.toString(hash, 16)
 259                 + ", hashCode: " + hashCode(); }
 260         public final int hashCode() {
 261             return Objects.hashCode(key) ^ Objects.hashCode(value);
 262         }
 263 
 264         public final V setValue(V newValue) {
 265             throw new IllegalStateException("YNode cannot set a value");
 266         }
 267 
 268         public final boolean equals(Object o) {
 269             if (o == this)
 270                 return true;
 271             if (o instanceof Map.Entry) {
 272                 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
 273                 if (Objects.equals(key, e.getKey()) &&
 274                         Objects.equals(value, e.getValue()))
 275                     return true;
 276             }
 277             return false;
 278         }
 279     }
 280 
 281     value class YNodeWrapper implements Map.Entry<K,V> {
 282         final int index;
 283         final YNode<K,V> entry;
 284 
 285         YNodeWrapper(int index) {
 286             this.index = index;
 287             this.entry = table[index];
 288         }
 289 
 290         public K getKey() {
 291             return entry.key;
 292         }
 293 
 294         public V getValue() {
 295             return entry.value;
 296         }
 297 
 298         public String toString() {
 299             return entry.toString();
 300         }
 301 
 302         public int hashCode() {
 303             return entry.hashCode();
 304         }
 305 
 306         public boolean equals(Object o) {
 307             return entry.equals(o);
 308         }
 309         /**
 310          * Replaces the value corresponding to this entry with the specified
 311          * value (optional operation).  (Writes through to the map.)  The
 312          * behavior of this call is undefined if the mapping has already been
 313          * removed from the map (by the iterator's {@code remove} operation).
 314          *
 315          * @param value new value to be stored in this entry
 316          * @return old value corresponding to the entry
 317          * @throws UnsupportedOperationException if the {@code put} operation
 318          *         is not supported by the backing map
 319          * @throws ClassCastException if the class of the specified value
 320          *         prevents it from being stored in the backing map
 321          * @throws NullPointerException if the backing map does not permit
 322          *         null values, and the specified value is null
 323          * @throws IllegalArgumentException if some property of this value
 324          *         prevents it from being stored in the backing map
 325          * @throws IllegalStateException implementations may, but are not
 326          *         required to, throw this exception if the entry has been
 327          *         removed from the backing map.
 328          */
 329         public V setValue(V value) {
 330             table[index] = new YNode<>(entry.hash, entry.key, value, entry.probes);
 331             return entry.value;
 332         }
 333     }
 334     /* ---------------- Static utilities -------------- */
 335 
 336     /**
 337      * Computes key.hashCode() and spreads (XORs) higher bits of hash
 338      * to lower.  Because the table uses power-of-two masking, sets of
 339      * hashes that vary only in bits above the current mask will
 340      * always collide. (Among known examples are sets of Float keys
 341      * holding consecutive whole numbers in small tables.)  So we
 342      * apply a transform that spreads the impact of higher bits
 343      * downward. There is a tradeoff between speed, utility, and
 344      * quality of bit-spreading. Because many common sets of hashes
 345      * are already reasonably distributed (so don't benefit from
 346      * spreading), and because we use trees to handle large sets of
 347      * collisions in bins, we just XOR some shifted bits in the
 348      * cheapest possible way to reduce systematic lossage, as well as
 349      * to incorporate impact of the highest bits that would otherwise
 350      * never be used in index calculations because of table bounds.
 351      */
 352     static final int hash(Object key) {
 353         int h;
 354         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
 355     }
 356 
 357     /**
 358      * Returns a power of two size for the given target capacity.
 359      */
 360     static final int tableSizeFor(int cap) {
 361         int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
 362         return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
 363     }
 364 
 365     /* ---------------- Fields -------------- */
 366 
 367     /**
 368      * The table, initialized on first use, and resized as
 369      * necessary. When allocated, length is always a power of two.
 370      * (We also tolerate length zero in some operations to allow
 371      * bootstrapping mechanics that are currently not needed.)
 372      */
 373     transient YNode<K,V>[] table;
 374 
 375     /**
 376      * Holds cached entrySet(). Note that AbstractMap fields are used
 377      * for keySet() and values().
 378      */
 379     transient Set<Map.Entry<K,V>> entrySet;
 380 
 381     /**
 382      * The number of key-value mappings contained in this map.
 383      */
 384     transient int size;
 385 
 386     /**
 387      * The number of times this HashMap has been structurally modified
 388      * Structural modifications are those that change the number of mappings in
 389      * the HashMap or otherwise modify its internal structure (e.g.,
 390      * rehash).  This field is used to make iterators on Collection-views of
 391      * the HashMap fail-fast.  (See ConcurrentModificationException).
 392      */
 393     transient int modCount;
 394 
 395     /**
 396      * The next size value at which to resize (capacity * load factor).
 397      *
 398      * @serial
 399      */
 400     // (The javadoc description is true upon serialization.
 401     // Additionally, if the table array has not been allocated, this
 402     // field holds the initial array capacity, or zero signifying
 403     // DEFAULT_INITIAL_CAPACITY.)
 404     int threshold;
 405 
 406     /**
 407      * The load factor for the hash table.
 408      *
 409      * @serial
 410      */
 411     final float loadFactor;
 412 
 413     private transient int[] getProbes = new int[16];
 414     private transient int[] putProbes = new int[16];
 415     private transient int[] notFoundProbes = new int[16];
 416 
 417 
 418     /* ---------------- Public operations -------------- */
 419 
 420     /**
 421      * Constructs an empty {@code HashMap} with the specified initial
 422      * capacity and load factor.
 423      *
 424      * @param  initialCapacity the initial capacity
 425      * @param  loadFactor      the load factor
 426      * @throws IllegalArgumentException if the initial capacity is negative
 427      *         or the load factor is nonpositive
 428      */
 429     public HashMap(int initialCapacity, float loadFactor) {
 430         if (initialCapacity < 0)
 431             throw new IllegalArgumentException("Illegal initial capacity: " +
 432                     initialCapacity);
 433         if (initialCapacity > MAXIMUM_CAPACITY)
 434             initialCapacity = MAXIMUM_CAPACITY;
 435         if (loadFactor <= 0 || Float.isNaN(loadFactor))
 436             throw new IllegalArgumentException("Illegal load factor: " +
 437                     loadFactor);
 438         this.loadFactor = loadFactor;
 439         this.threshold = tableSizeFor(initialCapacity);
 440     }
 441 
 442     /**
 443      * Constructs an empty {@code HashMap} with the specified initial
 444      * capacity and the default load factor (0.75).
 445      *
 446      * @param  initialCapacity the initial capacity.
 447      * @throws IllegalArgumentException if the initial capacity is negative.
 448      */
 449     public HashMap(int initialCapacity) {
 450         this(initialCapacity, DEFAULT_LOAD_FACTOR);
 451     }
 452 
 453     /**
 454      * Constructs an empty {@code HashMap} with the default initial capacity
 455      * (16) and the default load factor (0.75).
 456      */
 457     public HashMap() {
 458         this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
 459     }
 460 
 461     /**
 462      * Constructs a new {@code HashMap} with the same mappings as the
 463      * specified {@code Map}.  The {@code HashMap} is created with
 464      * default load factor (0.75) and an initial capacity sufficient to
 465      * hold the mappings in the specified {@code Map}.
 466      *
 467      * @param   m the map whose mappings are to be placed in this map
 468      * @throws  NullPointerException if the specified map is null
 469      */
 470     @SuppressWarnings("initialization")
 471     public HashMap(Map<? extends K, ? extends V> m) {
 472         this.loadFactor = DEFAULT_LOAD_FACTOR;
 473         putMapEntries(m, false);
 474     }
 475 
 476     /**
 477      * Implements Map.putAll and Map constructor.
 478      *
 479      * @param m the map
 480      * @param evict false when initially constructing this map, else true.
 481      */
 482     final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
 483         int s = m.size();
 484         if (s > 0) {
 485             if (table == null) { // pre-size
 486                 float ft = ((float)s / loadFactor) + 1.0F;
 487                 int t = ((ft < (float)MAXIMUM_CAPACITY) ?
 488                         (int)ft : MAXIMUM_CAPACITY);
 489                 if (t > threshold)
 490                     threshold = tableSizeFor(t);
 491             } else {
 492                 // Because of linked-list bucket constraints, we cannot
 493                 // expand all at once, but can reduce total resize
 494                 // effort by repeated doubling now vs later
 495                 while (s > threshold && table.length < MAXIMUM_CAPACITY)
 496                     resize();
 497             }
 498 
 499             for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
 500                 K key = e.getKey();
 501                 V value = e.getValue();
 502                 putVal(hash(key), key, value, false);
 503             }
 504         }
 505     }
 506 
 507     /**
 508      * Returns the number of key-value mappings in this map.
 509      *
 510      * @return the number of key-value mappings in this map
 511      */
 512     public int size() {
 513         return size;
 514     }
 515 
 516     /**
 517      * Returns {@code true} if this map contains no key-value mappings.
 518      *
 519      * @return {@code true} if this map contains no key-value mappings
 520      */
 521     public boolean isEmpty() {
 522         return size == 0;
 523     }
 524 
 525     /**
 526      * Returns the value to which the specified key is mapped,
 527      * or {@code null} if this map contains no mapping for the key.
 528      *
 529      * <p>More formally, if this map contains a mapping from a key
 530      * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
 531      * key.equals(k))}, then this method returns {@code v}; otherwise
 532      * it returns {@code null}.  (There can be at most one such mapping.)
 533      *
 534      * <p>A return value of {@code null} does not <i>necessarily</i>
 535      * indicate that the map contains no mapping for the key; it's also
 536      * possible that the map explicitly maps the key to {@code null}.
 537      * The {@link #containsKey containsKey} operation may be used to
 538      * distinguish these two cases.
 539      *
 540      * @see #put(Object, Object)
 541      */
 542     public V get(Object key) {
 543         final YNode<K, V>[] tab;
 544         final int mask;
 545 //        int probes = 0;
 546         if ((tab = table) != null && (mask = tab.length - 1) >= 0) {
 547             final int hash = hash(key);
 548             int h = hash;
 549             YNode<K, V> entry;
 550             while ((entry = tab[(mask & h)]).isValue()) {
 551 //                probes++;
 552                 K k;
 553                 if (entry.hash == hash &&
 554                         ((k = entry.key) == key || (key != null && key.equals(k)))) {
 555 //                    getProbes = incProbeCount(getProbes, probes);
 556                     return entry.value;
 557                 } else {
 558                     h += REHASH_HASH;
 559                 }
 560             }
 561         }
 562 //        notFoundProbes = incProbeCount(notFoundProbes, 0);
 563         return null;      // not found; empty table
 564     }
 565 
 566     /**
 567      * Same as Get caching the entry.
 568      * @param key the key
 569      * @return a value, or null
 570      */
 571     public V get1(Object key) {
 572         final int hash = hash(key);
 573         final YNode<K, V>[] tab;
 574         int n;
 575         if ((tab = table) != null && (n = tab.length) > 0) {
 576             int h = hash;
 577             int index = (n - 1) & h;
 578             YNode<K, V> entry = tab[index];
 579             for (; //int probes = 1
 580                  entry.isValue();
 581                  h += REHASH_HASH, index = (n - 1) & h, entry = tab[index]) {  //, probes++
 582                 K k;
 583                 if (entry.hash == hash &&
 584                         ((k = entry.key) == key || (key != null && key.equals(k)))) {
 585 //                    getProbes = incProbeCount(getProbes, probes);
 586                     return entry.value;
 587                 }
 588             }
 589         }
 590 //        notFoundProbes = incProbeCount(notFoundProbes, 0);
 591         return null;      // not found; empty table
 592     }
 593 
 594     /**
 595      * Implements Map.get and related methods.
 596      *
 597      * @param hash hash for key
 598      * @param key the key
 599      * @return the index of a matching node or -1
 600      */
 601     private final int getNode(final int hash, Object key) {
 602         YNode<K, V>[] tab;
 603         int n;
 604         if ((tab = table) != null && (n = tab.length) > 0) {
 605             final YNode<K, V> first;
 606             final int i = (n - 1) & hash;
 607             K k;
 608             if ((first = tab[i]).isValue() &&
 609                     first.hash == hash &&
 610                     ((k = first.key) == key || (key != null && key.equals(k)))) {
 611 //                getProbes = incProbeCount(getProbes, 1);
 612                 return i;
 613             }
 614             // non-empty table and not first entry
 615             int h = hash;
 616             for (int probes = 1; probes <= tab.length; probes++, h += REHASH_HASH) {
 617                 final int index = (n - 1) & h;
 618                 final YNode<K, V> entry = tab[index];
 619                 if (!entry.isValue()) {
 620 //                    notFoundProbes = incProbeCount(notFoundProbes, probes);
 621                     return -1;  // search ended without finding the key
 622                 } else if (entry.hash == hash &&
 623                         ((k = entry.key) == key || (key != null && key.equals(k)))) {
 624 //                    getProbes = incProbeCount(getProbes, probes);
 625                     return index;
 626                 }
 627             }
 628         }
 629 //        notFoundProbes = incProbeCount(notFoundProbes, 0);
 630         return -1;      // not found; empty table
 631     }
 632 
 633     /**
 634      * Returns {@code true} if this map contains a mapping for the
 635      * specified key.
 636      *
 637      * @param   key   The key whose presence in this map is to be tested
 638      * @return {@code true} if this map contains a mapping for the specified
 639      * key.
 640      */
 641     public boolean containsKey(Object key) {
 642         return getNode(hash(key), key) >= 0;
 643     }
 644 
 645     /**
 646      * Associates the specified value with the specified key in this map.
 647      * If the map previously contained a mapping for the key, the old
 648      * value is replaced.
 649      *
 650      * @param key key with which the specified value is to be associated
 651      * @param value value to be associated with the specified key
 652      * @return the previous value associated with {@code key}, or
 653      *         {@code null} if there was no mapping for {@code key}.
 654      *         (A {@code null} return can also indicate that the map
 655      *         previously associated {@code null} with {@code key}.)
 656      */
 657     public V put(K key, V value) {
 658         return putVal(hash(key), key, value, false);
 659     }
 660 
 661     /**
 662      * Implements Map.put and related methods.
 663      *
 664      * @param hash hash for key
 665      * @param key the key
 666      * @param value the value to put
 667      * @param onlyIfAbsent if true, don't change existing value
 668      * @return previous value, or null if none
 669      */
 670     private final V putVal(final int hash, final K key, final V value, boolean onlyIfAbsent) {
 671         YNode<K, V>[] tab;
 672         YNode<K, V> tp;
 673         int n, i;
 674         if ((tab = table) == null || (n = tab.length) == 0)
 675             n = (tab = resize()).length;
 676         debug("  putval", -1, new YNode<K,V>(hash, key, value, -1));
 677 
 678         int h = hash;
 679         int insert = -1;    // insertion point if not already present
 680         int insertProbes = -1;
 681         for (int probes = 1; ; probes++, h += REHASH_HASH) {
 682             if (probes > tab.length)
 683                 throw new IllegalStateException("No empty entries in table");
 684             final int index;
 685             final YNode<K, V> entry = tab[(index = ((n - 1) & h))];
 686 //            debug("    looking at", index, entry);
 687             if (entry.isEmpty()) {
 688                 // Absent; insert in the first place it could be added
 689                 // TBD: should it check onlyIfAbsent?
 690                 if (insert < 0) {
 691                     // no better place to insert than here
 692                     tab[index] = new YNode<>(hash, key, value, probes);
 693                     debug("    setting", index, tab[index]);
 694 //                    putProbes = incProbeCount(putProbes, probes);
 695                 } else {
 696                     // The new entry is more needy than the current one
 697                     final YNode<K,V> tmp = tab[insert];
 698                     tab[insert] = new YNode<>(hash, key, value, insertProbes);
 699                     debug("    robin-hood inserted", index, tab[index]);
 700 //                    putProbes = incProbeCount(putProbes, insertProbes);
 701                     putReinsert(insert, tmp);
 702                 }
 703                 break;  // break to update modCount and size
 704             }
 705 
 706             if (entry.isValue() && entry.hash == hash &&
 707                     (entry.key == key || (key != null && key.equals(entry.key)))) {
 708                 // TBD: consider if updated entry should be moved closer to the front
 709                 if (!onlyIfAbsent || entry.value == null) {
 710                     tab[index] = new YNode<>(hash, key, value, entry.probes);
 711                 }
 712                 debug("    oldvalue", index, entry);
 713                 debug("    updating", index, tab[index]);
 714 //                putProbes = incProbeCount(putProbes, probes);
 715                 return entry.value;
 716             }
 717 
 718             // Save first possible insert index
 719             if (insert < 0 && probes > entry.probes) {
 720                 insert = index;
 721                 insertProbes = probes;
 722             }
 723         }
 724         ++modCount;
 725         ++size;
 726         isTableOk(tab, "table not ok, putval");
 727         if (size >= threshold)
 728             resize();       // Ensure there is at least 1 empty available
 729         return null;
 730     }
 731 
 732     /**
 733      * Re-insert the entry in the table starting at the entry beyond the index.
 734      * Insert it at an empty slot.
 735      * Replace an entry with a lower probe count and repeat to reinsert that entry.
 736      * @param oldIndex the index just replaced
 737      * @param rEntry the entry to be replaced
 738      */
 739     private void putReinsert(final int oldIndex, YNode<K,V> rEntry) {
 740         final YNode<K, V>[] tab = table;
 741         final int n = tab.length;
 742 
 743         int h = oldIndex + REHASH_HASH;
 744         for (int probes = rEntry.probes + 1; probes <= n; probes++, h += REHASH_HASH) {
 745             isTableOk(tab, "bubble down loop");
 746             final int index = (n - 1) & h;
 747             final YNode<K,V> entry = tab[index];
 748             if (entry.isEmpty()) {
 749                 // Insert in the empty slot
 750                 tab[index] = new YNode<>(rEntry.hash, rEntry.key, rEntry.value, probes);
 751                 debug("    reinserted", index, tab[index]);
 752                 return;
 753             } else if (probes > entry.probes) {
 754                 // Replace a less deserving entry
 755                 tab[index] = new YNode<>(rEntry.hash, rEntry.key, rEntry.value, probes);
 756                 debug("    robin-hood bubble down", index, tab[index]);
 757                 rEntry = entry;
 758                 probes = rEntry.probes;
 759                 debug("    robin-hood moving", index, rEntry);
 760             } else {
 761                 debug("    robin-hood skipping", index, entry);
 762             }
 763         }
 764         throw new RuntimeException("bubble down failed");
 765     }
 766 
 767     private void debug(String msg, int index, YNode<K,V> entry) {
 768         if (DEBUG && System.out != null) {
 769             System.out.println(System.identityHashCode(this) + ": " + msg + ": index: " + index + ", node: " + Objects.toString(entry));
 770         }
 771     }
 772    private void debug2(String msg, int index, YNode<K,V> entry) {
 773         if (System.out != null) {
 774             System.out.println(System.identityHashCode(this) + ": " + msg + ": index: " + index +
 775                     ", " + "node: " + entry);
 776         }
 777     }
 778 
 779     /**
 780      * Initializes or doubles table size.  If null, allocates in
 781      * accord with initial capacity target held in field threshold.
 782      * Otherwise, because we are using power-of-two expansion, the
 783      * elements from each bin must either stay at same index, or move
 784      * with a power of two offset in the new table.
 785      *
 786      * @return the table
 787      */
 788     final YNode<K,V>[] resize() {
 789         YNode<K,V>[] oldTab = table;
 790         int oldCap = (oldTab == null) ? 0 : oldTab.length;
 791         int oldThr = threshold;
 792         int newCap, newThr = 0;
 793         if (oldCap > 0) {
 794             if (oldCap >= MAXIMUM_CAPACITY) {
 795                 threshold = Integer.MAX_VALUE;
 796                 return oldTab;
 797             }
 798             else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
 799                      oldCap >= DEFAULT_INITIAL_CAPACITY)
 800                 newThr = oldThr << 1; // double threshold
 801         }
 802         else if (oldThr > 0) // initial capacity was placed in threshold
 803             newCap = oldThr;
 804         else {               // zero initial threshold signifies using defaults
 805             newCap = DEFAULT_INITIAL_CAPACITY;
 806             newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
 807         }
 808         if (newThr == 0) {
 809             float ft = (float)newCap * loadFactor;
 810             newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
 811                     (int)ft : Integer.MAX_VALUE);
 812         }
 813         isTableOk(oldTab, "oldTab bad before resize");
 814         if (getProbes != null)
 815             Arrays.fill(getProbes, 0);
 816         if (putProbes != null)
 817             Arrays.fill(putProbes, 0);
 818         if (notFoundProbes != null)
 819             Arrays.fill(notFoundProbes, 0);
 820 
 821         // There must always be an empty entry, resize when it gets to capacity.
 822         threshold = (newThr > newCap) ? newCap : newThr;
 823         @SuppressWarnings({"rawtypes","unchecked"})
 824         YNode<K,V>[] newTab = (YNode<K,V>[])new YNode[newCap];
 825         table = newTab;
 826         if (oldTab != null) {
 827             for (int i = 0; i < oldCap; ++i) {
 828                 YNode<K,V> e;
 829                 if ((e = oldTab[i]).isValue()) {
 830                     final int ii;
 831                     if (newTab[ii = (newCap - 1) & e.hash].isEmpty()) {
 832                         newTab[ii] = new YNode<>(e.hash, e.key, e.value, 1);
 833                         putProbes = incProbeCount(putProbes, 1);
 834                     } else {
 835                         int h = e.hash + REHASH_HASH;
 836                         for (int probes = 2; ; probes++, h += REHASH_HASH) {
 837                             final int index;
 838                             if (newTab[(index = ((newCap - 1) & h))].isEmpty()) {
 839                                 newTab[index] = new YNode<>(e.hash, e.key, e.value, probes);
 840                                 putProbes = incProbeCount(putProbes, probes);
 841                                 break;
 842                             }
 843                             // TBD: Consider Robin-hood insert
 844                             if (probes > newTab.length)
 845                                 throw new IllegalStateException("NYI resize: no support for overflow");
 846                         }
 847                     }
 848                 }
 849             }
 850         }
 851 
 852         debug("resized", newTab.length, new YNode<K,V>());
 853         isTableOk(newTab, "newTab bad after resize");
 854         return newTab;
 855     }
 856 
 857     /**
 858      * Dump the hashtable.
 859      */
 860     public void dumpTable() {
 861         dumpTable(table, "dumpTable");
 862     }
 863 
 864     /**
 865      * Dump the hashtable
 866      * @param table the table
 867      * @param msg a message
 868      */
 869     private void dumpTable(YNode<K, V>[] table, String msg) {
 870         if (System.out == null || table == null)
 871             return;
 872         System.out.println(msg + ", size: " + size + ", len: " + table.length);
 873         for (int i = 0; i < table.length; ++i) {
 874             if (table[i].isValue())
 875                 System.out.println("   [" + i + "] " + table[i]);
 876         }
 877     }
 878 
 879     /**
 880      * Copies all of the mappings from the specified map to this map.
 881      * These mappings will replace any mappings that this map had for
 882      * any of the keys currently in the specified map.
 883      *
 884      * @param m mappings to be stored in this map
 885      * @throws NullPointerException if the specified map is null
 886      */
 887     public void putAll(Map<? extends K, ? extends V> m) {
 888         putMapEntries(m, true);
 889     }
 890 
 891     /**
 892      * Removes the mapping for the specified key from this map if present.
 893      *
 894      * @param  key key whose mapping is to be removed from the map
 895      * @return the previous value associated with {@code key}, or
 896      *         {@code null} if there was no mapping for {@code key}.
 897      *         (A {@code null} return can also indicate that the map
 898      *         previously associated {@code null} with {@code key}.)
 899      */
 900     public V remove(Object key) {
 901         YNode<K,V> entry = removeNode(hash(key), key, null, false, true);
 902         return entry.isValue() ? entry.value : null;
 903     }
 904 
 905     /**
 906      * Implements Map.remove and related methods.
 907      *
 908      * @param hash hash for key
 909      * @param key the key
 910      * @param value the value to match if matchValue, else ignored
 911      * @param matchValue if true only remove if value is equal
 912      * @param movable if false do not move other nodes while removing
 913      * @return the node, or null if none
 914      */
 915     @SuppressWarnings("unchecked")
 916     private final YNode<K,V> removeNode(final int hash, final Object key, final Object value,
 917                                          boolean matchValue, boolean movable) {
 918         YNode<K, V>[] tab;
 919         YNode<K, V> entry;
 920         V v = null;
 921         int curr;
 922         int n;
 923         debug("  removeNode", -2, new YNode<K,V>(hash, (K)key, (V)value, -2));
 924 
 925         if ((tab = table) != null && (n = tab.length) > 0 &&
 926                 (curr = getNode(hash, key)) >= 0 &&
 927                 (entry = tab[curr]).isValue() &&
 928                 ((!matchValue || (v = entry.value) == value ||
 929                         (value != null && value.equals(v))))) {
 930             // found entry; free and compress
 931             removeNode(curr);
 932             return entry;
 933         }
 934         return new YNode();
 935     }
 936 
 937     @SuppressWarnings("unchecked")
 938     private void removeNode(final int curr) {
 939         final YNode<K, V>[] tab = table;;
 940         final int n = tab.length;
 941 
 942         ++modCount;
 943         --size;
 944         int free = curr;        // The entry to be cleared, if not replaced
 945         int h = curr;
 946         int probes = 0;
 947         do {
 948             probes++;
 949             h += REHASH_HASH;
 950             final int index = (n - 1) & h;
 951             final YNode<K, V> entry = tab[index];
 952             if (entry.probes == 0) {
 953                 // Search ended at empty entry, clear the free entry
 954                 debug("    clearing", index, entry);
 955                 tab[free] = new YNode<>();
 956                 return;
 957             }
 958             if (entry.probes > probes) {
 959                 // move up the entry, skip if it is already in the best spot
 960                 debug("    replacing", free, entry);
 961                 tab[free] = new YNode<>(entry.hash, entry.key, entry.value, entry.probes - probes);
 962                 debug("         with", free, tab[free]);
 963                 free = index;
 964                 probes = 0;
 965             }
 966         } while (((n - 1) & h) != curr);
 967         isTableOk(tab, "table not ok, not found");
 968         throw new RuntimeException("removeNode too many probes");
 969     }
 970 
 971     /**
 972      * Removes all of the mappings from this map.
 973      * The map will be empty after this call returns.
 974      */
 975     @SuppressWarnings({"rawtypes","unchecked"})
 976     public void clear() {
 977         YNode<K,V>[] tab;
 978         modCount++;
 979         if ((tab = table) != null && size > 0) {
 980             size = 0;
 981             for (int i = 0; i < tab.length; i++)
 982                 tab[i] = new YNode();
 983         }
 984     }
 985 
 986     /**
 987      * Returns {@code true} if this map maps one or more keys to the
 988      * specified value.
 989      *
 990      * @param value value whose presence in this map is to be tested
 991      * @return {@code true} if this map maps one or more keys to the
 992      *         specified value
 993      */
 994     public boolean containsValue(Object value) {
 995         YNode<K,V>[] tab; V v;
 996         if ((tab = table) != null && size > 0) {
 997             for (YNode<K,V> te : tab) {
 998                 if (te.isValue()) {
 999                     if ((v = te.value) == value ||
1000                             (value != null && value.equals(v)))
1001                         return true;
1002                 }
1003             }
1004         }
1005         return false;
1006     }
1007 
1008     /**
1009      * Returns a {@link Set} view of the keys contained in this map.
1010      * The set is backed by the map, so changes to the map are
1011      * reflected in the set, and vice-versa.  If the map is modified
1012      * while an iteration over the set is in progress (except through
1013      * the iterator's own {@code remove} operation), the results of
1014      * the iteration are undefined.  The set supports element removal,
1015      * which removes the corresponding mapping from the map, via the
1016      * {@code Iterator.remove}, {@code Set.remove},
1017      * {@code removeAll}, {@code retainAll}, and {@code clear}
1018      * operations.  It does not support the {@code add} or {@code addAll}
1019      * operations.
1020      *
1021      * @return a set view of the keys contained in this map
1022      */
1023     public Set<K> keySet() {
1024         Set<K> ks = keySet;
1025         if (ks == null) {
1026             ks = new KeySet();
1027             keySet = ks;
1028         }
1029         return ks;
1030     }
1031 
1032     /**
1033      * Prepares the array for {@link Collection#toArray(Object[])} implementation.
1034      * If supplied array is smaller than this map size, a new array is allocated.
1035      * If supplied array is bigger than this map size, a null is written at size index.
1036      *
1037      * @param a an original array passed to {@code toArray()} method
1038      * @param <T> type of array elements
1039      * @return an array ready to be filled and returned from {@code toArray()} method.
1040      */
1041     @SuppressWarnings("unchecked")
1042     final <T> T[] prepareArray(T[] a) {
1043         int size = this.size;
1044         if (a.length < size) {
1045             return (T[]) java.lang.reflect.Array
1046                     .newInstance(a.getClass().getComponentType(), size);
1047         }
1048         if (a.length > size) {
1049             a[size] = null;
1050         }
1051         return a;
1052     }
1053 
1054     /**
1055      * Fills an array with this map keys and returns it. This method assumes
1056      * that input array is big enough to fit all the keys. Use
1057      * {@link #prepareArray(Object[])} to ensure this.
1058      *
1059      * @param a an array to fill
1060      * @param <T> type of array elements
1061      * @return supplied array
1062      */
1063     <T> T[] keysToArray(T[] a) {
1064         Object[] r = a;
1065         YNode<K,V>[] tab;
1066         int idx = 0;
1067         if (size > 0 && (tab = table) != null) {
1068             for (YNode<K,V> te : tab) {
1069                 if (te.isValue()) {
1070                     r[idx++] = te.key;
1071                 }
1072             }
1073         }
1074         return a;
1075     }
1076 
1077     /**
1078      * Fills an array with this map values and returns it. This method assumes
1079      * that input array is big enough to fit all the values. Use
1080      * {@link #prepareArray(Object[])} to ensure this.
1081      *
1082      * @param a an array to fill
1083      * @param <T> type of array elements
1084      * @return supplied array
1085      */
1086     <T> T[] valuesToArray(T[] a) {
1087         Object[] r = a;
1088         YNode<K,V>[] tab;
1089         int idx = 0;
1090         if (size > 0 && (tab = table) != null) {
1091             for (YNode<K,V> te : tab) {
1092                 if (te.isValue()) {
1093                     r[idx++] = te.value;
1094                 }
1095             }
1096         }
1097         return a;
1098     }
1099 
1100     final class KeySet extends AbstractSet<K> {
1101         public final int size()                 { return size; }
1102         public final void clear()               { HashMap.this.clear(); }
1103         public final Iterator<K> iterator()     { return new KeyIterator(); }
1104         public final boolean contains(Object o) { return containsKey(o); }
1105         public final boolean remove(Object key) {
1106             return removeNode(hash(key), key, null, false, true).isValue();
1107         }
1108 
1109         public Object[] toArray() {
1110             return keysToArray(new Object[size]);
1111         }
1112 
1113         public <T> T[] toArray(T[] a) {
1114             return keysToArray(prepareArray(a));
1115         }
1116 
1117         public final void forEach(Consumer<? super K> action) {
1118             YNode<K,V>[] tab;
1119             if (action == null)
1120                 throw new NullPointerException();
1121             if (size > 0 && (tab = table) != null) {
1122                 int mc = modCount;
1123                 for (YNode<K,V> te : tab) {
1124                     if (te.isValue()) {
1125                         action.accept(te.key);
1126                     }
1127                 }
1128                 if (modCount != mc)
1129                     throw new ConcurrentModificationException();
1130             }
1131         }
1132     }
1133 
1134     /**
1135      * Returns a {@link Collection} view of the values contained in this map.
1136      * The collection is backed by the map, so changes to the map are
1137      * reflected in the collection, and vice-versa.  If the map is
1138      * modified while an iteration over the collection is in progress
1139      * (except through the iterator's own {@code remove} operation),
1140      * the results of the iteration are undefined.  The collection
1141      * supports element removal, which removes the corresponding
1142      * mapping from the map, via the {@code Iterator.remove},
1143      * {@code Collection.remove}, {@code removeAll},
1144      * {@code retainAll} and {@code clear} operations.  It does not
1145      * support the {@code add} or {@code addAll} operations.
1146      *
1147      * @return a view of the values contained in this map
1148      */
1149     public Collection<V> values() {
1150         Collection<V> vs = values;
1151         if (vs == null) {
1152             vs = new Values();
1153             values = vs;
1154         }
1155         return vs;
1156     }
1157 
1158     final class Values extends AbstractCollection<V> {
1159         public final int size()                 { return size; }
1160         public final void clear()               { HashMap.this.clear(); }
1161         public final Iterator<V> iterator()     { return new ValueIterator(); }
1162         public final boolean contains(Object o) { return containsValue(o); }
1163 
1164         public Object[] toArray() {
1165             return valuesToArray(new Object[size]);
1166         }
1167 
1168         public <T> T[] toArray(T[] a) {
1169             return valuesToArray(prepareArray(a));
1170         }
1171 
1172         public final void forEach(Consumer<? super V> action) {
1173             YNode<K,V>[] tab;
1174             if (action == null)
1175                 throw new NullPointerException();
1176             if (size > 0 && (tab = table) != null) {
1177                 int mc = modCount;
1178                 for (YNode<K,V> te : tab) {
1179                     if (te.isValue()) {
1180                         action.accept(te.value);
1181                     }
1182                 }
1183                 if (modCount != mc)
1184                     throw new ConcurrentModificationException();
1185             }
1186         }
1187     }
1188 
1189     /**
1190      * Returns a {@link Set} view of the mappings contained in this map.
1191      * The set is backed by the map, so changes to the map are
1192      * reflected in the set, and vice-versa.  If the map is modified
1193      * while an iteration over the set is in progress (except through
1194      * the iterator's own {@code remove} operation, or through the
1195      * {@code setValue} operation on a map entry returned by the
1196      * iterator) the results of the iteration are undefined.  The set
1197      * supports element removal, which removes the corresponding
1198      * mapping from the map, via the {@code Iterator.remove},
1199      * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
1200      * {@code clear} operations.  It does not support the
1201      * {@code add} or {@code addAll} operations.
1202      *
1203      * @return a set view of the mappings contained in this map
1204      */
1205     public Set<Map.Entry<K,V>> entrySet() {
1206         Set<Map.Entry<K,V>> es;
1207         return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
1208     }
1209 
1210     final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1211         public final int size()                 { return size; }
1212         public final void clear()               { HashMap.this.clear(); }
1213         public final Iterator<Map.Entry<K,V>> iterator() {
1214             return new EntryIterator();
1215         }
1216         public final boolean contains(Object o) {
1217             if (!(o instanceof Map.Entry))
1218                 return false;
1219             Map.Entry<?,?> e = (Map.Entry<?,?>) o;
1220             Object key = e.getKey();
1221             int index = getNode(hash(key), key);
1222             return index >= 0 && table[index].equals(e);
1223         }
1224         public final boolean remove(Object o) {
1225             if (o instanceof Map.Entry) {
1226                 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
1227                 Object key = e.getKey();
1228                 Object value = e.getValue();
1229                 return removeNode(hash(key), key, value, true, true).isValue();
1230             }
1231             return false;
1232         }
1233 
1234         public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
1235             YNode<K,V>[] tab;
1236             if (action == null)
1237                 throw new NullPointerException();
1238             if (size > 0 && (tab = table) != null) {
1239                 int mc = modCount;
1240                 for (YNode<K,V> te : tab) {
1241                     if (te.isValue()) {
1242                         action.accept(new YNodeWrapper(te.hash & (tab.length - 1)));
1243                     }
1244                 }
1245                 if (modCount != mc)
1246                     throw new ConcurrentModificationException();
1247             }
1248         }
1249     }
1250 
1251     // Overrides of JDK8 Map extension methods
1252 
1253     @Override
1254     public V getOrDefault(Object key, V defaultValue) {
1255         final int index;
1256         return (index = getNode(hash(key), key)) < 0 ? defaultValue : table[index].value;
1257     }
1258 
1259     @Override
1260     public V putIfAbsent(K key, V value) {
1261         return putVal(hash(key), key, value, true);
1262     }
1263 
1264     @Override
1265     public boolean remove(Object key, Object value) {
1266         return removeNode(hash(key), key, value, true, true).isValue();
1267     }
1268 
1269     @Override
1270     public boolean replace(K key, V oldValue, V newValue) {
1271         int hash, index;
1272         V v;
1273         if ((index = getNode((hash = hash(key)), key)) >= 0 &&
1274                 ((v = table[index].value) == oldValue || (v != null && v.equals(oldValue)))) {
1275             table[index] = new YNode<>(hash, key, newValue, table[index].probes);
1276             return true;
1277         }
1278         return false;
1279     }
1280 
1281     @Override
1282     public V replace(K key, V value) {
1283         int hash, index;
1284         V v;
1285         if ((index = getNode((hash = hash(key)), key)) >= 0) {
1286             V oldValue = table[index].value;
1287             table[index] = new YNode<>(hash, key, value, table[index].probes);
1288             return oldValue;
1289         }
1290         return null;
1291     }
1292 
1293     /**
1294      * {@inheritDoc}
1295      *
1296      * <p>This method will, on a best-effort basis, throw a
1297      * {@link ConcurrentModificationException} if it is detected that the
1298      * mapping function modifies this map during computation.
1299      *
1300      * @throws ConcurrentModificationException if it is detected that the
1301      * mapping function modified this map
1302      */
1303     @Override
1304     public V computeIfAbsent(K key,
1305                              Function<? super K, ? extends V> mappingFunction) {
1306         if (mappingFunction == null)
1307             throw new NullPointerException();
1308         int hash = hash(key);
1309         YNode<K,V>[] tab = table;
1310         YNode<K,V> entry;
1311         int index;
1312 
1313         index = getNode(hash, key);
1314         if (index >= 0 && (entry = tab[index]).value != null) {
1315             return entry.value;
1316         }
1317         int mc = modCount;
1318         V v = mappingFunction.apply(key);
1319         if (mc != modCount) { throw new ConcurrentModificationException(); }
1320         if (v == null) {
1321             return null;
1322         }
1323         putVal(hash, key, v, false);
1324         return v;
1325     }
1326 
1327     /**
1328      * {@inheritDoc}
1329      *
1330      * <p>This method will, on a best-effort basis, throw a
1331      * {@link ConcurrentModificationException} if it is detected that the
1332      * remapping function modifies this map during computation.
1333      *
1334      * @throws ConcurrentModificationException if it is detected that the
1335      * remapping function modified this map
1336      */
1337     @Override
1338     public V computeIfPresent(K key,
1339                               BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1340         if (remappingFunction == null)
1341             throw new NullPointerException();
1342         YNode<K,V> oldValue;
1343         int hash = hash(key);
1344         int index = getNode(hash, key);
1345         if (index >= 0 && (oldValue = table[index]).value != null) {
1346             int mc = modCount;
1347             V v = remappingFunction.apply(key, oldValue.value);
1348             if (mc != modCount) { throw new ConcurrentModificationException(); }
1349             if (v != null) {
1350                 table[index] = new YNode<>(hash, key, v, oldValue.probes);
1351                 return v;
1352             } else
1353                 removeNode(hash, key, null, false, true);
1354         }
1355         return null;
1356     }
1357 
1358     /**
1359      * {@inheritDoc}
1360      *
1361      * <p>This method will, on a best-effort basis, throw a
1362      * {@link ConcurrentModificationException} if it is detected that the
1363      * remapping function modifies this map during computation.
1364      *
1365      * @throws ConcurrentModificationException if it is detected that the
1366      * remapping function modified this map
1367      */
1368     @Override
1369     @SuppressWarnings("unchecked")
1370     public V compute(K key,
1371                      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1372         if (remappingFunction == null)
1373             throw new NullPointerException();
1374 
1375         int hash = hash(key);
1376         int index = getNode(hash, key);
1377         YNode<K,V> oldValue = (index >= 0) ? table[index] : new YNode();
1378 
1379         int mc = modCount;
1380         V v = remappingFunction.apply(key, oldValue.value);
1381         if (mc != modCount) { throw new ConcurrentModificationException(); }
1382         if (v != null) {
1383             if (index >= 0) {
1384                 table[index] = new YNode<>(hash, key, v, oldValue.probes);
1385 //                modCount++;
1386             } else
1387                 putVal(hash, key, v, false);
1388         } else
1389             // TBD: 2nd lookup to remove even though we have index
1390             removeNode(hash, key, null, false, true);
1391         return v;
1392     }
1393 
1394     /**
1395      * {@inheritDoc}
1396      *
1397      * <p>This method will, on a best-effort basis, throw a
1398      * {@link ConcurrentModificationException} if it is detected that the
1399      * remapping function modifies this map during computation.
1400      *
1401      * @throws ConcurrentModificationException if it is detected that the
1402      * remapping function modified this map
1403      */
1404     @Override
1405     public V merge(K key, V value,
1406                    BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
1407         if (remappingFunction == null)
1408             throw new NullPointerException();
1409 
1410         final int hash = hash(key);
1411         final int index = getNode(hash, key);
1412         if (index >= 0) {
1413             int mc = modCount;
1414             V v = remappingFunction.apply(table[index].value, value);
1415             if (mc != modCount) { throw new ConcurrentModificationException(); }
1416             if (v != null) {
1417                 if (index >= 0) {
1418                     table[index] = new YNode<>(hash, key, v, table[index].probes);
1419 //                    modCount++;
1420                 } else
1421                     putVal(hash, key, v, false);
1422             } else {
1423                 // TBD: 2nd lookup to remove even though we have index
1424                 removeNode(hash, key, null, false, true);
1425             }
1426             return v;
1427         } else {
1428             // put new key/value (even if null)
1429             putVal(hash, key, value, false);
1430         }
1431         return value;
1432     }
1433 
1434     @Override
1435     public void forEach(BiConsumer<? super K, ? super V> action) {
1436         YNode<K,V>[] tab;
1437         if (action == null)
1438             throw new NullPointerException();
1439         if (size > 0 && (tab = table) != null) {
1440             int mc = modCount;
1441             for (YNode<K,V> te : tab) {
1442                 if (te.isValue()) {
1443                     action.accept(te.key, te.value);
1444                 }
1445             }
1446             if (modCount != mc)
1447                 throw new ConcurrentModificationException();
1448         }
1449     }
1450 
1451     @Override
1452     public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
1453         super.replaceAll(function);
1454     }
1455 
1456     /* ------------------------------------------------------------ */
1457     // Cloning and serialization
1458 
1459     /**
1460      * Returns a shallow copy of this {@code HashMap} instance: the keys and
1461      * values themselves are not cloned.
1462      *
1463      * @return a shallow copy of this map
1464      */
1465     @SuppressWarnings("unchecked")
1466     @Override
1467     public Object clone() {
1468         HashMap<K,V> result;
1469         try {
1470             result = (HashMap<K,V>)super.clone();
1471         } catch (CloneNotSupportedException e) {
1472             // this shouldn't happen, since we are Cloneable
1473             throw new InternalError(e);
1474         }
1475         result.reinitialize();
1476         result.putMapEntries(this, false);
1477         return result;
1478     }
1479 
1480     // These methods are also used when serializing HashSets
1481     final float loadFactor() { return loadFactor; }
1482     final int capacity() {
1483         return (table != null) ? table.length :
1484                 (threshold > 0) ? threshold :
1485                 DEFAULT_INITIAL_CAPACITY;
1486     }
1487 
1488     /**
1489      * Saves this map to a stream (that is, serializes it).
1490      *
1491      * @param s the stream
1492      * @throws IOException if an I/O error occurs
1493      * @serialData The <i>capacity</i> of the HashMap (the length of the
1494      *             bucket array) is emitted (int), followed by the
1495      *             <i>size</i> (an int, the number of key-value
1496      *             mappings), followed by the key (Object) and value (Object)
1497      *             for each key-value mapping.  The key-value mappings are
1498      *             emitted in no particular order.
1499      */
1500     private void writeObject(java.io.ObjectOutputStream s)
1501         throws IOException {
1502         int buckets = capacity();
1503         // Write out the threshold, loadfactor, and any hidden stuff
1504         s.defaultWriteObject();
1505         s.writeInt(buckets);
1506         s.writeInt(size);
1507         internalWriteEntries(s);
1508     }
1509 
1510     /**
1511      * Reconstitutes this map from a stream (that is, deserializes it).
1512      * @param s the stream
1513      * @throws ClassNotFoundException if the class of a serialized object
1514      *         could not be found
1515      * @throws IOException if an I/O error occurs
1516      */
1517     private void readObject(java.io.ObjectInputStream s)
1518         throws IOException, ClassNotFoundException {
1519         // Read in the threshold (ignored), loadfactor, and any hidden stuff
1520         s.defaultReadObject();
1521         reinitialize();
1522         if (loadFactor <= 0 || Float.isNaN(loadFactor))
1523             throw new InvalidObjectException("Illegal load factor: " +
1524                     loadFactor);
1525         s.readInt();                // Read and ignore number of buckets
1526         int mappings = s.readInt(); // Read number of mappings (size)
1527         if (mappings < 0)
1528             throw new InvalidObjectException("Illegal mappings count: " +
1529                     mappings);
1530         else if (mappings > 0) { // (if zero, use defaults)
1531             // Size the table using given load factor only if within
1532             // range of 0.25...4.0
1533             float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
1534             float fc = (float)mappings / lf + 1.0f;
1535             int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
1536                     DEFAULT_INITIAL_CAPACITY :
1537                     (fc >= MAXIMUM_CAPACITY) ?
1538                             MAXIMUM_CAPACITY :
1539                             tableSizeFor((int)fc));
1540             float ft = (float)cap * lf;
1541             threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
1542                     (int)ft : Integer.MAX_VALUE);
1543 
1544             // Check Map.Entry[].class since it's the nearest public type to
1545             // what we're actually creating.
1546 //            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, cap);
1547             @SuppressWarnings({"rawtypes","unchecked"})
1548             YNode<K,V>[] tab = (YNode<K,V>[])new YNode[cap];
1549             table = tab;
1550 
1551             // Read the keys and values, and put the mappings in the HashMap
1552             for (int i = 0; i < mappings; i++) {
1553                 @SuppressWarnings("unchecked")
1554                 K key = (K) s.readObject();
1555                 @SuppressWarnings("unchecked")
1556                 V value = (V) s.readObject();
1557                 putVal(hash(key), key, value, false);
1558             }
1559         }
1560     }
1561 
1562     /* ------------------------------------------------------------ */
1563     // iterators
1564 
1565     abstract class HashIterator {
1566         int next;        // next entry to return
1567         int current;     // current entry
1568         int expectedModCount;  // for fast-fail
1569         int count;
1570 
1571         @SuppressWarnings("initialization")
1572         HashIterator() {
1573             expectedModCount = modCount;
1574             current = -1;
1575             next = (size > 0 && table != null) ? findNext(0) : -1;
1576             count = 0;
1577         }
1578 
1579         public final boolean hasNext() {
1580             return next >= 0;
1581         }
1582 
1583         final Entry<K,V> nextNode() {
1584             if (modCount != expectedModCount)
1585                 throw new ConcurrentModificationException("ex: " + expectedModCount + " != " + modCount);
1586             if (!hasNext())
1587                 throw new NoSuchElementException();
1588             current = next;
1589             assert current >= 0;
1590 
1591             next = (current + REHASH_HASH) & (table.length - 1);
1592             next = (next == 0) ? -1 : findNext(next);
1593             return new YNodeWrapper(current);
1594         }
1595 
1596         public final void remove() {
1597             if (current < 0 || current > table.length)
1598                 throw new IllegalStateException();
1599             if (modCount != expectedModCount)
1600                 throw new ConcurrentModificationException();
1601             YNode<K, V> p = table[current];
1602             removeNode(p.hash, p.key, null, false, false);
1603             if (table[current].isValue()) {
1604                 // a node was moved into current
1605                 next = current;
1606             }
1607             current = -1;
1608             expectedModCount = modCount;
1609         }
1610 
1611         /**
1612          * Find the next value entry in the rehash sequence.
1613          */
1614         private final int findNext(int index) {
1615             final YNode<K,V>[] t = table;
1616             final int lowbitmask = table.length - 1;
1617             index = index & lowbitmask;
1618             int count = 0;
1619             while (!t[index].isValue()) {
1620                 count ++;
1621                 index = (index + REHASH_HASH) & lowbitmask;
1622 		if (index == 0)
1623 		    return -1;
1624             }
1625             return index;
1626         }
1627     }
1628 
1629     final class KeyIterator extends HashIterator
1630             implements Iterator<K> {
1631         public final K next() { return nextNode().getKey(); }
1632     }
1633 
1634     final class ValueIterator extends HashIterator
1635             implements Iterator<V> {
1636         public final V next() { return nextNode().getValue(); }
1637     }
1638 
1639     final class EntryIterator extends HashIterator
1640             implements Iterator<Map.Entry<K,V>> {
1641         public final Map.Entry<K,V> next() { return nextNode(); }
1642     }
1643 
1644     /**
1645      * Reset to initial default state.  Called by clone and readObject.
1646      */
1647     void reinitialize() {
1648         table = null;
1649         entrySet = null;
1650         keySet = null;
1651         values = null;
1652         modCount = 0;
1653         threshold = 0;
1654         size = 0;
1655     }
1656 
1657     // Called only from writeObject, to ensure compatible ordering.
1658     void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
1659         YNode<K,V>[] tab;
1660         if (size > 0 && (tab = table) != null) {
1661             for (YNode<K,V> te : tab) {
1662                 if (te.isValue()) {
1663                     s.writeObject(te.key);
1664                     s.writeObject(te.value);
1665                 }
1666             }
1667         }
1668     }
1669 
1670 
1671     /**
1672      * Check each entry in the table.
1673      *  - FindNode will find it from the key.
1674      *  - the probes value is correct.
1675      */
1676     boolean isTableOk(final YNode<K,V>[] tab, String msg) {
1677         int n;
1678         if (!VERIFYTABLEOK || tab == null || (n = tab.length) == 0)
1679             return true;
1680         boolean ok = true;
1681         int valueEntries = 0;
1682         for (int index = 0; index < tab.length; index++) {
1683             final YNode<K,V> te = tab[index];
1684             if (te.isValue()) {
1685                 valueEntries++;
1686                 if (te.key == this || te.value == this)
1687                     continue;   // skip self referential entries
1688                 int hash = hash(te.key);
1689                 int th = hash(te.key);
1690                 if (th != te.hash) {
1691                     ok = false;
1692                     debug2("ERROR: computed hash not equal stored hash: th: " + th, index, te);
1693                 }
1694 
1695                 int findex = getNode(hash, te.key);
1696                 if (findex < index) {
1697                     ok = false;
1698                     debug2("ERROR: getNode entry not found/found at wrong index: " + findex,
1699                             index , te);
1700                 }
1701                 if (findex >= 0) {
1702                     int h = hash;
1703                     for (int probes = 1; probes <= tab.length; probes++, h += REHASH_HASH) {
1704                         int i = (n - 1) & h;
1705                         if (i == findex) {
1706                             if (probes != te.probes) {
1707                                 ok = false;
1708                                 debug2("ERROR: computed probes not equal recorded " +
1709                                         "probes: " + probes, findex, te);
1710                             }
1711                             break;
1712                         }
1713                         if (probes == 500) {
1714                             debug2("probes > 500: " + probes, findex, te);
1715                         }
1716                     }
1717                 }
1718                 // Check for duplicate entry
1719                 for (int j = index + 1; j < tab.length; j++) {
1720                     if (te.hash == tab[j].hash &&
1721                             te.key.equals(tab[j].key)) {
1722                         debug2("ERROR: YNode at index ", index, te);
1723                         debug2("ERROR: duplicate YNode", j, tab[j]);
1724                     }
1725                 }
1726             }
1727         }
1728         if (valueEntries != size()) {
1729             debug2("ERROR: size wrong: " + valueEntries, size(), new YNode<K,V>());
1730             ok = false;
1731         }
1732         if (!ok) {
1733             if (System.out != null) {
1734                 Thread.dumpStack();
1735                 dumpTable(table, msg);
1736             }
1737         }
1738         return ok;
1739     }
1740 
1741     /**
1742      * Print stats of the table to the a stream.
1743      * @param out a stream
1744      */
1745     public void dumpStats(PrintStream out) {
1746         out.printf("%s instance: size: %d%n", this.getClass().getName(), this.size());
1747         long size = heapSize();
1748         long bytesPer = (this.size != 0) ? size / this.size() : 0;
1749         out.printf("    heap size: %d(bytes), avg bytes per entry: %d, table len: %d%n",
1750                 size, bytesPer, (table != null) ? table.length : 0);
1751         long[] types = entryTypes();
1752         out.printf("    values: %d, empty: %d%n",
1753                 types[0], types[1]);
1754         printStats(out, "hash collisions", entryRehashes());
1755         printStats(out, "getProbes      ", minCounts(getProbes));
1756         printStats(out, "putProbes      ", minCounts(putProbes));
1757         printStats(out, "notFoundProbes ", minCounts(notFoundProbes));
1758 
1759         isTableOk(table, "dumpStats");
1760     }
1761 
1762     private void printStats(PrintStream out, String label, int[] hist) {
1763         if (hist.length > 1) {
1764             out.printf("    %s: max: %d, mean: %3.2f, stddev: %3.2f, %s%n",
1765                     label, hist.length - 1,
1766                     computeMean(hist), computeStdDev(hist),
1767                     Arrays.toString(hist));
1768         } else if (hist.length > 0) {
1769             out.printf("    %s: max: %d, %s%n",
1770                     label, hist.length - 1,
1771                     Arrays.toString(hist));
1772         } else {
1773             out.printf("    %s: n/a%n", label);
1774         }
1775     }
1776 
1777     private double computeStdDev(int[] hist) {
1778         double mean = computeMean(hist);
1779         double sum = 0.0f;
1780         long count = 0L;
1781         for (int i = 1; i < hist.length; i++) {
1782             count += hist[i];
1783             sum += (i - mean) * (i - mean) * hist[i];
1784         }
1785         return Math.sqrt(sum / (count - 1));
1786     }
1787 
1788     private double computeMean(int[] hist) {
1789         long sum = 0L;
1790         long count = 0;
1791         for (int i = 1; i < hist.length; i++) {
1792             count += hist[i];
1793             sum += i * hist[i];
1794         }
1795         return (double)sum / (double)count;
1796     }
1797 
1798     private long[] entryTypes() {
1799         long[] counts = new long[2];
1800         if (table == null)
1801             return counts;
1802         for (YNode<K,V> te : table) {
1803             if (te.isEmpty())
1804                 counts[1]++;
1805             else
1806                 counts[0]++;
1807         }
1808         return counts;
1809     }
1810 
1811     private int[] incProbeCount(int[] counters, int probes) {
1812         if (counters == null)
1813             counters = new int[Math.max(probes + 1, 16)];
1814         else if (probes >= counters.length)
1815             counters = Arrays.copyOf(counters, Math.max(probes + 1, counters.length * 2));
1816         counters[probes]++;
1817         return counters;
1818     }
1819 
1820 
1821     // Returns a histogram array of the number of rehashs needed to find each key.
1822     private int[] entryRehashes() {
1823         if (table == null)
1824             return new int[0];
1825         int[] counts = new int[table.length + 1];
1826         YNode<K,V>[] tab = table;
1827         int n = tab.length;
1828         for (YNode<K,V> te : tab) {
1829 
1830             if (!te.isValue())
1831                 continue;
1832             int h = te.hash;
1833             int count;
1834             final K key = te.key;
1835             K k;
1836             for (count = 1; count < tab.length; count++, h += REHASH_HASH) {
1837                 final YNode<K, V> entry;
1838                 if ((entry = tab[(n - 1) & h]).isValue() &&
1839                         entry.hash == te.hash &&
1840                         ((k = entry.key) == key || (k != null && k.equals(key)))) {
1841                     break;
1842                 }
1843             }
1844 
1845             counts[count]++;
1846         }
1847 
1848         int i;
1849         for (i = counts.length - 1; i >= 0 && counts[i] == 0; i--) {
1850         }
1851         counts = Arrays.copyOf(counts, i + 1);
1852         return counts;
1853     }
1854 
1855     private int[] minCounts(int[] counts) {
1856         int i;
1857         for (i = counts.length - 1; i >= 0 && counts[i] == 0; i--) {
1858         }
1859         counts = Arrays.copyOf(counts, i + 1);
1860         return counts;
1861     }
1862 
1863     private long heapSize() {
1864         long acc = objectSizeMaybe(this);
1865         return acc + objectSizeMaybe(table);
1866     }
1867 
1868     private long objectSizeMaybe(Object o) {
1869         try {
1870             return (mObjectSize != null)
1871                     ? (long)mObjectSize.invoke(null, o)
1872                     : 0L;
1873         } catch (IllegalAccessException | InvocationTargetException e) {
1874             return 0L;
1875         }
1876     }
1877 
1878     private static boolean hasObjectSize = false;
1879     private static Method mObjectSize = getObjectSizeMethod();
1880 
1881     private static Method getObjectSizeMethod() {
1882         try {
1883             Method m = Objects.class.getDeclaredMethod("getObjectSize", Object.class);
1884             hasObjectSize = true;
1885             return m;
1886         } catch (NoSuchMethodException nsme) {
1887             return null;
1888         }
1889     }
1890 
1891 }