ClickHouse/base/common/SimpleCache.h

83 lines
1.8 KiB
C++
Raw Normal View History

#pragma once
#include <map>
#include <tuple>
#include <mutex>
2017-06-06 17:18:32 +00:00
#include <ext/function_traits.h>
2017-05-07 20:25:26 +00:00
/** The simplest cache for a free function.
* You can also pass a static class method or lambda without captures.
* The size is unlimited. Values are stored permanently and never evicted.
* But single record or all cache can be manually dropped.
* Mutex is used for synchronization.
2017-05-07 20:25:26 +00:00
* Suitable only for the simplest cases.
*
2017-05-07 20:25:26 +00:00
* Usage
*
* SimpleCache<decltype(func), &func> func_cached;
* std::cerr << func_cached(args...);
*/
template <typename F, F* f>
class SimpleCache
{
private:
using Key = typename function_traits<F>::arguments_decay;
using Result = typename function_traits<F>::result;
std::map<Key, Result> cache;
mutable std::mutex mutex;
public:
template <typename... Args>
Result operator() (Args &&... args)
{
Key key{std::forward<Args>(args)...};
{
2019-01-02 06:44:36 +00:00
std::lock_guard lock(mutex);
auto it = cache.find(key);
if (cache.end() != it)
return it->second;
}
2017-05-07 20:25:26 +00:00
/// The calculations themselves are not done under mutex.
Result res = std::apply(f, key);
{
2019-01-02 06:44:36 +00:00
std::lock_guard lock(mutex);
cache.emplace(std::forward_as_tuple(args...), res);
}
return res;
}
template <typename... Args>
void update(Args &&... args)
{
Key key{std::forward<Args>(args)...};
Result res = std::apply(f, key);
{
std::lock_guard lock(mutex);
cache[key] = std::move(res);
}
}
size_t size() const
{
std::lock_guard lock(mutex);
return cache.size();
}
void drop()
{
2019-01-02 06:44:36 +00:00
std::lock_guard lock(mutex);
cache.clear();
}
};