diff --git a/include/cachemere/cache.h b/include/cachemere/cache.h index 3023820..0f7817e 100644 --- a/include/cachemere/cache.h +++ b/include/cachemere/cache.h @@ -18,7 +18,6 @@ #include #include #include -#include #ifdef _WIN32 # pragma warning(pop) @@ -95,7 +94,7 @@ class Cache /// If the provided container has `size()` and `reserve()` methods, `collect_into` will reserve /// the appropriate amount of space in the container before inserting. /// @param container The container in which to insert the items. - template void collect_into(C& container) const; + template C> void collect_into(C& container) const; /// @brief Insert a key/value pair in the cache. /// @details If the key is new, the key/value pair will be inserted. @@ -340,28 +339,26 @@ template -template +template Container> void Cache::collect_into(Container& container) const { using namespace detail; - // Use emplace_back if container is a sequence container, or emplace if container is an associative container. - constexpr auto emplace_fn = boost::hana::if_( - traits::stl::has_emplace_back, - [](auto& seq_container, const auto& key, const auto& item) { seq_container.emplace_back(key, item.m_value); }, - [](auto& assoc_container, const auto& key, const auto& item) { assoc_container.emplace(key, item.m_value); }); - LockGuard guard(lock()); // Reserve space if the container has a reserve() method and a size method(). - boost::hana::if_( - boost::hana::and_(traits::stl::has_reserve, traits::stl::has_size), - [&](auto& c) { c.reserve(c.size() + m_data.size()); }, - [](auto&) {})(container); + if constexpr (traits::ReservableContainer) { + container.reserve(container.size() + m_data.size()); + } // Copy the cache contents to the container. for (const auto& [key, cached_item] : m_data) { - emplace_fn(container, key, cached_item); + // Use emplace_back if container is a sequence container, or emplace if container is an associative container. + if constexpr (traits::SequenceContainer) { + container.emplace_back(key, cached_item.m_value); + } else { + container.emplace(key, cached_item.m_value); + } } } @@ -518,8 +515,8 @@ void Cache::swap(CacheType& other) noexcept swap(m_hit_rate_acc, other.m_hit_rate_acc); swap(m_byte_hit_rate_acc, other.m_byte_hit_rate_acc); } catch (const std::system_error& e) { - // The only exception that can sensibly be thrown in the above block is a `system_error` when acquiring the mutexes of both caches (if the caches are - // running in thread-safe mode). + // The only exception that can sensibly be thrown in the above block is a `system_error` when acquiring the mutexes of both caches (if the caches + // are running in thread-safe mode). // // According to the [reference for std mutexes](https://en.cppreference.com/w/cpp/named_req/Mutex), this exception can be thrown for one of two // reasons: @@ -949,14 +946,14 @@ template void Cache::remove_popped_victim(DataMapIt it) { - boost::hana::if_( - detail::traits::event::has_on_evict, - [&](auto& x) { return x.on_evict(it->first, it->second); }, - [](auto&) {})(*m_insertion_policy); - boost::hana::if_( - detail::traits::event::has_on_evict, - [&](auto& x) { return x.on_evict(it->first, it->second); }, - [](auto&) {})(*m_constraint_policy); + if constexpr (detail::traits::event::HasOnEvict) { + m_eviction_policy->on_evict(it->first, it->second); + } + + if constexpr (detail::traits::event::HasOnEvict) { + m_constraint_policy->on_evict(it->first, it->second); + } + m_data.erase(it); } @@ -972,11 +969,17 @@ template::on_insert(const K& key, const CacheItem& item) const { // Call event handler iif the method is defined in the policy. - boost::hana::if_(detail::traits::event::has_on_insert, [&](auto& x) { return x.on_insert(key, item); }, [](auto&) {})(*m_insertion_policy); + if constexpr (detail::traits::event::HasOnInsert) { + m_insertion_policy->on_insert(key, item); + } - boost::hana::if_(detail::traits::event::has_on_insert, [&](auto& x) { return x.on_insert(key, item); }, [](auto&) {})(*m_eviction_policy); + if constexpr (detail::traits::event::HasOnInsert) { + m_eviction_policy->on_insert(key, item); + } - boost::hana::if_(detail::traits::event::has_on_insert, [&](auto& x) { return x.on_insert(key, item); }, [](auto&) {})(*m_constraint_policy); + if constexpr (detail::traits::event::HasOnInsert) { + m_constraint_policy->on_insert(key, item); + } } template::on_update(const K& key, const CacheItem& old_item, const CacheItem& new_item) const { // Call event handler iif the method is defined in the policy. - boost::hana::if_( - detail::traits::event::has_on_update, - [&](auto& x) { return x.on_update(key, old_item, new_item); }, - [](auto&) {})(*m_insertion_policy); - - boost::hana::if_( - detail::traits::event::has_on_update, - [&](auto& x) { return x.on_update(key, old_item, new_item); }, - [](auto&) {})(*m_eviction_policy); - - boost::hana::if_( - detail::traits::event::has_on_update, - [&](auto& x) { return x.on_update(key, old_item, new_item); }, - [](auto&) {})(*m_constraint_policy); + if constexpr (detail::traits::event::HasOnUpdate) { + m_insertion_policy->on_update(key, old_item, new_item); + } + + if constexpr (detail::traits::event::HasOnUpdate) { + m_eviction_policy->on_update(key, old_item, new_item); + } + + if constexpr (detail::traits::event::HasOnUpdate) { + m_constraint_policy->on_update(key, old_item, new_item); + } } template::on_cache_hit(const K& key, const Cach m_byte_hit_rate_acc(static_cast(item.m_value_size)); // Call event handler iif the method is defined in the policy. - boost::hana::if_( - detail::traits::event::has_on_cachehit, - [&](auto& x) { return x.on_cache_hit(key, item); }, - [](auto&) {})(*m_insertion_policy); + if constexpr (detail::traits::event::HasOnCacheHit) { + m_insertion_policy->on_cache_hit(key, item); + } - boost::hana::if_(detail::traits::event::has_on_cachehit, [&](auto& x) { return x.on_cache_hit(key, item); }, [](auto&) {})(*m_eviction_policy); + if constexpr (detail::traits::event::HasOnCacheHit) { + m_eviction_policy->on_cache_hit(key, item); + } - boost::hana::if_( - detail::traits::event::has_on_cachehit, - [&](auto& x) { return x.on_cache_hit(key, item); }, - [](auto&) {})(*m_constraint_policy); + if constexpr (detail::traits::event::HasOnCacheHit) { + m_constraint_policy->on_cache_hit(key, item); + } } template::on_cache_miss(const KeyView& key) con m_byte_hit_rate_acc(0); // Call event handler iif the method is defined in the policy. - boost::hana::if_(detail::traits::event::has_on_cachemiss, [&](auto& x) { return x.on_cache_miss(key); }, [](auto&) {})(*m_insertion_policy); + if constexpr (detail::traits::event::HasOnCacheMiss) { + m_insertion_policy->on_cache_miss(key); + } - boost::hana::if_(detail::traits::event::has_on_cachemiss, [&](auto& x) { return x.on_cache_miss(key); }, [](auto&) {})(*m_eviction_policy); + if constexpr (detail::traits::event::HasOnCacheMiss) { + m_eviction_policy->on_cache_miss(key); + } - boost::hana::if_(detail::traits::event::has_on_cachemiss, [&](auto& x) { return x.on_cache_miss(key); }, [](auto&) {})(*m_constraint_policy); + if constexpr (detail::traits::event::HasOnCacheMiss) { + m_constraint_policy->on_cache_miss(key); + } } template::on_evict(const K& key, const CacheItem& item) const { // Call event handler iif the method is defined in the policy. - boost::hana::if_(detail::traits::event::has_on_evict, [&](auto& x) { return x.on_evict(key, item); }, [](auto&) {})(*m_insertion_policy); + if constexpr (detail::traits::event::HasOnEvict) { + m_insertion_policy->on_evict(key, item); + } - boost::hana::if_(detail::traits::event::has_on_evict, [&](auto& x) { return x.on_evict(key, item); }, [](auto&) {})(*m_eviction_policy); + if constexpr (detail::traits::event::HasOnEvict) { + m_eviction_policy->on_evict(key, item); + } - boost::hana::if_(detail::traits::event::has_on_evict, [&](auto& x) { return x.on_evict(key, item); }, [](auto&) {})(*m_constraint_policy); + if constexpr (detail::traits::event::HasOnEvict) { + m_constraint_policy->on_evict(key, item); + } } template +#include +#include #include namespace cachemere::detail::traits { -// Traits for STL types. -namespace stl { - -template -constexpr auto has_reserve = - boost::hana::is_valid([](auto& t) -> decltype(boost::hana::traits::declval(t).reserve(std::declval())) {})(boost::hana::type_c); +template +concept SequenceContainer = requires(T t, Args... args) { + { t.emplace_back(args...) }; +}; -template -constexpr auto has_size = boost::hana::is_valid([](auto& t) -> decltype(boost::hana::traits::declval(t).size()) {})(boost::hana::type_c); +template +concept AssociativeContainer = requires(T t, Args... args) { + { t.emplace(args...) }; +}; template -constexpr auto has_emplace_back = - boost::hana::is_valid([](auto& t) -> decltype(boost::hana::traits::declval(t).emplace_back(std::declval()...)) {})(boost::hana::type_c); +concept CacheContainer = SequenceContainer || AssociativeContainer; -} // namespace stl +template +concept ReservableContainer = requires(T t) { + { t.reserve(std::declval()) }; + { t.size() } -> std::convertible_to; +}; // Traits for cache event handlers. namespace event { template typename P> -constexpr auto has_on_insert = boost::hana::is_valid( - [](auto& policy_t, auto& key_t, auto& item_t) -> decltype(boost::hana::traits::declval(policy_t).on_insert(boost::hana::traits::declval(key_t), - boost::hana::traits::declval(item_t))) { - })(boost::hana::type_c>, boost::hana::type_c, boost::hana::type_c>); +concept HasOnInsert = requires(P policy, K key, Item item) { + { policy.on_insert(key, item) }; +}; template typename P> -constexpr auto has_on_update = boost::hana::is_valid( - [](auto& policy_t, auto& key_t, auto& item_t) -> decltype(boost::hana::traits::declval(policy_t).on_update(boost::hana::traits::declval(key_t), - boost::hana::traits::declval(item_t), - boost::hana::traits::declval(item_t))) { - })(boost::hana::type_c>, boost::hana::type_c, boost::hana::type_c>); +concept HasOnUpdate = requires(P policy, K key, Item old_item, Item new_item) { + { policy.on_update(key, old_item, new_item) }; +}; template typename P> -constexpr auto has_on_cachehit = boost::hana::is_valid( - [](auto& policy_t, auto& key_t, auto& item_t) -> decltype(boost::hana::traits::declval(policy_t).on_cache_hit(boost::hana::traits::declval(key_t), - boost::hana::traits::declval(item_t))) { - })(boost::hana::type_c>, boost::hana::type_c, boost::hana::type_c>); +concept HasOnCacheHit = requires(P policy, K key, Item item) { + { policy.on_cache_hit(key, item) }; +}; template typename P> -constexpr auto has_on_cachemiss = boost::hana::is_valid( - [](auto& policy_t, auto& item_t) -> decltype(boost::hana::traits::declval(policy_t).on_cache_miss(boost::hana::traits::declval(item_t))) { - })(boost::hana::type_c>, boost::hana::type_c); +concept HasOnCacheMiss = requires(P policy, K key) { + { policy.on_cache_miss(key) }; +}; template typename P> -constexpr auto has_on_evict = boost::hana::is_valid( - [](auto& policy_t, auto& key_t, auto& value_t) -> decltype(boost::hana::traits::declval(policy_t).on_evict(boost::hana::traits::declval(key_t), - boost::hana::traits::declval(value_t))) { - })(boost::hana::type_c>, boost::hana::type_c, boost::hana::type_c>); +concept HasOnEvict = requires(P policy, K key, Item item) { + { policy.on_evict(key, item) }; +}; } // namespace event diff --git a/vcpkg.json b/vcpkg.json index 00d24e1..bf47f65 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,53 +1,39 @@ { - "name": "cachemere", - "version-semver": "0.3.0", - "dependencies": [ - { - "name": "abseil", - "version>=": "20220623.1", - "features": [ - "cxx17" - ] + "name": "cachemere", + "version-semver": "0.3.0", + "dependencies": [ + { + "name": "abseil", + "version>=": "20220623.1", + "features": ["cxx17"] + }, + { + "name": "vcpkg-cmake", + "version>=": "2021-02-28", + "host": true, + "$comment": "This transitive dependency needs to be specified explicitly." + }, + { + "name": "vcpkg-cmake-config", + "version>=": "2021-02-26", + "host": true, + "$comment": "This transitive dependency needs to be specified explicitly." + } + ], + "default-features": ["boost"], + "features": { + "boost": { + "description": "Use boost from vcpkg", + "dependencies": ["boost-accumulators", "boost-dynamic-bitset"] + }, + "tests": { + "description": "The unit tests", + "dependencies": ["gtest"] + }, + "benchmarks": { + "description": "The accuracy and performance benchmarks", + "dependencies": ["benchmark", "gtest", "tbb"] + } }, - { - "name": "vcpkg-cmake", - "version>=": "2021-02-28", - "host": true, - "$comment": "This transitive dependency needs to be specified explicitly." - }, - { - "name": "vcpkg-cmake-config", - "version>=": "2021-02-26", - "host": true, - "$comment": "This transitive dependency needs to be specified explicitly." - } - ], - "default-features": [ - "boost" - ], - "features": { - "boost": { - "description": "Use boost from vcpkg", - "dependencies": [ - "boost-accumulators", - "boost-dynamic-bitset", - "boost-hana" - ] - }, - "tests": { - "description": "The unit tests", - "dependencies": [ - "gtest" - ] - }, - "benchmarks": { - "description": "The accuracy and performance benchmarks", - "dependencies": [ - "benchmark", - "gtest", - "tbb" - ] - } - }, - "builtin-baseline": "3304e4ed22ae8e2a586ec4399c7d933f09475331" + "builtin-baseline": "3304e4ed22ae8e2a586ec4399c7d933f09475331" }