001/*
002 * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package Torello.Java.ReadOnly;
027
028import java.util.*;
029
030import java.util.function.BiConsumer;
031import java.io.Serializable;
032
033/**
034 * Immutable variant of Java Collections Framework interface
035 * <CODE>java&#46;util&#46;Map&lt;K, V&gt;</CODE>.
036 * 
037 * <EMBED CLASS='external-html' DATA-JDK=ReadOnlyMap DATA-FILE-ID=INTERFACES>
038 * 
039 * @param <K> the type of keys maintained by this map
040 * @param <V> the type of mapped values
041 */
042@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_INTERFACE")
043public interface ReadOnlyMap<K, V>
044{
045    // ********************************************************************************************
046    // ********************************************************************************************
047    // Query Operations
048    // ********************************************************************************************
049    // ********************************************************************************************
050
051
052    /**
053     * Returns the number of key-value mappings in this map.  If the map contains more than
054     * {@code Integer.MAX_VALUE} elements, returns {@code Integer.MAX_VALUE}.
055     *
056     * @return the number of key-value mappings in this map
057     */
058    int size();
059
060    /**
061     * Returns {@code TRUE} if this map contains no key-value mappings.
062     * @return {@code TRUE} if this map contains no key-value mappings
063     */
064    boolean isEmpty();
065
066    /**
067     * Returns {@code TRUE} if this map contains a mapping for the specified key.  More formally,
068     * returns {@code TRUE} if and only if this map contains a mapping for a key {@code k} such
069     * that {@code Objects.equals(key, k)}.  (There can be at most one such mapping.)
070     *
071     * @param key key whose presence in this map is to be tested
072     * @return {@code TRUE} if this map contains a mapping for the specified key
073     * 
074     * @throws ClassCastException if the key is of an inappropriate type for this map
075     * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
076     * 
077     * @throws NullPointerException if the specified key is null and this map does not permit null
078     * keys (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
079     */
080    boolean containsKey(Object key);
081
082    /**
083     * Returns {@code TRUE} if this map maps one or more keys to the specified value.  More
084     * formally, returns {@code TRUE} if and only if this map contains at least one mapping to a
085     * value {@code v} such that {@code Objects.equals(value, v)}.  This operation will probably
086     * require time linear in the map size for most implementations of the {@code Map} interface.
087     *
088     * @param value value whose presence in this map is to be tested
089     * @return {@code TRUE} if this map maps one or more keys to the specified value
090     * 
091     * @throws ClassCastException if the value is of an inappropriate type for
092     * this map (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
093     * 
094     * @throws NullPointerException if the specified value is null and this map does not permit
095     * null values
096     * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
097     */
098    boolean containsValue(Object value);
099
100    /**
101     * Returns the value to which the specified key is mapped, or {@code null} if this map contains
102     * no mapping for the key.
103     * 
104     * <BR /><BR />More formally, if this map contains a mapping from a key {@code k} to a value
105     * {@code v} such that {@code Objects.equals(key, k)}, then this method returns {@code v};
106     * otherwise it returns {@code null}.  (There can be at most one such mapping.)
107     *
108     * <BR /><BR />If this map permits null values, then a return value of {@code null} does not
109     * <i>necessarily</i> indicate that the map contains no mapping for the key; it's also possible
110     * that the map explicitly maps the key to {@code null}.  The {@link #containsKey containsKey}
111     * operation may be used to distinguish these two cases.
112     *
113     * @param key the key whose associated value is to be returned
114     * 
115     * @return the value to which the specified key is mapped, or {@code null} if this map contains
116     * no mapping for the key
117     * 
118     * @throws ClassCastException if the key is of an inappropriate type for this map
119     * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
120     * 
121     * @throws NullPointerException if the specified key is null and this map does not permit null
122     * keys (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
123     */
124    V get(Object key);
125
126
127    // ********************************************************************************************
128    // ********************************************************************************************
129    // Views
130    // ********************************************************************************************
131    // ********************************************************************************************
132
133
134    /**
135     * Returns a {@link ReadOnlySet} view of the keys contained in this map.  The set is backed by
136     * the map, so changes to the map are reflected in the set, and vice-versa.
137     * 
138     * @return a set view of the keys contained in this map
139     */
140    ReadOnlySet<K> keySet();
141
142    /**
143     * Returns a {@link ReadOnlyCollection} view of the values contained in this map.
144     * @return a collection view of the values contained in this map
145     */
146    ReadOnlyCollection<V> values();
147
148    /**
149     * Returns a {@link ReadOnlySet} view of the mappings contained in this map.
150     * @return a set view of the mappings contained in this map
151     */
152    ReadOnlySet<ReadOnlyMap.Entry<K, V>> entrySet();
153
154    /**
155     * A map entry (key-value pair). 
156     * 
157     * <BR /><BR />An Entry may also be obtained from a map's entry-set view by other means, for
158     * example, using the
159     * {@link ReadOnlySet#parallelStream parallelStream},
160     * {@link ReadOnlySet#stream stream},
161     * {@link ReadOnlySet#spliterator spliterator}
162     * methods, any of the
163     * {@link ReadOnlySet#toArray toArray}
164     * overloads, or by copying the entry-set view into another collection.
165     * 
166     * <BR /><BR />In addition, an Entry may be obtained directly from a map, for example via calls
167     * to methods directly on the {@link ReadOnlyNavigableMap} interface.
168     * 
169     * @param <K> the type of the key
170     * @param <V> the type of the value
171     *
172     * @see ReadOnlyMap#entrySet()
173     */
174    interface Entry<K, V>
175    {
176        /**
177         * Returns the key corresponding to this entry.
178         * @return the key corresponding to this entry
179         */
180        K getKey();
181
182        /**
183         * Returns the value corresponding to this entry.
184         * @return the value corresponding to this entry
185         */
186        V getValue();
187
188        /**
189         * Compares the specified object with this entry for equality.
190         * Returns {@code TRUE} if the given object is also a map entry and
191         * the two entries represent the same mapping.  More formally, two
192         * entries {@code e1} and {@code e2} represent the same mapping
193         * if
194         * 
195         * <BR /><DIV CLASS=SNIP>{@code
196         * (e1.getKey()==null
197         *      ? e2.getKey()==null
198         *      : e1.getKey().equals(e2.getKey()))
199         * &amp;&amp;
200         * (e1.getValue()==null
201         *      ? e2.getValue()==null
202         *      : e1.getValue().equals(e2.getValue()))
203         * }</DIV>
204         * 
205         * <BR /><BR />This ensures that the {@code equals} method works properly across different
206         * implementations of the {@code ReadOnlyMap.Entry} interface.
207         *
208         * @param o object to be compared for equality with this map entry
209         * @return {@code TRUE} if the specified object is equal to this map entry
210         */
211        boolean equals(Object o);
212
213        /**
214         * Returns the hash code value for this map entry.  The hash code of a map entry {@code e}
215         * is defined to be:
216         * 
217         * <BR /><DIV CLASS=SNIP>{@code
218         * (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
219         * (e.getValue()==null ? 0 : e.getValue().hashCode())
220         * }</DIV>
221         * 
222         * <BR /><BR />This ensures that {@code e1.equals(e2)} implies that
223         * {@code e1.hashCode()==e2.hashCode()} for any two Entries {@code e1} and {@code e2}, as
224         * required by the general contract of {@code Object.hashCode}.
225         *
226         * @return the hash code value for this map entry
227         * @see #equals(Object)
228         */
229        int hashCode();
230
231        /**
232         * Returns a comparator that compares {@link ReadOnlyMap.Entry} in natural order on key.
233         *
234         * <BR /><BR />The returned comparator is serializable and throws
235         * {@code NullPointerException} when comparing an entry with a null key.
236         *
237         * @param  <K> the {@link Comparable} type of then map keys
238         * @param  <V> the type of the map values
239         * @return a comparator that compares {@link ReadOnlyMap.Entry} in natural order on key.
240         */
241        public static <K extends Comparable<? super K>, V>
242            Comparator<ReadOnlyMap.Entry<K, V>>
243            comparingByKey()
244        {
245            return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable)
246                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
247        }
248
249        /**
250         * Returns a comparator that compares {@link ReadOnlyMap.Entry} in natural order on value.
251         *
252         * <BR /><BR />The returned comparator is serializable and throws
253         * {@code NullPointerException} when comparing an entry with null values.
254         *
255         * @param <K> the type of the map keys
256         * @param <V> the {@code Comparable} type of the map values
257         * @return a comparator that compares {@link ReadOnlyMap.Entry} in natural order on value.
258         * @see Comparable
259         */
260        public static <K, V extends Comparable<? super V>>
261            Comparator<ReadOnlyMap.Entry<K, V>>
262            comparingByValue()
263        {
264            return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable)
265                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
266        }
267
268        /**
269         * Returns a comparator that compares {@link ReadOnlyMap.Entry} by key using the given
270         * {@code Comparator}.
271         *
272         * <BR /><BR />The returned comparator is serializable if the specified comparator is also
273         * serializable.
274         *
275         * @param  <K> the type of the map keys
276         * @param  <V> the type of the map values
277         * @param  cmp the key {@code Comparator}
278         * @return a comparator that compares {@link ReadOnlyMap.Entry} by the key.
279         */
280        public static <K, V>
281            Comparator<ReadOnlyMap.Entry<K, V>>
282            comparingByKey(Comparator<? super K> cmp)
283        {
284            Objects.requireNonNull(cmp);
285            return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable)
286                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
287        }
288
289        /**
290         * Returns a comparator that compares {@link ReadOnlyMap.Entry} by value using the given
291         * {@code Comparator}.
292         * 
293         * <BR /><BR />The returned comparator is serializable if the specified comparator is also
294         * serializable.
295         * 
296         * @param  <K> the type of the map keys
297         * @param  <V> the type of the map values
298         * @param  cmp the value {@link Comparator}
299         * @return a comparator that compares {@link ReadOnlyMap.Entry} by the value.
300         */
301        public static <K, V>
302            Comparator<ReadOnlyMap.Entry<K, V>>
303            comparingByValue(Comparator<? super V> cmp)
304        {
305            Objects.requireNonNull(cmp);
306            return (Comparator<ReadOnlyMap.Entry<K, V>> & Serializable)
307                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
308        }
309    }
310
311
312    // ********************************************************************************************
313    // ********************************************************************************************
314    // Change The Type, Clone the Internal Data-Structure
315    // ********************************************************************************************
316    // ********************************************************************************************
317
318
319    /**
320     * Clones the internal {@code java.util.Map} representation, and returns it.  This is the
321     * Top-Level Interface-Variant of this method.  It returns the Interface-Implementation
322     * {@code java.util.Map}.
323     * 
324     * <BR /><BR /><B CLASS=JDDescLabel>Alternate Variant:</B>
325     * 
326     * <BR />The four classes which implement the interface {@code ReadOnlyMap}
327     * (which are {@link ReadOnlyHashMap}, {@link ReadOnlyTreeMap}, {@link ReadOnlyHashtable} and 
328     * {@link ReadOnlyProperties}), for convenience, also implement an identical "Wrap To" Method
329     * which returns the exact type of the internal {@code Map} representation (which are
330     * {@code java.util.HashMap, java.util.TreeMap, java.util.Hashtable} and
331     * {@code java.util.Properties}) - rather than the Interface-Type {@code java.util.Map}.
332     * 
333     * @return <UL CLASS=JDUL>
334     * 
335     * <LI> For the sub-class {@link ReadOnlyHashMap}, this will return a cloned instance of the
336     *      internal {@code java.util.HashMap}.
337     *      <BR /><BR />
338     *      </LI>
339     * 
340     * <LI> For the sub-class {@link ReadOnlyTreeMap}, this will return a cloned instance of the
341     *      internal {@code java.util.TreeMap}.
342     *      <BR /><BR />
343     *      </LI>
344     * 
345     * <LI> For the sub-class {@link ReadOnlyHashtable}, this will return a cloned instance of the
346     *      internal {@code java.util.Hashtable}.
347     *      <BR /><BR />
348     *      </LI>
349     * 
350     * <LI> For the sub-class {@link ReadOnlyProperties}, this will return a cloned instance of the
351     *      internal {@code java.util.Properties}.
352     *      </LI>
353     * 
354     * </UL>
355     */
356    Map<K, V> cloneToMap();
357
358    /**
359     * Invokes {@code java.util.Collections.unmodifiableMap} on the internal {@code Map}
360     * 
361     * <EMBED CLASS='external-html' DATA-JDK=Map DATA-RET_TYPE=Map
362     *      DATA-FILE-ID=WRAP_TO_IMMUTABLE>
363     * 
364     * @return A {@code Set} which adheres to the JDK interface {@code java.util.Set}, but throws
365     * an {@code UnsupportedOperationException} if a user attempts to invoke a Mutator-Method on
366     * the returned instance.
367     */
368    Map<K, V> wrapToImmutableMap();
369
370
371    // ********************************************************************************************
372    // ********************************************************************************************
373    // Comparison and hashing
374    // ********************************************************************************************
375    // ********************************************************************************************
376
377
378    /**
379     * Compares the specified object with this map for equality.  Returns {@code TRUE} if the given
380     * object is also a map and the two maps represent the same mappings.  More formally, two maps
381     * {@code m1} and {@code m2} represent the same mappings if
382     * {@code m1.entrySet().equals(m2.entrySet())}.  This ensures that the {@code equals} method
383     * works properly across different implementations of the {@code Map} interface.
384     * 
385     * @param o object to be compared for equality with this map
386     * @return {@code TRUE} if the specified object is equal to this map
387     */
388    boolean equals(Object o);
389
390    /**
391     * Returns the hash code value for this map.  The hash code of a map is defined to be the sum
392     * of the hash codes of each entry in the map's {@code entrySet()} view.  This ensures that
393     * {@code m1.equals(m2)} implies that {@code m1.hashCode()==m2.hashCode()} for any two maps
394     * {@code m1} and {@code m2}, as required by the general contract of {@code Object.hashCode}.
395     *
396     * @return the hash code value for this map
397     * @see ReadOnlyMap.Entry#hashCode()
398     * @see #equals(Object)
399     */
400    int hashCode();
401
402
403    // ********************************************************************************************
404    // ********************************************************************************************
405    // Defaultable methods
406    // ********************************************************************************************
407    // ********************************************************************************************
408
409
410    /**
411     * Returns the value to which the specified key is mapped, or {@code defaultValue} if this map
412     * contains no mapping for the key.
413     *
414     * @param key the key whose associated value is to be returned
415     * @param defaultValue the default mapping of the key
416     * 
417     * @return the value to which the specified key is mapped, or {@code defaultValue} if this map
418     * contains no mapping for the key
419     * 
420     * @throws ClassCastException if the key is of an inappropriate type for this map
421     * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
422     * 
423     * @throws NullPointerException if the specified key is null and this map does not permit null
424     * keys 
425     * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
426     */
427    default V getOrDefault(Object key, V defaultValue)
428    {
429        V v;
430        return (((v = get(key)) != null) || containsKey(key))
431            ? v
432            : defaultValue;
433    }
434
435    /**
436     * Performs the given action for each entry in this map until all entries have been processed
437     * or the action throws an exception.   Unless otherwise specified by the implementing class,
438     * actions are performed in the order of entry set iteration (if an iteration order is
439     * specified.) Exceptions thrown by the action are relayed to the caller.
440     * 
441     * <BR /><BR />The default implementation is equivalent to, for this {@code map}:
442     * 
443     * <BR /><DIV CLASS=SNIP>{@code
444     * for (ReadOnlyMap.Entry<K, V> entry : map.entrySet())
445     *     action.accept(entry.getKey(), entry.getValue());
446     * }</DIV>
447     * 
448     * <BR /><BR />The default implementation makes no guarantees about synchronization or
449     * atomicity properties of this method. Any implementation providing atomicity guarantees must
450     * override this method and document its concurrency properties.
451     * 
452     * @param action The action to be performed for each entry
453     * @throws NullPointerException if the specified action is null
454     */
455    default void forEach(BiConsumer<? super K, ? super V> action)
456    {
457        Objects.requireNonNull(action);
458
459        for (ReadOnlyMap.Entry<K, V> entry : entrySet())
460        {
461            K k;
462            V v;
463
464            try
465            {
466                k = entry.getKey();
467                v = entry.getValue();
468            }
469
470            catch (IllegalStateException ise)
471            {
472                // this usually means the entry is no longer in the map.
473                // throw new ConcurrentModificationException(ise);
474
475                throw new Torello.Java.UnreachableError();
476            }
477
478            action.accept(k, v);
479        }
480    }
481
482    /**
483     * Copies the contents of {@code 'this'} ReadOnlyMap into the user-provided {@code 'map'}.
484     * Utilizes the {@code java.util.Map} method {@code put(K key, V value)}.
485     * 
486     * @param map Any instance of java.util.Map
487     * @see #forEach(BiConsumer)
488     */
489    default void copyIntoMap(Map<? super K, ? super V> map)
490    { this.forEach((K k, V v) -> map.put(k, v)); }
491
492
493    // ********************************************************************************************
494    // ********************************************************************************************
495    // MAP-KEYS: contains - using Var-Args Arrays
496    // ********************************************************************************************
497    // ********************************************************************************************
498
499
500    /**
501     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
502     * <B STYLE='color: red;'>contains a matching key for every one of the elements</B> in
503     * Var-Args Parameter {@code 'elements'}
504     * 
505     * @param elements a list of elements
506     * 
507     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
508     * every element in {@code 'elements'}
509     */
510    default boolean containsKeyAND(Object... elements)
511    {
512        ReadOnlySet<K> keys = this.keySet();
513        for (Object elem : elements) if (! keys.contains(elem)) return false;
514        return true;
515    }
516
517    /**
518     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
519     * <B STYLE='color: red;'>does not contain any key that matches any of the elements</B> in
520     * Var-Args Parameter {@code 'elements'}
521     * 
522     * @param elements a list of elements
523     * 
524     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
525     * none of the elements in {@code 'elements'}
526     */
527    default boolean containsKeyNAND(Object... elements)
528    {
529        ReadOnlySet<K> keys = this.keySet();
530        for (Object elem : elements) if (keys.contains(elem)) return false;
531        return true;
532    }
533
534    /**
535     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
536     * <B STYLE='color: red;'>contains at least one key that matches at least one element</B> in
537     * Var-Args Parameter {@code 'elements'}
538     * 
539     * @param elements a list of elements
540     * 
541     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
542     * one or more of the elements in {@code 'elements'}
543     */
544    default boolean containsKeyOR(Object... elements)
545    {
546        ReadOnlySet<K> keys = this.keySet();
547        for (Object elem : elements) if (keys.contains(elem)) return true;
548        return false;
549    }
550
551    /**
552     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
553     * <B STYLE='color: red;'>contains exactly one key that matches an element</B> in Var-Args
554     * Parameter {@code 'elements'}
555     * 
556     * @param elements a list of elements
557     * 
558     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
559     * precisely one element that is also in {@code 'elements'}
560     */
561    default boolean containsKeyXOR(Object... elements)
562    {
563        ReadOnlySet<K>  keys    = this.keySet();
564        boolean         found   = false;
565
566        for (Object elem : elements)
567
568            if (keys.contains(elem))
569            {
570                if (found) return false;
571                else found = true;
572            }
573
574        return found;
575    }
576
577
578    // ********************************************************************************************
579    // ********************************************************************************************
580    // MAP-KEYS: contains - using java.lang.Iterable
581    // ********************************************************************************************
582    // ********************************************************************************************
583
584
585    /**
586     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
587     * <B STYLE='color: red;'>contains a matching key for every one of the elements</B> in
588     * {@code Iterable} parameter {@code 'i'}.
589     * 
590     * @param i any Java {@code Iterable}
591     * 
592     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
593     * every element in {@code 'i'}
594     */
595    default boolean containsKeyAND(Iterable<?> i)
596    {
597        ReadOnlySet<K> keys = this.keySet();
598        for (Object o: i) if (! keys.contains(o)) return false;
599        return true;
600    }
601
602    /**
603     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
604     * <B STYLE='color: red;'>does not contain any key that matches any of the elements</B> in
605     * {@code Iterable} parameter {@code 'i'}
606     *
607     * @param i any Java {@code Iterable}
608     * 
609     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
610     * none of the elements in {@code 'i'}
611     */
612    default boolean containsKeyNAND(Iterable<?> i)
613    {
614        ReadOnlySet<K> keys = this.keySet();
615        for (Object o: i) if (keys.contains(o)) return false;
616        return true;
617    }
618
619    /**
620     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
621     * <B STYLE='color: red;'>contains at least one key that matches at least one element</B> in
622     * {@code Iterable} parameter {@code 'i'}
623     *
624     * @param i any Java {@code Iterable}
625     * 
626     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
627     * one or more of the elements in {@code 'i'}
628     */
629    default boolean containsKeyOR(Iterable<?> i)
630    {
631        ReadOnlySet<K> keys = this.keySet();
632        for (Object o: i) if (keys.contains(o)) return true;
633        return false;
634    }
635
636    /**
637     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
638     * <B STYLE='color: red;'>contains exactly one key that matches an element</B> in 
639     * {@code Iterable} parameter {@code 'i'}
640     *
641     * @param i any Java {@code Iterable}
642     *  
643     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
644     * precisely one element that is also in {@code 'i'}
645     */
646    default boolean containsKeyXOR(Iterable<?> i)
647    {
648        ReadOnlySet<K>  keys    = this.keySet();
649        boolean         found   = false;
650
651        for (Object o: i)
652
653            if (keys.contains(o))
654            {
655                if (found) return false;
656                else found = true;
657            }
658
659        return found;
660    }
661
662
663    // ********************************************************************************************
664    // ********************************************************************************************
665    // MAP-VALUES: contains - using Var-Args Arrays
666    // ********************************************************************************************
667    // ********************************************************************************************
668
669
670    /**
671     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
672     * <B STYLE='color: red;'>contains a matching value for every one of the elements</B> in
673     * Var-Args Parameter {@code 'elements'}
674     * 
675     * @param elements a list of elements
676     * 
677     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
678     * every element in {@code 'elements'}
679     */
680    default boolean containsValueAND(Object... elements)
681    {
682        ReadOnlyCollection<V> values = this.values();
683        for (Object elem : elements) if (! values.contains(elem)) return false;
684        return true;
685    }
686
687    /**
688     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
689     * <B STYLE='color: red;'>does not contain any value that matches any of the elements</B> in
690     * Var-Args Parameter {@code 'elements'}
691     * 
692     * @param elements a list of elements
693     * 
694     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
695     * none of the elements in {@code 'elements'}
696     */
697    default boolean containsValueNAND(Object... elements)
698    {
699        ReadOnlyCollection<V> values = this.values();
700        for (Object elem : elements) if (values.contains(elem)) return false;
701        return true;
702    }
703
704    /**
705     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
706     * <B STYLE='color: red;'>contains at least one value that matches at least one element</B> in
707     * Var-Args Parameter {@code 'elements'}
708     * 
709     * @param elements a list of elements
710     * 
711     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
712     * one or more of the elements in {@code 'elements'}
713     */
714    default boolean containsValueOR(Object... elements)
715    {
716        ReadOnlyCollection<V> values = this.values();
717        for (Object elem : elements) if (values.contains(elem)) return true;
718        return false;
719    }
720
721    /**
722     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
723     * <B STYLE='color: red;'>contains exactly one value that matches an element</B> in Var-Args
724     * Parameter {@code 'elements'}
725     * 
726     * @param elements a list of elements
727     * 
728     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
729     * precisely one element that is also in {@code 'elements'}
730     */
731    default boolean containsValueXOR(Object... elements)
732    {
733        ReadOnlyCollection<V>   values  = this.values();
734        boolean                 found   = false;
735
736        for (Object elem : elements)
737
738            if (values.contains(elem))
739            {
740                if (found) return false;
741                else found = true;
742            }
743
744        return found;
745    }
746
747
748    // ********************************************************************************************
749    // ********************************************************************************************
750    // MAP-VALUES: contains - using java.lang.Iterable
751    // ********************************************************************************************
752    // ********************************************************************************************
753
754
755    /**
756     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
757     * <B STYLE='color: red;'>contains a matching value for every one of the elements</B> in
758     * {@code Iterable} parameter {@code 'i'}
759     * 
760     * @param i any Java {@code Iterable}
761     * 
762     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
763     * every element in {@code 'i'}
764     */
765    default boolean containsValueAND(Iterable<?> i)
766    {
767        ReadOnlyCollection<V> values = this.values();
768        for (Object o: i) if (! values.contains(o)) return false;
769        return true;
770    }
771
772    /**
773     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
774     * <B STYLE='color: red;'>does not contain any value that matches any of the elements</B> in
775     * {@code Iterable} parameter {@code 'i'}
776     * 
777     * @param i any Java {@code Iterable}
778     * 
779     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
780     * none of the elements in {@code 'i'}
781     */
782    default boolean containsValueNAND(Iterable<?> i)
783    {
784        ReadOnlyCollection<V> values = this.values();
785        for (Object o: i) if (values.contains(o)) return false;
786        return true;
787    }
788
789    /**
790     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
791     * <B STYLE='color: red;'>contains at least one value that matches at least one element</B> in
792     * {@code Iterable} parameter {@code 'i'}
793     *
794     * @param i any Java {@code Iterable}
795     * 
796     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
797     * one or more of the elements in {@code 'i'}
798     */
799    default boolean containsValueOR(Iterable<?> i)
800    {
801        ReadOnlyCollection<V> values = this.values();
802        for (Object o: i) if (values.contains(o)) return true;
803        return false;
804    }
805
806    /**
807     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
808     * <B STYLE='color: red;'>contains exactly one value that matches an element</B> in 
809     * {@code Iterable} parameter {@code 'i'}
810     *
811     * @param i any Java {@code Iterable}
812     *  
813     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
814     * precisely one element that is also in {@code 'i'}
815     */
816    default boolean containsValueXOR(Iterable<?> i)
817    {
818        ReadOnlyCollection<V>   values  = this.values();
819        boolean                 found   = false;
820
821        for (Object o: i)
822
823            if (values.contains(o))
824            {
825                if (found) return false;
826                else found = true;
827            }
828
829        return found;
830    }
831
832
833    // ********************************************************************************************
834    // ********************************************************************************************
835    // "of" ...
836    // ********************************************************************************************
837    // ********************************************************************************************
838
839
840    /**
841     * Returns an unmodifiable map containing zero mappings.
842     *
843     * @param <K> the {@code Map}'s key type
844     * @param <V> the {@code Map}'s value type
845     * @return an empty {@code Map}
846     */
847    @SuppressWarnings("unchecked")
848    static <K, V> ReadOnlyMap<K, V> of()
849    { return new JavaHTMLReadOnlyMap<>(Map.of()); }
850
851    /**
852     * Returns an unmodifiable map containing a single mapping.
853     *
854     * @param <K> the {@code Map}'s key type
855     * @param <V> the {@code Map}'s value type
856     * @param k1 the mapping's key
857     * @param v1 the mapping's value
858     * 
859     * @return a {@link ReadOnlyMap} containing the specified mapping
860     * @throws NullPointerException if the key or the value is {@code null}
861     */
862    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1)
863    { return new JavaHTMLReadOnlyMap<>(Map.of(k1, v1)); }
864
865    /**
866     * Returns an unmodifiable map containing two mappings.
867     *
868     * @param <K> the {@code Map}'s key type
869     * @param <V> the {@code Map}'s value type
870     * @param k1 the first mapping's key
871     * @param v1 the first mapping's value
872     * @param k2 the second mapping's key
873     * @param v2 the second mapping's value
874     * 
875     * @return a {@link ReadOnlyMap} containing the specified mappings
876     * @throws IllegalArgumentException if the keys are duplicates
877     * @throws NullPointerException if any key or value is {@code null}
878     */
879    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2)
880    { return new JavaHTMLReadOnlyMap<>(Map.of(k1, v1, k2, v2)); }
881
882    /**
883     * Returns an unmodifiable map containing three mappings.
884     *
885     * @param <K> the {@code Map}'s key type
886     * @param <V> the {@code Map}'s value type
887     * @param k1 the first mapping's key
888     * @param v1 the first mapping's value
889     * @param k2 the second mapping's key
890     * @param v2 the second mapping's value
891     * @param k3 the third mapping's key
892     * @param v3 the third mapping's value
893     * 
894     * @return a {@link ReadOnlyMap} containing the specified mappings
895     * @throws IllegalArgumentException if there are any duplicate keys
896     * @throws NullPointerException if any key or value is {@code null}
897     */
898    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3)
899    { return new JavaHTMLReadOnlyMap<>(Map.of(k1, v1, k2, v2, k3, v3)); }
900
901    /**
902     * Returns an unmodifiable map containing four mappings.
903     *
904     * @param <K> the {@code Map}'s key type
905     * @param <V> the {@code Map}'s value type
906     * @param k1 the first mapping's key
907     * @param v1 the first mapping's value
908     * @param k2 the second mapping's key
909     * @param v2 the second mapping's value
910     * @param k3 the third mapping's key
911     * @param v3 the third mapping's value
912     * @param k4 the fourth mapping's key
913     * @param v4 the fourth mapping's value
914     * 
915     * @return a {@link ReadOnlyMap} containing the specified mappings
916     * @throws IllegalArgumentException if there are any duplicate keys
917     * @throws NullPointerException if any key or value is {@code null}
918     */
919    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)
920    { return new JavaHTMLReadOnlyMap<>(Map.of(k1, v1, k2, v2, k3, v3, k4, v4)); }
921
922    /**
923     * Returns an unmodifiable map containing five mappings.
924     *
925     * @param <K> the {@code Map}'s key type
926     * @param <V> the {@code Map}'s value type
927     * @param k1 the first mapping's key
928     * @param v1 the first mapping's value
929     * @param k2 the second mapping's key
930     * @param v2 the second mapping's value
931     * @param k3 the third mapping's key
932     * @param v3 the third mapping's value
933     * @param k4 the fourth mapping's key
934     * @param v4 the fourth mapping's value
935     * @param k5 the fifth mapping's key
936     * @param v5 the fifth mapping's value
937     * 
938     * @return a {@link ReadOnlyMap} containing the specified mappings
939     * @throws IllegalArgumentException if there are any duplicate keys
940     * @throws NullPointerException if any key or value is {@code null}
941     *
942     */
943    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5)
944    { return new JavaHTMLReadOnlyMap<>(Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5)); }
945
946    /**
947     * Returns an unmodifiable map containing six mappings.
948     *
949     * @param <K> the {@code Map}'s key type
950     * @param <V> the {@code Map}'s value type
951     * @param k1 the first mapping's key
952     * @param v1 the first mapping's value
953     * @param k2 the second mapping's key
954     * @param v2 the second mapping's value
955     * @param k3 the third mapping's key
956     * @param v3 the third mapping's value
957     * @param k4 the fourth mapping's key
958     * @param v4 the fourth mapping's value
959     * @param k5 the fifth mapping's key
960     * @param v5 the fifth mapping's value
961     * @param k6 the sixth mapping's key
962     * @param v6 the sixth mapping's value
963     * 
964     * @return a {@link ReadOnlyMap} containing the specified mappings
965     * @throws IllegalArgumentException if there are any duplicate keys
966     * @throws NullPointerException if any key or value is {@code null}
967     */
968    static <K, V> ReadOnlyMap<K, V> of(
969            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
970            K k6, V v6
971        )
972    {
973        return new JavaHTMLReadOnlyMap<>
974            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6));
975    }
976
977    /**
978     * Returns an unmodifiable map containing seven mappings.
979     * 
980     * @param <K> the {@code Map}'s key type
981     * @param <V> the {@code Map}'s value type
982     * @param k1 the first mapping's key
983     * @param v1 the first mapping's value
984     * @param k2 the second mapping's key
985     * @param v2 the second mapping's value
986     * @param k3 the third mapping's key
987     * @param v3 the third mapping's value
988     * @param k4 the fourth mapping's key
989     * @param v4 the fourth mapping's value
990     * @param k5 the fifth mapping's key
991     * @param v5 the fifth mapping's value
992     * @param k6 the sixth mapping's key
993     * @param v6 the sixth mapping's value
994     * @param k7 the seventh mapping's key
995     * @param v7 the seventh mapping's value
996     * 
997     * @return a {@link ReadOnlyMap} containing the specified mappings
998     * @throws IllegalArgumentException if there are any duplicate keys
999     * @throws NullPointerException if any key or value is {@code null}
1000     */
1001    static <K, V> ReadOnlyMap<K, V> of(
1002            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
1003            K k6, V v6, K k7, V v7
1004        )
1005    {
1006        return new JavaHTMLReadOnlyMap<>
1007            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7));
1008    }
1009
1010    /**
1011     * Returns an unmodifiable map containing eight mappings.
1012     * 
1013     * @param <K> the {@code Map}'s key type
1014     * @param <V> the {@code Map}'s value type
1015     * @param k1 the first mapping's key
1016     * @param v1 the first mapping's value
1017     * @param k2 the second mapping's key
1018     * @param v2 the second mapping's value
1019     * @param k3 the third mapping's key
1020     * @param v3 the third mapping's value
1021     * @param k4 the fourth mapping's key
1022     * @param v4 the fourth mapping's value
1023     * @param k5 the fifth mapping's key
1024     * @param v5 the fifth mapping's value
1025     * @param k6 the sixth mapping's key
1026     * @param v6 the sixth mapping's value
1027     * @param k7 the seventh mapping's key
1028     * @param v7 the seventh mapping's value
1029     * @param k8 the eighth mapping's key
1030     * @param v8 the eighth mapping's value
1031     * 
1032     * @return a {@link ReadOnlyMap} containing the specified mappings
1033     * @throws IllegalArgumentException if there are any duplicate keys
1034     * @throws NullPointerException if any key or value is {@code null}
1035     */
1036    static <K, V> ReadOnlyMap<K, V> of(
1037            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
1038            K k6, V v6, K k7, V v7, K k8, V v8
1039        )
1040    {
1041        return new JavaHTMLReadOnlyMap<>
1042            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8));
1043    }
1044
1045    /**
1046     * Returns an unmodifiable map containing nine mappings.
1047     * 
1048     * @param <K> the {@code Map}'s key type
1049     * @param <V> the {@code Map}'s value type
1050     * @param k1 the first mapping's key
1051     * @param v1 the first mapping's value
1052     * @param k2 the second mapping's key
1053     * @param v2 the second mapping's value
1054     * @param k3 the third mapping's key
1055     * @param v3 the third mapping's value
1056     * @param k4 the fourth mapping's key
1057     * @param v4 the fourth mapping's value
1058     * @param k5 the fifth mapping's key
1059     * @param v5 the fifth mapping's value
1060     * @param k6 the sixth mapping's key
1061     * @param v6 the sixth mapping's value
1062     * @param k7 the seventh mapping's key
1063     * @param v7 the seventh mapping's value
1064     * @param k8 the eighth mapping's key
1065     * @param v8 the eighth mapping's value
1066     * @param k9 the ninth mapping's key
1067     * @param v9 the ninth mapping's value
1068     * 
1069     * @return a {@link ReadOnlyMap} containing the specified mappings
1070     * @throws IllegalArgumentException if there are any duplicate keys
1071     * @throws NullPointerException if any key or value is {@code null}
1072     */
1073    static <K, V> ReadOnlyMap<K, V> of(
1074            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
1075            K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9
1076        )
1077    {
1078        return new JavaHTMLReadOnlyMap<>
1079            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9));
1080    }
1081
1082    /**
1083     * Returns an unmodifiable map containing ten mappings.
1084     *
1085     * @param <K> the {@code Map}'s key type
1086     * @param <V> the {@code Map}'s value type
1087     * @param k1 the first mapping's key
1088     * @param v1 the first mapping's value
1089     * @param k2 the second mapping's key
1090     * @param v2 the second mapping's value
1091     * @param k3 the third mapping's key
1092     * @param v3 the third mapping's value
1093     * @param k4 the fourth mapping's key
1094     * @param v4 the fourth mapping's value
1095     * @param k5 the fifth mapping's key
1096     * @param v5 the fifth mapping's value
1097     * @param k6 the sixth mapping's key
1098     * @param v6 the sixth mapping's value
1099     * @param k7 the seventh mapping's key
1100     * @param v7 the seventh mapping's value
1101     * @param k8 the eighth mapping's key
1102     * @param v8 the eighth mapping's value
1103     * @param k9 the ninth mapping's key
1104     * @param v9 the ninth mapping's value
1105     * @param k10 the tenth mapping's key
1106     * @param v10 the tenth mapping's value
1107     * 
1108     * @return a {@link ReadOnlyMap} containing the specified mappings
1109     * @throws IllegalArgumentException if there are any duplicate keys
1110     * @throws NullPointerException if any key or value is {@code null}
1111     */
1112    static <K, V> ReadOnlyMap<K, V> of(
1113            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
1114            K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10
1115        )
1116    {
1117        return new JavaHTMLReadOnlyMap<>(
1118            Map.of(
1119                k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6,
1120                k7, v7, k8, v8, k9, v9, k10, v10
1121            ));
1122    }
1123
1124    /**
1125     * Returns an unmodifiable map containing keys and values extracted from the given entries.
1126     * The entries themselves are not stored in the map.
1127     *
1128     * <BR /><BR />It is convenient to create the map entries using the
1129     * {@link ReadOnlyMap#entry ReadOnlyMap.entry()} method.  For example,
1130     *
1131     * <DIV CLASS=EXAMPLE>{@code
1132     * import static Torello.Java.ReadOnly.ReadOnlyMap.entry;
1133     *
1134     * ReadOnlyMap<Integer,String> map = ReadOnlyMap.ofEntries(
1135     *      entry(1, "a"),
1136     *      entry(2, "b"),
1137     *      entry(3, "c"),
1138     *      ...
1139     *      entry(26, "z"));
1140     * }</DIV>
1141     *
1142     * @param <K> the {@link ReadOnlyMap}'s key type
1143     * @param <V> the {@link ReadOnlyMap}'s value type
1144     * 
1145     * @param entries {@code ReadOnlyMap.Entry}s containing the keys and values from which the map
1146     * is populated
1147     * 
1148     * @return a {@link ReadOnlyMap} containing the specified mappings
1149     * @throws IllegalArgumentException if there are any duplicate keys
1150     * 
1151     * @throws NullPointerException if any entry, key, or value is {@code null}, or if the
1152     * {@code entries} array is {@code null}
1153     *
1154     * @see ReadOnlyMap#entry Map.entry()
1155     */
1156    @SafeVarargs
1157    @SuppressWarnings("varargs")
1158    static <K, V>
1159        ReadOnlyMap<K, V>
1160        ofEntries
1161        (ReadOnlyMap.Entry<? extends K, ? extends V>... entries)
1162    {
1163        // *** Java-HTML: This arbitrarily uses TreeMap
1164        ROTreeMapBuilder<K, V> b = new ROTreeMapBuilder<>();
1165
1166        for (ReadOnlyMap.Entry<? extends K, ? extends V> e : entries)
1167            b.put(e.getKey(), e.getValue());
1168
1169        return b.build();
1170    }
1171
1172    /**
1173     * Returns an unmodifiable {@link Entry} containing the given key and value.
1174     * These entries are suitable for populating {@code ReadOnlyMap} instances using the
1175     * {@link ReadOnlyMap#ofEntries ReadOnlyMap.ofEntries()} method.
1176     * 
1177     * @param <K> the key's type
1178     * @param <V> the value's type
1179     * @param k the key
1180     * @param v the value
1181     * @return an {@code Entry} containing the specified key and value
1182     * @throws NullPointerException if the key or value is {@code null}
1183     *
1184     * @see ReadOnlyMap#ofEntries Map.ofEntries()
1185     */
1186    static <K, V> ReadOnlyMap.Entry<K, V> entry(K k, V v)
1187    {
1188        // KeyValueHolder checks for nulls
1189        // return new KeyValueHolder<>(k, v);
1190        return new EntryImpl<>(Objects.requireNonNull(k), Objects.requireNonNull(v));
1191    }
1192}