eric6/E5Utilities/E5Cache.py

changeset 6942
2602857055c5
parent 6755
009812744917
child 7229
53054eb5b15a
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2017 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing classes used for caching objects.
8 """
9
10 from __future__ import unicode_literals
11
12 from PyQt5.QtCore import QDateTime, QTimer
13
14
15 class E5Cache(object):
16 """
17 Class implementing a LRU cache of a specific size.
18
19 If the maximum number of entries is exceeded, the least recently used item
20 is removed from the cache. A cache hit moves the entry to the front of the
21 cache.
22 """
23 def __init__(self, size=100):
24 """
25 Constructor
26
27 @param size maximum number of entries that may be stored in the cache
28 @type int
29 """
30 assert size >= 0
31
32 self.__size = size
33
34 # internal objects
35 self.__keyList = []
36 self.__store = {} # stores the cache entries
37 self.__accesStore = {} # stores the last access date and times
38 self.__hits = 0
39 self.__misses = 0
40 self.__maxsize = 0
41 self.__maxCacheTime = 0 # 0 seconds means aging is disabled
42
43 self.__cacheTimer = QTimer()
44 self.__cacheTimer.setSingleShot(True)
45 self.__cacheTimer.timeout.connect(self.__pruneCache)
46
47 def __moveLast(self, key):
48 """
49 Private method to move a cached item to the MRU position.
50
51 @param key key of the item to be retrieved
52 @type any hashable type that can be used as a dict key
53 """
54 self.__keyList.remove(key)
55 self.__keyList.append(key)
56
57 def __adjustToSize(self):
58 """
59 Private method to adjust the cache to its size.
60 """
61 if self.__size:
62 removeList, self.__keyList = \
63 self.__keyList[:-self.__size], self.__keyList[-self.__size:]
64 for key in removeList:
65 del self.__store[key]
66 del self.__accesStore[key]
67 else:
68 self.reset()
69
70 def getSize(self):
71 """
72 Public method to get the maximum size of the cache.
73
74 @return maximum number of entries of the cache
75 @rtype int
76 """
77 return self.__size
78
79 def setSize(self, newSize):
80 """
81 Public method to change the maximum size of the cache.
82
83 @param newSize maximum number of entries that may be stored in the
84 cache
85 @type int
86 """
87 assert newSize >= 0
88
89 self.__size = newSize
90 self.__adjustToSize()
91
92 def getMaximumCacheTime(self):
93 """
94 Public method to get the maximum time entries may exist in the cache.
95
96 @return maximum cache time in seconds
97 @rtype int
98 """
99 return self.__maxCacheTime
100
101 def setMaximumCacheTime(self, time):
102 """
103 Public method to set the maximum time entries may exist in the cache.
104
105 @param time maximum cache time in seconds
106 @type int
107 """
108 if time != self.__maxCacheTime:
109 self.__cacheTimer.stop()
110 self.__pruneCache()
111 self.__maxCacheTime = time
112 if self.__maxCacheTime > 0:
113 self.__cacheTimer.setInterval(self.__maxCacheTime * 1000)
114 self.__cacheTimer.start()
115
116 def get(self, key):
117 """
118 Public method to get an entry from the cache given its key.
119
120 If the key is present in the cache, it is moved to the MRU position.
121
122 @param key key of the item to be retrieved
123 @type any hashable type that can be used as a dict key
124 @return cached item for the given key or None, if the key is not
125 present
126 @rtype object or None
127 """
128 if key in self.__store:
129 self.__hits += 1
130 self.__moveLast(key)
131 self.__accesStore[key] = QDateTime.currentDateTimeUtc()
132 return self.__store[key]
133 else:
134 self.__misses += 1
135 return None
136
137 def add(self, key, item):
138 """
139 Public method to add an item to the cache.
140
141 If the key is already in use, the cached item is replaced by the new
142 one given and is moved to the MRU position
143
144 @param key key of the item to be retrieved
145 @type any hashable type that can be used as a dict key
146 @param item item to be cached under the given key
147 @type object
148 """
149 if key in self.__store:
150 self.__moveLast(key)
151 else:
152 self.__keyList.append(key)
153 self.__store[key] = item
154 self.__accesStore[key] = QDateTime.currentDateTimeUtc()
155
156 self.__adjustToSize()
157
158 self.__maxsize = max(self.__maxsize, len(self.__keyList))
159
160 def remove(self, key):
161 """
162 Public method to remove an item from the cache.
163
164 @param key key of the item to be retrieved
165 @type any hashable type that can be used as a dict key
166 """
167 if key in self.__store:
168 del self.__store[key]
169 del self.__accesStore[key]
170 self.__keyList.remove(key)
171
172 def clear(self):
173 """
174 Public method to clear the cache.
175 """
176 self.__keyList = []
177 self.__store = {}
178 self.__accesStore = {}
179
180 def reset(self):
181 """
182 Public method to reset the cache.
183
184 This is like clear() but sets the various counters to their initial
185 value as well.
186 """
187 self.clear()
188 self.__hits = 0
189 self.__misses = 0
190 self.__maxsize = 0
191
192 def length(self):
193 """
194 Public method to get the current length of the cache.
195
196 @return current length of the cache
197 @rtype int
198 """
199 return len(self.__keyList)
200
201 def info(self):
202 """
203 Public method to get some information about the cache.
204
205 @return dictionary containing the cache info
206 @rtype dict (with keys "hits", "misses", "maxsize", "currsize")
207 """
208 return {
209 "hits": self.__hits,
210 "misses": self.__misses,
211 "maxsize": self.__maxsize,
212 "currsize": self.length(),
213 }
214
215 def __pruneCache(self):
216 """
217 Private slot to prune outdated cache entries and restart the timer.
218 """
219 if self.__maxCacheTime > 0:
220 current = QDateTime.currentDateTimeUtc()
221
222 keysToBeDeleted = []
223 for key, lastAccessTime in self.__accesStore.items():
224 if lastAccessTime.secsTo(current) > self.__maxCacheTime:
225 keysToBeDeleted.append(key)
226 for key in keysToBeDeleted:
227 self.remove(key)
228
229 self.__cacheTimer.start()

eric ide

mercurial