Skip to content

Commit df05355

Browse files
committed
Merge branch 'master' of https://github.com/functionaljava/functionaljava into optimizable-typeclasses
2 parents 7aa9e3b + 0e3187f commit df05355

34 files changed

Lines changed: 1168 additions & 199 deletions

core/src/main/java/fj/Equal.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import fj.data.TreeMap;
1515
import fj.data.Validation;
1616
import fj.data.Writer;
17+
import fj.data.hamt.BitSet;
1718
import fj.data.hlist.HList;
1819
import fj.data.vector.V2;
1920
import fj.data.vector.V3;
@@ -270,6 +271,11 @@ public boolean equal(A a1, A a2) {
270271
return false;
271272
});
272273

274+
/**
275+
* An equal instance for the {@link BitSet} type.
276+
*/
277+
public static final Equal<BitSet> bitSetSequal = equalDef((bs1, bs2) -> bs1.longValue() == bs2.longValue());
278+
273279
/**
274280
* An equal instance for the {@link Either} type.
275281
*

core/src/main/java/fj/P.java

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,51 @@ public static <A> P1<A> p(final A a) {
3232
@Override public A _1() {
3333
return a;
3434
}
35-
@Override public P1<A> memo() { return this; }
35+
@Override public P1<A> hardMemo() { return this; }
3636
@Override public P1<A> weakMemo() { return this; }
3737
@Override public P1<A> softMemo() { return this; }
3838
};
3939
}
4040

41+
/**
42+
* Convert a F0 into a P1, using call-by-need semantic:
43+
* function f is evaluated at most once, at first to {@link P1#_1()}.
44+
*/
45+
public static <A> P1<A> hardMemo(F0<A> f) {
46+
return new P1.Memo<>(f);
47+
}
4148

42-
public static <A> P1<A> lazy(final P1<A> pa) {
43-
return pa;
44-
}
49+
/**
50+
* Convert a F0 into a P1, using weak call-by-need semantic:
51+
* function f is evaluated at first call to {@link P1#_1()}
52+
* and at each subsequent call if and only if the reference have been garbage collected.
53+
*/
54+
public static <A> P1<A> weakMemo(F0<A> f) {
55+
return new P1.WeakReferenceMemo<>(f);
56+
}
57+
58+
/**
59+
* Convert a F0 into a P1, using soft call-by-need semantic:
60+
* function f is evaluated at first call to {@link P1#_1()}
61+
* and at each subsequent call if and only if the reference have been garbage collected
62+
* due of shortage of memory (ie. to avoid OutOfMemoryErrors).
63+
*/
64+
public static <A> P1<A> sofMemo(F0<A> f) {
65+
return new P1.SoftReferenceMemo<>(f);
66+
}
67+
68+
/**
69+
* Convert a F0 into a P1, using call-by-name semantic:
70+
* function f is evaluated at each call to {@link P1#_1()}.
71+
*/
72+
public static <A> P1<A> lazy(F0<A> f) {
73+
return new P1<A>() {
74+
@Override
75+
public A _1() {
76+
return f.f();
77+
}
78+
};
79+
}
4580

