All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pkl.thirdparty.paguro.collections.UnmodMap Maven / Gradle / Ivy

Go to download

Shaded fat Jar for pkl-config-java, a Java config library based on the Pkl config language.

There is a newer version: 0.27.1
Show newest version
// Copyright 2015-04-13 PlanBase Inc. & Glen Peterson
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.pkl.thirdparty.paguro.collections;

import org.pkl.thirdparty.jetbrains.annotations.NotNull;
import org.pkl.thirdparty.paguro.tuple.Tuple2;

import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 An unmodifiable map.
 This cannot extend Collection because the remove() method would then be inherited
 from both Collection and Map and Collection.remove() returns a boolean while Map.remove() returns
 a V (the type of the value in the key/value pair).  Maybe an UnmodSizedIterable is called for?
 */
public interface UnmodMap extends Map, UnmodIterable>, Sized {
    // ========================================== Static ==========================================

    /**
     * A map entry (key-value pair).  The UnmodMap.entrySet method returns
     * a collection-view of the map, whose elements are of this class.  The
     * only way to obtain a reference to a map entry is from the
     * iterator of this collection-view.
     *
     * @see UnmodMap#entrySet()
     */
    interface UnEntry extends Map.Entry {
        class EntryToUnEntryIter implements UnmodIterator> {
            //, Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
            // private static final long serialVersionUID = 20160903082500L;

            private final Iterator> innerIter;
            EntryToUnEntryIter(Iterator> i) { innerIter = i; }

            @Override
            public boolean hasNext() { return innerIter.hasNext(); }
            @Override
            public @NotNull UnEntry next() { return Tuple2.of(innerIter.next()); }
        }

        class EntryToUnEntrySortedIter extends EntryToUnEntryIter
                implements UnmodSortedIterator> {
            //, Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
//            private static final long serialVersionUID = 20160903082500L;

            EntryToUnEntrySortedIter(Iterator> i) { super(i); }
        }

        class UnmodKeyIter implements UnmodIterator {
            //, Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
            // private static final long serialVersionUID = 20160903174100L;

            private final Iterator> iter;
            UnmodKeyIter(Iterator> i) { iter = i; }

            @Override public boolean hasNext() { return iter.hasNext(); }
            @Override public K next() { return iter.next().getKey(); }
        }

        class UnmodSortedKeyIter extends UnmodKeyIter implements UnmodSortedIterator {
            // , Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
//            private static final long serialVersionUID = 20160903174100L;

            UnmodSortedKeyIter(Iterator> i) { super(i); }
        }

        class UnmodValIter implements UnmodIterator {
            //, Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
            // private static final long serialVersionUID = 20160903174100L;

            private final Iterator> iter;
            UnmodValIter(Iterator> i) { iter = i; }

            @Override public boolean hasNext() { return iter.hasNext(); }
            @Override public V next() { return iter.next().getValue(); }
        }

        class UnmodSortedValIter extends UnmodValIter implements UnmodSortedIterator {
                // , Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
//            private static final long serialVersionUID = 20160903174100L;

            UnmodSortedValIter(Iterator> i) { super(i); }
        }

        static 
        @NotNull UnmodIterator> entryIterToUnEntryUnIter(Iterator> innerIter) {
            return new EntryToUnEntryIter<>(innerIter);
        }

        static 
        @NotNull UnmodSortedIterator>
        entryIterToUnEntrySortedUnIter(Iterator> innerIter) {
            return new EntryToUnEntrySortedIter<>(innerIter);
        }

        // This should be done with a cast, not with code.
//        static  UnmodSortedIterator> unSortIterEntToUnSortIterUnEnt(
//                UnmodSortedIterator> innerIter) {
//            return new UnmodSortedIterator>() {
//                @Override public boolean hasNext() { return innerIter.hasNext(); }
//                @Override public UnEntry next() {
//                    return UnmodMap.UnEntry.entryToUnEntry(innerIter.next());
//                }
//            };
//        }
//
        /**
         Not compatible with immutability - use
         {@link ImMap#assoc(Object, Object)}
         instead because it returns a new map.
         */
        @Override @Deprecated default V setValue(V value) {
            throw new UnsupportedOperationException("Modification attempted");
        }
    }

    // ========================================= Instance =========================================

    // Modification Operations

    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated default void clear() {
        throw new UnsupportedOperationException("Modification attempted");
    }

    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated
    default V compute(K key, @NotNull BiFunction remappingFunction) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated
    default V computeIfAbsent(K key, @NotNull Function mappingFunction) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated
    default V computeIfPresent(K key,
                               @NotNull BiFunction remappingFunction) {
        throw new UnsupportedOperationException("Modification attempted");
    }
// boolean	containsKey(Object key)
// boolean	containsValue(Object value)

    /**
     Most maps are not designed for this - the default implementation has O(n) performance.
     {@inheritDoc}
     */
    // This is the place to define this slow operation so that it can be used in
    // values().contains(), UnmodSortedMap.containsValue() and UnmodSortedMap.values().contains().
    @Override default boolean containsValue(Object value) {
        for (UnEntry item : this) {
            if (Objects.equals(item.getValue(), value)) { return true; }
        }
        return false;
    }

    /**
     Returns a view of the mappings contained in this map.  The set will contain UnmodMap.UnEntry
     items, but that return signature is illegal in Java, so you'll just have to remember. An
     UnmodMap is iterable, so this method is probably not nearly as useful as it once was.

     {@inheritDoc}
     */
    @Override default @NotNull UnmodSet> entrySet() {
        class EntrySet extends AbstractUnmodSet>
                implements Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
            private static final long serialVersionUID = 20160903104400L;

            private final UnmodMap parent;
            private EntrySet(UnmodMap p) { parent = p; }

            @SuppressWarnings("unchecked")
            @Override public boolean contains(Object o) {
                if ( !(o instanceof Entry) ) { return false; }
                Entry entry = (Entry) o;
                if (!parent.containsKey(entry.getKey())) { return false; }
                V value = parent.get(entry.getKey());
                return Objects.equals(entry.getValue(), value);
            }

            @NotNull
            @SuppressWarnings("unchecked")
            @Override public UnmodIterator> iterator() {
                // Converting from
                // UnmodIterator> to
                // UnmodIterator>
                // Is a totally legal widening conversion (at runtime) because UnEntry extends
                // (is an) Entry.  But Java's type system doesn't know that because (I think)
                // it's a higher kinded type.  Thanks to type erasure, we can forget about all
                // that and cast it to a base type then suppress the unchecked warning.
                //
                // Hmm... It's possible for this to return an Entry if the wrapped collection
                // uses them...  Not sure how much that matters.
                return (UnmodIterator) parent.iterator();
            }

            @Override public int size() { return parent.size(); }

            @Override
            public @NotNull String toString() {
                return UnmodIterable.toString("UnmodMap.entrySet", this);
            }
        }
        return new EntrySet(this);
    }


// boolean	equals(Object o)

//    @Override default boolean equals(Object other) {
//        // Cheapest operation first...
//        if (this == other) { return true; }
//
//        if ( (other == null) ||
//                !(other instanceof Map) ||
//                (this.hashCode() != other.hashCode()) ) {
//            return false;
//        }
//        // Details...
//        final Map that = (Map) other;
//        if (this.size() != that.size()) {
//            return false;
//        }
//        return this.entrySet().containsAll(that.entrySet());
//    }

// default void	forEach(BiConsumer action)
// V	get(Object key)
// default V	getOrDefault(Object key, V defaultValue)

