1 /**
2 * ae.sys.persistence.memoize
3 *
4 * License:
5 * This Source Code Form is subject to the terms of
6 * the Mozilla Public License, v. 2.0. If a copy of
7 * the MPL was not distributed with this file, You
8 * can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * Authors:
11 * Vladimir Panteleev <vladimir@thecybershadow.net>
12 */
13
14 module ae.sys.persistence.memoize;
15
16 import std.traits;
17 import std.typecons;
18
19 import ae.sys.persistence.core;
20 import ae.sys.persistence.json;
21 import ae.utils.json;
22
23 // ****************************************************************************
24
25 // http://d.puremagic.com/issues/show_bug.cgi?id=7016
26 static import ae.utils.json;
27
28 /// std.functional.memoize variant with automatic persistence
29 struct PersistentMemoized(alias fun, FlushPolicy flushPolicy = FlushPolicy.atThreadExit)
30 {
31 alias AA = ReturnType!fun[string];
32 private JsonFileCache!(AA, flushPolicy) memo;
33
34 this(string fileName) { memo.fileName = fileName; }
35
36 ReturnType!fun opCall(ParameterTypeTuple!fun args)
37 {
38 string key;
39 static if (args.length==1 && is(typeof(args[0]) : string))
40 key = args[0];
41 else
42 key = toJson(tuple(args));
43 auto p = key in memo;
44 if (p) return *p;
45 auto r = fun(args);
46 return memo[key] = r;
47 }
48 }
49
50 unittest
51 {
52 import std.file : exists, remove;
53
54 static int value = 42;
55 int getValue(int x) { return value; }
56
57 enum FN = "test4.json";
58 scope(exit) if (FN.exists) remove(FN);
59
60 {
61 auto getValueMemoized = PersistentMemoized!(getValue, FlushPolicy.atScopeExit)(FN);
62
63 assert(getValueMemoized(1) == 42);
64 value = 24;
65 assert(getValueMemoized(1) == 42);
66 assert(getValueMemoized(2) == 24);
67 }
68
69 value = 0;
70
71 {
72 auto getValueMemoized = PersistentMemoized!(getValue, FlushPolicy.atScopeExit)(FN);
73 assert(getValueMemoized(1) == 42);
74 assert(getValueMemoized(2) == 24);
75 }
76 }
77
78 /// As above, but with synchronization
79 struct SynchronizedPersistentMemoized(alias fun, FlushPolicy flushPolicy = FlushPolicy.atThreadExit)
80 {
81 alias AA = ReturnType!fun[string];
82 private JsonFileCache!(AA, flushPolicy) memo;
83 Object mutex;
84
85 this(string fileName)
86 {
87 memo.fileName = fileName;
88 mutex = new Object;
89 }
90
91 ReturnType!fun opCall(ParameterTypeTuple!fun args)
92 {
93 string key;
94 static if (args.length==1 && is(typeof(args[0]) : string))
95 key = args[0];
96 else
97 key = toJson(tuple(args));
98 synchronized (mutex)
99 {
100 auto p = key in memo;
101 if (p) return *p;
102 }
103 auto r = fun(args);
104 synchronized (mutex)
105 return memo[key] = r;
106 }
107 }