4681
public static <A, B> P2<A, B> lazy(final F0<A> pa, final F0<B> pb) {
4782
return new P2<A, B>() {
@@ -538,15 +573,6 @@ public H _8() {
538573
};
539574
}
540575

541-
public static <A> P1<A> lazy(F0<A> f) {
542-
return new P1<A>() {
543-
@Override
544-
public A _1() {
545-
return f.f();
546-
}
547-
};
548-
}
549-
550576
public static <A> P1<A> lazy(F<Unit, A> f) {
551577
return lazy(() -> f.f(unit()));
552578
}

core/src/main/java/fj/P1.java

Lines changed: 68 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package fj;
22

3-
import java.lang.ref.Reference;
4-
import java.lang.ref.SoftReference;
5-
import java.lang.ref.WeakReference;
6-
73
import fj.data.Array;
8-
import fj.data.List;
9-
import fj.data.Stream;
104
import fj.data.Either;
5+
import fj.data.List;
116
import fj.data.Option;
7+
import fj.data.Stream;
128
import fj.data.Validation;
9+
10+
import java.lang.ref.Reference;
11+
import java.lang.ref.SoftReference;
12+
import java.lang.ref.WeakReference;
13+
14+
import static fj.P.p;
15+
import static fj.Unit.unit;
1316
//import fj.data.*;
1417

1518

@@ -138,7 +141,7 @@ public final <B, C> P1<C> liftM2(P1<B> pb, F2<A, B, C> f) {
138141
* @return A single P1 for the given List.
139142
*/
140143
public static <A> P1<List<A>> sequence(final List<P1<A>> as) {
141-
return as.foldRight(liftM2(List.cons()), P.p(List.nil()));
144+
return as.foldRight(liftM2(List.cons()), p(List.nil()));
142145
}
143146

144147
/**
@@ -157,7 +160,7 @@ public static <A> F<List<P1<A>>, P1<List<A>>> sequenceList() {
157160
* @return A single P1 for the given stream.
158161
*/
159162
public static <A> P1<Stream<A>> sequence(final Stream<P1<A>> as) {
160-
return as.foldRight(liftM2(Stream.cons()), P.p(Stream.nil()));
163+
return as.foldRight(liftM2(Stream.cons()), p(Stream.nil()));
161164
}
162165

163166
/**
@@ -238,7 +241,11 @@ public final <B> P1<B> map(final F<A, B> f) {
238241
return P.lazy(() -> f.f(self._1()));
239242
}
240243

241-
public P1<A> memo() {
244+
/**
245+
* @deprecated since 4.7. Use {@link P1#weakMemo()} instead.
246+
*/
247+
@Deprecated
248+
public final P1<A> memo() {
242249
return weakMemo();
243250
}
244251

@@ -247,7 +254,7 @@ public P1<A> memo() {
247254
*
248255
* @return A P1 that calls this P1 once and remembers the value for subsequent calls.
249256
*/
250-
public final P1<A> hardMemo() { return new Memo<>(this); }
257+
public P1<A> hardMemo() { return new Memo<>(this); }
251258

252259
/**
253260
* Like <code>memo</code>, but the memoized value is wrapped into a <code>WeakReference</code>
@@ -259,73 +266,85 @@ public P1<A> memo() {
259266
*/
260267
public P1<A> softMemo() { return new SoftReferenceMemo<>(this); }
261268

269+
/**
270+
* @deprecated since 4.7. Use {@link P#weakMemo(F0)} instead.
271+
*/
272+
@Deprecated
262273
public static <A> P1<A> memo(F<Unit, A> f) {
263-
return P.lazy(f).memo();
274+
return P.weakMemo(() -> f.f(unit()));
264275
}
265276

266-
public static <A> P1<A> memo(F0<A> f) {
267-
return P.lazy(f).memo();
277+
/**
278+
* @deprecated since 4.7. Use {@link P#weakMemo(F0)} instead.
279+
*/
280+
@Deprecated
281+
public static <A> P1<A> memo(F0<A> f) {
282+
return P.weakMemo(f);
268283
}
269284

270-
static class Memo<A> extends P1<A> {
271-
private volatile P1<A> self;
285+
static final class Memo<A> extends P1<A> {
286+
private volatile F0<A> fa;
272287
private A value;
273288

274-
Memo(P1<A> self) { this.self = self; }
289+
Memo(F0<A> fa) { this.fa = fa; }
275290

276291
@Override public final A _1() {
277-
if (self != null) {
278-
synchronized (this) {
279-
if (self != null) {
280-
A a = self._1();
281-
value = a;
282-
self = null;
283-
return a;
284-
}
285-
}
292+
return (fa == null) ? value : computeValue();
293+
}
294+
295+
private synchronized A computeValue() {
296+
F0<A> fa = this.fa;
297+
if (fa != null) {
298+
value = fa.f();
299+
this.fa = null;
286300
}
287301
return value;
288302
}
289303

290-
@Override public final P1<A> memo() { return this; }
304+
@Override public P1<A> hardMemo() { return this; }
305+
@Override public P1<A> softMemo() { return this; }
306+
@Override public P1<A> weakMemo() { return this; }
291307
}
292308

293309
abstract static class ReferenceMemo<A> extends P1<A> {
294-
private final P1<A> self;
295-
private final Object latch = new Object();
296-
private volatile Reference<Option<A>> v = null;
310+
private final F0<A> fa;
311+
private volatile Reference<P1<A>> v = null;
297312

298-
ReferenceMemo(final P1<A> self) { this.self = self; }
313+
ReferenceMemo(final F0<A> fa) { this.fa = fa; }
299314

300315
@Override public final A _1() {
301-
Option<A> o = v != null ? v.get() : null;
302-
if (o == null) {
303-
synchronized (latch) {
304-
o = v != null ? v.get() : null;
305-
if (o == null) {
306-
o = Option.some(self._1());
307-
v = newReference(o);
308-
}
309-
}
316+
Reference<P1<A>> v = this.v;
317+
P1<A> p1 = v != null ? v.get() : null;
318+
return p1 != null ? p1._1() : computeValue();
319+
}
320+
321+
private synchronized A computeValue() {
322+
Reference<P1<A>> v = this.v;
323+
P1<A> p1 = v != null ? v.get() : null;
324+
if (p1 == null) {
325+
A a = fa.f();
326+
this.v = newReference(p(a));
327+
return a;
310328
}
311-
return o.some();
329+
return p1._1();
312330
}
313331

314-
abstract Reference<Option<A>> newReference(Option<A> o);
332+
abstract <B> Reference<B> newReference(B ref);
315333
}
316334

317-
static class WeakReferenceMemo<A> extends ReferenceMemo<A> {
318-
WeakReferenceMemo(P1<A> self) { super(self); }
335+
static final class WeakReferenceMemo<A> extends ReferenceMemo<A> {
336+
WeakReferenceMemo(F0<A> fa) { super(fa); }
319337
@Override
320-
final Reference<Option<A>> newReference(final Option<A> o) { return new WeakReference<>(o); }
321-
@Override public final P1<A> weakMemo() { return this; }
338+
<B> Reference<B> newReference(final B ref) { return new WeakReference<>(ref); }
339+
@Override public P1<A> weakMemo() { return this; }
322340
}
323341

324-
static class SoftReferenceMemo<A> extends ReferenceMemo<A> {
325-
SoftReferenceMemo(P1<A> self) { super(self); }
342+
static final class SoftReferenceMemo<A> extends ReferenceMemo<A> {
343+
SoftReferenceMemo(F0<A> self) { super(self); }
326344
@Override
327-
final Reference<Option<A>> newReference(final Option<A> o) { return new SoftReference<>(o); }
328-
@Override public final P1<A> softMemo() { return this; }
345+
<B> Reference<B> newReference(final B ref) { return new SoftReference<>(ref); }
346+
@Override public P1<A> softMemo() { return this; }
347+
@Override public P1<A> weakMemo() { return this; }
329348
}
330349

331350
/**

core/src/main/java/fj/P2.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fj;
22

33
import static fj.Function.*;
4+
import static fj.P.weakMemo;
45
import static fj.data.optic.PLens.pLens;
56
import fj.data.*;
67
import fj.data.optic.Lens;
@@ -185,8 +186,8 @@ public final P1<B> _2_() {
185186
public final P2<A, B> memo() {
186187
P2<A, B> self = this;
187188
return new P2<A, B>() {
188-
private final P1<A> a = P1.memo(u -> self._1());
189-
private final P1<B> b = P1.memo(u -> self._2());
189+
private final P1<A> a = weakMemo(self::_1);
190+
private final P1<B> b = weakMemo(self::_2);
190191

191192
public A _1() {
192193
return a._1();

core/src/main/java/fj/P3.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fj;
22

3+
import static fj.P.weakMemo;
4+
35
/**
46
* A product-3.
57
*
@@ -128,9 +130,9 @@ public final P1<C> _3_() {
128130
public final P3<A, B, C> memo() {
129131
P3<A, B, C> self = this;
130132
return new P3<A, B, C>() {
131-
private final P1<A> a = P1.memo(u -> self._1());
132-
private final P1<B> b = P1.memo(u -> self._2());
133-
private final P1<C> c = P1.memo(u -> self._3());
133+
private final P1<A> a = weakMemo(self::_1);
134+
private final P1<B> b = weakMemo(self::_2);
135+
private final P1<C> c = weakMemo(self::_3);
134136

135137
public A _1() {
136138
return a._1();

core/src/main/java/fj/P4.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fj;
22

3+
import static fj.P.weakMemo;
4+
35
/**
46
* A product-4.
57
*
@@ -182,10 +184,10 @@ public final P1<D> _4_() {
182184
public final P4<A, B, C, D> memo() {
183185
P4<A, B, C, D> self = this;
184186
return new P4<A, B, C, D>() {
185-
private final P1<A> a = P1.memo(u -> self._1());
186-
private final P1<B> b = P1.memo(u -> self._2());
187-
private final P1<C> c = P1.memo(u -> self._3());
188-
private final P1<D> d = P1.memo(u -> self._4());
187+
private final P1<A> a = weakMemo(self::_1);
188+
private final P1<B> b = weakMemo(self::_2);
189+
private final P1<C> c = weakMemo(self::_3);
190+
private final P1<D> d = weakMemo(self::_4);
189191

190192
public A _1() {
191193
return a._1();

core/src/main/java/fj/P5.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fj;
22

3+
import static fj.P.weakMemo;
4+
35
/**
46
* A product-5.
57
*
@@ -244,11 +246,11 @@ public final P1<E> _5_() {
244246
public final P5<A, B, C, D, E> memo() {
245247
P5<A, B, C, D, E> self = this;
246248
return new P5<A, B, C, D, E>() {
247-
private final P1<A> a = P1.memo(u -> self._1());
248-
private final P1<B> b = P1.memo(u -> self._2());
249-
private final P1<C> c = P1.memo(u -> self._3());
250-
private final P1<D> d = P1.memo(u -> self._4());
251-
private final P1<E> e = P1.memo(u -> self._5());
249+
private final P1<A> a = weakMemo(self::_1);
250+
private final P1<B> b = weakMemo(self::_2);
251+
private final P1<C> c = weakMemo(self::_3);
252+
private final P1<D> d = weakMemo(self::_4);
253+
private final P1<E> e = weakMemo(self::_5);
252254

253255
public A _1() {
254256
return a._1();

core/src/main/java/fj/P6.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fj;
22

3+
import static fj.P.weakMemo;
4+
35
/**
46
* A product-6.
57
*
@@ -315,12 +317,12 @@ public final P1<F> _6_() {
315317
public final P6<A, B, C, D, E, F> memo() {
316318
P6<A, B, C, D, E, F> self = this;
317319
return new P6<A, B, C, D, E, F>() {
318-
private final P1<A> a = P1.memo(u -> self._1());
319-
private final P1<B> b = P1.memo(u -> self._2());
320-
private final P1<C> c = P1.memo(u -> self._3());
321-
private final P1<D> d = P1.memo(u -> self._4());
322-
private final P1<E> e = P1.memo(u -> self._5());
323-
private final P1<F> f = P1.memo(u -> self._6());
320+
private final P1<A> a = weakMemo(self::_1);
321+
private final P1<B> b = weakMemo(self::_2);
322+
private final P1<C> c = weakMemo(self::_3);
323+
private final P1<D> d = weakMemo(self::_4);
324+
private final P1<E> e = weakMemo(self::_5);
325+
private final P1<F> f = weakMemo(self::_6);
324326

325327
public A _1() {
326328
return a._1();

0 commit comments

Comments
 (0)