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

fj.Hash Maven / Gradle / Ivy

Go to download

Functional Java is an open source library that supports closures for the Java programming language

There is a newer version: 5.0
Show newest version
package fj;

import static fj.Function.compose;

import fj.data.*;
import fj.data.vector.V2;
import fj.data.vector.V3;
import fj.data.vector.V4;
import fj.data.vector.V5;
import fj.data.vector.V6;
import fj.data.vector.V7;
import fj.data.vector.V8;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * Produces a hash code for an object which should attempt uniqueness.
 *
 * @version %build.number%
 */
public final class Hash {
  private final F f;

  private Hash(final F f) {
    this.f = f;
  }

  /**
   * Compute the hash of the given value.
   *
   * @param a The value to compute the hash value for.
   * @return The hash value.
   */
  public int hash(final A a) {
    return f.f(a);
  }

  /**
   * Maps the given function across this hash as a contra-variant functor.
   *
   * @param g The function to map.
   * @return A new hash.
   */
  public  Hash contramap(final F g) {
    return hash(compose(f, g));
  }

  /**
   * Construct a hash with the given hash function.
   *
   * @param f The function to construct the hash with.
   * @return A hash that uses the given function.
   */
  public static  Hash hash(final F f) {
    return new Hash<>(f);
  }

  /**
   * A hash that uses {@link Object#hashCode()}.
   *
   * @return A hash that uses {@link Object#hashCode()}.
   */
  public static  Hash anyHash() {
    return hash(Object::hashCode);
  }

  /**
   * A hash instance for the boolean type.
   */
  public static final Hash booleanHash = anyHash();

  /**
   * A hash instance for the byte type.
   */
  public static final Hash byteHash = anyHash();

  /**
   * A hash instance for the char type.
   */
  public static final Hash charHash = anyHash();

  /**
   * A hash instance for the double type.
   */
  public static final Hash doubleHash = anyHash();

  /**
   * A hash instance for the float type.
   */
  public static final Hash floatHash = anyHash();

  /**
   * A hash instance for the int type.
   */
  public static final Hash intHash = anyHash();

  /**
   * A hash instance for the long type.
   */
  public static final Hash longHash = anyHash();

  /**
   * A hash instance for the short type.
   */
  public static final Hash shortHash = anyHash();

  /**
   * A hash instance for the BigInteger type.
   */
  public static final Hash bigintHash = anyHash();

  /**
   * A hash instance for the BigDecimal type.
   */
  public static final Hash bigdecimalHash = anyHash();

  /**
   * A hash instance for the {@link Natural} type.
   */
  public static final Hash naturalHash = bigintHash.contramap(Natural::bigIntegerValue);

  /**
   * A hash instance for the String type.
   */
  public static final Hash stringHash = anyHash();

  /**
   * A hash instance for the {@link StringBuffer} type.
   */
  public static final Hash stringBufferHash = hash(sb -> {
      final int p = 419;
      int r = 239;

      for (int i = 0; i < sb.length(); i++)
          r = p * r + sb.charAt(i);

      return r;
  });

  /**
   * A hash instance for the {@link StringBuilder} type.
   */
  public static final Hash stringBuilderHash = hash(sb -> {
      final int p = 419;
      int r = 239;

      for (int i = 0; i < sb.length(); i++)
          r = p * r + sb.charAt(i);

      return r;
  });

  /**
   * A hash instance for the {@link Either} type.
   *
   * @param ha Hash the left side of Either.
   * @param hb Hash the right side of Either.
   * @return A hash instance for the {@link Either} type.
   */
  public static  Hash> eitherHash(final Hash ha, final Hash hb) {
    return hash(e -> e.isLeft() ? ha.hash(e.left().value()) : hb.hash(e.right().value()));
  }

  /**
   * A hash instance for the {@link Validation} type.
   *
   * @param ha Hash the failing side of Validation.
   * @param hb Hash the succeeding side of Validation.
   * @return A hash instance for the {@link Validation} type.
   */
  public static  Hash> validationHash(final Hash ha, final Hash hb) {
    return eitherHash(ha, hb).contramap(Validation.either());
  }

  /**
   * A hash instance for the {@link List} type.
   *
   * @param ha A hash for the elements of the list.
   * @return A hash instance for the {@link List} type.
   */
  public static  Hash> listHash(final Hash ha) {
    return hash(as -> {
        final int p = 419;
        int r = 239;
        List aas = as;

        while (!aas.isEmpty()) {
            r = p * r + ha.hash(aas.head());
            aas = aas.tail();
        }

        return r;
    });
  }

  /**
   * A hash instance for the {@link NonEmptyList} type.
   *
   * @param ha A hash for the elements of the non-empty list.
   * @return A hash instance for the {@link NonEmptyList} type.
   */
  public static  Hash> nonEmptyListHash(final Hash ha) {
    return listHash(ha).contramap(NonEmptyList.toList_());
  }

