Skip to content

Commit 05f7dbf

Browse files
committed
Changed memo() to use strong references. Added weakMemo() and softMemo().
1 parent eaa03ca commit 05f7dbf

File tree

3 files changed

+82
-38
lines changed

3 files changed

+82
-38
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public static <A> P1<A> p(final A a) {
3737
return a;
3838
}
3939
@Override public P1<A> memo() { return this; }
40+
@Override public P1<A> weakMemo() { return this; }
41+
@Override public P1<A> softMemo() { return this; }
4042
};
4143
}
4244

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

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

3+
import java.lang.ref.Reference;
4+
import java.lang.ref.SoftReference;
35
import java.lang.ref.WeakReference;
46

57
import fj.data.Array;
@@ -208,53 +210,93 @@ public <X> P1<X> map(final F<A, X> f) {
208210
}
209211

210212
/**
211-
* Provides a memoising P1 that remembers its value.
212-
*
213-
* @return A P1 that calls this P1 once and remembers the value for subsequent calls.
214-
*/
215-
public P1<A> memo() {
216-
final P1<A> self = this;
217-
return new P1<A>() {
218-
private final Object latch = new Object();
219-
private volatile WeakReference<Option<A>> v = null;
220-
221-
@Override
222-
public A _1() {
223-
Option<A> o = v != null ? v.get() : null;
224-
if (o == null) {
225-
synchronized (latch) {
226-
o = v != null ? v.get() : null;
227-
if (o == null) {
228-
o = Option.some(self._1());
229-
v = new WeakReference<>(o);
230-
}
231-
}
232-
}
233-
return o.some();
234-
}
213+
* Returns a P1 that remembers its value.
214+
*
215+
* @return A P1 that calls this P1 once and remembers the value for subsequent calls.
216+
*/
217+
public P1<A> memo() { return new Memo<>(this); }
235218

236-
@Override
237-
public P1<A> memo() {
238-
return this;
239-
}
219+
/**
220+
* Like <code>memo</code>, but the memoized value is wrapped into a <code>WeakReference</code>
221+
*/
222+
public P1<A> weakMemo() { return new WeakReferenceMemo<>(this); }
240223

241-
};
242-
}
224+
/**
225+
* Like <code>memo</code>, but the memoized value is wrapped into a <code>SoftReference</code>
226+
*/
227+
public P1<A> softMemo() { return new SoftReferenceMemo<>(this); }
243228

244229
static <A> P1<A> memo(F<Unit, A> f) {
245230
return P.lazy(f).memo();
246231
}
247232

248-
/**
249-
* Returns a constant function that always uses this value.
250-
*
251-
* @return A constant function that always uses this value.
252-
*/
253-
public <B> F<B, A> constant() {
233+
static class Memo<A> extends P1<A> {
234+
private final P1<A> self;
235+
private volatile boolean initialized;
236+
private A value;
237+
238+
Memo(P1<A> self) { this.self = self; }
239+
240+
@Override public A _1() {
241+
if (!initialized) {
242+
synchronized (this) {
243+
if (!initialized) {
244+
A a = self._1();
245+
value = a;
246+
initialized = true;
247+
return a;
248+
}
249+
}
250+
}
251+
return value;
252+
}
253+
254+
@Override public P1<A> memo() { return this; }
255+
}
256+
257+
abstract static class ReferenceMemo<A> extends P1<A> {
258+
private final P1<A> self;
259+
private final Object latch = new Object();
260+
private volatile Reference<Option<A>> v = null;
261+
262+
ReferenceMemo(final P1<A> self) { this.self = self; }
254263

255-
return b -> P1.this._1();
264+
@Override public A _1() {
265+
Option<A> o = v != null ? v.get() : null;
266+
if (o == null) {
267+
synchronized (latch) {
268+
o = v != null ? v.get() : null;
269+
if (o == null) {
270+
o = Option.some(self._1());
271+
v = newReference(o);
272+
}
273+
}
274+
}
275+
return o.some();
256276
}
257277

278+
abstract Reference<Option<A>> newReference(Option<A> o);
279+
}
280+
281+
static class WeakReferenceMemo<A> extends ReferenceMemo<A> {
282+
WeakReferenceMemo(P1<A> self) { super(self); }
283+
@Override Reference<Option<A>> newReference(final Option<A> o) { return new WeakReference<>(o); }
284+
@Override public P1<A> weakMemo() { return this; }
285+
}
286+
287+
static class SoftReferenceMemo<A> extends ReferenceMemo<A> {
288+
SoftReferenceMemo(P1<A> self) { super(self); }
289+
@Override Reference<Option<A>> newReference(final Option<A> o) { return new SoftReference<>(o); }
290+
@Override public P1<A> softMemo() { return this; }
291+
}
292+
293+
/**
294+
* Returns a constant function that always uses this value.
295+
*
296+
* @return A constant function that always uses this value.
297+
*/
298+
public <B> F<B, A> constant() { return Function.constant(_1()); }
299+
258300
@Override
259301
public String toString() {
260302
return Show.p1Show(Show.<A>anyShow()).showS(this);

core/src/main/java/fj/data/Stream.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1430,7 +1430,7 @@ private static final class Cons<A> extends Stream<A> {
14301430

14311431
Cons(final A head, final P1<Stream<A>> tail) {
14321432
this.head = head;
1433-
this.tail = tail.memo();
1433+
this.tail = tail.weakMemo();
14341434
}
14351435

14361436
public A head() {

0 commit comments

Comments
 (0)