diff --git a/src/amdis/GridTransferManager.hpp b/src/amdis/GridTransferManager.hpp index f9e31fd0314d20216ff38c671bcd628857bdcd88..55c95550a92f282866dbcaee4c6050fda1277ff3 100644 --- a/src/amdis/GridTransferManager.hpp +++ b/src/amdis/GridTransferManager.hpp @@ -78,7 +78,8 @@ namespace AMDiS static GridTransferInterface* gridTransferInterface(Grid const &grid) { Key key = Key(&grid); - auto& gridTransferInterfaceUniquePtr = GridTransferCache::get(key, [&](Key const&) + GridTransferCache cache; + auto& gridTransferInterfaceUniquePtr = cache.get(key, [&](Key const&) { return std::make_unique<GridTransfer<Grid>>(); }); diff --git a/src/amdis/utility/ConcurrentCache.hpp b/src/amdis/utility/ConcurrentCache.hpp index 322d0067bf5f129330a97b0371538474a4117d29..8e84f7b5fa350768f17865955fa737a3eac26458 100644 --- a/src/amdis/utility/ConcurrentCache.hpp +++ b/src/amdis/utility/ConcurrentCache.hpp @@ -11,6 +11,10 @@ namespace AMDiS { + /// Store cache in instance. + template <class Container> + struct ConsecutivePolicy; + /// Store cache thread local, requires no locking. template <class Container> struct ThreadLocalPolicy; @@ -29,9 +33,10 @@ namespace AMDiS * \tparam Key The type of key to access the data. * \tparam Data The type of the data stored in the cache. The behaviur is undefined if Data is not * the same type as Container::mapped_type. - * \tparam Policy A policy class template implementing the method `get_or_init()`. Two implementations - * are provided: \ref ThreadLocalPolicy and \ref StaticLockedPolicy. By default, if not - * Policy class template is specified, the `ThreadLocalPolicy` is used. \see ConcurrentCachePolicy + * \tparam Policy A policy class template implementing the method `get_or_init()`. Three implementations + * are provided: \ref ConsecutivePolicy, \ref ThreadLocalPolicy and \ref StaticLockedPolicy. + * By default, if no policy class template is specified, the `ThreadLocalPolicy` is used. + * \see ConcurrentCachePolicy * \tparam Container The type of the underlying associative container to use to store the data. The * container must satisfy the requirements of AssociativeContainer. The standard * containers `std::map` and `std::unordered_map` satisfie this requirement. By default, @@ -54,7 +59,7 @@ namespace AMDiS * Provide a static cache and a `get_or_init()` static method that extracts the data from the cache if it exists or * creates a new extry by using an initialization functor. * - * Realizations of this template are \ref ThreadLocalPolicy and \ref StaticLockedPolicy. + * Realizations of this template are \ref ConsecutivePolicy, \ref ThreadLocalPolicy and \ref StaticLockedPolicy. * * \tparam Container The Type of the associative container key->data to store the cached data. **/ @@ -62,7 +67,54 @@ namespace AMDiS class ConcurrentCachePolicy; #endif - // implementation of the ThreadLocal policy + // implementation of the consecutive policy. Data is stored in instance variable. + template <class Container> + struct ConsecutivePolicy + { + using key_type = typename Container::key_type; + using data_type = typename Container::mapped_type; + using container_type = Container; + + template <class F, class... Args> + data_type const& get_or_init(key_type const& key, F&& f, Args&&... args) const + { + return impl(std::is_default_constructible<data_type>{}, + key, std::forward<F>(f), std::forward<Args>(args)...); + } + + private: + // data_type is default_constructible + template <class F, class... Args> + data_type const& impl(std::true_type, key_type const& key, F&& f, Args&&... args) const + { + data_type empty; + auto it = cachedData_.emplace(key, std::move(empty)); + if (it.second) { + data_type data = f(key, std::forward<Args>(args)...); + it.first->second = std::move(data); + } + return it.first->second; + } + + // data_type is not default_constructible + template <class F, class... Args> + data_type const& impl(std::false_type, key_type const& key, F&& f, Args&&... args) const + { + auto it = cachedData_.find(key); + if (it != cachedData_.end()) + return it->second; + else { + data_type data = f(key, std::forward<Args>(args)...); + auto it = cachedData_.emplace(key, std::move(data)); + return it.first->second; + } + } + + mutable container_type cachedData_; + }; + + + // implementation of the ThreadLocal policy. Data is stored in thread_local variable. template <class Container> struct ThreadLocalPolicy { @@ -113,7 +165,7 @@ namespace AMDiS }; - // implementation of the Shared policy + // implementation of the Shared policy. Data is stored in static variable. template <class Container> struct StaticLockedPolicy { @@ -151,7 +203,7 @@ namespace AMDiS template <class Key, class Data, template <class> class Policy, class Container> class ConcurrentCache - : private Policy<Container> + : protected Policy<Container> { using key_type = Key; using data_type = Data; @@ -167,7 +219,7 @@ namespace AMDiS * \param args... Arguments passed additionally to the functor f **/ template <class F, class... Args> - static data_type const& get(key_type const& key, F&& f, Args&&... args) + data_type const& get(key_type const& key, F&& f, Args&&... args) const { static_assert(Dune::Std::is_callable<F(key_type, Args...), data_type>::value, "Functor F must have the signature data_type(key_type, Args...)");