  /**
   * A hash instance for the {@link Option} type.
   *
   * @param ha A hash for the element of the optional value.
   * @return A hash instance for the {@link Option} type.
   */
  public static  Hash> optionHash(final Hash ha) {
    return hash(o -> o.isNone() ? 0 : ha.hash(o.some()));
  }

    public static  Hash> seqHash(final Hash h) {
        return hash(s -> streamHash(h).hash(s.toStream()));
    }

    public static  Hash> setHash(final Hash h) {
        return hash(s -> streamHash(h).hash(s.toStream()));
    }

  /**
   * A hash instance for the {@link Stream} type.
   *
   * @param ha A hash for the elements of the stream.
   * @return A hash instance for the {@link Stream} type.
   */
  public static  Hash> streamHash(final Hash ha) {
    return hash(as -> {
        final int p = 419;
        int r = 239;
        Stream aas = as;

        while (!aas.isEmpty()) {
            r = p * r + ha.hash(aas.head());
            aas = aas.tail()._1();
        }

        return r;
    });
  }

  /**
   * A hash instance for the {@link Array} type.
   *
   * @param ha A hash for the elements of the array.
   * @return A hash instance for the {@link Array} type.
   */
  public static  Hash> arrayHash(final Hash ha) {
    return hash(as -> {
        final int p = 419;
        int r = 239;

        for (int i = 0; i < as.length(); i++) {
            r = p * r + ha.hash(as.get(i));
        }

        return r;
    });
  }

  /**
   * A hash instance for the {@link Tree} type.
   *
   * @param ha A hash for the elements of the tree.
   * @return A hash instance for the {@link Tree} type.
   */
  public static  Hash> treeHash(final Hash ha) {
    return streamHash(ha).contramap(Tree.flatten_());
  }

    public static  Hash> treeMapHash(final Hash h, final Hash v) {
        return hash(t -> streamHash(p2Hash(h, v)).hash(t.toStream()));
    }

  /**
   * A hash instance for a product-1.
   *
   * @param ha A hash for the first element of the product.
   * @return A hash instance for a product-1.
   */
  public static  Hash> p1Hash(final Hash ha) {
    return ha.contramap(P1.__1());
  }

  /**
   * A hash instance for a product-2.
   *
   * @param ha A hash for the first element of the product.
   * @param hb A hash for the second element of the product.
   * @return A hash instance for a product-2.
   */
  public static  Hash> p2Hash(final Hash ha, final Hash hb) {
    return hash(p2 -> {
        final int p = 419;
        int r = 239;

        r = p * r + ha.hash(p2._1());
        r = p * r + hb.hash(p2._2());

        return r;
    });
  }

  /**
   * A hash instance for a product-3.
   *
   * @param ha A hash for the first element of the product.
   * @param hb A hash for the second element of the product.
   * @param hc A hash for the third element of the product.
   * @return A hash instance for a product-3.
   */
  public static  Hash> p3Hash(final Hash ha, final Hash hb, final Hash hc) {
    return hash(p3 -> {
        final int p = 419;
        int r = 239;

        r = p * r + ha.hash(p3._1());
        r = p * r + hb.hash(p3._2());
        r = p * r + hc.hash(p3._3());

        return r;
    });
  }

  /**
   * A hash instance for a product-4.
   *
   * @param ha A hash for the first element of the product.
   * @param hb A hash for the second element of the product.
   * @param hc A hash for the third element of the product.
   * @param hd A hash for the fourth element of the product.
   * @return A hash instance for a product-4.
   */
  public static  Hash> p4Hash(final Hash ha, final Hash hb, final Hash hc,
                                                         final Hash hd) {
    return hash(p4 -> {
      final int p = 419;
      int r = 239;

      r = p * r + ha.hash(p4._1());
      r = p * r + hb.hash(p4._2());
      r = p * r + hc.hash(p4._3());
      r = p * r + hd.hash(p4._4());

      return r;
    });
  }

  /**
   * A hash instance for a product-5.
   *
   * @param ha A hash for the first element of the product.
   * @param hb A hash for the second element of the product.
   * @param hc A hash for the third element of the product.
   * @param hd A hash for the fourth element of the product.
   * @param he A hash for the fifth element of the product.
   * @return A hash instance for a product-5.
   */
  public static  Hash> p5Hash(final Hash ha, final Hash hb, final Hash hc,
                                                               final Hash hd, final Hash he) {
    return hash(p5 -> {
      final int p = 419;
      int r = 239;

      r = p * r + ha.hash(p5._1());
      r = p * r + hb.hash(p5._2());
      r = p * r + hc.hash(p5._3());
      r = p * r + hd.hash(p5._4());
      r = p * r + he.hash(p5._5());

      return r;
    });
  }

