1 module re.util.cache;
2 
3 import std.array;
4 import std.typecons;
5 
6 /// represents a cache that associates string keys with items
7 struct KeyedCache(T) {
8     private T[string] _cache;
9     void delegate(T) _free;
10 
11     this(void delegate(T) on_free) {
12         _free = on_free;
13     }
14 
15     /// cache an item
16     public void put(string key, T value) {
17         _cache[key] = value;
18     }
19 
20     /// check if an item is cached
21     public Nullable!T get(string key) {
22         if (key in _cache) {
23             return Nullable!T(_cache[key]);
24         }
25         return Nullable!T.init;
26     }
27 
28     /// get all items
29     public T[] get_all() {
30         return _cache.byValue().array;
31     }
32 
33     /// clear cache
34     public void drop() {
35         // run free on each item
36         if (_free !is null) {
37             foreach (item; get_all()) {
38                 _free(item);
39             }
40         }
41         _cache.clear();
42     }
43 }
44 
45 @("cache-basic")
46 unittest {
47     auto num_cache = KeyedCache!int();
48 
49     enum VAL_APPLE = 4;
50 
51     num_cache.put("apple", VAL_APPLE);
52 
53     immutable auto i1 = num_cache.get("apple");
54     assert(!i1.isNull);
55     assert(i1.get == VAL_APPLE);
56     assert(num_cache.get_all.length == 1);
57 
58     num_cache.drop();
59 
60     immutable auto i2 = num_cache.get("apple");
61     assert(i2.isNull);
62 }
63 
64 @("cache-cleanup")
65 unittest {
66     auto resources_used = 0;
67     auto res_cache = KeyedCache!int((x) { resources_used += x; });
68 
69     enum handle = 3;
70     res_cache.put("handle", handle);
71 
72     res_cache.drop();
73     assert(res_cache.get_all.length == 0);
74 
75     assert(resources_used > 0, "free was not called");
76 }