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