diff src/fschmidt/util/java/Memoizer.java @ 68:00520880ad02

add fschmidt source
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 05 Oct 2025 17:24:15 -0600
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fschmidt/util/java/Memoizer.java	Sun Oct 05 17:24:15 2025 -0600
@@ -0,0 +1,100 @@
+package fschmidt.util.java;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+// based on Memoizer from Java Concurrency in Practice
+
+public final class Memoizer<A,V> implements Computable<A,V> {
+	private final ConcurrentMap<A, Future<V>> cache
+			= new ConcurrentHashMap<A, Future<V>>();
+	private final Computable<A,V> comp;
+
+	public Memoizer(Computable<A,V> comp) {
+		this.comp = comp;
+	}
+
+	public V get(final A arg) throws ComputationException {
+		while (true) {
+			Future<V> f = cache.get(arg);
+			if (f == null) {
+				Callable<V> eval = new Callable<V>() {
+					public V call() throws Exception {
+						return comp.get(arg);
+					}
+				};
+				FastFuture<V> ft = new FastFuture<V>(eval);
+				f = cache.putIfAbsent(arg, ft);
+				if (f == null) {
+					f = ft;
+					ft.run();
+				}
+			}
+			try {
+				return f.get();
+			} catch (InterruptedException e) {
+				throw new RuntimeException(e);
+			} catch (CancellationException e) {
+				cache.remove(arg, f);
+			} catch (ExecutionException e) {
+				throw ComputationException.newInstance(e);
+			}
+		}
+	}
+
+	public Map<A,V> get(final Collection<A> args) throws ComputationException {
+		outer:
+		while (true) {
+			Map<A,Future<V>> fmap = new HashMap<A,Future<V>>();
+			for( final A arg : args ) {
+				Future<V> f = cache.get(arg);
+				if (f == null) {
+					Callable<V> eval = new Callable<V>() {
+						public V call() throws Exception {
+							return comp.get(arg);
+						}
+					};
+					FastFuture<V> ft = new FastFuture<V>(eval);
+					f = cache.putIfAbsent(arg, ft);
+					if (f == null) {
+						f = ft;
+						ft.run();
+					}
+				}
+				fmap.put(arg,f);
+			}
+			Map<A,V> map = new HashMap<A,V>();
+			for( Map.Entry<A,Future<V>> entry : fmap.entrySet() ) {
+				A arg = entry.getKey();
+				Future<V> f = entry.getValue();
+				try {
+					map.put( arg, f.get() );
+				} catch (InterruptedException e) {
+					throw new RuntimeException(e);
+				} catch (CancellationException e) {
+					cache.remove(arg, f);
+					continue outer;
+				} catch (ExecutionException e) {
+					throw ComputationException.newInstance(e);
+				}
+			}
+			return map;
+		}
+	}
+
+	public void remove(final A arg) {
+		cache.remove(arg);
+	}
+/*
+	public void clear() {
+		cache.clear();
+	}
+*/
+}