1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.collection.HashMap;
13 
14 import hunt.collection.AbstractMap;
15 import hunt.collection.Map;
16 import hunt.collection.Iterator;
17 
18 import hunt.Exceptions;
19 import hunt.Object;
20 import hunt.util.StringBuilder;
21 import hunt.util.ObjectUtils;
22 import hunt.util.Traits;
23 
24 import std.algorithm;
25 import std.conv;
26 import std.format: format;
27 import std.math;
28 import std.range;
29 import std.traits;
30 
31 
32 /**
33  * The maximum capacity, used if a higher value is implicitly specified
34  * by either of the constructors with arguments.
35  * MUST be a power of two <= 1<<30.
36  */
37 private enum int MAXIMUM_CAPACITY = 1 << 30;
38 
39 
40 
41 /**
42  * Computes key.toHash() and spreads (XORs) higher bits of hash
43  * to lower.  Because the table uses power-of-two masking, sets of
44  * hashes that vary only in bits above the current mask will
45  * always collide. (Among known examples are sets of Float keys
46  * holding consecutive whole numbers in small tables.)  So we
47  * apply a transform that spreads the impact of higher bits
48  * downward. There is a tradeoff between speed, utility, and
49  * quality of bit-spreading. Because many common sets of hashes
50  * are already reasonably distributed (so don't benefit from
51  * spreading), and because we use trees to handle large sets of
52  * collisions in bins, we just XOR some shifted bits in the
53  * cheapest possible way to reduce systematic lossage, as well as
54  * to incorporate impact of the highest bits that would otherwise
55  * never be used in index calculations because of table bounds.
56  */
57 package size_t hash(K)(K key) {
58     size_t h;
59     static if(is(K == class)) {
60         return (key is null) ? 0 : (h = key.toHash()) ^ (h >>> 16);
61     }
62     else {
63         h = hashOf(key);
64         return  h ^ (h >>> 16);
65     }
66 }
67 
68 /**
69  * Returns x's Class if it is of the form "class C implements
70  * Comparable<C>", else null.
71  */
72 // static Class<?> comparableClassFor(Object x) {
73 //     if (x instanceof Comparable) {
74 //         Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
75 //         if ((c = x.getClass()) == string.class) // bypass checks
76 //             return c;
77 //         if ((ts = c.getGenericInterfaces()) !is null) {
78 //             for (int i = 0; i < ts.length; ++i) {
79 //                 if (((t = ts[i]) instanceof ParameterizedType) &&
80 //                     ((p = (ParameterizedType)t).getRawType() ==
81 //                      Comparable.class) &&
82 //                     (as = p.getActualTypeArguments()) !is null &&
83 //                     as.length == 1 && as[0] == c) // type arg is c
84 //                     return c;
85 //             }
86 //         }
87 //     }
88 //     return null;
89 // }
90 
91 /**
92  * Returns k.compareTo(x) if x matches kc (k's screened comparable
93  * class), else 0.
94  */
95 //  // for cast to Comparable
96 // static int compareComparables(Class<?> kc, Object k, Object x) {
97 //     return (x is null || x.getClass() != kc ? 0 :
98 //             ((Comparable)k).compareTo(x));
99 // }
100 
101 /**
102  * Returns a power of two size for the given target capacity.
103  */
104 package int tableSizeFor(int cap) {
105     int n = cap - 1;
106     n |= n >>> 1;
107     n |= n >>> 2;
108     n |= n >>> 4;
109     n |= n >>> 8;
110     n |= n >>> 16;
111     return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
112 }
113 
114 /**
115 */
116 class HashMap(K,V) : AbstractMap!(K,V) {
117 
118     // private enum long serialVersionUID = 362498820763181265L;
119 
120     /*
121      * Implementation notes.
122      *
123      * This map usually acts as a binned (bucketed) hash table, but
124      * when bins get too large, they are transformed into bins of
125      * TreeNodes, each structured similarly to those in
126      * java.util.TreeMap. Most methods try to use normal bins, but
127      * relay to TreeNode methods when applicable (simply by checking
128      * instanceof a node).  Bins of TreeNodes may be traversed and
129      * used like any others, but additionally support faster lookup
130      * when overpopulated. However, since the vast majority of bins in
131      * normal use are not overpopulated, checking for existence of
132      * tree bins may be delayed in the course of table methods.
133      *
134      * Tree bins (i.e., bins whose elements are all TreeNodes) are
135      * ordered primarily by toHash, but in the case of ties, if two
136      * elements are of the same "class C implements Comparable<C>",
137      * type then their compareTo method is used for ordering. (We
138      * conservatively check generic types via reflection to validate
139      * this -- see method comparableClassFor).  The added complexity
140      * of tree bins is worthwhile in providing worst-case O(log n)
141      * operations when keys either have distinct hashes or are
142      * orderable, Thus, performance degrades gracefully under
143      * accidental or malicious usages in which toHash() methods
144      * return values that are poorly distributed, as well as those in
145      * which many keys share a toHash, so long as they are also
146      * Comparable. (If neither of these apply, we may waste about a
147      * factor of two in time and space compared to taking no
148      * precautions. But the only known cases stem from poor user
149      * programming practices that are already so slow that this makes
150      * little difference.)
151      *
152      * Because TreeNodes are about twice the size of regular nodes, we
153      * use them only when bins contain enough nodes to warrant use
154      * (see TREEIFY_THRESHOLD). And when they become too small (due to
155      * removal or resizing) they are converted back to plain bins.  In
156      * usages with well-distributed user hashCodes, tree bins are
157      * rarely used.  Ideally, under random hashCodes, the frequency of
158      * nodes in bins follows a Poisson distribution
159      * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
160      * parameter of about 0.5 on average for the default resizing
161      * threshold of 0.75, although with a large variance because of
162      * resizing granularity. Ignoring variance, the expected
163      * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
164      * factorial(k)). The first values are:
165      *
166      * 0:    0.60653066
167      * 1:    0.30326533
168      * 2:    0.07581633
169      * 3:    0.01263606
170      * 4:    0.00157952
171      * 5:    0.00015795
172      * 6:    0.00001316
173      * 7:    0.00000094
174      * 8:    0.00000006
175      * more: less than 1 in ten million
176      *
177      * The root of a tree bin is normally its first node.  However,
178      * sometimes (currently only upon Iterator.remove), the root might
179      * be elsewhere, but can be recovered following parent links
180      * (method TreeNode.root()).
181      *
182      * All applicable internal methods accept a hash code as an
183      * argument (as normally supplied from a method), allowing
184      * them to call each other without recomputing user hashCodes.
185      * Most internal methods also accept a "tab" argument, that is
186      * normally the current table, but may be a new or old one when
187      * resizing or converting.
188      *
189      * When bin lists are treeified, split, or untreeified, we keep
190      * them in the same relative access/traversal order (i.e., field
191      * Node.next) to better preserve locality, and to slightly
192      * simplify handling of splits and traversals that invoke
193      * iterator.remove. When using comparators on insertion, to keep a
194      * total ordering (or as close as is required here) across
195      * rebalancings, we compare classes and identityHashCodes as
196      * tie-breakers.
197      *
198      * The use and transitions among plain vs tree modes is
199      * complicated by the existence of subclass LinkedHashMap. See
200      * below for hook methods defined to be invoked upon insertion,
201      * removal and access that allow LinkedHashMap internals to
202      * otherwise remain independent of these mechanics. (This also
203      * requires that a map instance be passed to some utility methods
204      * that may create new nodes.)
205      *
206      * The concurrent-programming-like SSA-based coding style helps
207      * avoid aliasing errors amid all of the twisty pointer operations.
208      */
209 
210     /**
211      * The default initial capacity - MUST be a power of two.
212      */
213     enum int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
214 
215 
216     /**
217      * The load factor used when none specified in constructor.
218      */
219     enum float DEFAULT_LOAD_FACTOR = 0.75f;
220 
221     /**
222      * The bin count threshold for using a tree rather than list for a
223      * bin.  Bins are converted to trees when adding an element to a
224      * bin with at least this many nodes. The value must be greater
225      * than 2 and should be at least 8 to mesh with assumptions in
226      * tree removal about conversion back to plain bins upon
227      * shrinkage.
228      */
229     enum int TREEIFY_THRESHOLD = 8;
230 
231     /**
232      * The smallest table capacity for which bins may be treeified.
233      * (Otherwise the table is resized if too many nodes in a bin.)
234      * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
235      * between resizing and treeification thresholds.
236      */
237     enum int MIN_TREEIFY_CAPACITY = 64;
238 
239     /* ---------------- Static utilities -------------- */
240 
241 
242     /* ---------------- Fields -------------- */
243 
244     /**
245      * The table, initialized on first use, and resized as
246      * necessary. When allocated, length is always a power of two.
247      * (We also tolerate length zero in some operations to allow
248      * bootstrapping mechanics that are currently not needed.)
249      */
250     HashMapNode!(K,V)[] table;
251 
252     /**
253      * Holds cached entrySet(). Note that AbstractMap fields are used
254      * for keySet() and values().
255      */
256     // Set<MapEntry!(K,V)> entrySet;
257 
258     /**
259      * The number of key-value mappings contained in this map.
260      */
261     // int _size;
262 
263     /**
264      * The number of times this HashMap has been structurally modified
265      * Structural modifications are those that change the number of mappings in
266      * the HashMap or otherwise modify its internal structure (e.g.,
267      * rehash).  This field is used to make iterators on Collection-views of
268      * the HashMap fail-fast.  (See ConcurrentModificationException).
269      */
270     int modCount;
271 
272     /**
273      * The next size value at which to resize (capacity * load factor).
274      *
275      * @serial
276      */
277     // (The javadoc description is true upon serialization.
278     // Additionally, if the table array has not been allocated, this
279     // field holds the initial array capacity, or zero signifying
280     // DEFAULT_INITIAL_CAPACITY.)
281     int threshold;
282 
283     /**
284      * The load factor for the hash table.
285      *
286      * @serial
287      */
288     float loadFactor;
289 
290     /* ---------------- Public operations -------------- */
291 
292     /**
293      * Constructs an empty <tt>HashMap</tt> with the specified initial
294      * capacity and load factor.
295      *
296      * @param  initialCapacity the initial capacity
297      * @param  loadFactor      the load factor
298      * @throws IllegalArgumentException if the initial capacity is negative
299      *         or the load factor is nonpositive
300      */
301     this(int initialCapacity, float loadFactor) {
302         if (initialCapacity < 0)
303             throw new IllegalArgumentException("Illegal initial capacity: " ~
304                                                initialCapacity.to!string());
305         if (initialCapacity > MAXIMUM_CAPACITY)
306             initialCapacity = MAXIMUM_CAPACITY;
307         if (loadFactor <= 0 || isNaN(loadFactor))
308             throw new IllegalArgumentException("Illegal load factor: " ~
309                                                loadFactor.to!string());
310         this.loadFactor = loadFactor;
311         this.threshold = tableSizeFor(initialCapacity);
312     }
313 
314     /**
315      * Constructs an empty <tt>HashMap</tt> with the specified initial
316      * capacity and the default load factor (0.75).
317      *
318      * @param  initialCapacity the initial capacity.
319      * @throws IllegalArgumentException if the initial capacity is negative.
320      */
321     this(int initialCapacity) {
322         this(initialCapacity, DEFAULT_LOAD_FACTOR);
323     }
324 
325     /**
326      * Constructs an empty <tt>HashMap</tt> with the default initial capacity
327      * (16) and the default load factor (0.75).
328      */
329     this() {
330         this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
331     }
332 
333     /**
334      * Constructs a new <tt>HashMap</tt> with the same mappings as the
335      * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
336      * default load factor (0.75) and an initial capacity sufficient to
337      * hold the mappings in the specified <tt>Map</tt>.
338      *
339      * @param   m the map whose mappings are to be placed in this map
340      * @throws  NullPointerException if the specified map is null
341      */
342     this(Map!(K, V) m) {
343         this.loadFactor = DEFAULT_LOAD_FACTOR;
344         putMapEntries(m, false);
345     }
346 
347     this(V[K] m) {
348         this.loadFactor = DEFAULT_LOAD_FACTOR;
349         putMapEntries(m, false);
350     }
351 
352     /**
353      * Implements Map.putAll and Map constructor
354      *
355      * @param m the map
356      * @param evict false when initially constructing this map, else
357      * true (relayed to method afterNodeInsertion).
358      */
359     final void putMapEntries(Map!(K, V) m, bool evict) {
360         assert(m !is null);
361         int s = m.size();
362         if (s > 0) {
363             if (table is null) { // pre-size
364                 float ft = (cast(float)s / loadFactor) + 1.0F;
365                 int t = ((ft < cast(float)MAXIMUM_CAPACITY) ?
366                          cast(int)ft : MAXIMUM_CAPACITY);
367                 if (t > threshold)
368                     threshold = tableSizeFor(t);
369             }
370             else if (s > threshold)
371                 resize();
372             foreach(K key, V value; m) {
373                 putVal(hash(key), key, value, false, evict);
374             }
375         }
376     }
377 
378     final void putMapEntries(V[K] m, bool evict) {
379         int s = cast(int)m.length;
380         if (s > 0) {
381             if (table is null) { // pre-size
382                 float ft = (cast(float)s / loadFactor) + 1.0F;
383                 int t = ((ft < cast(float)MAXIMUM_CAPACITY) ?
384                          cast(int)ft : MAXIMUM_CAPACITY);
385                 if (t > threshold)
386                     threshold = tableSizeFor(t);
387             }
388             else if (s > threshold)
389                 resize();
390             foreach(K key, V value; m) {
391                 putVal(hash(key), key, value, false, evict);
392             }
393         }
394     }
395 
396   
397     /**
398      * Returns the value to which the specified key is mapped,
399      * or {@code null} if this map contains no mapping for the key.
400      *
401      * <p>More formally, if this map contains a mapping from a key
402      * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
403      * key.equals(k))}, then this method returns {@code v}; otherwise
404      * it returns {@code null}.  (There can be at most one such mapping.)
405      *
406      * <p>A return value of {@code null} does not <i>necessarily</i>
407      * indicate that the map contains no mapping for the key; it's also
408      * possible that the map explicitly maps the key to {@code null}.
409      * The {@link #containsKey containsKey} operation may be used to
410      * distinguish these two cases.
411      *
412      * @see #put(Object, Object)
413      */
414     override V get(K key) {
415         HashMapNode!(K, V) e = getNode(hash(key), key);
416         static if(is(V == class) || is(V == interface) || isSomeString!(V)) {
417             return e is null ? V.init : e.value;
418         } else {
419             if(e is null) {
420                 throw new NoSuchElementException(key.to!string());
421             }
422             return e.value;
423         }
424     }
425 
426     /**
427      * Implements Map.get and related methods
428      *
429      * @param hash hash for key
430      * @param key the key
431      * @return the node, or null if none
432      */
433     final HashMapNode!(K, V) getNode(size_t hash, K key) {
434         HashMapNode!(K, V)[] tab; HashMapNode!(K, V) first, e; size_t n; K k;
435         if ((tab = table) !is null && (n = tab.length) > 0 &&
436             (first = tab[(n - 1) & hash]) !is null) {
437             k = first.key;
438             if (first.hash == hash && // always check first node
439                 k == key )
440                 return first;
441             if ((e = first.next) !is null) {
442                 auto tempNode = cast(TreeNode!(K, V))first;
443                 if (tempNode !is null)
444                     return tempNode.getTreeNode(hash, key);
445                 do {
446                     k = e.key;
447                     if (e.hash == hash && k == key)
448                         return e;
449                 } while ((e = e.next) !is null);
450             }
451         }
452         return null;
453     }
454 
455     /**
456      * Returns <tt>true</tt> if this map contains a mapping for the
457      * specified key.
458      *
459      * @param   key   The key whose presence in this map is to be tested
460      * @return <tt>true</tt> if this map contains a mapping for the specified
461      * key.
462      */
463     override bool containsKey(K key) {
464         return getNode(hash(key), key) !is null;
465     }
466 
467     /**
468      * Associates the specified value with the specified key in this map.
469      * If the map previously contained a mapping for the key, the old
470      * value is replaced.
471      *
472      * @param key key with which the specified value is to be associated
473      * @param value value to be associated with the specified key
474      * @return the previous value associated with <tt>key</tt>, or
475      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
476      *         (A <tt>null</tt> return can also indicate that the map
477      *         previously associated <tt>null</tt> with <tt>key</tt>.)
478      */
479     override V put(K key, V value) {
480         return putVal(hash(key), key, value, false, true);
481     }
482 
483     /**
484      * Implements Map.put and related methods
485      *
486      * @param hash hash for key
487      * @param key the key
488      * @param value the value to put
489      * @param onlyIfAbsent if true, don't change existing value
490      * @param evict if false, the table is in creation mode.
491      * @return previous value, or null if none
492      */
493     final V putVal(size_t hash, K key, V value, bool onlyIfAbsent, bool evict) {
494         HashMapNode!(K, V)[] tab; HashMapNode!(K, V) p; 
495         size_t n;
496         if ((tab = table) is null || (n = tab.length) == 0)
497             n = (tab = resize()).length;
498 
499         size_t i = (n - 1) & hash;
500         if ((p = tab[i]) is null) {
501             tab[i] = newNode(hash, key, value, null);
502         }
503         else {
504             HashMapNode!(K, V) e; K k;
505             k = p.key;
506             if (p.hash == hash && k == key)
507                 e = p;
508             else{
509                 TreeNode!(K, V) pp = cast(TreeNode!(K, V))p;
510                 if (pp !is null)
511                     e = pp.putTreeVal(this, tab, hash, key, value);
512                 else {
513                     for (int binCount = 0; ; ++binCount) {
514                         if ((e = p.next) is null) {
515                             p.next = newNode(hash, key, value, null);
516                             if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
517                                 treeifyBin(tab, hash);
518                             break;
519                         }
520                         k = e.key;
521                         if (e.hash == hash && k == key )
522                             break;
523                         p = e;
524                     }
525                 }
526             }
527 
528             if (e !is null) { // existing mapping for key
529                 V oldValue = e.value;
530                 static if( is(V == class)) {
531                     if (!onlyIfAbsent || oldValue is null)
532                         e.value = value;
533                 }
534                 else {
535                     if (!onlyIfAbsent)
536                         e.value = value;
537                 }
538                 afterNodeAccess(e);
539                 return oldValue;
540             }
541         }
542         ++modCount;
543         if (++_size > threshold)
544             resize();
545         afterNodeInsertion(evict);
546         return V.init;                       
547     }
548 
549   
550     /**
551      * Initializes or doubles table size.  If null, allocates in
552      * accord with initial capacity target held in field threshold.
553      * Otherwise, because we are using power-of-two expansion, the
554      * elements from each bin must either stay at same index, or move
555      * with a power of two offset in the new table.
556      *
557      * @return the table
558      */
559     final HashMapNode!(K,V)[] resize() {
560         HashMapNode!(K,V)[] oldTab = table;
561         int oldCap = (oldTab is null) ? 0 : cast(int)oldTab.length;
562         int oldThr = threshold;
563         int newCap, newThr = 0;
564         if (oldCap > 0) {
565             if (oldCap >= MAXIMUM_CAPACITY) {
566                 threshold = int.max;
567                 return oldTab;
568             }
569             else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
570                      oldCap >= DEFAULT_INITIAL_CAPACITY)
571                 newThr = oldThr << 1; // double threshold
572         }
573         else if (oldThr > 0) // initial capacity was placed in threshold
574             newCap = oldThr;
575         else {               // zero initial threshold signifies using defaults
576             newCap = DEFAULT_INITIAL_CAPACITY;
577             newThr = cast(int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
578         }
579         if (newThr == 0) {
580             float ft = cast(float)newCap * loadFactor;
581             newThr = (newCap < MAXIMUM_CAPACITY && ft < cast(float)MAXIMUM_CAPACITY ?
582                       cast(int)ft : int.max);
583         }
584         threshold = newThr;
585 
586         HashMapNode!(K,V)[] newTab = new HashMapNode!(K,V)[newCap];
587         TreeNode!(K,V) ee;
588         table = newTab;
589         if (oldTab !is null) {
590             for (int j = 0; j < oldCap; ++j) {
591                 HashMapNode!(K,V) e;
592                 if ((e = oldTab[j]) !is null) {
593                     oldTab[j] = null;
594                     if (e.next is null)
595                         newTab[e.hash & (newCap - 1)] = e;
596                     else if ((ee = cast(TreeNode!(K,V))e) !is null)
597                         ee.split(this, newTab, j, oldCap);
598                     else { // preserve order
599                         HashMapNode!(K,V) loHead = null, loTail = null;
600                         HashMapNode!(K,V) hiHead = null, hiTail = null;
601                         HashMapNode!(K,V) next;
602                         do {
603                             next = e.next;
604                             if ((e.hash & oldCap) == 0) {
605                                 if (loTail is null)
606                                     loHead = e;
607                                 else
608                                     loTail.next = e;
609                                 loTail = e;
610                             }
611                             else {
612                                 if (hiTail is null)
613                                     hiHead = e;
614                                 else
615                                     hiTail.next = e;
616                                 hiTail = e;
617                             }
618                         } while ((e = next) !is null);
619                         if (loTail !is null) {
620                             loTail.next = null;
621                             newTab[j] = loHead;
622                         }
623                         if (hiTail !is null) {
624                             hiTail.next = null;
625                             newTab[j + oldCap] = hiHead;
626                         }
627                     }
628                 }
629             }
630         }
631         return newTab;
632     }
633 
634     /**
635      * Replaces all linked nodes in bin at index for given hash unless
636      * table is too small, in which case resizes instead.
637      */
638     final void treeifyBin(HashMapNode!(K,V)[] tab, size_t hash) {
639         size_t n, index; HashMapNode!(K,V) e;
640         if (tab is null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
641             resize();
642         else if ((e = tab[index = (n - 1) & hash]) !is null) {
643             TreeNode!(K,V) hd = null, tl = null;
644             do {
645                 TreeNode!(K,V) p = replacementTreeNode(e, null);
646                 if (tl is null)
647                     hd = p;
648                 else {
649                     p.prev = tl;
650                     tl.next = p;
651                 }
652                 tl = p;
653             } while ((e = e.next) !is null);
654             if ((tab[index] = hd) !is null)
655                 hd.treeify(tab);
656         }
657     }
658 
659     /**
660      * Copies all of the mappings from the specified map to this map.
661      * These mappings will replace any mappings that this map had for
662      * any of the keys currently in the specified map.
663      *
664      * @param m mappings to be stored in this map
665      * @throws NullPointerException if the specified map is null
666      */
667     // override void putAll(Map!(K, V) m) {
668     //     putMapEntries(m, true);
669     // }
670 
671     /**
672      * Removes the mapping for the specified key from this map if present.
673      *
674      * @param  key key whose mapping is to be removed from the map
675      * @return the previous value associated with <tt>key</tt>, or
676      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
677      *         (A <tt>null</tt> return can also indicate that the map
678      *         previously associated <tt>null</tt> with <tt>key</tt>.)
679      */
680     override V remove(K key) {
681         HashMapNode!(K,V) e = removeNode(hash(key), key, V.init, false, true);
682         return e is null ? V.init : e.value;
683     }
684 
685     alias remove = AbstractMap!(K, V).remove;
686 
687     /**
688      * Implements Map.remove and related methods
689      *
690      * @param hash hash for key
691      * @param key the key
692      * @param value the value to match if matchValue, else ignored
693      * @param matchValue if true only remove if value is equal
694      * @param movable if false do not move other nodes while removing
695      * @return the node, or null if none
696      */
697     final HashMapNode!(K,V) removeNode(size_t hash, K key, V value,
698                                bool matchValue, bool movable) {
699         HashMapNode!(K,V)[] tab; HashMapNode!(K,V) p; 
700         size_t n, index;
701         if ((tab = table) !is null && (n = tab.length) > 0 &&
702             (p = tab[index = (n - 1) & hash]) !is null) {
703             HashMapNode!(K,V) node = null, e; K k; V v;
704             k = p.key;
705             if (p.hash == hash && k == key )
706                 node = p;
707             else if ((e = p.next) !is null) {
708                 TreeNode!(K,V) pp = cast(TreeNode!(K,V))p;
709                 if (pp !is null)
710                     node = pp.getTreeNode(hash, key);
711                 else {
712                     do {
713                         k = e.key;
714                         if (e.hash == hash && k == key ) {
715                             node = e;
716                             break;
717                         }
718                         p = e;
719                     } while ((e = e.next) !is null);
720                 }
721             }
722             if (node !is null && (!matchValue || (v = node.value) == value)) {
723                 auto _node = cast(TreeNode!(K,V))node;
724                 if (_node !is null)
725                     _node.removeTreeNode(this, tab, movable);
726                 else if (node == p)
727                     tab[index] = node.next;
728                 else
729                     p.next = node.next;
730                 ++modCount;
731                 --_size;
732                 afterNodeRemoval(node);
733                 return node;
734             }
735         }
736         return null;
737     }
738 
739     /**
740      * Removes all of the mappings from this map.
741      * The map will be empty after this call returns.
742      */
743     override void clear() {
744         HashMapNode!(K,V)[] tab;
745         modCount++;
746         if ((tab = table) !is null && size > 0) {
747             _size = 0;
748             for (size_t i = 0; i < tab.length; ++i)
749                 tab[i] = null;
750         }
751     }
752 
753     /**
754      * Returns <tt>true</tt> if this map maps one or more keys to the
755      * specified value.
756      *
757      * @param value value whose presence in this map is to be tested
758      * @return <tt>true</tt> if this map maps one or more keys to the
759      *         specified value
760      */
761     override bool containsValue(V value) {
762         HashMapNode!(K, V)[] tab; V v;
763         if ((tab = table) !is null && size > 0) {
764             for (size_t i = 0; i < tab.length; ++i) {
765                 for (HashMapNode!(K, V) e = tab[i]; e !is null; e = e.next) {
766                     v = e.value;
767                     // if ((v = e.value) == value ||
768                     //     (value !is null && value == v))
769                     if(v == value)
770                         return true;
771                 }
772             }
773         }
774         return false;
775     }
776 
777 
778     /**
779      * Returns a shallow copy of this {@code HashMap} instance: the keys and
780      * values themselves are not cloned.
781      *
782      * @return a shallow copy of this map
783      */
784     mixin CloneMemberTemplate!(typeof(this), TopLevel.no, (typeof(this) from, typeof(this) to) {
785         to.reinitialize();
786         to.putMapEntries(from, false);
787     });
788 
789     /* ------------------------------------------------------------ */
790     // iterators
791 
792     override int opApply(scope int delegate(ref K, ref V) dg) {
793         if(dg is null)
794             throw new NullPointerException();
795         HashMapNode!(K, V)[] tab = table;
796 
797         int result = 0;
798         if(_size > 0 && tab !is null) {
799             int mc = modCount;
800             for(size_t i=0; i<tab.length; i++) {
801                 for(HashMapNode!(K, V) e = tab[i]; e !is null; e = e.next) {
802                     result = dg(e.key, e.value);
803                     if(result != 0) return result;
804                 }
805             }
806 
807             if(modCount != mc)
808                 throw new ConcurrentModificationException();
809         }
810 
811         return result;
812     }
813 
814     override int opApply(scope int delegate(MapEntry!(K, V) entry) dg) {
815         if(dg is null)
816             throw new NullPointerException("");
817         HashMapNode!(K, V)[] tab = table;
818 
819         if(_size <= 0 || tab is null) 
820             return 0;
821         
822         int result = 0;
823         int mc = modCount;
824         for(size_t i=0; i<tab.length; i++) {
825             for(HashMapNode!(K, V) e = tab[i]; e !is null; e = e.next) {
826                 result = dg(e);
827                 if(result != 0) return result;
828             }
829         }
830 
831         if(modCount != mc)
832             throw new ConcurrentModificationException("");
833 
834         return result;
835     }
836 
837 
838     /**
839      * Returns a {@link Set} view of the keys contained in this map.
840      * The set is backed by the map, so changes to the map are
841      * reflected in the set, and vice-versa.  If the map is modified
842      * while an iteration over the set is in progress (except through
843      * the iterator's own <tt>remove</tt> operation), the results of
844      * the iteration are undefined.  The set supports element removal,
845      * which removes the corresponding mapping from the map, via the
846      * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
847      * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
848      * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
849      * operations.
850      *
851      * @return a set view of the keys contained in this map
852      */
853     override InputRange!K byKey() {
854         return new KeyInputRange();
855     }
856 
857     override InputRange!V byValue() {
858         return new ValueInputRange();
859     }
860     
861     
862     mixin template HashIterator() {
863         protected HashMapNode!(K, V) next;        // next entry to return
864         protected HashMapNode!(K, V) current;     // current entry
865         protected int expectedModCount;  // for fast-fail
866         protected int index;             // current slot
867 
868         this() {
869             expectedModCount = modCount;
870             HashMapNode!(K, V)[] t = table;
871             next = null;
872             index = 0;
873             if (t !is null && size > 0) { // advance to first entry
874                 do {} while (index < t.length && (next = t[index++]) is null);
875             }
876             current = next;
877         }
878 
879         final bool empty() {
880             return next is null;
881         }
882 
883         void popFront() {
884             HashMapNode!(K, V)[] t;
885             HashMapNode!(K, V) e = next;
886             if (modCount != expectedModCount)
887                 throw new ConcurrentModificationException();
888             if (e is null)
889                 throw new NoSuchElementException();
890             if ((next = (current = e).next) is null && (t = table) !is null) {
891                 do {} while (index < t.length && (next = t[index++]) is null);
892             }
893         }
894     }
895 
896     final class KeyInputRange : InputRange!K {
897         mixin HashIterator;
898 
899         final K front() @property { return next.key; }
900 
901         // https://forum.dlang.org/thread/amzthhonuozlobghqqgk@forum.dlang.org?page=1
902         // https://issues.dlang.org/show_bug.cgi?id=18036
903         final K moveFront() @property { throw new NotSupportedException(); }
904         
905         int opApply(scope int delegate(K) dg) {
906             if(dg is null)
907                 throw new NullPointerException("");
908 
909             if(_size <= 0 || table is null) 
910                 return 0;
911             
912             HashMapNode!(K, V)[] tab = table;
913             int result = 0;
914             int mc = modCount;
915             for(size_t i=0; i<tab.length; i++) {
916                 for(HashMapNode!(K, V) e = tab[i]; e !is null; e = e.next) {
917                     result = dg(e.key);
918                     if(result != 0) return result;
919                 }
920             }
921 
922             if(modCount != mc)
923                 throw new ConcurrentModificationException("");
924 
925             return result;
926         }
927 
928         int opApply(scope int delegate(size_t, K) dg) {
929             if(dg is null)
930                 throw new NullPointerException("");
931                 
932             if(_size <= 0 || table is null) 
933                 return 0;
934             
935             HashMapNode!(K, V)[] tab = table;
936             int result = 0;
937             int mc = modCount;            
938             size_t index = 0;
939 
940             for(size_t i=0; i<tab.length; i++) {
941                 for(HashMapNode!(K, V) e = tab[i]; e !is null; e = e.next) {
942                     result = dg(index++, e.key);
943                     if(result != 0) return result;
944                 }
945             }
946 
947             if(modCount != mc)
948                 throw new ConcurrentModificationException("");
949 
950             return result;
951         }
952     }
953     
954     final class ValueInputRange :  InputRange!V {
955         mixin HashIterator;
956 
957         final V front() @property { return next.value; }
958 
959         final V moveFront() @property { throw new NotSupportedException(); }
960         
961         int opApply(scope int delegate(V) dg) {
962             if(dg is null)
963                 throw new NullPointerException("No handler avaliable");
964 
965             if(_size <= 0 || table is null) 
966                 return 0;
967             
968             HashMapNode!(K, V)[] tab = table;
969             int result = 0;
970             int mc = modCount;
971             for(size_t i=0; i<tab.length; i++)
972             {
973                 for(HashMapNode!(K, V) e = tab[i]; e !is null; e = e.next)
974                 {
975                     result = dg(e.value);
976                     if(result != 0) return result;
977                 }
978             }
979 
980             if(modCount != mc)
981                 throw new ConcurrentModificationException("");
982 
983             return result;
984         }
985 
986         int opApply(scope int delegate(size_t, V) dg) {
987             if(dg is null)
988                 throw new NullPointerException("");
989                 
990             if(_size <= 0 || table is null) 
991                 return 0;
992             
993             HashMapNode!(K, V)[] tab = table;
994             int result = 0;
995             int mc = modCount;
996             size_t index = 0;
997             for(size_t i=0; i<tab.length; i++) {
998                 for(HashMapNode!(K, V) e = tab[i]; e !is null; e = e.next)
999                 {
1000                     result = dg(index++, e.value);
1001                     if(result != 0) return result;
1002                 }
1003             }
1004 
1005             if(modCount != mc)
1006                 throw new ConcurrentModificationException("");
1007 
1008             return result;
1009         }
1010     }
1011 
1012     /* ------------------------------------------------------------ */
1013     // LinkedHashMap support
1014 
1015     /*
1016      * The following package-protected methods are designed to be
1017      * overridden by LinkedHashMap, but not by any other subclass.
1018      * Nearly all other internal methods are also package-protected
1019      * but are declared final, so can be used by LinkedHashMap, view
1020      * classes, and HashSet.
1021      */
1022 
1023     // Create a regular (non-tree) node
1024     HashMapNode!(K,V) newNode(size_t hash, K key, V value, HashMapNode!(K,V) next) {
1025         return new HashMapNode!(K,V)(hash, key, value, next);
1026     }
1027 
1028     // For conversion from TreeNodes to plain nodes
1029     HashMapNode!(K,V) replacementNode(HashMapNode!(K,V) p, HashMapNode!(K,V) next) {
1030         return new HashMapNode!(K,V)(p.hash, p.key, p.value, next);
1031     }
1032 
1033     // Create a tree bin node
1034     TreeNode!(K,V) newTreeNode(size_t hash, K key, V value, HashMapNode!(K,V) next) {
1035         return new TreeNode!(K,V)(hash, key, value, next);
1036     }
1037 
1038     // For treeifyBin
1039     TreeNode!(K,V) replacementTreeNode(HashMapNode!(K,V) p, HashMapNode!(K,V) next) {
1040         return new TreeNode!(K,V)(p.hash, p.key, p.value, next);
1041     }
1042 
1043     /**
1044      * Reset to initial default state.  Called by clone and readObject.
1045      */
1046     void reinitialize() {
1047         table = null;
1048         // entrySet = null;
1049         // _keySet = null;
1050         // _values = null;
1051         modCount = 0;
1052         threshold = 0;
1053         _size = 0;
1054     }
1055 
1056     // Callbacks to allow LinkedHashMap post-actions
1057     void afterNodeAccess(HashMapNode!(K,V) p) { }
1058     void afterNodeInsertion(bool evict) { }
1059     void afterNodeRemoval(HashMapNode!(K,V) p) { }
1060 
1061     // Called only from writeObject, to ensure compatible ordering.
1062     // void internalWriteEntries(java.io.ObjectOutputStream s) {
1063     //     HashMapNode!(K,V)[] tab;
1064     //     if (size > 0 && (tab = table) !is null) {
1065     //         for (int i = 0; i < tab.length; ++i) {
1066     //             for (HashMapNode!(K,V) e = tab[i]; e !is null; e = e.next) {
1067     //                 s.writeObject(e.key);
1068     //                 s.writeObject(e.value);
1069     //             }
1070     //         }
1071     //     }
1072     // }
1073   
1074 }
1075 
1076 /* ------------------------------------------------------------ */
1077 // Tree bins
1078 
1079 /**
1080  * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
1081  * extends Node) so can be used as extension of either regular or
1082  * linked node.
1083  */
1084 final class TreeNode(K, V) : LinkedHashMapEntry!(K, V) {
1085 
1086     /**
1087      * The bin count threshold for untreeifying a (split) bin during a
1088      * resize operation. Should be less than TREEIFY_THRESHOLD, and at
1089      * most 6 to mesh with shrinkage detection under removal.
1090      */
1091     enum int UNTREEIFY_THRESHOLD = 6;
1092 
1093     TreeNode!(K, V) parent;  // red-black tree links
1094     TreeNode!(K, V) left;
1095     TreeNode!(K, V) right;
1096     TreeNode!(K, V) prev;    // needed to unlink next upon deletion
1097     bool red;
1098 
1099     this(size_t hash, K key, V val, HashMapNode!(K, V) next) {
1100         super(hash, key, val, next);
1101     }
1102 
1103     /**
1104      * Returns root of tree containing this node.
1105      */
1106     final TreeNode!(K, V) root() {
1107         for (TreeNode!(K, V) r = this, p;;) {
1108             if ((p = r.parent) is null)
1109                 return r;
1110             r = p;
1111         }
1112     }
1113 
1114     /**
1115      * Ensures that the given root is the first node of its bin.
1116      */
1117     static void moveRootToFront(K, V)(HashMapNode!(K, V)[] tab, TreeNode!(K, V) root) {
1118         size_t n;
1119         if (root !is null && tab !is null && (n = tab.length) > 0) {
1120             size_t index = (n - 1) & root.hash;
1121             TreeNode!(K, V) first = cast(TreeNode!(K, V))tab[index];
1122             if (root != first) {
1123                 HashMapNode!(K, V) rn;
1124                 tab[index] = root;
1125                 TreeNode!(K, V) rp = root.prev;
1126                 if ((rn = root.next) !is null)
1127                     (cast(TreeNode!(K, V))rn).prev = rp;
1128                 if (rp !is null)
1129                     rp.next = rn;
1130                 if (first !is null)
1131                     first.prev = root;
1132                 root.next = first;
1133                 root.prev = null;
1134             }
1135             assert(checkInvariants(root));
1136         }
1137     }
1138 
1139     /**
1140      * Finds the node starting at root p with the given hash and key.
1141      * The kc argument caches comparableClassFor(key) upon first use
1142      * comparing keys.
1143      */
1144     final TreeNode!(K, V) find(size_t h, K k) {
1145         TreeNode!(K, V) p = this;
1146         do {
1147             size_t ph; int dir; K pk;
1148             TreeNode!(K, V) pl = p.left, pr = p.right, q;
1149             if ((ph = p.hash) > h)
1150                 p = pl;
1151             else if (ph < h)
1152                 p = pr;
1153             else {
1154                 pk = p.key;
1155                 if (pk == k)
1156                     return p;
1157                 else if (pl is null)
1158                     p = pr;
1159                 else if (pr is null)
1160                     p = pl;
1161                 else {
1162                     // static if(isNumeric!(K)) { dir = std.math.cmp(cast(float)k, cast(float)pk); }
1163                     // else { dir = std.algorithm.cmp(k, pk); }    
1164 
1165                     // if (dir != 0)
1166                     //     p = (dir < 0) ? pl : pr;
1167                     // else if ((q = pr.find(h, k)) !is null)
1168                     //     return q;
1169                     // else
1170                     //     p = pl;
1171                     if(k < pk) 
1172                         p = pl;
1173                     else if( k>pk) 
1174                         p = pr;
1175                     else if ((q = pr.find(h, k)) !is null)
1176                         return q;
1177                     else
1178                         p = pl; 
1179                 }
1180             } 
1181         } while (p !is null);
1182         return null;
1183     }
1184 
1185     /**
1186      * Calls find for root node.
1187      */
1188     final TreeNode!(K, V) getTreeNode(size_t h, K k) {
1189         return ((parent !is null) ? root() : this).find(h, k);
1190     }
1191 
1192     /**
1193      * Tie-breaking utility for ordering insertions when equal
1194      * hashCodes and non-comparable. We don't require a total
1195      * order, just a consistent insertion rule to maintain
1196      * equivalence across rebalancings. Tie-breaking further than
1197      * necessary simplifies testing a bit.
1198      */
1199     static int tieBreakOrder(T)(T a, T b) if(isBasicType!(T) || isSomeString!T || isByteArray!T) {
1200         return (hashOf(a) <= hashOf(b) ? -1 : 1);
1201     }
1202 
1203     static int tieBreakOrder(T)(T a, T b) if(is(T == class) || is(T == interface)) {
1204         int d = 0;
1205         if (a is null || b is null  ||
1206             (d = std.algorithm.cmp(typeid(a).name, 
1207                 typeid(b).name)) == 0)
1208             d = ((cast(Object)a).toHash() <= (cast(Object)b).toHash() ? -1 : 1);
1209         return d;
1210     }
1211 
1212     static int tieBreakOrder(T)(T a, T b) if(is(T == struct)) {
1213         int d = std.algorithm.cmp(typeid(a).name,
1214                 typeid(b).name);
1215         if (d == 0)
1216             d = (a.toHash() <= b.toHash() ? -1 : 1);
1217         return d;
1218     }
1219 
1220     /**
1221      * Forms tree of the nodes linked from this node.
1222      * @return root of tree
1223      */
1224     final void treeify(HashMapNode!(K, V)[] tab) {
1225         TreeNode!(K, V) root = null;
1226         for (TreeNode!(K, V) x = this, next; x !is null; x = next) {
1227             next = cast(TreeNode!(K, V))x.next;
1228             x.left = x.right = null;
1229             if (root is null) {
1230                 x.parent = null;
1231                 x.red = false;
1232                 root = x;
1233             }
1234             else {
1235                 K k = x.key;
1236                 size_t h = x.hash;
1237                 for (TreeNode!(K, V) p = root;;) {
1238                     size_t dir, ph;
1239                     K pk = p.key;
1240                     if ((ph = p.hash) > h)
1241                         dir = -1;
1242                     else if (ph < h)
1243                         dir = 1;
1244                     else {
1245                         // static if(isNumeric!(K)) { dir = std.math.cmp(cast(float)k, cast(float)pk); }
1246                         // else { dir = std.algorithm.cmp(k, pk); }
1247                         if (k == pk)
1248                             dir = tieBreakOrder!(K)(k, pk);
1249                         else if(k > pk)
1250                             dir = 1;
1251                         else 
1252                             dir = -1;
1253                     }
1254 
1255                     TreeNode!(K, V) xp = p;
1256                     if ((p = (dir <= 0) ? p.left : p.right) is null) {
1257                         x.parent = xp;
1258                         if (dir <= 0)
1259                             xp.left = x;
1260                         else
1261                             xp.right = x;
1262                         root = balanceInsertion(root, x);
1263                         break;
1264                     }
1265                 }
1266             }
1267         }
1268         moveRootToFront(tab, root);
1269     }
1270 
1271     /**
1272      * Returns a list of non-TreeNodes replacing those linked from
1273      * this node.
1274      */
1275     final HashMapNode!(K, V) untreeify(HashMap!(K, V) map) {
1276         HashMapNode!(K, V) hd = null, tl = null;
1277         for (HashMapNode!(K, V) q = this; q !is null; q = q.next) {
1278             HashMapNode!(K, V) p = map.replacementNode(q, null);
1279             if (tl is null)
1280                 hd = p;
1281             else
1282                 tl.next = p;
1283             tl = p;
1284         }
1285         return hd;
1286     }
1287 
1288     /**
1289      * Tree version of putVal.
1290      */
1291     final TreeNode!(K, V) putTreeVal(HashMap!(K, V) map, HashMapNode!(K, V)[] tab,
1292                                    size_t h, K k, V v) {
1293         // Class<?> kc = null;
1294         bool searched = false;
1295         TreeNode!(K, V) root = (parent !is null) ? root() : this;
1296         for (TreeNode!(K, V) p = root;;) {
1297             size_t ph; K pk; int dir;
1298 
1299             if ((ph = p.hash) > h)
1300                 dir = -1;
1301             else if (ph < h)
1302                 dir = 1;
1303             else {
1304                 pk = p.key;
1305                 if (pk == k)
1306                     return p;
1307                 else {
1308                     // static if(isNumeric!(K)) { dir = std.math.cmp(cast(float)k, cast(float)pk); }
1309                     // else { dir = std.algorithm.cmp(k, pk); }
1310 
1311                     if(k == pk) {
1312                         if (!searched) {
1313                             TreeNode!(K, V) q, ch;
1314                             searched = true;
1315                             if (((ch = p.left) !is null &&
1316                                 (q = ch.find(h, k)) !is null) ||
1317                                 ((ch = p.right) !is null &&
1318                                 (q = ch.find(h, k)) !is null))
1319                                 return q;
1320                         }
1321                         dir = tieBreakOrder!(K)(k, pk);
1322                     } else if(k > pk)
1323                         dir = 1;
1324                     else
1325                         dir = -1;
1326                 }
1327             }
1328 
1329             TreeNode!(K, V) xp = p;
1330             if ((p = (dir <= 0) ? p.left : p.right) is null) {
1331                 HashMapNode!(K, V) xpn = xp.next;
1332                 TreeNode!(K, V) x = map.newTreeNode(h, k, v, xpn);
1333                 if (dir <= 0)
1334                     xp.left = x;
1335                 else
1336                     xp.right = x;
1337                 xp.next = x;
1338                 x.parent = x.prev = xp;
1339                 if (xpn !is null)
1340                     (cast(TreeNode!(K, V))xpn).prev = x;
1341                 moveRootToFront(tab, balanceInsertion(root, x));
1342                 return null;
1343             }
1344         }
1345     }
1346 
1347     /**
1348      * Removes the given node, that must be present before this call.
1349      * This is messier than typical red-black deletion code because we
1350      * cannot swap the contents of an interior node with a leaf
1351      * successor that is pinned by "next" pointers that are accessible
1352      * independently during traversal. So instead we swap the tree
1353      * linkages. If the current tree appears to have too few nodes,
1354      * the bin is converted back to a plain bin. (The test triggers
1355      * somewhere between 2 and 6 nodes, depending on tree structure).
1356      */
1357     final void removeTreeNode(HashMap!(K, V) map, HashMapNode!(K, V)[] tab,
1358                               bool movable) {
1359         size_t n;
1360         if (tab is null || (n = tab.length) == 0)
1361             return;
1362         size_t index = (n - 1) & hash;
1363         TreeNode!(K, V) first = cast(TreeNode!(K, V))tab[index], root = first, rl;
1364         TreeNode!(K, V) succ = cast(TreeNode!(K, V))next, pred = prev;
1365         if (pred is null)
1366             tab[index] = first = succ;
1367         else
1368             pred.next = succ;
1369         if (succ !is null)
1370             succ.prev = pred;
1371         if (first is null)
1372             return;
1373         if (root.parent !is null)
1374             root = root.root();
1375         if (root is null || root.right is null ||
1376             (rl = root.left) is null || rl.left is null) {
1377             tab[index] = first.untreeify(map);  // too small
1378             return;
1379         }
1380         TreeNode!(K, V) p = this, pl = left, pr = right, replacement;
1381         if (pl !is null && pr !is null) {
1382             TreeNode!(K, V) s = pr, sl;
1383             while ((sl = s.left) !is null) // find successor
1384                 s = sl;
1385             bool c = s.red; s.red = p.red; p.red = c; // swap colors
1386             TreeNode!(K, V) sr = s.right;
1387             TreeNode!(K, V) pp = p.parent;
1388             if (s == pr) { // p was s's direct parent
1389                 p.parent = s;
1390                 s.right = p;
1391             }
1392             else {
1393                 TreeNode!(K, V) sp = s.parent;
1394                 if ((p.parent = sp) !is null) {
1395                     if (s == sp.left)
1396                         sp.left = p;
1397                     else
1398                         sp.right = p;
1399                 }
1400                 if ((s.right = pr) !is null)
1401                     pr.parent = s;
1402             }
1403             p.left = null;
1404             if ((p.right = sr) !is null)
1405                 sr.parent = p;
1406             if ((s.left = pl) !is null)
1407                 pl.parent = s;
1408             if ((s.parent = pp) is null)
1409                 root = s;
1410             else if (p == pp.left)
1411                 pp.left = s;
1412             else
1413                 pp.right = s;
1414             if (sr !is null)
1415                 replacement = sr;
1416             else
1417                 replacement = p;
1418         }
1419         else if (pl !is null)
1420             replacement = pl;
1421         else if (pr !is null)
1422             replacement = pr;
1423         else
1424             replacement = p;
1425         if (replacement != p) {
1426             TreeNode!(K, V) pp = replacement.parent = p.parent;
1427             if (pp is null)
1428                 root = replacement;
1429             else if (p == pp.left)
1430                 pp.left = replacement;
1431             else
1432                 pp.right = replacement;
1433             p.left = p.right = p.parent = null;
1434         }
1435 
1436         TreeNode!(K, V) r = p.red ? root : balanceDeletion(root, replacement);
1437 
1438         if (replacement == p) {  // detach
1439             TreeNode!(K, V) pp = p.parent;
1440             p.parent = null;
1441             if (pp !is null) {
1442                 if (p == pp.left)
1443                     pp.left = null;
1444                 else if (p == pp.right)
1445                     pp.right = null;
1446             }
1447         }
1448         if (movable)
1449             moveRootToFront(tab, r);
1450     }
1451 
1452     /**
1453      * Splits nodes in a tree bin into lower and upper tree bins,
1454      * or untreeifies if now too small. Called only from resize;
1455      * see above discussion about split bits and indices.
1456      *
1457      * @param map the map
1458      * @param tab the table for recording bin heads
1459      * @param index the index of the table being split
1460      * @param bit the bit of hash to split on
1461      */
1462     final void split(HashMap!(K, V) map, HashMapNode!(K, V)[] tab, int index, int bit) {
1463         TreeNode!(K, V) b = this;
1464         // Relink into lo and hi lists, preserving order
1465         TreeNode!(K, V) loHead = null, loTail = null;
1466         TreeNode!(K, V) hiHead = null, hiTail = null;
1467         int lc = 0, hc = 0;
1468         for (TreeNode!(K, V) e = b, next; e !is null; e = next) {
1469             next = cast(TreeNode!(K, V))e.next;
1470             e.next = null;
1471             if ((e.hash & bit) == 0) {
1472                 if ((e.prev = loTail) is null)
1473                     loHead = e;
1474                 else
1475                     loTail.next = e;
1476                 loTail = e;
1477                 ++lc;
1478             }
1479             else {
1480                 if ((e.prev = hiTail) is null)
1481                     hiHead = e;
1482                 else
1483                     hiTail.next = e;
1484                 hiTail = e;
1485                 ++hc;
1486             }
1487         }
1488 
1489         if (loHead !is null) {
1490             if (lc <= UNTREEIFY_THRESHOLD)
1491                 tab[index] = loHead.untreeify(map);
1492             else {
1493                 tab[index] = loHead;
1494                 if (hiHead !is null) // (else is already treeified)
1495                     loHead.treeify(tab);
1496             }
1497         }
1498         if (hiHead !is null) {
1499             if (hc <= UNTREEIFY_THRESHOLD)
1500                 tab[index + bit] = hiHead.untreeify(map);
1501             else {
1502                 tab[index + bit] = hiHead;
1503                 if (loHead !is null)
1504                     hiHead.treeify(tab);
1505             }
1506         }
1507     }
1508 
1509     /* ------------------------------------------------------------ */
1510     // Red-black tree methods, all adapted from CLR
1511 
1512     static TreeNode!(K, V) rotateLeft(K, V)(TreeNode!(K, V) root,
1513                                           TreeNode!(K, V) p) {
1514         TreeNode!(K, V) r, pp, rl;
1515         if (p !is null && (r = p.right) !is null) {
1516             if ((rl = p.right = r.left) !is null)
1517                 rl.parent = p;
1518             if ((pp = r.parent = p.parent) is null)
1519                 (root = r).red = false;
1520             else if (pp.left == p)
1521                 pp.left = r;
1522             else
1523                 pp.right = r;
1524             r.left = p;
1525             p.parent = r;
1526         }
1527         return root;
1528     }
1529 
1530     static TreeNode!(K, V) rotateRight(K, V)(TreeNode!(K, V) root,
1531                                            TreeNode!(K, V) p) {
1532         TreeNode!(K, V) l, pp, lr;
1533         if (p !is null && (l = p.left) !is null) {
1534             if ((lr = p.left = l.right) !is null)
1535                 lr.parent = p;
1536             if ((pp = l.parent = p.parent) is null)
1537                 (root = l).red = false;
1538             else if (pp.right == p)
1539                 pp.right = l;
1540             else
1541                 pp.left = l;
1542             l.right = p;
1543             p.parent = l;
1544         }
1545         return root;
1546     }
1547 
1548     static TreeNode!(K, V) balanceInsertion(K, V)(TreeNode!(K, V) root,
1549                                                 TreeNode!(K, V) x) {
1550         x.red = true;
1551         for (TreeNode!(K, V) xp, xpp, xppl, xppr;;) {
1552             if ((xp = x.parent) is null) {
1553                 x.red = false;
1554                 return x;
1555             }
1556             else if (!xp.red || (xpp = xp.parent) is null)
1557                 return root;
1558             if (xp == (xppl = xpp.left)) {
1559                 if ((xppr = xpp.right) !is null && xppr.red) {
1560                     xppr.red = false;
1561                     xp.red = false;
1562                     xpp.red = true;
1563                     x = xpp;
1564                 }
1565                 else {
1566                     if (x == xp.right) {
1567                         root = rotateLeft(root, x = xp);
1568                         xpp = (xp = x.parent) is null ? null : xp.parent;
1569                     }
1570                     if (xp !is null) {
1571                         xp.red = false;
1572                         if (xpp !is null) {
1573                             xpp.red = true;
1574                             root = rotateRight(root, xpp);
1575                         }
1576                     }
1577                 }
1578             }
1579             else {
1580                 if (xppl !is null && xppl.red) {
1581                     xppl.red = false;
1582                     xp.red = false;
1583                     xpp.red = true;
1584                     x = xpp;
1585                 }
1586                 else {
1587                     if (x == xp.left) {
1588                         root = rotateRight(root, x = xp);
1589                         xpp = (xp = x.parent) is null ? null : xp.parent;
1590                     }
1591                     if (xp !is null) {
1592                         xp.red = false;
1593                         if (xpp !is null) {
1594                             xpp.red = true;
1595                             root = rotateLeft(root, xpp);
1596                         }
1597                     }
1598                 }
1599             }
1600         }
1601     }
1602 
1603     static TreeNode!(K, V) balanceDeletion(K, V)(TreeNode!(K, V) root,
1604                                                TreeNode!(K, V) x) {
1605         for (TreeNode!(K, V) xp, xpl, xpr;;)  {
1606             if (x is null || x == root)
1607                 return root;
1608             else if ((xp = x.parent) is null) {
1609                 x.red = false;
1610                 return x;
1611             }
1612             else if (x.red) {
1613                 x.red = false;
1614                 return root;
1615             }
1616             else if ((xpl = xp.left) == x) {
1617                 if ((xpr = xp.right) !is null && xpr.red) {
1618                     xpr.red = false;
1619                     xp.red = true;
1620                     root = rotateLeft(root, xp);
1621                     xpr = (xp = x.parent) is null ? null : xp.right;
1622                 }
1623                 if (xpr is null)
1624                     x = xp;
1625                 else {
1626                     TreeNode!(K, V) sl = xpr.left, sr = xpr.right;
1627                     if ((sr is null || !sr.red) &&
1628                         (sl is null || !sl.red)) {
1629                         xpr.red = true;
1630                         x = xp;
1631                     }
1632                     else {
1633                         if (sr is null || !sr.red) {
1634                             if (sl !is null)
1635                                 sl.red = false;
1636                             xpr.red = true;
1637                             root = rotateRight(root, xpr);
1638                             xpr = (xp = x.parent) is null ?
1639                                 null : xp.right;
1640                         }
1641                         if (xpr !is null) {
1642                             xpr.red = (xp is null) ? false : xp.red;
1643                             if ((sr = xpr.right) !is null)
1644                                 sr.red = false;
1645                         }
1646                         if (xp !is null) {
1647                             xp.red = false;
1648                             root = rotateLeft(root, xp);
1649                         }
1650                         x = root;
1651                     }
1652                 }
1653             }
1654             else { // symmetric
1655                 if (xpl !is null && xpl.red) {
1656                     xpl.red = false;
1657                     xp.red = true;
1658                     root = rotateRight(root, xp);
1659                     xpl = (xp = x.parent) is null ? null : xp.left;
1660                 }
1661                 if (xpl is null)
1662                     x = xp;
1663                 else {
1664                     TreeNode!(K, V) sl = xpl.left, sr = xpl.right;
1665                     if ((sl is null || !sl.red) &&
1666                         (sr is null || !sr.red)) {
1667                         xpl.red = true;
1668                         x = xp;
1669                     }
1670                     else {
1671                         if (sl is null || !sl.red) {
1672                             if (sr !is null)
1673                                 sr.red = false;
1674                             xpl.red = true;
1675                             root = rotateLeft(root, xpl);
1676                             xpl = (xp = x.parent) is null ?
1677                                 null : xp.left;
1678                         }
1679                         if (xpl !is null) {
1680                             xpl.red = (xp is null) ? false : xp.red;
1681                             if ((sl = xpl.left) !is null)
1682                                 sl.red = false;
1683                         }
1684                         if (xp !is null) {
1685                             xp.red = false;
1686                             root = rotateRight(root, xp);
1687                         }
1688                         x = root;
1689                     }
1690                 }
1691             }
1692         }
1693     }
1694 
1695     /**
1696      * Recursive invariant check
1697      */
1698     static bool checkInvariants(K, V)(TreeNode!(K, V) t) {
1699         TreeNode!(K, V) tp = t.parent, tl = t.left, tr = t.right,
1700             tb = t.prev, tn = cast(TreeNode!(K, V))t.next;
1701         if (tb !is null && tb.next != t)
1702             return false;
1703         if (tn !is null && tn.prev != t)
1704             return false;
1705         if (tp !is null && t != tp.left && t != tp.right)
1706             return false;
1707         if (tl !is null && (tl.parent != t || tl.hash > t.hash))
1708             return false;
1709         if (tr !is null && (tr.parent != t || tr.hash < t.hash))
1710             return false;
1711         if (t.red && tl !is null && tl.red && tr !is null && tr.red)
1712             return false;
1713         if (tl !is null && !checkInvariants(tl))
1714             return false;
1715         if (tr !is null && !checkInvariants(tr))
1716             return false;
1717         return true;
1718     }
1719 }
1720 
1721     
1722 /**
1723 * Basic hash bin node, used for most entries.  (See below for
1724 * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
1725 */
1726 class HashMapNode(K, V) : AbstractMapEntry!(K,V) {
1727     package size_t hash;
1728     package HashMapNode!(K, V) next;
1729 
1730     this(size_t hash, K key, V value, HashMapNode!(K, V) next) {
1731         super(key, value);
1732         this.hash = hash;
1733         this.next = next;
1734     }
1735 }
1736 
1737 
1738 /**
1739 * HashMap.Node subclass for normal LinkedHashMap entries.
1740 */
1741 class LinkedHashMapEntry(K, V) : HashMapNode!(K, V) {
1742     LinkedHashMapEntry!(K, V) before, after;
1743 
1744     this(size_t hash, K key, V value, HashMapNode!(K, V) next) {
1745         super(hash, key, value, next);
1746     }
1747 }