/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection;

import java.util.function.BiPredicate;
import java.util.function.ToIntFunction;

/**
 * Generalization of Comparator interface.
 * Offers equality and hash methods for objects of type T.
 * It can be used by HashMaps in the same way as Comparator can be used by TreeMap (SortedMap).
 * @param <K> K
 */
public interface HashFunction<K> {

    /**
     * Calculates hashCode for specified object
     *
     * @param object object
     * @return hashCode
     */
    int hashCode(K object);

    /**
     * Checks if two objects are equal
     * @param a a
     * @param b b
     * @return bool
     */
    boolean equals(K a, K b);

    /**
     * Takes two lambda expressions (one for hash, second for equals) and creates new HashFunction from them.
     *
     * @param hash hash
     * @param eq eq
     * @param <K> K
     * @return HashFunction
     */
    static <K> HashFunction<K> produce(ToIntFunction<K> hash, BiPredicate<K,K> eq) {
        return new HashFunction<K>(){
            @Override
            public int hashCode(K object) {
                return hash.applyAsInt(object);
            }

            @Override
            public boolean equals(K a, K b) {
                return eq.test(a, b);
            }
            
        };
    }

    static <K> HashFunction<K> identity() {
        return IdentityHashFunction.INSTANCE;
    }

    final class IdentityHashFunction<K> implements HashFunction<K>  {

        private static final HashFunction INSTANCE = new IdentityHashFunction();

        private IdentityHashFunction() {
            // do nothing
        }

        @Override
        public int hashCode(K object) {
            return System.identityHashCode(object);
        }

        @Override
        public boolean equals(K a, K b) {
            return a == b;
        }
    }

}