//    @Override default int hashCode() {
//        if (size() == 0) { return 0; }
//        return Arrays.hashCode(entrySet().toArray());
//    };

    /** {@inheritDoc} */
    @Override default boolean isEmpty() { return size() == 0; }

    /**
     Returns a view of the keys contained in this map.  An UnmodMap is iterable, so this method
     is probably not nearly as useful as it once was.

     {@inheritDoc}
     */
    @Override default @NotNull UnmodSet keySet() {
        class KeySet extends AbstractUnmodSet implements Serializable {
            // For serializable.  Make sure to change whenever internal data format changes.
            private static final long serialVersionUID = 20160903104400L;

            private final UnmodMap parent;
            private KeySet(UnmodMap p) { parent = p; }

            @SuppressWarnings("SuspiciousMethodCalls")
            @Override public boolean contains(Object o) { return parent.containsKey(o); }

            @NotNull
            @Override public UnmodIterator iterator() {
                return parent.keyIterator();
            }
            @Override public int size() { return parent.size(); }

            @Override
            public @NotNull String toString() {
                return UnmodIterable.toString("UnmodMap.keySet", this);
            }
        }
        return new KeySet(this);
    }

    default @NotNull UnmodIterator keyIterator() {
        return new UnEntry.UnmodKeyIter<>(this.iterator());
    }

    default @NotNull UnmodIterator valIterator() {
        return new UnEntry.UnmodValIter<>(this.iterator());
    }

    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated
    default V merge(
            K key,
            @NotNull V value,
            @NotNull BiFunction remappingFunction
    ) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /**
     Not compatible with immutability - use
     {@link ImMap#assoc(Object, Object)}
     instead because it returns a new map.
     */
    @Override @Deprecated default V put(K key, V value) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated default void putAll(@NotNull Map m) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated default V putIfAbsent(K key, V value) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated default V remove(Object key) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated default boolean remove(Object key, Object value) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated default boolean replace(K key, V oldValue, V newValue) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated default V replace(K key, V value) {
        throw new UnsupportedOperationException("Modification attempted");
    }
    /** Not allowed - this is supposed to be unmodifiable */
    @Override @Deprecated
    default void replaceAll(BiFunction function) {
        throw new UnsupportedOperationException("Modification attempted");
    }

// int	size()

    /**
     This method has been deprecated because it is impossible to implement equals() or hashCode()
     on the resulting collection, and calling this method is probably at least a missed opportunity,
     if not an outright error.  Use an UnmodMap as an UnmodIterable<UnmodMap.UnEntry> instead.

     If you don't care about eliminating duplicate values, and want a compatible return type call:
     
myMap.map((UnEntry<K,V> entry) -> entry.getValue())
             .toImSet();
If you want to keep a count of duplicates, try something like this, but it has a different signature:
ImMap<V,Integer> valueCounts = myMap.fold(PersistentHashMap.empty(),
                     (ImMap<V,Integer> accum, UnEntry<K,V> origEntry) -> {
                             V inVal = origEntry.getValue();
                             return accum.assoc(inVal,
                                                accum.getOrElse(inVal, 0) + 1);
                         });
You really shouldn't turn values() into a List, because a List has order and an unsorted Map is unordered by key, and especially unordered by value. On a SortedMap, List is the proper return type. java.util.HashMap.values() returns an instance of java.util.HashMap.Values which does *not* have equals() or hashCode() defined. This is because List.equals() and Set.equals() return not-equal when compared to a Collection. There is no good way to implement a reflexive equals with both of those because they are just too different. Ultimately, Collection just isn't specific enough to instantiate, but we do it anyway here for backward compatibility. We don't implement equals() or hashCode() either because the result could have duplicates. If the Map isn't sorted, the result could have random ordering. {@inheritDoc} */ @Override @Deprecated default @NotNull UnmodCollection values() { class Impl implements UnmodCollection, Serializable { // For serializable. Make sure to change whenever internal data format changes. private static final long serialVersionUID = 20160903104400L; private final UnmodMap parent; private Impl(UnmodMap p) { parent = p; } @SuppressWarnings("SuspiciousMethodCalls") @Override public boolean contains(Object o) { return parent.containsValue(o); } @NotNull @Override public UnmodIterator iterator() { return parent.valIterator(); } @Override public int size() { return parent.size(); } @Override public @NotNull String toString() { return UnmodIterable.toString("UnmodMap.values", this); } } return new Impl(this); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy