001    package fj.pre;
002    
003    import fj.F;
004    import static fj.Function.compose;
005    import fj.P1;
006    import fj.P2;
007    import fj.P3;
008    import fj.P4;
009    import fj.P5;
010    import fj.P6;
011    import fj.P7;
012    import fj.P8;
013    import fj.data.Array;
014    import fj.data.Either;
015    import fj.data.List;
016    import fj.data.NonEmptyList;
017    import fj.data.Option;
018    import fj.data.Stream;
019    import fj.data.Tree;
020    import fj.data.Validation;
021    import fj.data.vector.V2;
022    import fj.data.vector.V3;
023    import fj.data.vector.V4;
024    import fj.data.vector.V5;
025    import fj.data.vector.V6;
026    import fj.data.vector.V7;
027    import fj.data.vector.V8;
028    
029    /**
030     * Produces a hash code for an object which should attempt uniqueness.
031     *
032     * @version %build.number%<br>
033     *          <ul>
034     *          <li>$LastChangedRevision: 122 $</li>
035     *          <li>$LastChangedDate: 2009-04-25 08:24:38 +1000 (Sat, 25 Apr 2009) $</li>
036     *          </ul>
037     */
038    public final class Hash<A> {
039      private final F<A, Integer> f;
040    
041      private Hash(final F<A, Integer> f) {
042        this.f = f;
043      }
044    
045      /**
046       * Compute the hash of the given value.
047       *
048       * @param a The value to compute the hash value for.
049       * @return The hash value.
050       */
051      public int hash(final A a) {
052        return f.f(a);
053      }
054    
055      /**
056       * Maps the given function across this hash as a contra-variant functor.
057       *
058       * @param g The function to map.
059       * @return A new hash.
060       */
061      public <B> Hash<B> comap(final F<B, A> g) {
062        return new Hash<B>(compose(f, g));
063      }
064    
065      /**
066       * Construct a hash with the given hash function.
067       *
068       * @param f The function to construct the hash with.
069       * @return A hash that uses the given function.
070       */
071      public static <A> Hash<A> hash(final F<A, Integer> f) {
072        return new Hash<A>(f);
073      }
074    
075      /**
076       * A hash that uses {@link Object#hashCode()}.
077       *
078       * @return A hash that uses {@link Object#hashCode()}.
079       */
080      public static <A> Hash<A> anyHash() {
081        return new Hash<A>(new F<A, Integer>() {
082          public Integer f(final A a) {
083            return a.hashCode();
084          }
085        });
086      }
087    
088      /**
089       * A hash instance for the <code>boolean</code> type.
090       */
091      public static final Hash<Boolean> booleanHash = anyHash();
092    
093      /**
094       * A hash instance for the <code>byte</code> type.
095       */
096      public static final Hash<Byte> byteHash = anyHash();
097    
098      /**
099       * A hash instance for the <code>char</code> type.
100       */
101      public static final Hash<Character> charHash = anyHash();
102    
103      /**
104       * A hash instance for the <code>double</code> type.
105       */
106      public static final Hash<Double> doubleHash = anyHash();
107    
108      /**
109       * A hash instance for the <code>float</code> type.
110       */
111      public static final Hash<Float> floatHash = anyHash();
112    
113      /**
114       * A hash instance for the <code>int</code> type.
115       */
116      public static final Hash<Integer> intHash = anyHash();
117    
118      /**
119       * A hash instance for the <code>long</code> type.
120       */
121      public static final Hash<Long> longHash = anyHash();
122    
123      /**
124       * A hash instance for the <code>short</code> type.
125       */
126      public static final Hash<Short> shortHash = anyHash();
127    
128      /**
129       * A hash instance for the <code>String</code> type.
130       */
131      public static final Hash<String> stringHash = anyHash();
132    
133      /**
134       * A hash instance for the {@link StringBuffer} type.
135       */
136      public static final Hash<StringBuffer> stringBufferHash = new Hash<StringBuffer>(new F<StringBuffer, Integer>() {
137        public Integer f(final StringBuffer sb) {
138          final int p = 419;
139          int r = 239;
140    
141          for (int i = 0; i < sb.length(); i++)
142            r = p * r + sb.charAt(i);
143    
144          return r;
145        }
146      });
147    
148      /**
149       * A hash instance for the {@link StringBuilder} type.
150       */
151      public static final Hash<StringBuilder> stringBuilderHash = new Hash<StringBuilder>(new F<StringBuilder, Integer>() {
152        public Integer f(final StringBuilder sb) {
153          final int p = 419;
154          int r = 239;
155    
156          for (int i = 0; i < sb.length(); i++)
157            r = p * r + sb.charAt(i);
158    
159          return r;
160        }
161      });
162    
163      /**
164       * A hash instance for the {@link Either} type.
165       *
166       * @param ha Hash the left side of <code>Either</code>.
167       * @param hb Hash the right side of <code>Either</code>.
168       * @return A hash instance for the {@link Either} type.
169       */
170      public static <A, B> Hash<Either<A, B>> eitherHash(final Hash<A> ha, final Hash<B> hb) {
171        return new Hash<Either<A, B>>(new F<Either<A, B>, Integer>() {
172          public Integer f(final Either<A, B> e) {
173            return e.isLeft() ? ha.hash(e.left().value()) : hb.hash(e.right().value());
174          }
175        });
176      }
177    
178      /**
179       * A hash instance for the {@link Validation} type.
180       *
181       * @param ha Hash the failing side of <code>Validation</code>.
182       * @param hb Hash the succeeding side of <code>Validation</code>.
183       * @return A hash instance for the {@link Validation} type.
184       */
185      public static <A, B> Hash<Validation<A, B>> validationHash(final Hash<A> ha, final Hash<B> hb) {
186        return eitherHash(ha, hb).comap(Validation.<A, B>either());
187      }
188    
189      /**
190       * A hash instance for the {@link List} type.
191       *
192       * @param ha A hash for the elements of the list.
193       * @return A hash instance for the {@link List} type.
194       */
195      public static <A> Hash<List<A>> listHash(final Hash<A> ha) {
196        return new Hash<List<A>>(new F<List<A>, Integer>() {
197          public Integer f(final List<A> as) {
198            final int p = 419;
199            int r = 239;
200            List<A> aas = as;
201    
202            while (!aas.isEmpty()) {
203              r = p * r + ha.hash(aas.head());
204              aas = aas.tail();
205            }
206    
207            return r;
208          }
209        });
210      }
211    
212      /**
213       * A hash instance for the {@link NonEmptyList} type.
214       *
215       * @param ha A hash for the elements of the non-empty list.
216       * @return A hash instance for the {@link NonEmptyList} type.
217       */
218      public static <A> Hash<NonEmptyList<A>> nonEmptyListHash(final Hash<A> ha) {
219        return listHash(ha).comap(NonEmptyList.<A>toList_());
220      }
221    
222      /**
223       * A hash instance for the {@link Option} type.
224       *
225       * @param ha A hash for the element of the optional value.
226       * @return A hash instance for the {@link Option} type.
227       */
228      public static <A> Hash<Option<A>> optionHash(final Hash<A> ha) {
229        return new Hash<Option<A>>(new F<Option<A>, Integer>() {
230          public Integer f(final Option<A> o) {
231            return o.isNone() ? 0 : ha.hash(o.some());
232          }
233        });
234      }
235    
236      /**
237       * A hash instance for the {@link Stream} type.
238       *
239       * @param ha A hash for the elements of the stream.
240       * @return A hash instance for the {@link Stream} type.
241       */
242      public static <A> Hash<Stream<A>> streamHash(final Hash<A> ha) {
243        return new Hash<Stream<A>>(new F<Stream<A>, Integer>() {
244          public Integer f(final Stream<A> as) {
245            final int p = 419;
246            int r = 239;
247            Stream<A> aas = as;
248    
249            while (!aas.isEmpty()) {
250              r = p * r + ha.hash(aas.head());
251              aas = aas.tail()._1();
252            }
253    
254            return r;
255          }
256        });
257      }
258    
259      /**
260       * A hash instance for the {@link Array} type.
261       *
262       * @param ha A hash for the elements of the array.
263       * @return A hash instance for the {@link Array} type.
264       */
265      public static <A> Hash<Array<A>> arrayHash(final Hash<A> ha) {
266        return new Hash<Array<A>>(new F<Array<A>, Integer>() {
267          public Integer f(final Array<A> as) {
268            final int p = 419;
269            int r = 239;
270    
271            for (int i = 0; i < as.length(); i++) {
272              r = p * r + ha.hash(as.get(i));
273            }
274    
275            return r;
276          }
277        });
278      }
279    
280      /**
281       * A hash instance for the {@link Tree} type.
282       *
283       * @param ha A hash for the elements of the tree.
284       * @return A hash instance for the {@link Tree} type.
285       */
286      public static <A> Hash<Tree<A>> treeHash(final Hash<A> ha) {
287        return streamHash(ha).comap(Tree.<A>flatten_());
288      }
289    
290      /**
291       * A hash instance for a product-1.
292       *
293       * @param ha A hash for the first element of the product.
294       * @return A hash instance for a product-1.
295       */
296      public static <A> Hash<P1<A>> p1Hash(final Hash<A> ha) {
297        return ha.comap(P1.<A>__1());
298      }
299    
300      /**
301       * A hash instance for a product-2.
302       *
303       * @param ha A hash for the first element of the product.
304       * @param hb A hash for the second element of the product.
305       * @return A hash instance for a product-2.
306       */
307      public static <A, B> Hash<P2<A, B>> p2Hash(final Hash<A> ha, final Hash<B> hb) {
308        return new Hash<P2<A, B>>(new F<P2<A, B>, Integer>() {
309          public Integer f(final P2<A, B> p2) {
310            final int p = 419;
311            int r = 239;
312    
313            r = p * r + ha.hash(p2._1());
314            r = p * r + hb.hash(p2._2());
315    
316            return r;
317          }
318        });
319      }
320    
321      /**
322       * A hash instance for a product-3.
323       *
324       * @param ha A hash for the first element of the product.
325       * @param hb A hash for the second element of the product.
326       * @param hc A hash for the third element of the product.
327       * @return A hash instance for a product-3.
328       */
329      public static <A, B, C> Hash<P3<A, B, C>> p3Hash(final Hash<A> ha, final Hash<B> hb, final Hash<C> hc) {
330        return new Hash<P3<A, B, C>>(new F<P3<A, B, C>, Integer>() {
331          public Integer f(final P3<A, B, C> p3) {
332            final int p = 419;
333            int r = 239;
334    
335            r = p * r + ha.hash(p3._1());
336            r = p * r + hb.hash(p3._2());
337            r = p * r + hc.hash(p3._3());
338    
339            return r;
340          }
341        });
342      }
343    
344      /**
345       * A hash instance for a product-4.
346       *
347       * @param ha A hash for the first element of the product.
348       * @param hb A hash for the second element of the product.
349       * @param hc A hash for the third element of the product.
350       * @param hd A hash for the fourth element of the product.
351       * @return A hash instance for a product-4.
352       */
353      public static <A, B, C, D> Hash<P4<A, B, C, D>> p4Hash(final Hash<A> ha, final Hash<B> hb, final Hash<C> hc,
354                                                             final Hash<D> hd) {
355        return new Hash<P4<A, B, C, D>>(new F<P4<A, B, C, D>, Integer>() {
356          public Integer f(final P4<A, B, C, D> p4) {
357            final int p = 419;
358            int r = 239;
359    
360            r = p * r + ha.hash(p4._1());
361            r = p * r + hb.hash(p4._2());
362            r = p * r + hc.hash(p4._3());
363            r = p * r + hd.hash(p4._4());
364    
365            return r;
366          }
367        });
368      }
369    
370      /**
371       * A hash instance for a product-5.
372       *
373       * @param ha A hash for the first element of the product.
374       * @param hb A hash for the second element of the product.
375       * @param hc A hash for the third element of the product.
376       * @param hd A hash for the fourth element of the product.
377       * @param he A hash for the fifth element of the product.
378       * @return A hash instance for a product-5.
379       */
380      public static <A, B, C, D, E> Hash<P5<A, B, C, D, E>> p5Hash(final Hash<A> ha, final Hash<B> hb, final Hash<C> hc,
381                                                                   final Hash<D> hd, final Hash<E> he) {
382        return new Hash<P5<A, B, C, D, E>>(new F<P5<A, B, C, D, E>, Integer>() {
383          public Integer f(final P5<A, B, C, D, E> p5) {
384            final int p = 419;
385            int r = 239;
386    
387            r = p * r + ha.hash(p5._1());
388            r = p * r + hb.hash(p5._2());
389            r = p * r + hc.hash(p5._3());
390            r = p * r + hd.hash(p5._4());
391            r = p * r + he.hash(p5._5());
392    
393            return r;
394          }
395        });
396      }
397    
398      /**
399       * A hash instance for a product-6.
400       *
401       * @param ha A hash for the first element of the product.
402       * @param hb A hash for the second element of the product.
403       * @param hc A hash for the third element of the product.
404       * @param hd A hash for the fourth element of the product.
405       * @param he A hash for the fifth element of the product.
406       * @param hf A hash for the sixth element of the product.
407       * @return A hash instance for a product-6.
408       */
409      public static <A, B, C, D, E, F$> Hash<P6<A, B, C, D, E, F$>> p6Hash(final Hash<A> ha, final Hash<B> hb,
410                                                                           final Hash<C> hc, final Hash<D> hd,
411                                                                           final Hash<E> he, final Hash<F$> hf) {
412        return new Hash<P6<A, B, C, D, E, F$>>(new F<P6<A, B, C, D, E, F$>, Integer>() {
413          public Integer f(final P6<A, B, C, D, E, F$> p6) {
414            final int p = 419;
415            int r = 239;
416    
417            r = p * r + ha.hash(p6._1());
418            r = p * r + hb.hash(p6._2());
419            r = p * r + hc.hash(p6._3());
420            r = p * r + hd.hash(p6._4());
421            r = p * r + he.hash(p6._5());
422            r = p * r + hf.hash(p6._6());
423    
424            return r;
425          }
426        });
427      }
428    
429      /**
430       * A hash instance for a product-7.
431       *
432       * @param ha A hash for the first element of the product.
433       * @param hb A hash for the second element of the product.
434       * @param hc A hash for the third element of the product.
435       * @param hd A hash for the fourth element of the product.
436       * @param he A hash for the fifth element of the product.
437       * @param hf A hash for the sixth element of the product.
438       * @param hg A hash for the seventh element of the product.
439       * @return A hash instance for a product-7.
440       */
441      public static <A, B, C, D, E, F$, G> Hash<P7<A, B, C, D, E, F$, G>> p7Hash(final Hash<A> ha, final Hash<B> hb,
442                                                                                 final Hash<C> hc, final Hash<D> hd,
443                                                                                 final Hash<E> he, final Hash<F$> hf,
444                                                                                 final Hash<G> hg) {
445        return new Hash<P7<A, B, C, D, E, F$, G>>(new F<P7<A, B, C, D, E, F$, G>, Integer>() {
446          public Integer f(final P7<A, B, C, D, E, F$, G> p7) {
447            final int p = 419;
448            int r = 239;
449    
450            r = p * r + ha.hash(p7._1());
451            r = p * r + hb.hash(p7._2());
452            r = p * r + hc.hash(p7._3());
453            r = p * r + hd.hash(p7._4());
454            r = p * r + he.hash(p7._5());
455            r = p * r + hf.hash(p7._6());
456            r = p * r + hg.hash(p7._7());
457    
458            return r;
459          }
460        });
461      }
462    
463      /**
464       * A hash instance for a product-8.
465       *
466       * @param ha A hash for the first element of the product.
467       * @param hb A hash for the second element of the product.
468       * @param hc A hash for the third element of the product.
469       * @param hd A hash for the fourth element of the product.
470       * @param he A hash for the fifth element of the product.
471       * @param hf A hash for the sixth element of the product.
472       * @param hg A hash for the seventh element of the product.
473       * @param hh A hash for the eighth element of the product.
474       * @return A hash instance for a product-8.
475       */
476      public static <A, B, C, D, E, F$, G, H> Hash<P8<A, B, C, D, E, F$, G, H>> p8Hash(final Hash<A> ha, final Hash<B> hb,
477                                                                                       final Hash<C> hc, final Hash<D> hd,
478                                                                                       final Hash<E> he, final Hash<F$> hf,
479                                                                                       final Hash<G> hg, final Hash<H> hh) {
480        return new Hash<P8<A, B, C, D, E, F$, G, H>>(new F<P8<A, B, C, D, E, F$, G, H>, Integer>() {
481          public Integer f(final P8<A, B, C, D, E, F$, G, H> p8) {
482            final int p = 419;
483            int r = 239;
484    
485            r = p * r + ha.hash(p8._1());
486            r = p * r + hb.hash(p8._2());
487            r = p * r + hc.hash(p8._3());
488            r = p * r + hd.hash(p8._4());
489            r = p * r + he.hash(p8._5());
490            r = p * r + hf.hash(p8._6());
491            r = p * r + hg.hash(p8._7());
492            r = p * r + hh.hash(p8._8());
493    
494            return r;
495          }
496        });
497      }
498    
499      /**
500       * A hash instance for a vector-2.
501       *
502       * @param ea A hash for the elements of the vector.
503       * @return A hash instance for a vector-2.
504       */
505      public static <A> Hash<V2<A>> v2Hash(final Hash<A> ea) {
506        return streamHash(ea).comap(V2.<A>toStream_());
507      }
508    
509      /**
510       * A hash instance for a vector-3.
511       *
512       * @param ea A hash for the elements of the vector.
513       * @return A hash instance for a vector-3.
514       */
515      public static <A> Hash<V3<A>> v3Hash(final Hash<A> ea) {
516        return streamHash(ea).comap(V3.<A>toStream_());
517      }
518    
519      /**
520       * A hash instance for a vector-4.
521       *
522       * @param ea A hash for the elements of the vector.
523       * @return A hash instance for a vector-4.
524       */
525      public static <A> Hash<V4<A>> v4Hash(final Hash<A> ea) {
526        return streamHash(ea).comap(V4.<A>toStream_());
527      }
528    
529      /**
530       * A hash instance for a vector-5.
531       *
532       * @param ea A hash for the elements of the vector.
533       * @return A hash instance for a vector-5.
534       */
535      public static <A> Hash<V5<A>> v5Hash(final Hash<A> ea) {
536        return streamHash(ea).comap(V5.<A>toStream_());
537      }
538    
539      /**
540       * A hash instance for a vector-6.
541       *
542       * @param ea A hash for the elements of the vector.
543       * @return A hash instance for a vector-6.
544       */
545      public static <A> Hash<V6<A>> v6Hash(final Hash<A> ea) {
546        return streamHash(ea).comap(V6.<A>toStream_());
547      }
548    
549      /**
550       * A hash instance for a vector-7.
551       *
552       * @param ea A hash for the elements of the vector.
553       * @return A hash instance for a vector-7.
554       */
555      public static <A> Hash<V7<A>> v7Hash(final Hash<A> ea) {
556        return streamHash(ea).comap(V7.<A>toStream_());
557      }
558    
559      /**
560       * A hash instance for a vector-8.
561       *
562       * @param ea A hash for the elements of the vector.
563       * @return A hash instance for a vector-8.
564       */
565      public static <A> Hash<V8<A>> v8Hash(final Hash<A> ea) {
566        return streamHash(ea).comap(V8.<A>toStream_());
567      }
568    }