001package Torello.Java.Additional;
002
003import java.util.*;
004
005import java.util.function.BiConsumer;
006
007/**
008 * A great class, heavily used by the Java Doc Upgrader Tool, that extends Java's
009 * <CODE>TreeMap</CODE> class to eliminate "Least Recently Used" elements from the 
010 * Map, <I>effectively creating an <CODE>'in-memory cache'</CODE> for the tool.</I>
011 * 
012 * <EMBED CLASS='external-html' DATA-FILE-ID=LRUTREEMAP>
013 * 
014 * @param <K> This is the type for the map {@code 'key'}.  It should be thought of as
015 * identical to the {@code java.util.TreeMap} type-parameter {@code 'K'}
016 * 
017 * @param <V> This is the type used by the map for {@code 'value'}.  It should be thought of as
018 * identical to the {@code java.util.TreeMap} type-parameter {@code 'V'}
019 */
020public class LRUTreeMap<K, V> extends TreeMap<K, V>
021{
022    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
023    protected static final long serialVersionUID = 1;
024
025    // ********************************************************************************************
026    // ********************************************************************************************
027    // INHERITED FROM: java.util.TreeMap - THESE WORK JUST-FINE, NO @Override NEEDED
028    // ********************************************************************************************
029    // ********************************************************************************************
030
031
032    // public int size()
033
034    // public Comparator<? super K> comparator()
035
036    // public Set<K> keySet();
037
038    // public NavigableSet<K> navigableKeySet()
039
040    // public NavigableSet<K> descendingKeySet()
041
042    // public Collection<V> values()
043
044    // public Set<Map.Entry<K,V>> entrySet()
045
046    // public NavigableMap<K,V> descendingMap()
047
048    // public NavigableMap<K,V> subMap
049    //   (K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
050
051    // public NavigableMap<K,V> headMap(K toKey, boolean inclusive)
052
053    // public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive)
054
055    // public SortedMap<K,V> subMap(K fromKey, K toKey)
056
057    // public SortedMap<K,V> headMap(K toKey)
058
059    // public SortedMap<K,V> tailMap(K fromKey)
060
061    // public void replaceAll(BiFunction<? super K,? super V,? extends V> function)
062    
063
064    // ********************************************************************************************
065    // ********************************************************************************************
066    // LRUTreeMaps "Helper Class" - Keeps Track of each Tree-Node's "Place In Line"
067    // ********************************************************************************************
068    // ********************************************************************************************
069
070
071    // This just keeps track of which Key-Value Pairs are the Least-Recently-Used (and of course)
072    // The Most-Recently-Used
073    private final class LRUTreeMaps
074    {
075        // Each TreeMap has TWO INTERNAL "Place In Line" TreeMap's
076        // 
077        // NOTE-ABOUT-EFFICIENCY: This class was developed for use with the EmbedTag's of the
078        // "Java Doc Upgrader" package.  These two additional TreeMap's do not create additional
079        // keys, just references to keys.  Furthermore, even if a "Reference to Key" was a real
080        // memory-hog (which it isn't, a 'refernce' is just a 'long'), the Key's themselves are
081        // all 8-character String's
082        //
083        // The values in this map are 1,000 - 2,000 node long html-page vectors.  These can be
084        // quite memory-intensive.  Holding more than 500 of them might slow Java down to an
085        // "unusable state".  In any case, only the "Keys" are saved multiple times (not the
086        // web-pages, and furthermore, only a **REFERENCE** to the keys are saved multiple times)
087
088        // A TreeMap that can be queried using the "Key" (the same "Key") that the real OUTER
089        // "Real" TreeMap is using.  This is just a "Mirror"   We need this because the OUTER
090        // tree map is pruned when it grows larger than MAX_NUM_ELEMENTS.
091        private final TreeMap<K, Integer> keyToPlaceInLine = new TreeMap<>();
092        private final TreeMap<Integer, K> placeInLineToKey = new TreeMap<>();
093
094        // The "Place In Line" is just the value in this counterLRU.  This counter is incremented
095        // every single time that it is assigned to a key-value pair.
096        private int counterLRU = 0;
097
098        final void added(K key)
099        {
100            Integer possiblyNullPreviousPlaceInLine = keyToPlaceInLine.put(key, counterLRU);
101            placeInLineToKey.put(counterLRU, key);
102            counterLRU++;
103
104            if (possiblyNullPreviousPlaceInLine != null)
105                placeInLineToKey.remove(possiblyNullPreviousPlaceInLine);
106
107            // NOTE: .size() is an OUTER TREE-MAP METHOD-REFERENCE
108            else if (size() > MAX_NUM_ELEMENTS)
109            {
110                // This is difficult to read.
111                //
112                // 1) 'pollFirstEntry' removes *AND* returns the key/place-in-line combo from the
113                //    first of the two Queue-Information TreeMap's
114                // 2) Therefore: 'beingRemoved' has the 'key' (saved as the value), and the
115                //    'place-in-line' saved as the key.  This needs to be removed from the second
116                //    of the two Queue-Information TreeMap's
117
118                Map.Entry<Integer, K>   beingRemoved    = placeInLineToKey.pollFirstEntry();
119                K                       keyBeingRemoved = beingRemoved.getValue();
120
121                // 'placeInLineToKey' has had this 'key' removed, *NOW* (here) the
122                // 'keyToPlaceInLine' will be purged of this key.
123
124                keyToPlaceInLine.remove(keyBeingRemoved);
125
126                // Make a call to the **OUTER-CLASS*, We just eliminated the "Place In Line"
127                // Queue-TreeMap's (of which there are TWO).  The last thing is to remove the
128                // key-value from the actual (Main) TreeMap - the one the user has.
129                //
130                // THIS MEAS: if we call the usual (outer-class) 'remove' method, it would remove
131                //            the key from the main TreeMap - AND THEN try to remove the
132                //            'place-in-line' information AGAIN!  (What was just done in the
133                //            previous lines)
134                //
135                // INSTEAD:   a method "removeINTERNAL" is being built.
136
137                // System.out.println("Removig [" + keyBeingRemoved + "] from LRUTreeMap");
138
139                removeINTERNAL(keyBeingRemoved);
140            }
141        }
142
143        final void removed(K key)
144        { placeInLineToKey.remove(keyToPlaceInLine.remove(key)); }
145
146        final void changed(K key)
147        {
148            // System.out.println("Changed: " + key);
149            Integer previousPlaceInLine = keyToPlaceInLine.put(key, counterLRU);
150
151            placeInLineToKey.remove(previousPlaceInLine);
152            placeInLineToKey.put(counterLRU, key);
153
154            counterLRU++;
155        }
156
157        final void clear()
158        {
159            placeInLineToKey.clear();
160            keyToPlaceInLine.clear();
161        }
162
163        final int trimToFit()
164        {
165            int numExtra = size() - MAX_NUM_ELEMENTS;
166    
167            if (numExtra <= 0) return 0;
168
169            // If you read it - 'descendingMap' is sort-of *LINKED* to the map from which it
170            // originated.  When you remove something from the descending map, you also remove
171            // from the original map from which it was created.
172
173            NavigableMap<Integer, K> entriesToRemove = placeInLineToKey.descendingMap();
174
175            while (numExtra-- > 0)
176                keyToPlaceInLine.remove(entriesToRemove.pollFirstEntry().getValue());
177
178            // This is how many elements were removed
179            return numExtra;
180        }
181    }
182
183
184    // ********************************************************************************************
185    // ********************************************************************************************
186    // LRUTreeMap: This class extends "TreeMap" - **AND** These are the methods being added
187    // ********************************************************************************************
188    // ********************************************************************************************
189
190
191    // This one is only used above, once.
192    private void removeINTERNAL(Object key) { super.remove(key); }
193
194    /**
195     * Keeps a record of the <I>'Ordering of Use'</I> for the elements in {@code 'this'} map.  The
196     * values stored here are set by a counter that increases with each use.
197     */
198    protected LRUTreeMaps mapLRU = new LRUTreeMaps();
199
200    /**
201     * This is, literally, the maximum number of Key-Value pairs allowed into this instance of
202     * {@code LRUTreeMap}.  When an insert or {@code 'put'} operation is made after the tree has
203     * reached this maximum size, it will remove the oldest element in the tree, first, before
204     * inserting the new addition(s)j.
205     */
206    protected int MAX_NUM_ELEMENTS;
207
208    /**
209     * This merely retrieves the value stored in {@link #MAX_NUM_ELEMENTS}.
210     * 
211     * @return The maximum number of elements allowed in this tree before it begins discarding
212     * Key-Value Pairs.
213     */
214    public int getMaxNumElements() { return this.MAX_NUM_ELEMENTS; }
215
216    /**
217     * Sets a new value for the maximum number of elements allowed into this tree.  If this number
218     * is smaller than the current size of the tree, then the oldest elements will be removed until
219     * the tree has a {@code size()} smaller than the value of {@code 'maxNumElements'}
220     * 
221     * @param maxNumElements This is thee new maximum allowable size for this {@code LRUTreeMap}
222     * instance.
223     * 
224     * @return The number of elements that had to be removed from this tree in order to adhere to
225     * this new size-specifier.  {@code '0'} is returned if no elements were removed.
226     * 
227     * @throws IllegalArgumentException The value provided to {@code 'maxNumElements'} must be
228     * at least {@code '3'}, or this exception throws.
229     */
230    public int setMaxNumElements(int maxNumElements)
231    {
232        CHECK_MAX_NUM_ELEMENTS(maxNumElements);
233
234        this.MAX_NUM_ELEMENTS = maxNumElements;
235
236        // No elements need to be removed from the tree.
237        if (this.size() <= maxNumElements) return 0;
238
239        // Returns how many elements were removed.
240        return mapLRU.trimToFit();
241    }
242
243    private void CHECK_NEW_MAP_SIZE(int mapSize)
244    {
245        if (mapSize > this.MAX_NUM_ELEMENTS) throw new IllegalArgumentException(
246            "The size of the 'map' provided is [" + mapSize + "], unfortunately this is " +
247            "greater than 'maxNumElements' [" + this.MAX_NUM_ELEMENTS + ']'
248        );
249    }
250
251    private void CHECK_MAX_NUM_ELEMENTS(int maxNumElements)
252    {
253        if (maxNumElements < 3) throw new IllegalArgumentException(
254            "The value provided to 'maxNumElements' [" + maxNumElements + "] must be greater " +
255            "than 2"
256        );
257    }
258    
259
260    // ********************************************************************************************
261    // ********************************************************************************************
262    // The Usual TreeMap Constructors - Copied from JDK 'java.util.TreeMap'
263    // ********************************************************************************************
264    // ********************************************************************************************
265
266
267    /**
268     * Constructs a new, empty tree map, using the <I>natural ordering</I> of its keys. All keys
269     * inserted into the map must implement the interface {@code 'Comparable'}. Furthermore, all
270     * such keys must be mutually comparable: {@code k1.compareTo(k2)}, and must not throw a
271     * {@code ClassCastException} for any keys k1 and k2 in the map. If the user attempts to put
272     * a key into the map that violates this constraint (for example, the user attempts to put a
273     * string key into a map whose keys are integers), the {@code put(Object key, Object value)}
274     * call will throw a {@code ClassCastException}.
275     * 
276     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
277     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
278     * 
279     * @param maxNumElements The maximum allowable number of elements that may be inserted into
280     * {@code 'this'} tree before older elements are discarded.
281     */
282    public LRUTreeMap(int maxNumElements)
283    {
284        super();
285
286        CHECK_MAX_NUM_ELEMENTS(maxNumElements);
287
288        this.MAX_NUM_ELEMENTS = maxNumElements;
289    }
290
291    /**
292     * Constructs a new, empty tree map, ordered according to the given comparator. All keys
293     * inserted into the map must be mutually comparable by the given comparator:
294     * {@code comparator.compare(k1, k2)}, must not throw a {@code ClassCastException} for any keys
295     * k1 and k2 in the map. If the user attempts to put a key into the map that violates this
296     * constraint, the {@code put(Object key, Object value)}
297     * call will throw a {@code ClassCastException}.
298     * 
299     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
300     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
301     * 
302     * @param comparator the {@code java.util.Comparator} that will be used to order {@code 'this'}
303     * map. If null, the <I>natural ordering</I> of the keys will be used.
304     * 
305     * @param maxNumElements The maximum allowable number of elements that may be inserted into
306     * {@code 'this'} tree before older elements are discarded.
307     */
308    public LRUTreeMap(Comparator<? super K> comparator, int maxNumElements)
309    {
310        super(comparator);
311
312        CHECK_MAX_NUM_ELEMENTS(maxNumElements);
313
314        this.MAX_NUM_ELEMENTS = maxNumElements;
315    }
316
317    /**
318     * Constructs a new tree map containing the same mappings as the given map, ordered according
319     * to the <I>natural ordering</I> of its keys. All keys inserted into the new map must
320     * implement the interface {@code 'Comparable'}. Furthermore, all such keys must be mutually
321     * comparable: {@code k1.compareTo(k2)} must not throw a {@code ClassCastException} for any
322     * keys k1 and k2 in the map. This method runs in <B>{@code n * log(n)}</B> time.
323     * 
324     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
325     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
326     * 
327     * @param m the map whose mappings are to be placed in {@code 'this'} map
328     * 
329     * @param maxNumElements The maximum allowable number of elements that may be inserted into
330     * {@code 'this'} tree before older elements are discarded.
331     * 
332     * @throws ClassCastException if the keys in {@code m} are not Comparable, or are not mutually
333     * comparable
334     * 
335     * @throws NullPointerException if the specified map is null
336     */
337    public LRUTreeMap(Map<? extends K,? extends V> m, int maxNumElements)
338    {
339        super(m);
340
341        // Brief Check to make sure that 'maxNumElements' is at least 3 (and non-negative)
342        CHECK_MAX_NUM_ELEMENTS(maxNumElements);
343
344        this.MAX_NUM_ELEMENTS = maxNumElements;
345
346        // Throws if map.size() is greater than MAX_NUM_ELEMENTS
347        CHECK_NEW_MAP_SIZE(m.size());
348
349        for (K key : m.keySet()) mapLRU.added(key);
350    }
351
352    /**
353     * Constructs a new tree map containing the same mappings and using the same ordering as the
354     * specified sorted map. This method runs in linear time.
355     * 
356     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
357     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
358     * 
359     * @param m the sorted map whose mappings are to be placed in {@code 'this'} map, and whose
360     * {@code Comparator} is to be used to sort {@code 'this'} map
361     * 
362     * @param maxNumElements The maximum allowable number of elements that may be inserted into
363     * {@code 'this'} tree before older elements are discarded.
364     * 
365     * @throws NullPointerException if the specified map is null
366     */
367    public LRUTreeMap(SortedMap<K,? extends V> m, int maxNumElements)
368    {
369        super(m);
370
371        // Brief Check to make sure that 'maxNumElements' is at least 3 (and non-negative)
372        CHECK_MAX_NUM_ELEMENTS(maxNumElements);
373
374        this.MAX_NUM_ELEMENTS = maxNumElements;
375
376        // Throws if map.size() is greater than MAX_NUM_ELEMENTS
377        CHECK_NEW_MAP_SIZE(m.size());
378
379        for (K key : m.keySet()) mapLRU.added(key);
380    }
381
382
383    // ********************************************************************************************
384    // ********************************************************************************************
385    // The Usual TreeMap Methods - Copied from JDK 'java.util.TreeMap'
386    // ********************************************************************************************
387    // ********************************************************************************************
388
389
390    /**
391     * Returns {@code TRUE} if {@code 'this'} map contains a mapping for the specified
392     * {@code 'key'}.
393     * 
394     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
395     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
396     * 
397     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
398     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
399     * 
400     * @param key key whose presence in {@code 'this'} map is to be tested
401     * 
402     * @return {@code TRUE} if {@code 'this'} map contains a mapping for the specified {@code 'key'}
403     * 
404     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
405     * currently in {@code 'this'} map
406     * 
407     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
408     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
409     */
410    @SuppressWarnings("unchecked") // If the map contains "key", it must have been of type "K"
411    public boolean containsKey(Object key)
412    {
413        boolean ret = super.containsKey(key);
414
415        // Change the time-stamp-counter for 'key' (if it was present)
416        // It is now the 'Most Recently Used'
417
418        if (ret) this.mapLRU.changed((K) key);
419
420        return ret;
421    }
422
423    /**
424     * Returns {@code TRUE} if {@code 'this'} map maps one or more keys to the specified
425     * {@code 'value'}. More formally, returns {@code TRUE} if and only if {@code 'this'} map
426     * contains at least one mapping to a value v such that {@code (value==null ? v==null :
427     * value.equals(v))}.
428     * 
429     * <BR /><BR />This operation will probably require time linear in the map size for most
430     * implementations.
431     * 
432     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
433     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
434     * 
435     * @param value value whose presence in {@code 'this'} map is to be tested
436     * 
437     * @return {@code TRUE} if a mapping to value exists; {@code FALSE} otherwise
438     */
439    public boolean containsValue(Object value)
440    {
441        for (Map.Entry<K, V> entry : this.entrySet())
442            if (value.equals(entry.getValue()))
443            {
444                // Change the time-stamp-counter for 'entry.key'
445                // These are all now the 'Most Recently Used' keys
446                //
447                // NOTE: The counter-value assigned to each key is in order consistent with the
448                //       the order of the entries returned by the iterator.
449
450                this.mapLRU.changed(entry.getKey());
451                return true;
452            }
453
454        return false;
455    }
456
457    /**
458     * Returns the value to which the specified {@code 'key'} is mapped, or null if {@code 'this'}
459     * map contains no mapping for the {@code 'key'}.  More formally, if {@code 'this'} map
460     * contains a mapping from a key {@code k} to a value {@code v} such that {@code 'key'}
461     * compares equal to {@code k} according to the map's ordering, then this method returns
462     * {@code v}; otherwise it returns null. (There can be at most one such mapping.)
463     *
464     * <BR /><BR />A return value of null does not necessarily indicate that the map contains no
465     * mapping for the {@code 'key'}; it's also possible that the map explicitly maps the
466     * {@code 'key'} to null. The {@code 'containsKey'} operation may be used to distinguish these
467     * two cases.
468     * 
469     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
470     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
471     * 
472     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
473     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
474     *
475     * @param key the key whose associated value is to be returned
476     * 
477     * @return the value to which the specified {@code 'key'} is mapped, or null if
478     * {@code 'this'} map contains no mapping for the {@code 'key'}
479     * 
480     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
481     * currently in {@code 'this'} map
482     * 
483     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
484     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
485     */
486    @SuppressWarnings("unchecked") // If the map contains "key", it must have been of type "K"
487    public V get(Object key)
488    {
489        V ret = super.get(key);
490
491        // Change the time-stamp-counter for 'key' (if it was present)
492        // It is now the 'Most Recently Used'
493
494        if (ret != null) mapLRU.changed((K) key);
495
496        return ret;
497    }
498
499    /**
500     * Returns the first (lowest) key currently in {@code 'this'} map.
501     * 
502     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
503     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
504     * 
505     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
506     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
507     * 
508     * @return the first (lowest) key currently in {@code 'this'} map
509     * 
510     * @throws NoSuchElementException if {@code 'this'} map is empty
511     */
512    public K firstKey()
513    {
514        K ret = super.firstKey();
515
516        // Change the time-stamp-counter for 'first-key' (if present) before returning it.
517        // It is now the 'Most Recently Used'
518
519        if (ret != null) mapLRU.changed(ret);
520
521        return ret;
522    }
523
524    /**
525     * Returns the last (highest) key currently in {@code 'this'} map.
526     * 
527     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
528     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
529     * 
530     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
531     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
532     * 
533     * @return the last (highest) key currently in {@code 'this'} map
534     * 
535     * @throws NoSuchElementException if {@code 'this'} map is empty
536     */
537    public K lastKey()
538    {
539        K ret = super.lastKey();
540
541        // Change the time-stamp-counter for 'last-key' (if present) before returning it.
542        // It is now the 'Most Recently Used'
543
544        if (ret != null) mapLRU.changed(ret);
545
546        return ret;    
547    }
548
549    /**
550     * Copies all of the mappings from the specified {@code 'map'} to {@code 'this'} map. These
551     * mappings replace any mappings that {@code 'this'} map had for any of the keys currently in
552     * the specified {@code 'map'}.
553     * 
554     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
555     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
556     * 
557     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
558     * <I>overridden method</I>, the internal LRU-Counter is updated.
559     * 
560     * @param map mappings to be stored in {@code 'this'} map
561     * 
562     * @throws ClassCastException if the class of a key or value in the specified map prevents it
563     * from being stored in {@code 'this'} map
564     * 
565     * @throws NullPointerException if the specified map is null or the specified map contains a
566     * null key and {@code 'this'} map does not permit null keys
567     */
568    public void putAll(Map<? extends K,? extends V> map)
569    {
570        // Throws if map.size() is greater than MAX_NUM_ELEMENTS
571        CHECK_NEW_MAP_SIZE(map.size());
572
573        super.putAll(map);
574
575        // Add all of the entries in 'map' into the (Internal) LRU-Counter class
576        for (K key : map.keySet()) this.mapLRU.added(key);
577
578        if (this.size() > this.MAX_NUM_ELEMENTS) mapLRU.trimToFit();
579    }
580
581    /**
582     * Associates the specified {@code value} with the specified {@code key} in {@code 'this'} map.
583     * If the map previously contained a mapping for the {@code 'key'}, the old value is replaced.
584     * 
585     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
586     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
587     * 
588     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
589     * <I>overridden method</I>, the internal LRU-Counter is updated.
590     *
591     * @param key key with which the specified {@code 'value'} is to be associated
592     * 
593     * @param value value to be associated with the specified {@code 'key'}
594     * 
595     * @return the previous value associated with {@code 'key'}, or null if there was no mapping
596     * for {@code 'key'}. (A null return can also indicate that the map previously associated
597     * null with key.)
598     * 
599     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
600     * currently in {@code 'this'} map
601     * 
602     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
603     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
604     */
605    public V put(K key, V value)
606    {
607        V ret = super.put(key, value);
608
609        // Add this 'key' into the (Internal) LRU-Counter class
610        this.mapLRU.added(key);
611
612        return ret;
613    }
614
615    /**
616     * Removes the mapping for this {@code 'key'} from {@code 'this' TreeMap} if present.
617     * 
618     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
619     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
620     * 
621     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
622     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
623     * 
624     * @param key key for which mapping should be removed
625     * 
626     * @return the previous value associated with {@code 'key'}, or null if there was no mapping
627     * for {@code 'key'}. (A null return can also indicate that the map previously associated null
628     * with {@code 'key'}.)
629     * 
630     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
631     * currently in {@code 'this'} map
632     * 
633     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
634     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
635     */
636    @SuppressWarnings("unchecked") // If the map contained "key", that key must have been type "K"
637    public V remove(Object key)
638    {
639        V ret = super.remove(key);
640
641        // Remove this 'key' from the (Internal) LRU-Counter class, if it was present.
642        if (ret != null) this.mapLRU.removed((K) key);
643
644        return ret;
645    }
646
647    /**
648     * Removes all of the mappings from {@code 'this'} map. The map will be empty after this call
649     * returns.
650     * 
651     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
652     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
653     * 
654     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
655     * <I>overridden method</I>, the internal LRU-Counter is updated.
656     */
657    public void clear()
658    { super.clear(); this.mapLRU.clear(); }
659
660    /**
661     * Returns a shallow copy of this {@code LRUTreeMap} instance. (The keys and values themselves
662     * are not cloned.)
663     * 
664     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
665     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
666     * 
667     * @return a shallow copy of {@code 'this'} map
668     */
669    public Object clone()
670    { return new LRUTreeMap<K, V>(this, this.MAX_NUM_ELEMENTS); }
671
672    /**
673     * Returns a key-value mapping associated with the least key in {@code 'this'} map, or null if
674     * the map is empty.
675     * 
676     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
677     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
678     * 
679     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
680     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
681     * 
682     * @return an entry with the least key, or null if {@code 'this'} map is empty
683     */
684    public Map.Entry<K,V> firstEntry()
685    {
686        Map.Entry<K, V> ret = super.firstEntry();
687
688        // Change the time-stamp-counter for 'first-key' before returning it.
689        // It is now the 'Most Recently Used'
690        //
691        // NOTE: The (internal) mapLRU only needs to watch the 'key', not the 'key-value' pair.
692
693        if (ret != null) this.mapLRU.changed(ret.getKey());
694
695        return ret;
696    }
697
698    /**
699     * Returns a key-value mapping associated with the greatest key in {@code 'this'} map, or
700     * null if the map is empty.
701     * 
702     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
703     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
704     * 
705     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
706     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
707     * 
708     * @return an entry with the greatest key, or null if {@code 'this'} map is empty
709     */
710    public Map.Entry<K,V> lastEntry()
711    {
712        Map.Entry<K, V> ret = super.lastEntry();
713
714        // Change the time-stamp-counter for 'last-key' before returning it.
715        // It is now the 'Most Recently Used'
716        //
717        // NOTE: The (internal) mapLRU only needs to watch the 'key', not the 'key-value' pair.
718
719        if (ret != null) this.mapLRU.changed(ret.getKey());
720
721        return ret;
722    }
723
724    /**
725     * Removes and returns a key-value mapping associated with the least key in {@code 'this'} map,
726     * or null if the map is empty.
727     * 
728     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
729     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
730     * 
731     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
732     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
733     * 
734     * @return the removed first entry of {@code 'this'} map, or null if {@code 'this'} map is
735     * empty
736     */
737    public Map.Entry<K,V> pollFirstEntry()
738    {
739        Map.Entry<K, V> ret = super.pollFirstEntry();
740
741        // If there was a 'first key', it was just removed from the TreeMap
742        // Make sure to remove it from the (internal) LRU-Counter class
743
744        if (ret != null) this.mapLRU.removed(ret.getKey());
745
746        return ret;
747    }
748
749    /**
750     * Removes and returns a key-value mapping associated with the greatest key in this
751     * map, or null if the map is empty.
752     * 
753     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
754     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
755     * 
756     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
757     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
758     * 
759     * @return the removed last entry of {@code 'this'} map, or null if {@code 'this'} map is empty
760     */
761    public Map.Entry<K,V> pollLastEntry()
762    {
763        Map.Entry<K, V> ret = super.pollLastEntry();
764
765        // If there was a 'last key', it was just removed from the TreeMap
766        // Make sure to remove it from the (internal) LRU-Counter class
767
768        if (ret != null) this.mapLRU.removed(ret.getKey());
769
770        return ret;
771    }
772
773    /**
774     * Returns a key-value mapping associated with the greatest key strictly less than the
775     * given {@code 'key'}, or null if there is no such key.
776     * 
777     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
778     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
779     * 
780     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
781     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
782     * 
783     * @param key the key
784     * 
785     * @return an entry with the greatest key less than {@code 'key'}, or null if there is no such
786     * key
787     * 
788     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
789     * currently in the map
790     * 
791     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
792     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
793     */
794    public Map.Entry<K,V> lowerEntry(K key)
795    {
796        Map.Entry<K, V> ret = super.lowerEntry(key);
797
798        // Change the time-stamp-counter for the lower-entry 'key' (if there is one)
799        // before returning it.   It is now the 'Most Recently Used'
800
801        if (ret != null) this.mapLRU.changed(ret.getKey());
802
803        return ret;
804    }
805
806    /**
807     * Returns the greatest key strictly less than the given {@code 'key'}, or null if there is no
808     * such key.
809     * 
810     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
811     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
812     * 
813     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
814     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
815     * 
816     * @param key the key
817     * 
818     * @return the greatest key less than {@code 'key'}, or null if there is no such key
819     * 
820     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
821     * currently in {@code 'this'} map
822     * 
823     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
824     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
825     */
826    public K lowerKey(K key)
827    {
828        K ret = super.lowerKey(key);
829
830        // Change the time-stamp-counter for the lower-key (if there is one)
831        // before returning it.   It is now the 'Most Recently Used'
832
833        if (ret != null) this.mapLRU.changed(ret);
834
835        return ret;    
836    }
837
838    /**
839     * Returns a key-value mapping associated with the greatest key less than or equal to the
840     * given {@code 'key'}, or null if there is no such key.
841     * 
842     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
843     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
844     * 
845     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
846     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
847     * 
848     * @param key the key
849     * 
850     * @return an entry with the greatest key less than or equal to {@code 'key'}, or null if there
851     * is no such key
852     * 
853     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
854     * currently in {@code 'this'} map
855     * 
856     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
857     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
858     */
859    public Map.Entry<K,V> floorEntry(K key)
860    {
861        Map.Entry<K, V> ret = super.floorEntry(key);
862
863        // Change the time-stamp-counter for the 'key' of the floor-entry (if there is one)
864        // before returning it.   It is now the 'Most Recently Used'
865
866        if (ret != null) this.mapLRU.changed(ret.getKey());
867
868        return ret;
869    }
870
871    /**
872     * Returns the greatest key less than or equal to the given {@code 'key'}, or null if there is
873     * no such key.
874     * 
875     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
876     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
877     * 
878     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
879     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
880     * 
881     * @param key the key
882     * 
883     * @return the greatest key less than or equal to {@code 'key'}, or null if there is no such
884     * key
885     * 
886     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
887     * currently in the map
888     * 
889     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
890     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
891     */
892    public K floorKey(K key)
893    {
894        K ret = super.floorKey(key);
895
896        // Change the time-stamp-counter for the floor-key (if there is one)
897        // before returning it.   It is now the 'Most Recently Used'
898
899        if (ret != null) this.mapLRU.changed(ret);
900
901        return ret;
902    }
903
904    /**
905     * Returns a key-value mapping associated with the least key greater than or equal to
906     * the given {@code 'key'}, or null if there is no such key.
907     * 
908     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
909     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
910     * 
911     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
912     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
913     * 
914     * @param key the key
915     * 
916     * @return an entry with the least key greater than or equal to {@code 'key'}, or null if
917     * there is no such key
918     * 
919     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
920     * currently in the map
921     * 
922     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
923     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
924     */
925    public Map.Entry<K,V> ceilingEntry(K key)
926    {
927        Map.Entry<K, V> ret = super.ceilingEntry(key);
928
929        // Change the time-stamp-counter for the 'key' of the ceiling-entry (if there is one)
930        // before returning it.   It is now the 'Most Recently Used'
931
932        if (ret != null) this.mapLRU.changed(ret.getKey());
933
934        return ret;
935    }
936
937    /**
938     * Returns the least key greater than or equal to the given {@code 'key'}, or null if there is
939     * no such key.
940     * 
941     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
942     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
943     * 
944     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
945     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
946     * 
947     * @param key the key
948     * 
949     * @return the least key greater than or equal to {@code 'key'}, or null if there is no such
950     * key
951     * 
952     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
953     * currently in the map
954     * 
955     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
956     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
957     */
958    public K ceilingKey(K key)
959    {
960        K ret = super.ceilingKey(key);
961
962        // Change the time-stamp-counter for the ceiling-key (if there is one)
963        // before returning it.   It is now the 'Most Recently Used'
964
965        if (ret != null) this.mapLRU.changed(ret);
966
967        return ret;
968    }
969
970    /**
971     * Returns a key-value mapping associated with the least key strictly greater than the
972     * given {@code 'key'}, or null if there is no such key.
973     * 
974     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
975     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
976     * 
977     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
978     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
979     * 
980     * @param key the key
981     * 
982     * @return an entry with the least key greater than key, or null if there is no such key
983     * 
984     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
985     * currently in the map
986     * 
987     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
988     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
989     */
990    public Map.Entry<K,V> higherEntry(K key)
991    {
992        Map.Entry<K, V> ret = super.higherEntry(key);
993
994        // Change the time-stamp-counter for the 'key' of the higher-entry (if there is one)
995        // before returning it.   It is now the 'Most Recently Used'
996
997        if (ret != null) this.mapLRU.changed(ret.getKey());
998
999        return ret;
1000    }
1001
1002    /**
1003     * Returns the least key strictly greater than the given {@code 'key'}, or null if
1004     * there is no such key.
1005     * 
1006     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
1007     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
1008     * 
1009     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
1010     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
1011     * 
1012     * @param key the key
1013     * 
1014     * @return the least key greater than {@code 'key'}, or null if there is no such key
1015     * 
1016     * @throws ClassCastException if the specified {@code 'key'} cannot be compared with the keys
1017     * currently in {@code 'this'} map
1018     * 
1019     * @throws NullPointerException if the specified {@code 'key'} is null and {@code 'this'} map
1020     * uses <I>natural ordering</I>, or its {@code Comparator} does not permit null keys
1021     */
1022    public K higherKey(K key)
1023    {
1024        K ret = super.higherKey(key);
1025
1026        // Change the time-stamp-counter for the higher-key (if there is one)
1027        // before returning it.   It is now the 'Most Recently Used'
1028
1029        if (ret != null) this.mapLRU.changed(ret);
1030
1031        return ret;
1032    }
1033
1034    /**
1035     * Replaces the entry for the specified {@code 'key'} only if currently mapped to the specified
1036     * {@code 'value'}.
1037     * 
1038     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
1039     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
1040     * 
1041     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
1042     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
1043     * 
1044     * @param key key with which the specified {@code 'value'} is associated
1045     * @param oldValue value expected to be associated with the specified {@code 'key'}
1046     * @param newValue value to be associated with the specified {@code 'key'}
1047     * 
1048     * @return {@code TRUE} if the value was replaced
1049     */
1050    public boolean replace(K key, V oldValue, V newValue)
1051    {
1052        boolean ret = super.replace(key, oldValue, newValue);
1053
1054        // Change the time-stamp-counter for 'key' - if-and-only-if it was present and it mapped
1055        // to 'oldValue'
1056        // If both of these conditions were met, then it is now the 'Most Recently Used'
1057
1058        if (ret) this.mapLRU.changed(key);
1059
1060        return ret;
1061    }
1062
1063    /**
1064     * Replaces the entry for the specified {@code 'key'} only if it is currently mapped to some
1065     * value.
1066     * 
1067     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
1068     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
1069     * 
1070     * <BR /><B STYLE='color:red'>UPDATES:</B> After invoking the {@code 'super'} of this
1071     * <I>overridden method</I>, the internal LRU-Counter is updated, if necessary.
1072     * 
1073     * @param key key with which the specified {@code 'value'} is associated
1074     * @param value value to be associated with the specified {@code 'key'}
1075     *
1076     * @return the previous value associated with the specified {@code 'key'}, or null if there was
1077     * no mapping for the {@code 'key'}. (A null return can also indicate that the map previously
1078     * associated null with the key, if the implementation supports null values.)
1079     */
1080    public V replace(K key, V value)
1081    {
1082        V ret = super.replace(key, value);
1083
1084        // Change the time-stamp-counter for 'key' - if-and-only-if it was present and mapped
1085        // to any value.
1086        // If it was, then it is now the 'Most Recently Used'
1087
1088        if (ret != null) this.mapLRU.changed(key);
1089
1090        if (this.size() > this.MAX_NUM_ELEMENTS) this.mapLRU.trimToFit();
1091
1092        return ret;
1093    }
1094
1095    /**
1096     * Performs the given action for each entry in {@code 'this'} map until all entries have been
1097     * processed or the action throws an exception. Unless otherwise specified by the implementing
1098     * class, actions are performed in the order of entry set iteration (if an iteration order is
1099     * specified.) Exceptions thrown by the action are relayed to the caller.
1100     * 
1101     * <BR /><BR /><SPAN CLASS=CopiedJDK>Description copied from class:
1102     * {@code java.util.TreeMap<K, V>}, <B>JDK 1.8</B></SPAN>
1103     * 
1104     * @param action The action to be performed for each entry
1105     */
1106    public void forEach(BiConsumer<? super K,? super V> action)
1107    {
1108        super.forEach(action);
1109
1110        // No need to touch the (internal) LRU-Counter class.  All keys are being visited
1111        // at the same time.
1112
1113        if (this.size() > this.MAX_NUM_ELEMENTS) this.mapLRU.trimToFit();
1114    }
1115}