Twitch SDK (Internal)
cache.h
Go to the documentation of this file.
1 /********************************************************************************************
2 * Twitch Broadcasting SDK
3 *
4 * This software is supplied under the terms of a license agreement with Twitch Interactive, Inc. and
5 * may not be copied or used except in accordance with the terms of that agreement
6 * Copyright (c) 2012-2016 Twitch Interactive, Inc.
7 *********************************************************************************************/
8 
9 #pragma once
10 
13 
14 #include <memory>
15 #include <unordered_map>
16 
17 namespace ttv
18 {
22  template <typename KEY_TYPE, typename VALUE_TYPE>
23  class Cache
24  {
25  public:
26  struct CacheEntry
27  {
29  : expiryTime(0)
30  , lastUsedTime(0)
31  {
32  }
33 
34  KEY_TYPE key;
35  uint64_t expiryTime;
36  uint64_t lastUsedTime;
37  VALUE_TYPE data;
38  };
39 
40  typedef std::function<void(CacheEntry& entry)> VisitorFunc;
41 
42  protected:
43  typedef std::unordered_map<KEY_TYPE, CacheEntry> MapType;
44 
45  public:
47  : mExpiryAge(1000 * 60 * 60)
48  {
49  }
50 
54  void SetExpiryAge(uint64_t age)
55  {
56  mExpiryAge = age;
57  }
58 
62  uint32_t GetSize() const
63  {
64  return static_cast<uint32_t>(mCache.size());
65  }
66 
70  void PurgeUnused(uint64_t olderThan)
71  {
72  auto now = GetSystemTimeMilliseconds();
73  if (olderThan > now)
74  {
75  olderThan = 0;
76  }
77  else
78  {
79  olderThan = now - olderThan;
80  }
81 
82  for (auto iter = mCache.begin(); iter != mCache.end();)
83  {
84  if ((*iter).second.lastUsedTime < olderThan)
85  {
86  iter = mCache.erase(iter);
87  }
88  else
89  {
90  ++iter;
91  }
92  }
93  }
94 
98  void PurgeExpired()
99  {
100  auto now = GetSystemTimeMilliseconds();
101 
102  for (auto iter = mCache.begin(); iter != mCache.end();)
103  {
104  if ((*iter).second.expiryTime <= now)
105  {
106  iter = mCache.erase(iter);
107  }
108  else
109  {
110  ++iter;
111  }
112  }
113  }
114 
118  void Clear()
119  {
120  mCache.clear();
121  }
122 
127  bool MarkEntryUsed(const KEY_TYPE& key)
128  {
129  auto iter = mCache.find(key);
130  if (iter == mCache.end())
131  {
132  return false;
133  }
134 
135  (*iter).second.lastUsedTime = GetSystemTimeMilliseconds();
136 
137  return true;
138  }
139 
144  bool MarkEntryNeverUnused(const KEY_TYPE& key)
145  {
146  auto iter = mCache.find(key);
147  if (iter == mCache.end())
148  {
149  return false;
150  }
151 
152  (*iter).second.lastUsedTime = std::numeric_limits<uint64_t>::max();
153 
154  return true;
155  }
156 
162  bool MarkEntryNeverExpires(const KEY_TYPE& key)
163  {
164  auto iter = mCache.find(key);
165  if (iter == mCache.end())
166  {
167  return false;
168  }
169 
170  (*iter).second.expiryTime = std::numeric_limits<uint64_t>::max();
171 
172  return true;
173  }
174 
179  bool SetEntryExpiryTime(const KEY_TYPE& key, uint64_t time)
180  {
181  auto iter = mCache.find(key);
182  if (iter == mCache.end())
183  {
184  return false;
185  }
186 
187  (*iter).second.expiryTime = time;
188 
189  return true;
190  }
191 
196  bool ExpireEntry(const KEY_TYPE& key)
197  {
198  return SetEntryExpiryTime(key, 0);
199  }
200 
204  void ExpireAll()
205  {
206  for (auto& kvp : mCache)
207  {
208  kvp.second.expiryTime = 0;
209  }
210  }
211 
215  void SetEntry(const KEY_TYPE& key, VALUE_TYPE data)
216  {
217  uint64_t now = GetSystemTimeMilliseconds();
218 
219  CacheEntry entry;
220 
221  typename MapType::iterator iter = mCache.find(key);
222  if (iter != mCache.end())
223  {
224  entry = (*iter).second;
225  }
226  else
227  {
228  entry.key = key;
229  entry.lastUsedTime = now;
230  }
231 
232  entry.data = data;
233 
234  // Set the expiry time, handle overflow
235  if (now <= std::numeric_limits<uint64_t>::max() - mExpiryAge)
236  {
237  entry.expiryTime = now + mExpiryAge;
238  }
239  else
240  {
241  entry.expiryTime = std::numeric_limits<uint64_t>::max();
242  }
243 
244  mCache[key] = entry;
245  }
246 
250  void RemoveEntry(const KEY_TYPE& key)
251  {
252  auto iter = mCache.find(key);
253  if (iter == mCache.end())
254  {
255  return;
256  }
257 
258  mCache.erase(iter);
259  }
260 
265  bool GetEntry(const KEY_TYPE& key, VALUE_TYPE& result)
266  {
267  auto iter = mCache.find(key);
268  if (iter != mCache.end())
269  {
270  result = (*iter).second.data;
271  }
272 
273  return iter != mCache.end();
274  }
275 
279  void GetKeys(std::vector<KEY_TYPE>& result)
280  {
281  for (auto kvp : mCache)
282  {
283  result.push_back(kvp.first);
284  }
285  }
286 
290  bool ContainsEntry(const KEY_TYPE& key) const
291  {
292  return mCache.find(key) != mCache.end();
293  }
294 
298  void ForEach(VisitorFunc func)
299  {
300  auto copy = mCache;
301 
302  for (auto& kvp : copy)
303  {
304  func(kvp.second);
305  }
306  }
307 
308  bool HasExpiredEntries() const
309  {
310  Timestamp now = static_cast<Timestamp>(GetSystemTimeMilliseconds());
311  for (const auto& kvp : mCache)
312  {
313  if (kvp.second.expiryTime <= now)
314  {
315  return true;
316  }
317  }
318 
319  return false;
320  }
321 
325  void ForEachExpired(VisitorFunc func)
326  {
327  auto now = GetSystemTimeMilliseconds();
328 
329  auto copy = mCache;
330 
331  for (auto& kvp : copy)
332  {
333  if (kvp.second.expiryTime <= now)
334  {
335  func(kvp.second);
336  }
337  }
338  }
339 
340  protected:
341  MapType mCache;
342  uint64_t mExpiryAge;
343  };
344 }
bool GetEntry(const KEY_TYPE &key, VALUE_TYPE &result)
Definition: cache.h:265
bool MarkEntryNeverUnused(const KEY_TYPE &key)
Definition: cache.h:144
CacheEntry()
Definition: cache.h:28
bool ContainsEntry(const KEY_TYPE &key) const
Definition: cache.h:290
void SetExpiryAge(uint64_t age)
Definition: cache.h:54
uint64_t mExpiryAge
The amount of time after which entries expire.
Definition: cache.h:342
uint64_t GetSystemTimeMilliseconds()
VALUE_TYPE data
The cached data.
Definition: cache.h:37
void SetEntry(const KEY_TYPE &key, VALUE_TYPE data)
Definition: cache.h:215
Definition: cache.h:23
void ForEachExpired(VisitorFunc func)
Definition: cache.h:325
KEY_TYPE key
Definition: cache.h:34
uint32_t Timestamp
Definition: coretypes.h:27
MapType mCache
The mapping of key to the data.
Definition: cache.h:341
std::function< void(CacheEntry &entry)> VisitorFunc
Definition: cache.h:40
Definition: cache.h:26
Cache()
Definition: cache.h:46
JSON (JavaScript Object Notation).
Definition: adsapi.h:16
bool SetEntryExpiryTime(const KEY_TYPE &key, uint64_t time)
Definition: cache.h:179
bool HasExpiredEntries() const
Definition: cache.h:308
void RemoveEntry(const KEY_TYPE &key)
Definition: cache.h:250
void Clear()
Definition: cache.h:118
uint64_t expiryTime
The time the data will expire.
Definition: cache.h:35
void ForEach(VisitorFunc func)
Definition: cache.h:298
std::unordered_map< KEY_TYPE, CacheEntry > MapType
Definition: cache.h:43
bool MarkEntryNeverExpires(const KEY_TYPE &key)
Definition: cache.h:162
void PurgeExpired()
Definition: cache.h:98
void PurgeUnused(uint64_t olderThan)
Definition: cache.h:70
bool MarkEntryUsed(const KEY_TYPE &key)
Definition: cache.h:127
void GetKeys(std::vector< KEY_TYPE > &result)
Definition: cache.h:279
uint64_t lastUsedTime
The last time the data was used.
Definition: cache.h:36
uint32_t GetSize() const
Definition: cache.h:62
void ExpireAll()
Definition: cache.h:204
bool ExpireEntry(const KEY_TYPE &key)
Definition: cache.h:196