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.AbstractMap;
13 
14 import hunt.collection.Collection;
15 import hunt.collection.Iterator;
16 import hunt.collection.Map;
17 import hunt.collection.Set;
18 
19 import hunt.Exceptions;
20 import hunt.Object;
21 import hunt.util.ObjectUtils;
22 
23 import std.array;
24 // import std.container.array;
25 import hunt.collection.Array;
26 import std.conv;
27 import std.exception;
28 import std.range;
29 
30 /**
31 */
32 abstract class AbstractMap(K, V) : Map!(K, V) {
33 
34     /**
35      * The number of key-value mappings contained in this map.
36      */
37     protected int _size;
38 
39     /**
40      * Sole constructor.  (For invocation by subclass constructors, typically
41      * implicit.)
42      */
43     protected this() {
44     }
45 
46     // Query Operations
47 
48     /**
49      * Returns the number of key-value mappings in this map.
50      *
51      * @return the number of key-value mappings in this map
52      */
53     int size() {
54         return _size;
55     }
56 
57     /**
58      * Returns <tt>true</tt> if this map contains no key-value mappings.
59      *
60      * @return <tt>true</tt> if this map contains no key-value mappings
61      */
62     bool isEmpty() {
63         return _size == 0;
64     }
65 
66     /**
67      * {@inheritDoc}
68      *
69      * @implSpec
70      * This implementation iterates over <tt>entrySet()</tt> searching
71      * for an entry with the specified value.  If such an entry is found,
72      * <tt>true</tt> is returned.  If the iteration terminates without
73      * finding such an entry, <tt>false</tt> is returned.  Note that this
74      * implementation requires linear time in the size of the map.
75      *
76      * @throws ClassCastException   {@inheritDoc}
77      * @throws NullPointerException {@inheritDoc}
78      */
79     bool containsKey(K key) {
80         throw new UnsupportedOperationException();
81     }
82     /**
83      * {@inheritDoc}
84      *
85      * @implSpec
86      * This implementation iterates over <tt>entrySet()</tt> searching
87      * for an entry with the specified value.  If such an entry is found,
88      * <tt>true</tt> is returned.  If the iteration terminates without
89      * finding such an entry, <tt>false</tt> is returned.  Note that this
90      * implementation requires linear time in the size of the map.
91      *
92      * @throws ClassCastException   {@inheritDoc}
93      * @throws NullPointerException {@inheritDoc}
94      */
95     bool containsValue(V value) {
96         throw new UnsupportedOperationException();
97     }
98 
99     V opIndex(K key) {
100         return get(key);
101     }
102 
103     /**
104      * {@inheritDoc}
105      *
106      * @implSpec
107      * This implementation iterates over <tt>entrySet()</tt> searching
108      * for an entry with the specified key.  If such an entry is found,
109      * the entry's value is returned.  If the iteration terminates without
110      * finding such an entry, <tt>null</tt> is returned.  Note that this
111      * implementation requires linear time in the size of the map; many
112      * implementations will override this method.
113      *
114      * @throws ClassCastException            {@inheritDoc}
115      * @throws NullPointerException          {@inheritDoc}
116      */
117     V get(K key) {
118         throw new UnsupportedOperationException();
119     }
120 
121     /**
122      * Returns the value to which the specified key is mapped, or
123      * {@code defaultValue} if this map contains no mapping for the key.
124      *
125      * @implSpec
126      * The default implementation makes no guarantees about synchronization
127      * or atomicity properties of this method. Any implementation providing
128      * atomicity guarantees must override this method and document its
129      * concurrency properties.
130      *
131      * @param key the key whose associated value is to be returned
132      * @param defaultValue the default mapping of the key
133      * @return the value to which the specified key is mapped, or
134      * {@code defaultValue} if this map contains no mapping for the key
135      * @throws ClassCastException if the key is of an inappropriate type for
136      * this map
137      * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
138      * @throws NullPointerException if the specified key is null and this map
139      * does not permit null keys
140      * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
141      */
142     V getOrDefault(K k, V value) {
143         throw new UnsupportedOperationException();
144     }
145 
146     // Modification Operations
147 
148     /**
149      * {@inheritDoc}
150      *
151      * @implSpec
152      * This implementation always throws an
153      * <tt>UnsupportedOperationException</tt>.
154      *
155      * @throws UnsupportedOperationException {@inheritDoc}
156      * @throws ClassCastException            {@inheritDoc}
157      * @throws NullPointerException          {@inheritDoc}
158      * @throws IllegalArgumentException      {@inheritDoc}
159      */
160     V put(K key, V value) {
161         throw new UnsupportedOperationException();
162     }
163 
164     V putIfAbsent(K key, V value) {
165         V v = V.init;
166 
167         if (!containsKey(key))
168             v = put(key, value);
169 
170         return v;
171     }
172 
173     /**
174      * {@inheritDoc}
175      *
176      * @implSpec
177      * This implementation iterates over <tt>entrySet()</tt> searching for an
178      * entry with the specified key.  If such an entry is found, its value is
179      * obtained with its <tt>getValue</tt> operation, the entry is removed
180      * from the collection (and the backing map) with the iterator's
181      * <tt>remove</tt> operation, and the saved value is returned.  If the
182      * iteration terminates without finding such an entry, <tt>null</tt> is
183      * returned.  Note that this implementation requires linear time in the
184      * size of the map; many implementations will override this method.
185      *
186      * <p>Note that this implementation throws an
187      * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
188      * iterator does not support the <tt>remove</tt> method and this map
189      * contains a mapping for the specified key.
190      *
191      * @throws UnsupportedOperationException {@inheritDoc}
192      * @throws ClassCastException            {@inheritDoc}
193      * @throws NullPointerException          {@inheritDoc}
194      */
195     V remove(K key) {
196         throw new UnsupportedOperationException();
197     }
198 
199     bool remove(K key, V value) {
200         V curValue = get(key);
201         if (curValue != value || !containsKey(key))
202             return false;
203         remove(key);
204         return true;
205     }
206 
207     // Bulk Operations
208 
209     /**
210      * {@inheritDoc}
211      *
212      * @implSpec
213      * This implementation iterates over the specified map's
214      * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt>
215      * operation once for each entry returned by the iteration.
216      *
217      * <p>Note that this implementation throws an
218      * <tt>UnsupportedOperationException</tt> if this map does not support
219      * the <tt>put</tt> operation and the specified map is nonempty.
220      *
221      * @throws UnsupportedOperationException {@inheritDoc}
222      * @throws ClassCastException            {@inheritDoc}
223      * @throws NullPointerException          {@inheritDoc}
224      * @throws IllegalArgumentException      {@inheritDoc}
225      */
226     void putAll(Map!(K, V) m) {
227         foreach (K k, V v; m)
228             put(k, v);
229     }
230 
231     /**
232      * {@inheritDoc}
233      *
234      * @implSpec
235      * This implementation calls <tt>entrySet().clear()</tt>.
236      *
237      * <p>Note that this implementation throws an
238      * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
239      * does not support the <tt>clear</tt> operation.
240      *
241      * @throws UnsupportedOperationException {@inheritDoc}
242      */
243     void clear() {
244         throw new NotImplementedException("");
245     }
246 
247     bool replace(K key, V oldValue, V newValue) {
248         V curValue = get(key);
249         if (curValue != oldValue || !containsKey(key)) {
250             return false;
251         }
252         put(key, newValue);
253         return true;
254     }
255 
256     V replace(K key, V value) {
257         V curValue = V.init;
258         if (containsKey(key)) {
259             curValue = put(key, value);
260         }
261         return curValue;
262     }
263 
264     int opApply(scope int delegate(ref K, ref V) dg) {
265         throw new NotImplementedException();
266     }
267 
268     int opApply(scope int delegate(MapEntry!(K, V) entry) dg) {
269         throw new NotImplementedException();
270     }
271 
272     InputRange!K byKey() {
273         throw new NotImplementedException();
274     }
275 
276     InputRange!V byValue() {
277         throw new NotImplementedException();
278     }
279 
280     // Views
281 
282     /**
283      * Each of these fields are initialized to contain an instance of the
284      * appropriate view the first time this view is requested.  The views are
285      * stateless, so there's no reason to create more than one of each.
286      *
287      * <p>Since there is no synchronization performed while accessing these fields,
288      * it is expected that java.util.Map view classes using these fields have
289      * no non-final fields (or any fields at all except for outer-this). Adhering
290      * to this rule would make the races on these fields benign.
291      *
292      * <p>It is also imperative that implementations read the field only once,
293      * as in:
294      *
295      * <pre> {@code
296      * public Set!K keySet() {
297      *   Set!K ks = keySet;  // single racy read
298      *   if (ks is null) {
299      *     ks = new KeySet();
300      *     keySet = ks;
301      *   }
302      *   return ks;
303      * }
304      *}</pre>
305      */
306     // protected Set!K       _keySet;
307     // protected Collection!V _values;
308 
309     /**
310      * {@inheritDoc}
311      *
312      * @implSpec
313      * This implementation returns a set that subclasses {@link AbstractSet}.
314      * The subclass's iterator method returns a "wrapper object" over this
315      * map's <tt>entrySet()</tt> iterator.  The <tt>size</tt> method
316      * delegates to this map's <tt>size</tt> method and the
317      * <tt>contains</tt> method delegates to this map's
318      * <tt>containsKey</tt> method.
319      *
320      * <p>The set is created the first time this method is called,
321      * and returned in response to all subsequent calls.  No synchronization
322      * is performed, so there is a slight chance that multiple calls to this
323      * method will not all return the same set.
324      */
325     K[] keySet() {
326         Array!K arr;
327         foreach (K key; byKey()) {
328             arr.insertBack(key);
329         }
330         return arr.array();
331     }
332 
333     /**
334      * {@inheritDoc}
335      *
336      * @implSpec
337      * This implementation returns a collection that subclasses {@link
338      * AbstractCollection}.  The subclass's iterator method returns a
339      * "wrapper object" over this map's <tt>entrySet()</tt> iterator.
340      * The <tt>size</tt> method delegates to this map's <tt>size</tt>
341      * method and the <tt>contains</tt> method delegates to this map's
342      * <tt>containsValue</tt> method.
343      *
344      * <p>The collection is created the first time this method is called, and
345      * returned in response to all subsequent calls.  No synchronization is
346      * performed, so there is a slight chance that multiple calls to this
347      * method will not all return the same collection.
348      */
349     V[] values() {
350         // FIXME: Needing refactor or cleanup -@zxp at 9/26/2018, 6:00:54 PM
351         // 
352         // Array!V arr;
353         // foreach(V value; byValue()) {
354         //     arr.insertBack(value);
355         // }
356         // return arr.array();
357         // V[] arr;
358         // foreach (V value; byValue()) {
359         //     arr ~= value;
360         // }
361         // return arr;
362         return byValue().array();
363     }
364 
365     // Comparison and hashing
366 
367     /**
368      * Compares the specified object with this map for equality.  Returns
369      * <tt>true</tt> if the given object is also a map and the two maps
370      * represent the same mappings.  More formally, two maps <tt>m1</tt> and
371      * <tt>m2</tt> represent the same mappings if
372      * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
373      * <tt>equals</tt> method works properly across different implementations
374      * of the <tt>Map</tt> interface.
375      *
376      * @implSpec
377      * This implementation first checks if the specified object is this map;
378      * if so it returns <tt>true</tt>.  Then, it checks if the specified
379      * object is a map whose size is identical to the size of this map; if
380      * not, it returns <tt>false</tt>.  If so, it iterates over this map's
381      * <tt>entrySet</tt> collection, and checks that the specified map
382      * contains each mapping that this map contains.  If the specified map
383      * fails to contain such a mapping, <tt>false</tt> is returned.  If the
384      * iteration completes, <tt>true</tt> is returned.
385      *
386      * @param o object to be compared for equality with this map
387      * @return <tt>true</tt> if the specified object is equal to this map
388      */
389     override bool opEquals(Object o) {
390         if(o is null) return false;
391         if (o is this) return true;
392 
393         auto m = cast(Map!(K, V)) o;
394         if(m is null) return false;
395         if (m.size() != size())
396             return false;
397 
398         try {
399             foreach(K key, V value; this) {
400                 if(value != m.get(key))
401                     return false;
402             }
403         } catch (Exception) {
404             return false;
405         }
406 
407         return true;
408     }
409 
410     bool opEquals(IObject o) {
411         return opEquals(cast(Object) o);
412     }
413 
414     // Iterator!(MapEntry!(K,V)) iterator()
415     // {
416     //     throw new UnsupportedOperationException();
417     // }
418 
419     /**
420      * Returns the hash code value for this map.  The hash code of a map is
421      * defined to be the sum of the hash codes of each entry in the map's
422      * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
423      * implies that <tt>m1.toHash()==m2.toHash()</tt> for any two maps
424      * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
425      * {@link Object#toHash}.
426      *
427      * @implSpec
428      * This implementation iterates over <tt>entrySet()</tt>, calling
429      * {@link MapEntry#toHash toHash()} on each element (entry) in the
430      * set, and adding up the results.
431      *
432      * @return the hash code value for this map
433      * @see MapEntry#toHash()
434      * @see Object#equals(Object)
435      * @see Set#equals(Object)
436      */
437     override size_t toHash() @trusted nothrow {
438         size_t h = 0;
439         try {
440             foreach (MapEntry!(K, V) i; this) {
441                 h += i.toHash();
442             }
443         } catch (Exception ex) {
444         }
445         return h;
446     }
447 
448     /**
449      * Returns a string representation of this map.  The string representation
450      * consists of a list of key-value mappings in the order returned by the
451      * map's <tt>entrySet</tt> view's iterator, enclosed in braces
452      * (<tt>"{}"</tt>).  Adjacent mappings are separated by the characters
453      * <tt>", "</tt> (comma and space).  Each key-value mapping is rendered as
454      * the key followed by an equals sign (<tt>"="</tt>) followed by the
455      * associated value.  Keys and values are converted to strings as by
456      * {@link string#valueOf(Object)}.
457      *
458      * @return a string representation of this map
459      */
460     override string toString() {
461         if (isEmpty())
462             return "{}";
463 
464         Appender!string sb;
465         sb.put("{");
466         bool isFirst = true;
467         foreach (K key, V value; this) {
468             if (!isFirst) {
469                 sb.put(", ");
470             }
471             sb.put(key.to!string() ~ "=" ~ value.to!string());
472             isFirst = false;
473         }
474         sb.put("}");
475 
476         return sb.data;
477     }
478 
479     /**
480      * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys
481      * and values themselves are not cloned.
482      *
483      * @return a shallow copy of this map
484      */
485     mixin CloneMemberTemplate!(typeof(this));
486 
487     /**
488      * Utility method for SimpleEntry and SimpleImmutableEntry.
489      * Test for equality, checking for nulls.
490      *
491      * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
492      */
493     // private static bool eq(Object o1, Object o2) {
494     //     return o1 is null ? o2 is null : o1.equals(o2);
495     // }
496 
497     // Implementation Note: SimpleEntry and SimpleImmutableEntry
498     // are distinct unrelated classes, even though they share
499     // some code. Since you can't add or subtract final-ness
500     // of a field in a subclass, they can't share representations,
501     // and the amount of duplicated code is too small to warrant
502     // exposing a common abstract class.
503 
504     /**
505      * An Entry maintaining a key and a value.  The value may be
506      * changed using the <tt>setValue</tt> method.  This class
507      * facilitates the process of building custom map
508      * implementations. For example, it may be convenient to return
509      * arrays of <tt>SimpleEntry</tt> instances in method
510      * <tt>Map.entrySet().toArray</tt>.
511      *
512      */
513     // static class SimpleEntry!(K,V)
514     //     implements Entry!(K,V), java.io.Serializable
515     // {
516     //     private static final long serialVersionUID = -8499721149061103585L;
517 
518     //     private final K key;
519     //     private V value;
520 
521     //     /**
522     //      * Creates an entry representing a mapping from the specified
523     //      * key to the specified value.
524     //      *
525     //      * @param key the key represented by this entry
526     //      * @param value the value represented by this entry
527     //      */
528     //     SimpleEntry(K key, V value) {
529     //         this.key   = key;
530     //         this.value = value;
531     //     }
532 
533     //     /**
534     //      * Creates an entry representing the same mapping as the
535     //      * specified entry.
536     //      *
537     //      * @param entry the entry to copy
538     //      */
539     //     SimpleEntry(Entry!(K, V) entry) {
540     //         this.key   = entry.getKey();
541     //         this.value = entry.getValue();
542     //     }
543 
544     //     /**
545     //      * Returns the key corresponding to this entry.
546     //      *
547     //      * @return the key corresponding to this entry
548     //      */
549     //     K getKey() {
550     //         return key;
551     //     }
552 
553     //     /**
554     //      * Returns the value corresponding to this entry.
555     //      *
556     //      * @return the value corresponding to this entry
557     //      */
558     //     V getValue() {
559     //         return value;
560     //     }
561 
562     //     /**
563     //      * Replaces the value corresponding to this entry with the specified
564     //      * value.
565     //      *
566     //      * @param value new value to be stored in this entry
567     //      * @return the old value corresponding to the entry
568     //      */
569     //     V setValue(V value) {
570     //         V oldValue = this.value;
571     //         this.value = value;
572     //         return oldValue;
573     //     }
574 
575     //     /**
576     //      * Compares the specified object with this entry for equality.
577     //      * Returns {@code true} if the given object is also a map entry and
578     //      * the two entries represent the same mapping.  More formally, two
579     //      * entries {@code e1} and {@code e2} represent the same mapping
580     //      * if<pre>
581     //      *   (e1.getKey()==null ?
582     //      *    e2.getKey()==null :
583     //      *    e1.getKey().equals(e2.getKey()))
584     //      *   &amp;&amp;
585     //      *   (e1.getValue()==null ?
586     //      *    e2.getValue()==null :
587     //      *    e1.getValue().equals(e2.getValue()))</pre>
588     //      * This ensures that the {@code equals} method works properly across
589     //      * different implementations of the {@code MapEntry} interface.
590     //      *
591     //      * @param o object to be compared for equality with this map entry
592     //      * @return {@code true} if the specified object is equal to this map
593     //      *         entry
594     //      * @see    #toHash
595     //      */
596     //     bool equals(Object o) {
597     //         if (!(o instanceof MapEntry))
598     //             return false;
599     //         MapEntry<?,?> e = (MapEntry<?,?>)o;
600     //         return eq(key, e.getKey()) && eq(value, e.getValue());
601     //     }
602 
603     //     /**
604     //      * Returns the hash code value for this map entry.  The hash code
605     //      * of a map entry {@code e} is defined to be: <pre>
606     //      *   (e.getKey()==null   ? 0 : e.getKey().toHash()) ^
607     //      *   (e.getValue()==null ? 0 : e.getValue().toHash())</pre>
608     //      * This ensures that {@code e1.equals(e2)} implies that
609     //      * {@code e1.toHash()==e2.toHash()} for any two Entries
610     //      * {@code e1} and {@code e2}, as required by the general
611     //      * contract of {@link Object#toHash}.
612     //      *
613     //      * @return the hash code value for this map entry
614     //      * @see    #equals
615     //      */
616     //     size_t toHash() @trusted nothrow {
617     //         return (key   is null ? 0 :   key.toHash()) ^
618     //                (value is null ? 0 : value.toHash());
619     //     }
620 
621     //     /**
622     //      * Returns a string representation of this map entry.  This
623     //      * implementation returns the string representation of this
624     //      * entry's key followed by the equals character ("<tt>=</tt>")
625     //      * followed by the string representation of this entry's value.
626     //      *
627     //      * @return a string representation of this map entry
628     //      */
629     //     string toString() {
630     //         return key ~ "=" ~ value;
631     //     }
632 
633     // }
634 }
635 
636 /**
637 * An Entry maintaining an immutable key and value.  This class
638 * does not support method <tt>setValue</tt>.  This class may be
639 * convenient in methods that return thread-safe snapshots of
640 * key-value mappings.
641 *
642 * @since 1.6
643 */
644 class SimpleImmutableEntry(K, V) : AbstractMapEntry!(K, V) {
645 
646     /**
647         * Creates an entry representing a mapping from the specified
648         * key to the specified value.
649         *
650         * @param key the key represented by this entry
651         * @param value the value represented by this entry
652         */
653     this(K key, V value) {
654         super(key, value);
655     }
656 
657     /**
658         * Creates an entry representing the same mapping as the
659         * specified entry.
660         *
661         * @param entry the entry to copy
662         */
663     this(MapEntry!(K, V) entry) {
664         super(entry.getKey(), entry.getValue());
665     }
666 
667     /**
668     * Replaces the value corresponding to this entry with the specified
669     * value (optional operation).  This implementation simply throws
670     * <tt>UnsupportedOperationException</tt>, as this class implements
671     * an <i>immutable</i> map entry.
672     *
673     * @param value new value to be stored in this entry
674     * @return (Does not return)
675     * @throws UnsupportedOperationException always
676     */
677     override V setValue(V value) {
678         throw new UnsupportedOperationException();
679     }
680 
681     /**
682      * Returns the hash code value for this map entry.  The hash code
683      * of a map entry {@code e} is defined to be: <pre>
684      *   (e.getKey()==null   ? 0 : e.getKey().toHash()) ^
685      *   (e.getValue()==null ? 0 : e.getValue().toHash())</pre>
686      * This ensures that {@code e1.equals(e2)} implies that
687      * {@code e1.toHash()==e2.toHash()} for any two Entries
688      * {@code e1} and {@code e2}, as required by the general
689      * contract of {@link Object#toHash}.
690      *
691      * @return the hash code value for this map entry
692      * @see    #equals
693      */
694     override size_t toHash() @trusted nothrow {
695         static if (is(K == class)) {
696             size_t kHash = 0;
697             if (key !is null)
698                 kHash = key.toHash();
699         } else {
700             size_t kHash = hashOf(key);
701         }
702 
703         static if (is(V == class)) {
704             size_t vHash = 0;
705             if (value !is null)
706                 vHash = value.toHash();
707         } else {
708             size_t vHash = hashOf(value);
709         }
710 
711         return kHash ^ vHash;
712     }
713 }
714 
715 /**
716 */
717 class EmptyMap(K, V) : AbstractMap!(K, V) {
718 
719     override int size() {
720         return 0;
721     }
722 
723     override bool isEmpty() {
724         return true;
725     }
726 
727     override bool containsKey(K key) {
728         return false;
729     }
730 
731     // override
732     // bool containsValue(V value) {return false;}
733 
734     override V get(K key) {
735         return V.init;
736     }
737 
738     override K[] keySet() {
739         return null;
740     }
741 
742     override V[] values() {
743         return null;
744     }
745     // Collection!(V) values()              {return emptySet();}
746     // Set!(MapEntry!(K,V)) entrySet()      {return emptySet();}
747 
748     override bool opEquals(Object o) {
749         return (typeid(o) == typeid(Map!(K, V))) && (cast(Map!(K, V)) o).isEmpty();
750     }
751 
752     override size_t toHash() {
753         return 0;
754     }
755 
756     // Override default methods in Map
757     override V getOrDefault(K k, V defaultValue) {
758         return defaultValue;
759     }
760 
761     override int opApply(scope int delegate(ref K, ref V) dg) {
762         return 0;
763     }
764 
765     // override
766     // void replaceAll(BiFunction!(K, V, V) function) {
767     //     Objects.requireNonNull(function);
768     // }
769 
770     // override
771     // V putIfAbsent(K key, V value) {
772     //     throw new UnsupportedOperationException();
773     // }
774 
775     // override
776     // bool remove(Object key, Object value) {
777     //     throw new UnsupportedOperationException();
778     // }
779 
780     // override
781     // bool replace(K key, V oldValue, V newValue) {
782     //     throw new UnsupportedOperationException();
783     // }
784 
785     // override
786     // V replace(K key, V value) {
787     //     throw new UnsupportedOperationException();
788     // }
789 
790     // override
791     // V computeIfAbsent(K key,
792     //         Function!(K, V) mappingFunction) {
793     //     throw new UnsupportedOperationException();
794     // }
795 
796     // override
797     // V computeIfPresent(K key,
798     //         BiFunction!(K, V, V) remappingFunction) {
799     //     throw new UnsupportedOperationException();
800     // }
801 
802     // override
803     // V compute(K key,
804     //         BiFunction!(K, V, V) remappingFunction) {
805     //     throw new UnsupportedOperationException();
806     // }
807 
808     // override
809     // V merge(K key, V value,
810     //         BiFunction!(V, V, V) remappingFunction) {
811     //     throw new UnsupportedOperationException();
812     // }
813 
814     // // Preserves singleton property
815     // private Object readResolve() {
816     //     return EMPTY_MAP;
817     // }
818 }