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