68
|
1 package fschmidt.util.java;
|
|
2
|
|
3 import java.util.Collection;
|
|
4 import java.util.HashMap;
|
|
5 import java.util.Map;
|
|
6 import java.util.concurrent.Callable;
|
|
7 import java.util.concurrent.CancellationException;
|
|
8 import java.util.concurrent.ConcurrentHashMap;
|
|
9 import java.util.concurrent.ConcurrentMap;
|
|
10 import java.util.concurrent.ExecutionException;
|
|
11 import java.util.concurrent.Future;
|
|
12
|
|
13 // based on Memoizer from Java Concurrency in Practice
|
|
14
|
|
15 public final class Memoizer<A,V> implements Computable<A,V> {
|
|
16 private final ConcurrentMap<A, Future<V>> cache
|
|
17 = new ConcurrentHashMap<A, Future<V>>();
|
|
18 private final Computable<A,V> comp;
|
|
19
|
|
20 public Memoizer(Computable<A,V> comp) {
|
|
21 this.comp = comp;
|
|
22 }
|
|
23
|
|
24 public V get(final A arg) throws ComputationException {
|
|
25 while (true) {
|
|
26 Future<V> f = cache.get(arg);
|
|
27 if (f == null) {
|
|
28 Callable<V> eval = new Callable<V>() {
|
|
29 public V call() throws Exception {
|
|
30 return comp.get(arg);
|
|
31 }
|
|
32 };
|
|
33 FastFuture<V> ft = new FastFuture<V>(eval);
|
|
34 f = cache.putIfAbsent(arg, ft);
|
|
35 if (f == null) {
|
|
36 f = ft;
|
|
37 ft.run();
|
|
38 }
|
|
39 }
|
|
40 try {
|
|
41 return f.get();
|
|
42 } catch (InterruptedException e) {
|
|
43 throw new RuntimeException(e);
|
|
44 } catch (CancellationException e) {
|
|
45 cache.remove(arg, f);
|
|
46 } catch (ExecutionException e) {
|
|
47 throw ComputationException.newInstance(e);
|
|
48 }
|
|
49 }
|
|
50 }
|
|
51
|
|
52 public Map<A,V> get(final Collection<A> args) throws ComputationException {
|
|
53 outer:
|
|
54 while (true) {
|
|
55 Map<A,Future<V>> fmap = new HashMap<A,Future<V>>();
|
|
56 for( final A arg : args ) {
|
|
57 Future<V> f = cache.get(arg);
|
|
58 if (f == null) {
|
|
59 Callable<V> eval = new Callable<V>() {
|
|
60 public V call() throws Exception {
|
|
61 return comp.get(arg);
|
|
62 }
|
|
63 };
|
|
64 FastFuture<V> ft = new FastFuture<V>(eval);
|
|
65 f = cache.putIfAbsent(arg, ft);
|
|
66 if (f == null) {
|
|
67 f = ft;
|
|
68 ft.run();
|
|
69 }
|
|
70 }
|
|
71 fmap.put(arg,f);
|
|
72 }
|
|
73 Map<A,V> map = new HashMap<A,V>();
|
|
74 for( Map.Entry<A,Future<V>> entry : fmap.entrySet() ) {
|
|
75 A arg = entry.getKey();
|
|
76 Future<V> f = entry.getValue();
|
|
77 try {
|
|
78 map.put( arg, f.get() );
|
|
79 } catch (InterruptedException e) {
|
|
80 throw new RuntimeException(e);
|
|
81 } catch (CancellationException e) {
|
|
82 cache.remove(arg, f);
|
|
83 continue outer;
|
|
84 } catch (ExecutionException e) {
|
|
85 throw ComputationException.newInstance(e);
|
|
86 }
|
|
87 }
|
|
88 return map;
|
|
89 }
|
|
90 }
|
|
91
|
|
92 public void remove(final A arg) {
|
|
93 cache.remove(arg);
|
|
94 }
|
|
95 /*
|
|
96 public void clear() {
|
|
97 cache.clear();
|
|
98 }
|
|
99 */
|
|
100 }
|