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    // Comparison and hashing
315    // ********************************************************************************************
316    // ********************************************************************************************
317
318
319    /**
320     * Compares the specified object with this map for equality.  Returns {@code TRUE} if the given
321     * object is also a map and the two maps represent the same mappings.  More formally, two maps
322     * {@code m1} and {@code m2} represent the same mappings if
323     * {@code m1.entrySet().equals(m2.entrySet())}.  This ensures that the {@code equals} method
324     * works properly across different implementations of the {@code Map} interface.
325     * 
326     * @param o object to be compared for equality with this map
327     * @return {@code TRUE} if the specified object is equal to this map
328     */
329    boolean equals(Object o);
330
331    /**
332     * Returns the hash code value for this map.  The hash code of a map is defined to be the sum
333     * of the hash codes of each entry in the map's {@code entrySet()} view.  This ensures that
334     * {@code m1.equals(m2)} implies that {@code m1.hashCode()==m2.hashCode()} for any two maps
335     * {@code m1} and {@code m2}, as required by the general contract of {@code Object.hashCode}.
336     *
337     * @return the hash code value for this map
338     * @see ReadOnlyMap.Entry#hashCode()
339     * @see #equals(Object)
340     */
341    int hashCode();
342
343
344    // ********************************************************************************************
345    // ********************************************************************************************
346    // Defaultable methods
347    // ********************************************************************************************
348    // ********************************************************************************************
349
350
351    /**
352     * Returns the value to which the specified key is mapped, or {@code defaultValue} if this map
353     * contains no mapping for the key.
354     *
355     * @param key the key whose associated value is to be returned
356     * @param defaultValue the default mapping of the key
357     * 
358     * @return the value to which the specified key is mapped, or {@code defaultValue} if this map
359     * contains no mapping for the key
360     * 
361     * @throws ClassCastException if the key is of an inappropriate type for this map
362     * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
363     * 
364     * @throws NullPointerException if the specified key is null and this map does not permit null
365     * keys 
366     * (<A HREF='ReadOnlyCollection.html#optional-restrictions'>optional-restrictions</A>)
367     */
368    default V getOrDefault(Object key, V defaultValue)
369    {
370        V v;
371        return (((v = get(key)) != null) || containsKey(key))
372            ? v
373            : defaultValue;
374    }
375
376    /**
377     * Performs the given action for each entry in this map until all entries have been processed
378     * or the action throws an exception.   Unless otherwise specified by the implementing class,
379     * actions are performed in the order of entry set iteration (if an iteration order is
380     * specified.) Exceptions thrown by the action are relayed to the caller.
381     * 
382     * <BR /><BR />The default implementation is equivalent to, for this {@code map}:
383     * 
384     * <BR /><DIV CLASS=SNIP>{@code
385     * for (ReadOnlyMap.Entry<K, V> entry : map.entrySet())
386     *     action.accept(entry.getKey(), entry.getValue());
387     * }</DIV>
388     * 
389     * <BR /><BR />The default implementation makes no guarantees about synchronization or
390     * atomicity properties of this method. Any implementation providing atomicity guarantees must
391     * override this method and document its concurrency properties.
392     * 
393     * @param action The action to be performed for each entry
394     * @throws NullPointerException if the specified action is null
395     */
396    default void forEach(BiConsumer<? super K, ? super V> action)
397    {
398        Objects.requireNonNull(action);
399
400        for (ReadOnlyMap.Entry<K, V> entry : entrySet())
401        {
402            K k;
403            V v;
404
405            try
406            {
407                k = entry.getKey();
408                v = entry.getValue();
409            }
410
411            catch (IllegalStateException ise)
412            {
413                // this usually means the entry is no longer in the map.
414                // throw new ConcurrentModificationException(ise);
415
416                throw new Torello.Java.UnreachableError();
417            }
418
419            action.accept(k, v);
420        }
421    }
422
423    /**
424     * Copies the contents of {@code 'this'} ReadOnlyMap into the user-provided {@code 'map'}.
425     * Utilizes the {@code java.util.Map} method {@code put(K key, V value)}.
426     * 
427     * @param map Any instance of java.util.Map
428     * @see #forEach(BiConsumer)
429     */
430    default void copyIntoMap(Map<? super K, ? super V> map)
431    { this.forEach((K k, V v) -> map.put(k, v)); }
432
433
434    // ********************************************************************************************
435    // ********************************************************************************************
436    // MAP-KEYS: contains - using Var-Args Arrays
437    // ********************************************************************************************
438    // ********************************************************************************************
439
440
441    /**
442     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
443     * <B STYLE='color: red;'>contains a matching key for every one of the elements</B> in
444     * Var-Args Parameter {@code 'elements'}
445     * 
446     * @param elements a list of elements
447     * 
448     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
449     * every element in {@code 'elements'}
450     */
451    default boolean containsKeyAND(Object... elements)
452    {
453        ReadOnlySet<K> keys = this.keySet();
454        for (Object elem : elements) if (! keys.contains(elem)) return false;
455        return true;
456    }
457
458    /**
459     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
460     * <B STYLE='color: red;'>does not contain any key that matches any of the elements</B> in
461     * Var-Args Parameter {@code 'elements'}
462     * 
463     * @param elements a list of elements
464     * 
465     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
466     * none of the elements in {@code 'elements'}
467     */
468    default boolean containsKeyNAND(Object... elements)
469    {
470        ReadOnlySet<K> keys = this.keySet();
471        for (Object elem : elements) if (keys.contains(elem)) return false;
472        return true;
473    }
474
475    /**
476     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
477     * <B STYLE='color: red;'>contains at least one key that matches at least one element</B> in
478     * Var-Args Parameter {@code 'elements'}
479     * 
480     * @param elements a list of elements
481     * 
482     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
483     * one or more of the elements in {@code 'elements'}
484     */
485    default boolean containsKeyOR(Object... elements)
486    {
487        ReadOnlySet<K> keys = this.keySet();
488        for (Object elem : elements) if (keys.contains(elem)) return true;
489        return false;
490    }
491
492    /**
493     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
494     * <B STYLE='color: red;'>contains exactly one key that matches an element</B> in Var-Args
495     * Parameter {@code 'elements'}
496     * 
497     * @param elements a list of elements
498     * 
499     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
500     * precisely one element that is also in {@code 'elements'}
501     */
502    default boolean containsKeyXOR(Object... elements)
503    {
504        ReadOnlySet<K>  keys    = this.keySet();
505        boolean         found   = false;
506
507        for (Object elem : elements)
508
509            if (keys.contains(elem))
510            {
511                if (found) return false;
512                else found = true;
513            }
514
515        return found;
516    }
517
518
519    // ********************************************************************************************
520    // ********************************************************************************************
521    // MAP-KEYS: contains - using java.lang.Iterable
522    // ********************************************************************************************
523    // ********************************************************************************************
524
525
526    /**
527     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
528     * <B STYLE='color: red;'>contains a matching key for every one of the elements</B> in
529     * {@code Iterable} parameter {@code 'i'}.
530     * 
531     * @param i any Java {@code Iterable}
532     * 
533     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
534     * every element in {@code 'i'}
535     */
536    default boolean containsKeyAND(Iterable<?> i)
537    {
538        ReadOnlySet<K> keys = this.keySet();
539        for (Object o: i) if (! keys.contains(o)) return false;
540        return true;
541    }
542
543    /**
544     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
545     * <B STYLE='color: red;'>does not contain any key that matches any of the elements</B> in
546     * {@code Iterable} parameter {@code 'i'}
547     *
548     * @param i any Java {@code Iterable}
549     * 
550     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
551     * none of the elements in {@code 'i'}
552     */
553    default boolean containsKeyNAND(Iterable<?> i)
554    {
555        ReadOnlySet<K> keys = this.keySet();
556        for (Object o: i) if (keys.contains(o)) return false;
557        return true;
558    }
559
560    /**
561     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
562     * <B STYLE='color: red;'>contains at least one key that matches at least one element</B> in
563     * {@code Iterable} parameter {@code 'i'}
564     *
565     * @param i any Java {@code Iterable}
566     * 
567     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
568     * one or more of the elements in {@code 'i'}
569     */
570    default boolean containsKeyOR(Iterable<?> i)
571    {
572        ReadOnlySet<K> keys = this.keySet();
573        for (Object o: i) if (keys.contains(o)) return true;
574        return false;
575    }
576
577    /**
578     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
579     * <B STYLE='color: red;'>contains exactly one key that matches an element</B> in 
580     * {@code Iterable} parameter {@code 'i'}
581     *
582     * @param i any Java {@code Iterable}
583     *  
584     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'keySet()'} contains
585     * precisely one element that is also in {@code 'i'}
586     */
587    default boolean containsKeyXOR(Iterable<?> i)
588    {
589        ReadOnlySet<K>  keys    = this.keySet();
590        boolean         found   = false;
591
592        for (Object o: i)
593
594            if (keys.contains(o))
595            {
596                if (found) return false;
597                else found = true;
598            }
599
600        return found;
601    }
602
603
604    // ********************************************************************************************
605    // ********************************************************************************************
606    // MAP-VALUES: contains - using Var-Args Arrays
607    // ********************************************************************************************
608    // ********************************************************************************************
609
610
611    /**
612     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
613     * <B STYLE='color: red;'>contains a matching value for every one of the elements</B> in
614     * Var-Args Parameter {@code 'elements'}
615     * 
616     * @param elements a list of elements
617     * 
618     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
619     * every element in {@code 'elements'}
620     */
621    default boolean containsValueAND(Object... elements)
622    {
623        ReadOnlyCollection<V> values = this.values();
624        for (Object elem : elements) if (! values.contains(elem)) return false;
625        return true;
626    }
627
628    /**
629     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
630     * <B STYLE='color: red;'>does not contain any value that matches any of the elements</B> in
631     * Var-Args Parameter {@code 'elements'}
632     * 
633     * @param elements a list of elements
634     * 
635     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
636     * none of the elements in {@code 'elements'}
637     */
638    default boolean containsValueNAND(Object... elements)
639    {
640        ReadOnlyCollection<V> values = this.values();
641        for (Object elem : elements) if (values.contains(elem)) return false;
642        return true;
643    }
644
645    /**
646     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
647     * <B STYLE='color: red;'>contains at least one value that matches at least one element</B> in
648     * Var-Args Parameter {@code 'elements'}
649     * 
650     * @param elements a list of elements
651     * 
652     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
653     * one or more of the elements in {@code 'elements'}
654     */
655    default boolean containsValueOR(Object... elements)
656    {
657        ReadOnlyCollection<V> values = this.values();
658        for (Object elem : elements) if (values.contains(elem)) return true;
659        return false;
660    }
661
662    /**
663     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
664     * <B STYLE='color: red;'>contains exactly one value that matches an element</B> in Var-Args
665     * Parameter {@code 'elements'}
666     * 
667     * @param elements a list of elements
668     * 
669     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
670     * precisely one element that is also in {@code 'elements'}
671     */
672    default boolean containsValueXOR(Object... elements)
673    {
674        ReadOnlyCollection<V>   values  = this.values();
675        boolean                 found   = false;
676
677        for (Object elem : elements)
678
679            if (values.contains(elem))
680            {
681                if (found) return false;
682                else found = true;
683            }
684
685        return found;
686    }
687
688
689    // ********************************************************************************************
690    // ********************************************************************************************
691    // MAP-VALUES: contains - using java.lang.Iterable
692    // ********************************************************************************************
693    // ********************************************************************************************
694
695
696    /**
697     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
698     * <B STYLE='color: red;'>contains a matching value for every one of the elements</B> in
699     * {@code Iterable} parameter {@code 'i'}
700     * 
701     * @param i any Java {@code Iterable}
702     * 
703     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
704     * every element in {@code 'i'}
705     */
706    default boolean containsValueAND(Iterable<?> i)
707    {
708        ReadOnlyCollection<V> values = this.values();
709        for (Object o: i) if (! values.contains(o)) return false;
710        return true;
711    }
712
713    /**
714     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
715     * <B STYLE='color: red;'>does not contain any value that matches any of the elements</B> in
716     * {@code Iterable} parameter {@code 'i'}
717     * 
718     * @param i any Java {@code Iterable}
719     * 
720     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
721     * none of the elements in {@code 'i'}
722     */
723    default boolean containsValueNAND(Iterable<?> i)
724    {
725        ReadOnlyCollection<V> values = this.values();
726        for (Object o: i) if (values.contains(o)) return false;
727        return true;
728    }
729
730    /**
731     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
732     * <B STYLE='color: red;'>contains at least one value that matches at least one element</B> in
733     * {@code Iterable} parameter {@code 'i'}
734     *
735     * @param i any Java {@code Iterable}
736     * 
737     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
738     * one or more of the elements in {@code 'i'}
739     */
740    default boolean containsValueOR(Iterable<?> i)
741    {
742        ReadOnlyCollection<V> values = this.values();
743        for (Object o: i) if (values.contains(o)) return true;
744        return false;
745    }
746
747    /**
748     * Checks to ensure that {@code 'this'} instance of {@code ReadOnlyMap}
749     * <B STYLE='color: red;'>contains exactly one value that matches an element</B> in 
750     * {@code Iterable} parameter {@code 'i'}
751     *
752     * @param i any Java {@code Iterable}
753     *  
754     * @return {@code TRUE} If and only if {@code 'this'} instance' {@code 'values()'} contains
755     * precisely one element that is also in {@code 'i'}
756     */
757    default boolean containsValueXOR(Iterable<?> i)
758    {
759        ReadOnlyCollection<V>   values  = this.values();
760        boolean                 found   = false;
761
762        for (Object o: i)
763
764            if (values.contains(o))
765            {
766                if (found) return false;
767                else found = true;
768            }
769
770        return found;
771    }
772
773
774    // ********************************************************************************************
775    // ********************************************************************************************
776    // "of" ...
777    // ********************************************************************************************
778    // ********************************************************************************************
779
780
781    /**
782     * Returns an unmodifiable map containing zero mappings.
783     *
784     * @param <K> the {@code Map}'s key type
785     * @param <V> the {@code Map}'s value type
786     * @return an empty {@code Map}
787     */
788    @SuppressWarnings("unchecked")
789    static <K, V> ReadOnlyMap<K, V> of()
790    { return InterfaceBuilder.toReadOnlyMap(Map.of()); }
791
792    /**
793     * Returns an unmodifiable map containing a single mapping.
794     *
795     * @param <K> the {@code Map}'s key type
796     * @param <V> the {@code Map}'s value type
797     * @param k1 the mapping's key
798     * @param v1 the mapping's value
799     * 
800     * @return a {@link ReadOnlyMap} containing the specified mapping
801     * @throws NullPointerException if the key or the value is {@code null}
802     */
803    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1)
804    { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1)); }
805
806    /**
807     * Returns an unmodifiable map containing two mappings.
808     *
809     * @param <K> the {@code Map}'s key type
810     * @param <V> the {@code Map}'s value type
811     * @param k1 the first mapping's key
812     * @param v1 the first mapping's value
813     * @param k2 the second mapping's key
814     * @param v2 the second mapping's value
815     * 
816     * @return a {@link ReadOnlyMap} containing the specified mappings
817     * @throws IllegalArgumentException if the keys are duplicates
818     * @throws NullPointerException if any key or value is {@code null}
819     */
820    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2)
821    { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2)); }
822
823    /**
824     * Returns an unmodifiable map containing three mappings.
825     *
826     * @param <K> the {@code Map}'s key type
827     * @param <V> the {@code Map}'s value type
828     * @param k1 the first mapping's key
829     * @param v1 the first mapping's value
830     * @param k2 the second mapping's key
831     * @param v2 the second mapping's value
832     * @param k3 the third mapping's key
833     * @param v3 the third mapping's value
834     * 
835     * @return a {@link ReadOnlyMap} containing the specified mappings
836     * @throws IllegalArgumentException if there are any duplicate keys
837     * @throws NullPointerException if any key or value is {@code null}
838     */
839    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3)
840    { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2, k3, v3)); }
841
842    /**
843     * Returns an unmodifiable map containing four mappings.
844     *
845     * @param <K> the {@code Map}'s key type
846     * @param <V> the {@code Map}'s value type
847     * @param k1 the first mapping's key
848     * @param v1 the first mapping's value
849     * @param k2 the second mapping's key
850     * @param v2 the second mapping's value
851     * @param k3 the third mapping's key
852     * @param v3 the third mapping's value
853     * @param k4 the fourth mapping's key
854     * @param v4 the fourth mapping's value
855     * 
856     * @return a {@link ReadOnlyMap} containing the specified mappings
857     * @throws IllegalArgumentException if there are any duplicate keys
858     * @throws NullPointerException if any key or value is {@code null}
859     */
860    static <K, V> ReadOnlyMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)
861    { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2, k3, v3, k4, v4)); }
862
863    /**
864     * Returns an unmodifiable map containing five mappings.
865     *
866     * @param <K> the {@code Map}'s key type
867     * @param <V> the {@code Map}'s value type
868     * @param k1 the first mapping's key
869     * @param v1 the first mapping's value
870     * @param k2 the second mapping's key
871     * @param v2 the second mapping's value
872     * @param k3 the third mapping's key
873     * @param v3 the third mapping's value
874     * @param k4 the fourth mapping's key
875     * @param v4 the fourth mapping's value
876     * @param k5 the fifth mapping's key
877     * @param v5 the fifth mapping's value
878     * 
879     * @return a {@link ReadOnlyMap} containing the specified mappings
880     * @throws IllegalArgumentException if there are any duplicate keys
881     * @throws NullPointerException if any key or value is {@code null}
882     *
883     */
884    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)
885    { return InterfaceBuilder.toReadOnlyMap(Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5)); }
886
887    /**
888     * Returns an unmodifiable map containing six mappings.
889     *
890     * @param <K> the {@code Map}'s key type
891     * @param <V> the {@code Map}'s value type
892     * @param k1 the first mapping's key
893     * @param v1 the first mapping's value
894     * @param k2 the second mapping's key
895     * @param v2 the second mapping's value
896     * @param k3 the third mapping's key
897     * @param v3 the third mapping's value
898     * @param k4 the fourth mapping's key
899     * @param v4 the fourth mapping's value
900     * @param k5 the fifth mapping's key
901     * @param v5 the fifth mapping's value
902     * @param k6 the sixth mapping's key
903     * @param v6 the sixth mapping's value
904     * 
905     * @return a {@link ReadOnlyMap} containing the specified mappings
906     * @throws IllegalArgumentException if there are any duplicate keys
907     * @throws NullPointerException if any key or value is {@code null}
908     */
909    static <K, V> ReadOnlyMap<K, V> of(
910            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
911            K k6, V v6
912        )
913    {
914        return InterfaceBuilder.toReadOnlyMap
915            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6));
916    }
917
918    /**
919     * Returns an unmodifiable map containing seven mappings.
920     * 
921     * @param <K> the {@code Map}'s key type
922     * @param <V> the {@code Map}'s value type
923     * @param k1 the first mapping's key
924     * @param v1 the first mapping's value
925     * @param k2 the second mapping's key
926     * @param v2 the second mapping's value
927     * @param k3 the third mapping's key
928     * @param v3 the third mapping's value
929     * @param k4 the fourth mapping's key
930     * @param v4 the fourth mapping's value
931     * @param k5 the fifth mapping's key
932     * @param v5 the fifth mapping's value
933     * @param k6 the sixth mapping's key
934     * @param v6 the sixth mapping's value
935     * @param k7 the seventh mapping's key
936     * @param v7 the seventh 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    static <K, V> ReadOnlyMap<K, V> of(
943            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
944            K k6, V v6, K k7, V v7
945        )
946    {
947        return InterfaceBuilder.toReadOnlyMap
948            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7));
949    }
950
951    /**
952     * Returns an unmodifiable map containing eight mappings.
953     * 
954     * @param <K> the {@code Map}'s key type
955     * @param <V> the {@code Map}'s value type
956     * @param k1 the first mapping's key
957     * @param v1 the first mapping's value
958     * @param k2 the second mapping's key
959     * @param v2 the second mapping's value
960     * @param k3 the third mapping's key
961     * @param v3 the third mapping's value
962     * @param k4 the fourth mapping's key
963     * @param v4 the fourth mapping's value
964     * @param k5 the fifth mapping's key
965     * @param v5 the fifth mapping's value
966     * @param k6 the sixth mapping's key
967     * @param v6 the sixth mapping's value
968     * @param k7 the seventh mapping's key
969     * @param v7 the seventh mapping's value
970     * @param k8 the eighth mapping's key
971     * @param v8 the eighth mapping's value
972     * 
973     * @return a {@link ReadOnlyMap} containing the specified mappings
974     * @throws IllegalArgumentException if there are any duplicate keys
975     * @throws NullPointerException if any key or value is {@code null}
976     */
977    static <K, V> ReadOnlyMap<K, V> of(
978            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
979            K k6, V v6, K k7, V v7, K k8, V v8
980        )
981    {
982        return InterfaceBuilder.toReadOnlyMap
983            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8));
984    }
985
986    /**
987     * Returns an unmodifiable map containing nine mappings.
988     * 
989     * @param <K> the {@code Map}'s key type
990     * @param <V> the {@code Map}'s value type
991     * @param k1 the first mapping's key
992     * @param v1 the first mapping's value
993     * @param k2 the second mapping's key
994     * @param v2 the second mapping's value
995     * @param k3 the third mapping's key
996     * @param v3 the third mapping's value
997     * @param k4 the fourth mapping's key
998     * @param v4 the fourth mapping's value
999     * @param k5 the fifth mapping's key
1000     * @param v5 the fifth mapping's value
1001     * @param k6 the sixth mapping's key
1002     * @param v6 the sixth mapping's value
1003     * @param k7 the seventh mapping's key
1004     * @param v7 the seventh mapping's value
1005     * @param k8 the eighth mapping's key
1006     * @param v8 the eighth mapping's value
1007     * @param k9 the ninth mapping's key
1008     * @param v9 the ninth mapping's value
1009     * 
1010     * @return a {@link ReadOnlyMap} containing the specified mappings
1011     * @throws IllegalArgumentException if there are any duplicate keys
1012     * @throws NullPointerException if any key or value is {@code null}
1013     */
1014    static <K, V> ReadOnlyMap<K, V> of(
1015            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
1016            K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9
1017        )
1018    {
1019        return InterfaceBuilder.toReadOnlyMap
1020            (Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9));
1021    }
1022
1023    /**
1024     * Returns an unmodifiable map containing ten mappings.
1025     *
1026     * @param <K> the {@code Map}'s key type
1027     * @param <V> the {@code Map}'s value type
1028     * @param k1 the first mapping's key
1029     * @param v1 the first mapping's value
1030     * @param k2 the second mapping's key
1031     * @param v2 the second mapping's value
1032     * @param k3 the third mapping's key
1033     * @param v3 the third mapping's value
1034     * @param k4 the fourth mapping's key
1035     * @param v4 the fourth mapping's value
1036     * @param k5 the fifth mapping's key
1037     * @param v5 the fifth mapping's value
1038     * @param k6 the sixth mapping's key
1039     * @param v6 the sixth mapping's value
1040     * @param k7 the seventh mapping's key
1041     * @param v7 the seventh mapping's value
1042     * @param k8 the eighth mapping's key
1043     * @param v8 the eighth mapping's value
1044     * @param k9 the ninth mapping's key
1045     * @param v9 the ninth mapping's value
1046     * @param k10 the tenth mapping's key
1047     * @param v10 the tenth mapping's value
1048     * 
1049     * @return a {@link ReadOnlyMap} containing the specified mappings
1050     * @throws IllegalArgumentException if there are any duplicate keys
1051     * @throws NullPointerException if any key or value is {@code null}
1052     */
1053    static <K, V> ReadOnlyMap<K, V> of(
1054            K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
1055            K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10
1056        )
1057    {
1058        return InterfaceBuilder.toReadOnlyMap(
1059            Map.of(
1060                k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6,
1061                k7, v7, k8, v8, k9, v9, k10, v10
1062            ));
1063    }
1064
1065    /**
1066     * Returns an unmodifiable map containing keys and values extracted from the given entries.
1067     * The entries themselves are not stored in the map.
1068     *
1069     * <BR /><BR />It is convenient to create the map entries using the
1070     * {@link ReadOnlyMap#entry ReadOnlyMap.entry()} method.  For example,
1071     *
1072     * <DIV CLASS=EXAMPLE>{@code
1073     * import static Torello.Java.ReadOnly.ReadOnlyMap.entry;
1074     *
1075     * ReadOnlyMap<Integer,String> map = ReadOnlyMap.ofEntries(
1076     *      entry(1, "a"),
1077     *      entry(2, "b"),
1078     *      entry(3, "c"),
1079     *      ...
1080     *      entry(26, "z"));
1081     * }</DIV>
1082     *
1083     * @param <K> the {@link ReadOnlyMap}'s key type
1084     * @param <V> the {@link ReadOnlyMap}'s value type
1085     * 
1086     * @param entries {@code ReadOnlyMap.Entry}s containing the keys and values from which the map
1087     * is populated
1088     * 
1089     * @return a {@link ReadOnlyMap} containing the specified mappings
1090     * @throws IllegalArgumentException if there are any duplicate keys
1091     * 
1092     * @throws NullPointerException if any entry, key, or value is {@code null}, or if the
1093     * {@code entries} array is {@code null}
1094     *
1095     * @see ReadOnlyMap#entry Map.entry()
1096     */
1097    @SafeVarargs
1098    @SuppressWarnings("varargs")
1099    static <K, V>
1100        ReadOnlyMap<K, V>
1101        ofEntries
1102        (ReadOnlyMap.Entry<? extends K, ? extends V>... entries)
1103    {
1104        // *** Java-HTML: This arbitrarily uses TreeMap
1105        ROTreeMapBuilder<K, V> b = new ROTreeMapBuilder<>();
1106
1107        for (ReadOnlyMap.Entry<? extends K, ? extends V> e : entries)
1108            b.put(e.getKey(), e.getValue());
1109
1110        return b.build();
1111    }
1112
1113    /**
1114     * Returns an unmodifiable {@link Entry} containing the given key and value.
1115     * These entries are suitable for populating {@code ReadOnlyMap} instances using the
1116     * {@link ReadOnlyMap#ofEntries ReadOnlyMap.ofEntries()} method.
1117     * 
1118     * @param <K> the key's type
1119     * @param <V> the value's type
1120     * @param k the key
1121     * @param v the value
1122     * @return an {@code Entry} containing the specified key and value
1123     * @throws NullPointerException if the key or value is {@code null}
1124     *
1125     * @see ReadOnlyMap#ofEntries Map.ofEntries()
1126     */
1127    static <K, V> ReadOnlyMap.Entry<K, V> entry(K k, V v)
1128    {
1129        // KeyValueHolder checks for nulls
1130        // return new KeyValueHolder<>(k, v);
1131        return new EntryImpl<>(Objects.requireNonNull(k), Objects.requireNonNull(v));
1132    }
1133}