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 }