lsst.cpputils
g87389fa792+0bb42a27e1
Toggle main menu visibility
Loading...
Searching...
No Matches
include
lsst
cpputils
Cache.h
Go to the documentation of this file.
1
/*
2
* LSST Data Management System
3
* See COPYRIGHT file at the top of the source tree.
4
*
5
* This product includes software developed by the
6
* LSST Project (http://www.lsst.org/).
7
*
8
* This program is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation, either version 3 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the LSST License Statement and
19
* the GNU General Public License along with this program. If not,
20
* see <http://www.lsstcorp.org/LegalNotices/>.
21
*/
22
#ifndef LSST_CPPUTILS_CACHE_H
23
#define LSST_CPPUTILS_CACHE_H
24
25
#include <vector>
26
#include <optional>
27
#include <utility>
// std::pair
28
29
#include "boost/multi_index_container.hpp"
30
#include "boost/multi_index/sequenced_index.hpp"
31
#include "boost/multi_index/hashed_index.hpp"
32
#include "boost/multi_index/composite_key.hpp"
33
#include "boost/multi_index/member.hpp"
34
#include "boost/format.hpp"
35
36
#include "
lsst/pex/exceptions.h
"
37
#include "
lsst/cpputils/CacheFwd.h
"
38
39
//#define LSST_CACHE_DEBUG 1 // Define this variable to instrument for debugging
40
41
42
#ifdef LSST_CACHE_DEBUG
43
#include <iostream>
44
#include <fstream>
45
#include <typeinfo>
46
#include "
lsst/cpputils/Demangle.h
"
47
#endif
48
49
namespace
lsst
{
50
namespace
cpputils
{
51
74
template
<
typename
Key,
typename
Value,
typename
KeyHash,
typename
KeyPred>
75
class
Cache
{
76
public
:
85
Cache
(
std::size_t
maxElements=0) : _maxElements(maxElements) {
86
_container.template
get<Hash>
().reserve(maxElements);
87
#ifdef LSST_CACHE_DEBUG
88
_debuggingEnabled =
false
;
89
_hits = 0;
90
_total = 0;
91
_requests.reserve(maxElements);
92
#endif
93
}
94
95
// Defaulted stuff
96
Cache
(
Cache
const
&) =
default
;
97
Cache
(
Cache
&&) =
default
;
98
Cache
&
operator=
(
Cache
const
&) =
default
;
99
Cache
&
operator=
(
Cache
&&) =
default
;
100
102
#ifdef LSST_CACHE_DEBUG
105
~Cache
();
106
#else
107
~Cache
() =
default
;
108
#endif
109
130
template
<
typename
Generator>
131
Value
operator()
(Key
const
&
key
, Generator func);
132
133
/* Lookup a value
134
*
135
* If the key is in the cache, it will be promoted to the
136
* most recently used value.
137
*
138
* @throws lsst::pex::exceptions::NotFoundError If key is not in the
139
* cache.
140
*
141
* @exceptsafe Basic exception safety: exceptions will leave the
142
* system in a valid but unpredictable state.
143
*/
144
Value
operator[]
(Key
const
&
key
);
145
154
void
add
(Key
const
&
key
, Value
const
& value);
155
161
std::size_t
size
()
const
{
return
_container.size(); }
162
168
std::vector<Key>
keys
()
const
;
169
178
bool
contains
(Key
const
&
key
) {
return
_lookup(
key
).second; }
179
188
std::optional<Value>
get
(Key
const
&
key
) {
189
auto
result = _lookup(
key
);
190
if
(result.second) {
191
return
std::optional<Value>(result.first->second);
192
}
else
{
193
return
std::optional<Value>();
194
}
195
}
196
201
std::size_t
capacity
()
const
{
return
_maxElements; }
202
208
void
reserve
(
std::size_t
maxElements) { _maxElements = maxElements; _trim(); }
209
215
void
flush
();
216
217
#ifdef LSST_CACHE_DEBUG
218
void
enableDebugging() { _debuggingEnabled =
true
; }
219
#endif
220
221
private
:
222
223
// Trim the cache to size
224
void
_trim() {
225
if
(
capacity
() == 0)
return
;
// Allowed to grow without limit
226
while
(
size
() >
capacity
()) {
227
_container.template
get<Sequence>
().pop_back();
228
}
229
}
230
231
// Element in the multi_index container
232
typedef
std::pair<Key, Value> Element;
233
234
// Tags for multi_index container
235
struct
Sequence {};
236
struct
Hash {};
237
238
// The multi_index container
239
typedef
boost::multi_index_container<
240
Element,
241
boost::multi_index::indexed_by<
242
boost::multi_index::sequenced<boost::multi_index::tag<Sequence>>,
243
boost::multi_index::hashed_unique<
244
boost::multi_index::tag<Hash>,
245
boost::multi_index::member<Element, Key, &Element::first>,
246
KeyHash>>> Container;
247
248
// Lookup key in the container
249
//
250
// Returns the iterator and whether there's anything there.
251
//
252
// If the key exists, updates the cache to make that key the most recent.
253
std::pair<typename Container::template index<Hash>::type::iterator,
bool
> _lookup(Key
const
& key) {
254
auto
const
& hashContainer = _container.template
get<Hash>
();
255
auto
it = hashContainer.find(key);
256
bool
found = (it != hashContainer.end());
257
if
(found) {
258
_container.relocate(_container.template
get<Sequence>
().begin(),
259
_container.template project<Sequence>(it));
260
}
261
#ifdef LSST_CACHE_DEBUG
262
if
(_debuggingEnabled) {
263
_requests.push_back(key);
264
++_total;
265
if
(found) ++_hits;
266
}
267
#endif
268
return
std::make_pair
(it, found);
269
}
270
271
// Add a key-value pair that are not already present
272
void
_addNew(Key
const
& key, Value
const
& value) {
273
_container.template
get<Sequence>
().emplace_front(key, value);
274
_trim();
275
}
276
277
std::size_t _maxElements;
// Maximum number of elements; 0 means infinite
278
Container _container;
// Container of key,value pairs
279
#ifdef LSST_CACHE_DEBUG
280
bool
_debuggingEnabled;
281
mutable
std::size_t _hits, _total;
// Statistics of cache hits
282
mutable
std::vector<Key> _requests;
// Cache requests
283
static
std::size_t getId() {
284
static
std::size_t _id = 0;
// Identifier
285
return
_id++;
286
}
287
#endif
288
};
289
290
// Definitions
291
292
template
<
typename
Key,
typename
Value,
typename
KeyHash,
typename
KeyPred>
293
template
<
typename
Generator>
294
Value
Cache<Key, Value, KeyHash, KeyPred>::operator()
(
295
Key
const
&
key
,
296
Generator func
297
) {
298
auto
result = _lookup(
key
);
299
if
(result.second) {
300
return
result.first->second;
301
}
302
Value value = func(
key
);
303
_addNew(
key
, value);
304
return
value;
305
}
306
307
template
<
typename
Key,
typename
Value,
typename
KeyHash,
typename
KeyPred>
308
Value
Cache<Key, Value, KeyHash, KeyPred>::operator[]
(Key
const
&
key
) {
309
auto
result = _lookup(
key
);
310
if
(result.second) {
311
return
result.first->second;
312
}
313
throw
LSST_EXCEPT
(
pex::exceptions::NotFoundError
,
314
(boost::format(
"Unable to find key: %s"
) %
key
).str());
315
}
316
317
template
<
typename
Key,
typename
Value,
typename
KeyHash,
typename
KeyPred>
318
void
Cache<Key, Value, KeyHash, KeyPred>::add
(Key
const
&
key
, Value
const
& value) {
319
auto
result = _lookup(
key
);
320
if
(!result.second) {
321
_addNew(
key
, value);
322
}
323
}
324
325
template
<
typename
Key,
typename
Value,
typename
KeyHash,
typename
KeyPred>
326
std::vector<Key>
Cache<Key, Value, KeyHash, KeyPred>::keys
()
const
{
327
std::vector<Key>
result;
328
result.
reserve
(
size
());
329
for
(
auto
& keyValue : _container.template
get<Sequence>
()) {
330
result.
push_back
(keyValue.first);
331
}
332
return
result;
333
}
334
335
template
<
typename
Key,
typename
Value,
typename
KeyHash,
typename
KeyPred>
336
void
Cache<Key, Value, KeyHash, KeyPred>::flush
() {
337
while
(
size
() > 0) {
338
_container.template
get<Sequence>
().pop_back();
339
}
340
}
341
342
#ifdef LSST_CACHE_DEBUG
343
template
<
typename
Key,
typename
Value,
typename
KeyHash,
typename
KeyPred>
344
Cache<Key, Value, KeyHash, KeyPred>::~Cache
() {
345
if
(!_debuggingEnabled) {
346
return
;
347
}
348
std::string
filename = (boost::format(
"lsst-cache-%s-%d.dat"
) %
349
demangleType
(
typeid
(*this).name()) % getId()).str();
350
std::ofstream
file(filename);
351
for
(
auto
const
& key : _requests) {
352
file << key <<
"\n"
;
353
}
354
file.close();
355
std::cerr
<<
"Wrote cache requests to "
<< filename <<
": "
<< _hits <<
"/"
<< _total <<
" hits"
;
356
std::cerr
<<
std::endl
;
357
}
358
#endif
359
360
}
361
}
// namespace lsst::cpputils
362
363
364
#endif
// ifndef LSST_CPPUTILS_CACHE_H
CacheFwd.h
Demangle.h
LSST_EXCEPT
#define LSST_EXCEPT(type,...)
std::ofstream
std::cerr
std::string
lsst::cpputils::Cache::keys
std::vector< Key > keys() const
Return all keys in the cache, most recent first.
Definition
Cache.h:326
lsst::cpputils::Cache::size
std::size_t size() const
Return the number of values in the cache.
Definition
Cache.h:161
lsst::cpputils::Cache::operator()
Value operator()(Key const &key, Generator func)
Lookup or generate a value.
Definition
Cache.h:294
lsst::cpputils::Cache::contains
bool contains(Key const &key)
Does the cache contain the key?
Definition
Cache.h:178
lsst::cpputils::Cache::Cache
Cache(Cache &&)=default
lsst::cpputils::Cache::Cache
Cache(Cache const &)=default
lsst::cpputils::Cache::capacity
std::size_t capacity() const
Return the capacity of the cache.
Definition
Cache.h:201
lsst::cpputils::Cache::flush
void flush()
Empty the cache.
Definition
Cache.h:336
lsst::cpputils::Cache::add
void add(Key const &key, Value const &value)
Add a value to the cache.
Definition
Cache.h:318
lsst::cpputils::Cache::Cache
Cache(std::size_t maxElements=0)
Ctor.
Definition
Cache.h:85
lsst::cpputils::Cache::~Cache
~Cache()=default
Dtor.
lsst::cpputils::Cache::operator=
Cache & operator=(Cache &&)=default
lsst::cpputils::Cache::operator[]
Value operator[](Key const &key)
Definition
Cache.h:308
lsst::cpputils::Cache::get
std::optional< Value > get(Key const &key)
Return the cached value if it exists.
Definition
Cache.h:188
lsst::cpputils::Cache::reserve
void reserve(std::size_t maxElements)
Change the capacity of the cache.
Definition
Cache.h:208
lsst::cpputils::Cache::operator=
Cache & operator=(Cache const &)=default
lsst::pex::exceptions::NotFoundError
std::endl
T endl(T... args)
exceptions.h
std::make_pair
T make_pair(T... args)
lsst::cpputils
Definition
main.dox:1
lsst::cpputils::demangleType
std::string demangleType(std::string const _typeName)
Definition
Demangle.cc:113
lsst
std::vector::push_back
T push_back(T... args)
std::vector::reserve
T reserve(T... args)
std::size_t
lsst::cpputils::key
Definition
Demangle.cc:63
std::vector
Generated on
for lsst.cpputils by
1.17.0