  /**
   * A hash instance for a product-6.
   *
   * @param ha A hash for the first element of the product.
   * @param hb A hash for the second element of the product.
   * @param hc A hash for the third element of the product.
   * @param hd A hash for the fourth element of the product.
   * @param he A hash for the fifth element of the product.
   * @param hf A hash for the sixth element of the product.
   * @return A hash instance for a product-6.
   */
  public static  Hash> p6Hash(final Hash ha, final Hash hb,
                                                                       final Hash hc, final Hash hd,
                                                                       final Hash he, final Hash hf) {
    return hash(p6 -> {
      final int p = 419;
      int r = 239;

      r = p * r + ha.hash(p6._1());
      r = p * r + hb.hash(p6._2());
      r = p * r + hc.hash(p6._3());
      r = p * r + hd.hash(p6._4());
      r = p * r + he.hash(p6._5());
      r = p * r + hf.hash(p6._6());

      return r;
    });
  }

  /**
   * A hash instance for a product-7.
   *
   * @param ha A hash for the first element of the product.
   * @param hb A hash for the second element of the product.
   * @param hc A hash for the third element of the product.
   * @param hd A hash for the fourth element of the product.
   * @param he A hash for the fifth element of the product.
   * @param hf A hash for the sixth element of the product.
   * @param hg A hash for the seventh element of the product.
   * @return A hash instance for a product-7.
   */
  public static  Hash> p7Hash(final Hash ha, final Hash hb,
                                                                             final Hash hc, final Hash hd,
                                                                             final Hash he, final Hash hf,
                                                                             final Hash hg) {
    return hash(p7 -> {
      final int p = 419;
      int r = 239;

      r = p * r + ha.hash(p7._1());
      r = p * r + hb.hash(p7._2());
      r = p * r + hc.hash(p7._3());
      r = p * r + hd.hash(p7._4());
      r = p * r + he.hash(p7._5());
      r = p * r + hf.hash(p7._6());
      r = p * r + hg.hash(p7._7());

      return r;
    });
  }

  /**
   * A hash instance for a product-8.
   *
   * @param ha A hash for the first element of the product.
   * @param hb A hash for the second element of the product.
   * @param hc A hash for the third element of the product.
   * @param hd A hash for the fourth element of the product.
   * @param he A hash for the fifth element of the product.
   * @param hf A hash for the sixth element of the product.
   * @param hg A hash for the seventh element of the product.
   * @param hh A hash for the eighth element of the product.
   * @return A hash instance for a product-8.
   */
  public static  Hash> p8Hash(final Hash ha, final Hash hb,
                                                                                   final Hash hc, final Hash hd,
                                                                                   final Hash he, final Hash hf,
                                                                                   final Hash hg, final Hash hh) {
    return hash(p8 -> {
      final int p = 419;
      int r = 239;

      r = p * r + ha.hash(p8._1());
      r = p * r + hb.hash(p8._2());
      r = p * r + hc.hash(p8._3());
      r = p * r + hd.hash(p8._4());
      r = p * r + he.hash(p8._5());
      r = p * r + hf.hash(p8._6());
      r = p * r + hg.hash(p8._7());
      r = p * r + hh.hash(p8._8());

      return r;
    });
  }

  /**
   * A hash instance for a vector-2.
   *
   * @param ea A hash for the elements of the vector.
   * @return A hash instance for a vector-2.
   */
  public static  Hash> v2Hash(final Hash ea) {
    return streamHash(ea).contramap(V2.toStream_());
  }

  /**
   * A hash instance for a vector-3.
   *
   * @param ea A hash for the elements of the vector.
   * @return A hash instance for a vector-3.
   */
  public static  Hash> v3Hash(final Hash ea) {
    return streamHash(ea).contramap(V3.toStream_());
  }

  /**
   * A hash instance for a vector-4.
   *
   * @param ea A hash for the elements of the vector.
   * @return A hash instance for a vector-4.
   */
  public static  Hash> v4Hash(final Hash ea) {
    return streamHash(ea).contramap(V4.toStream_());
  }

  /**
   * A hash instance for a vector-5.
   *
   * @param ea A hash for the elements of the vector.
   * @return A hash instance for a vector-5.
   */
  public static  Hash> v5Hash(final Hash ea) {
    return streamHash(ea).contramap(V5.toStream_());
  }

  /**
   * A hash instance for a vector-6.
   *
   * @param ea A hash for the elements of the vector.
   * @return A hash instance for a vector-6.
   */
  public static  Hash> v6Hash(final Hash ea) {
    return streamHash(ea).contramap(V6.toStream_());
  }

  /**
   * A hash instance for a vector-7.
   *
   * @param ea A hash for the elements of the vector.
   * @return A hash instance for a vector-7.
   */
  public static  Hash> v7Hash(final Hash ea) {
    return streamHash(ea).contramap(V7.toStream_());
  }

  /**
   * A hash instance for a vector-8.
   *
   * @param ea A hash for the elements of the vector.
   * @return A hash instance for a vector-8.
   */
  public static  Hash> v8Hash(final Hash ea) {
    return streamHash(ea).contramap(V8.toStream_());
  }

}