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 }