diff --git a/src/amdis/common/TupleUtility.hpp b/src/amdis/common/TupleUtility.hpp
index 0a6f1c03b475fef208d86ded0960f5c212d24fd0..8b10ec3fc8720e94760cc1d409dcaa536c52b9f5 100644
--- a/src/amdis/common/TupleUtility.hpp
+++ b/src/amdis/common/TupleUtility.hpp
@@ -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>
diff --git a/src/amdis/utility/ConcurrentCache.hpp b/src/amdis/utility/ConcurrentCache.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..884a1360c09fe7c5f876dd8037055fdd397538f1
--- /dev/null
+++ b/src/amdis/utility/ConcurrentCache.hpp
@@ -0,0 +1,86 @@
+#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