001 package fj.test; 002 003 import fj.F; 004 import static fj.test.Gen.gen; 005 006 import java.util.HashMap; 007 008 /** 009 * A memoised generator variant. Stores generators that have already been computed for the given arguments. 010 * 011 * @version %build.number%<br> 012 * <ul> 013 * <li>$LastChangedRevision: 5 $</li> 014 * <li>$LastChangedDate: 2008-12-06 16:49:43 +1000 (Sat, 06 Dec 2008) $</li> 015 * <li>$LastChangedBy: tonymorris $</li> 016 * </ul> 017 */ 018 public final class Variant { 019 private static final HashMap<LongGen, Gen<?>> variantMemo = new HashMap<LongGen, Gen<?>>(); 020 021 private static final class LongGen { 022 private final long n; 023 private final Gen<?> gen; 024 025 LongGen(final long n, final Gen<?> gen) { 026 this.n = n; 027 this.gen = gen; 028 } 029 030 public boolean equals(final Object o) { 031 return o != null && 032 o.getClass() == LongGen.class && 033 n == ((LongGen)o).n && 034 gen == ((LongGen)o).gen; 035 } 036 037 public int hashCode() { 038 final int p = 419; 039 int result = 239; 040 result = p * result + (int) (n ^ n >>> 32); 041 result = p * result + gen.hashCode(); 042 return result; 043 } 044 } 045 046 private Variant() { 047 throw new UnsupportedOperationException(); 048 } 049 050 /** 051 * Produces a generator that is independent of the given generator using the given value. 052 * 053 * @param n The value to produce the new generator from. 054 * @param g The generator to produce the new generator from. 055 * @return A generator that is independent of the given generator using the given value. 056 */ 057 public static <A> Gen<A> variant(final long n, final Gen<A> g) { 058 final LongGen p = new LongGen(n, g); 059 final Gen<?> gx = variantMemo.get(p); 060 if(gx == null) { 061 final Gen<A> t = gen(new F<Integer, F<Rand, A>>() { 062 public F<Rand, A> f(final Integer i) { 063 return new F<Rand, A>() { 064 public A f(final Rand r) { 065 return g.gen(i, r.reseed(n)); 066 } 067 }; 068 } 069 }); 070 variantMemo.put(p, t); 071 return t; 072 } else return gen(new F<Integer, F<Rand, A>>() { 073 public F<Rand, A> f(final Integer i) { 074 return new F<Rand, A>() { 075 @SuppressWarnings({"unchecked"}) 076 public A f(final Rand r) { 077 return (A)gx.gen(i, r); 078 } 079 }; 080 } 081 }); 082 } 083 084 /** 085 * A curried version of {@link #variant(long, Gen)}. 086 * 087 * @param n The value to produce the new generator from. 088 * @return A curried version of {@link #variant(long, Gen)}. 089 */ 090 public static <A> F<Gen<A>, Gen<A>> variant(final long n) { 091 return new F<Gen<A>, Gen<A>>() { 092 public Gen<A> f(final Gen<A> g) { 093 return variant(n, g); 094 } 095 }; 096 } 097 } 098