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

com.jnape.palatable.shoki.api.Map Maven / Gradle / Ivy

The newest version!
package com.jnape.palatable.shoki.api;

import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
import com.jnape.palatable.lambda.semigroup.Semigroup;

import static com.jnape.palatable.lambda.functions.Fn2.curried;
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map;
import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
import static com.jnape.palatable.lambda.monoid.builtin.And.and;
import static com.jnape.palatable.shoki.api.EquivalenceRelation.equivalent;

/**
 * A {@link Collection} of key/value {@link Tuple2 pairs} supporting {@link RandomAccess random access} from a key to
 * {@link Maybe} a value.
 *
 * @param  the known size {@link Number} type
 * @param     the key type
 * @param     the value type
 */
public interface Map extends
        Collection>,
        RandomAccess> {

    /**
     * Associate k with v inside this map.
     *
     * @param k the key
     * @param v the value
     * @return the updated {@link Map}
     */
    Map put(K k, V v);

    /**
     * Remove all associations for k inside this map.
     *
     * @param k the key
     * @return the updated {@link Map}
     */
    Map remove(K k);

    /**
     * The {@link Set set} of all keys associated to a value inside this {@link Map}.
     *
     * @return this {@link Map Map's} {@link Set key set}
     * @see Map#values()
     */
    Set keys();

    /**
     * A {@link Collection} of all values associated to a key inside this {@link Map Map}.
     *
     * @return the {@link Map Map's} {@link Collection} of values
     * @see Map#keys()
     */
    Collection values();

    /**
     * {@inheritDoc}
     * If key is associated to a value inside this {@link Map}, retrieve {@link Maybe#just(Object) just}
     * the value it maps to; otherwise, return {@link Maybe#nothing() nothing}.
     *
     * @see Map#put(Object, Object)
     * @see Map#remove(Object)
     */
    @Override
    Maybe get(K k);

    /**
     * {@inheritDoc}
     * True if key is associated to a value in this {@link Map}; false otherwise.
     */
    @Override
    default boolean contains(K k) {
        return get(k).match(constantly(false), constantly(true));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    default boolean isEmpty() {
        return Collection.super.isEmpty();
    }

    /**
     * {@inheritDoc}
     *
     * @return the head key/value {@link Tuple2 pair}
     */
    @Override
    Maybe> head();

    /**
     * {@inheritDoc}
     *
     * @return this {@link Map} without the {@link Map#head() head} key/value {@link Tuple2 pair}
     */
    @Override
    Map tail();

    /**
     * {@link Map#put(Object, Object) Put} each entry in map in this {@link Map}, relying on
     * semigroup to consolidate colliding values in the case of duplicate keys.
     *
     * @param other     the other {@link Map}
     * @param semigroup the {@link Semigroup}
     * @return the merged {@link Map}
     */
    default Map merge(Map other, Semigroup semigroup) {
        return foldLeft(curried(m -> into((k, v) -> m.put(k, m.get(k).fmap(semigroup.flip().apply(v)).orElse(v)))),
                        this,
                        other);
    }

    /**
     * {@link Map#remove(Object) Remove} every key {@link Map#contains(Object) contained} in keys from
     * this {@link Map}.
     *
     * @param keys the {@link Set} of keys to remove from this {@link Map}
     * @return the updated {@link Map}
     */
    default Map removeAll(Set keys) {
        return foldLeft(Map::remove, this, keys);
    }

    /**
     * Common {@link EquivalenceRelation}s between {@link Map}s.
     */
    final class EquivalenceRelations {
        private EquivalenceRelations() {
        }

        /**
         * An {@link EquivalenceRelation} between two {@link Map}s that holds if, and only if, both {@link Map}s have
         * equivalent {@link SizeInfo}s and contain the same entries.
         *
         * @param valueEqRel the {@link EquivalenceRelation} to use to compare entry values
         * @param         the key type
         * @param         the value type
         * @param         the {@link Map} subtype of the arguments
         * @return the {@link EquivalenceRelation}
         */
        public static > EquivalenceRelation entries(
                EquivalenceRelation valueEqRel) {
            return Sizable.EquivalenceRelations.sizeInfos()
                    .and((m1, m2) -> and()
                            .foldMap(into((k, v) -> m2.get(k).fmap(valueEqRel.apply(v)).orElse(false)), m1));
        }

        /**
         * An {@link EquivalenceRelation} between two {@link Map}s that holds if, and only if, both {@link Map}s have
         * equivalent {@link SizeInfo}s and {@link Map#keys() key sets}.
         *
         * @param keySetEqRel the {@link EquivalenceRelation} to use to compare key sets
         * @param          the key type
         * @param          the value type
         * @param          the {@link Map} subtype of the arguments
         * @return the {@link EquivalenceRelation}
         */
        public static > EquivalenceRelation keys(
                EquivalenceRelation> keySetEqRel) {
            return Sizable.EquivalenceRelations.sizeInfos()
                    .and((m1, m2) -> equivalent(keySetEqRel, m1.keys(), m2.keys()));
        }
    }

    /**
     * Common {@link HashingAlgorithm}s for {@link Map}s.
     */
    final class HashingAlgorithms {
        private HashingAlgorithms() {
        }

        /**
         * A {@link HashingAlgorithm} derived from the key/value pairs contained in any order in a given {@link Map}.
         *
         * @param keyHashingAlgorithm   the key {@link HashingAlgorithm}
         * @param valueHashingAlgorithm the value {@link HashingAlgorithm}
         * @param                    the key type
         * @param                    the value type
         * @param                    the  {@link Map} subtype of the argument
         * @return the {@link HashingAlgorithm}
         */
        public static > HashingAlgorithm entries(
                HashingAlgorithm keyHashingAlgorithm,
                HashingAlgorithm valueHashingAlgorithm) {
            return m -> foldLeft(Integer::sum, 0,
                                 map(into((K k, V v) -> keyHashingAlgorithm.apply(k)
                                         ^ valueHashingAlgorithm.apply(v)), m));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy