1 /**
2 Copyright: Copyright (c) 2019, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 Based on require in `object.d` in druntime therefor the Boost license.
7 
8 A convenient function extending cachetools with a common recurring function.
9 */
10 module dextool.cachetools;
11 
12 import std.datetime : Duration;
13 
14 import my.from_;
15 
16 /***********************************
17  * Looks up key; if it exists returns corresponding value else evaluates
18  * value, adds it to the associative array and returns it.
19  * Params:
20  *      aa =     The cache.
21  *      key =    The key.
22  *      value =  The required value.
23  * Returns:
24  *      The value.
25  *
26  * Example:
27  * ---
28  * auto cache = CacheLRU!(int,string);
29  * cache.require(5, { return "5"; }());
30  * ---
31  */
32 //TODO: rename to require when the workaround for <2.082 compiles is removed.
33 V cacheToolsRequire(CT, K, V)(CT aa, K key, lazy V value = V.init)
34         if (is(CT == class) && !is(CT == V[K])) {
35     // TODO: when upgrading to a 2.082+ compiler use this constraint instead
36     //if (is(CT == from!"cachetools".CacheLRU!(K, V))) {
37     auto q = aa.get(key);
38     if (q.isNull) {
39         auto v = value;
40         aa.put(key, v);
41         return v;
42     }
43     return q.get;
44 }
45 
46 // TODO: remove this when upgrading the minimal compiler.
47 static if (__VERSION__ < 2082L) {
48     /***********************************
49  * Looks up key; if it exists returns corresponding value else evaluates
50  * value, adds it to the associative array and returns it.
51  * Params:
52  *      aa =     The associative array.
53  *      key =    The key.
54  *      value =  The required value.
55  * Returns:
56  *      The value.
57  */
58     ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init) @trusted {
59         if (auto v = key in aa) {
60             return *v;
61         }
62 
63         aa[key] = value;
64         return aa[key];
65     }
66 }
67 
68 struct NullableCache(K, V, alias getValue) {
69     import std.typecons : Nullable;
70     import cachetools : CacheLRU;
71 
72     CacheLRU!(K, V) cache;
73 
74     this(CacheLRU!(K, V) cache, int size = 0, Duration ttl = Duration.zero) {
75         this.cache = cache;
76         if (size != 0)
77             cache.size = size;
78         if (ttl != Duration.zero)
79             cache.ttl = ttl;
80     }
81 
82     static if (__VERSION__ > 2089L) {
83         ~this() {
84             .destroy(cache);
85         }
86     }
87 
88     auto get(K k) {
89         Nullable!V rval = cache.get(k);
90         if (rval.isNull) {
91             rval = getValue(k);
92             if (!rval.isNull) {
93                 cache.put(k, rval.get);
94             }
95         }
96         return rval;
97     }
98 
99     auto opCall(K k) {
100         return get(k);
101     }
102 }
103 
104 auto nullableCache(K, V, alias getValue)(int size = 0, Duration ttl = Duration.zero) {
105     import cachetools : CacheLRU;
106 
107     return NullableCache!(K, V, getValue)(new CacheLRU!(K, V));
108 }