mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
83 lines
1.8 KiB
C++
83 lines
1.8 KiB
C++
#pragma once
|
|
|
|
#include <map>
|
|
#include <tuple>
|
|
#include <mutex>
|
|
#include <ext/function_traits.h>
|
|
|
|
|
|
/** 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.
|
|
* Suitable only for the simplest cases.
|
|
*
|
|
* 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)...};
|
|
|
|
{
|
|
std::lock_guard lock(mutex);
|
|
|
|
auto it = cache.find(key);
|
|
|
|
if (cache.end() != it)
|
|
return it->second;
|
|
}
|
|
|
|
/// The calculations themselves are not done under mutex.
|
|
Result res = std::apply(f, key);
|
|
|
|
{
|
|
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()
|
|
{
|
|
std::lock_guard lock(mutex);
|
|
cache.clear();
|
|
}
|
|
};
|