|
1 | 1 | package fj; |
2 | 2 |
|
| 3 | +import java.lang.ref.Reference; |
| 4 | +import java.lang.ref.SoftReference; |
3 | 5 | import java.lang.ref.WeakReference; |
4 | 6 |
|
5 | 7 | import fj.data.Array; |
@@ -208,53 +210,93 @@ public <X> P1<X> map(final F<A, X> f) { |
208 | 210 | } |
209 | 211 |
|
210 | 212 | /** |
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); } |
235 | 218 |
|
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); } |
240 | 223 |
|
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); } |
243 | 228 |
|
244 | 229 | static <A> P1<A> memo(F<Unit, A> f) { |
245 | 230 | return P.lazy(f).memo(); |
246 | 231 | } |
247 | 232 |
|
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; } |
254 | 263 |
|
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(); |
256 | 276 | } |
257 | 277 |
|
| 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 | + |
258 | 300 | @Override |
259 | 301 | public String toString() { |
260 | 302 | return Show.p1Show(Show.<A>anyShow()).showS(this); |
|
0 commit comments