Skip to content
Snippets Groups Projects
Commit 18c95e67 authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

cache with concurrent access policies added

parent a6593546
No related branches found
No related tags found
No related merge requests found
......@@ -3,12 +3,38 @@
#include <tuple>
#include <type_traits>
#include <dune/common/hash.hh>
#include <amdis/common/IndexSeq.hpp>
#include <amdis/common/Mpl.hpp>
#include <amdis/common/Utility.hpp>
namespace AMDiS
{
namespace Impl
{
// Recursive template code derived from Matthieu M.
template <class Tuple, std::size_t I = std::tuple_size<Tuple>::value - 1>
struct HashTupleImpl
{
static void apply(size_t& seed, Tuple const& tuple)
{
HashTupleImpl<Tuple, I-1>::apply(seed, tuple);
Dune::hash_combine(seed, std::get<I>(tuple));
}
};
template <class Tuple>
struct HashTupleImpl<Tuple, 0>
{
static void apply(std::size_t& seed, Tuple const& tuple)
{
Dune::hash_combine(seed, std::get<0>(tuple));
}
};
} // end namespace Impl
namespace Impl
{
template <class Tuple, std::size_t N>
......
#pragma once
#include <mutex>
#include <thread>
#include <tuple>
#include <unordered_map>
#include <amdis/common/Concepts.hpp>
namespace AMDiS
{
namespace tag
{
struct thread_local_policy {};
struct shared_policy {};
}
template <class Key,
class Data,
class Policy = tag::thread_local_policy>
class ConcurrentCache
{
using key_type = Key;
using data_type = Data;
public:
/// Return the data associated to the key. If not yet initialized, call functor f
template <class F,
REQUIRES(Concepts::Callable<F,data_type*,key_type>)>
static data_type const& get(key_type key, F&& f)
{
return instance(Policy{}).get_or_init(key, std::forward<F>(f));
}
private:
auto& guarded_get(key_type const& key, tag::shared_policy)
{
std::lock_guard<std::mutex> lock(access_mutex);
return cached_data[key];
}
auto& guarded_get(key_type const& key, tag::thread_local_policy)
{
return cached_data[key];
}
template <class F>
data_type const& get_or_init(key_type const& key, F&& f)
{
auto& data = guarded_get(key, Policy{});
std::call_once(data.first, std::forward<F>(f), &data.second, key);
return data.second;
}
private:
// Return an instance of this class with static storage
static ConcurrentCache& instance(tag::shared_policy)
{
static ConcurrentCache cache;
return cache;
}
// Return an instance of this class with thread_local storage
static ConcurrentCache& instance(tag::thread_local_policy)
{
thread_local ConcurrentCache cache;
return cache;
}
// private constructor
ConcurrentCache() = default;
// mutex used to access the data in the container, necessary since
// access by operator[] is read+write access, i.e. an empty data element
// is created if it does not exist yet.
std::mutex access_mutex;
// Container to store the cached values
std::unordered_map<key_type, std::pair<std::once_flag, data_type>> cached_data;
};
} // end namespace AMDiS
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment