From af13de7f211903586da97ee21e2c9be52ac2b58c Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 31 Dec 2024 13:35:35 +0100 Subject: Core/Misc: Add concepts restrictions on container utilities for better compiler error messages (cherry picked from commit 380dac62fdf88ab11de5547398e4bd9f0855b081) --- src/common/Containers/Utilities/MapUtils.h | 13 ++++-- src/common/Utilities/Containers.h | 73 ++++++++++++++++-------------- 2 files changed, 49 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/common/Containers/Utilities/MapUtils.h b/src/common/Containers/Utilities/MapUtils.h index 910f16022a6..88f25c1d28a 100644 --- a/src/common/Containers/Utilities/MapUtils.h +++ b/src/common/Containers/Utilities/MapUtils.h @@ -23,10 +23,17 @@ namespace Trinity::Containers { +template +concept Map = requires (M) +{ + typename M::key_type; + typename M::mapped_type; +}; + /** * Returns a pointer to mapped value (or the value itself if map stores pointers) */ -template +template inline auto MapGetValuePtr(M& map, typename M::key_type const& key) { using mapped_type = typename M::mapped_type; @@ -46,8 +53,8 @@ inline auto MapGetValuePtr(M& map, typename M::key_type const& key) return itr != map.end() ? std::addressof(itr->second) : nullptr; // value } -template class M, class... Rest> -void MultimapErasePair(M& multimap, K const& key, V const& value) +template +void MultimapErasePair(M& multimap, typename M::key_type const& key, typename M::mapped_type const& value) { auto range = multimap.equal_range(key); for (auto itr = range.first; itr != range.second;) diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h index c53dde9d770..563d86449cc 100644 --- a/src/common/Utilities/Containers.h +++ b/src/common/Utilities/Containers.h @@ -18,6 +18,7 @@ #ifndef TRINITY_CONTAINERS_H #define TRINITY_CONTAINERS_H +#include "Concepts.h" #include "Define.h" #include "MapUtils.h" #include "Random.h" @@ -63,14 +64,15 @@ namespace Trinity { // resizes to have at most elements // if it has more than elements, the elements to keep are selected randomly - template + template void RandomResize(C& container, std::size_t requestedSize) { - static_assert(std::is_base_of::iterator_category>::value, "Invalid container passed to Trinity::Containers::RandomResize"); - if (std::size(container) <= requestedSize) + uint32 elementsToProcess = uint32(std::ranges::size(container)); + if (elementsToProcess <= requestedSize) return; - auto keepIt = std::begin(container), curIt = std::begin(container); - uint32 elementsToKeep = requestedSize, elementsToProcess = std::size(container); + + auto keepIt = std::ranges::begin(container), curIt = std::ranges::begin(container); + uint32 elementsToKeep = uint32(requestedSize); while (elementsToProcess) { // this element has chance (elementsToKeep / elementsToProcess) of being kept @@ -84,15 +86,15 @@ namespace Trinity ++curIt; --elementsToProcess; } - container.erase(keepIt, std::end(container)); + container.erase(keepIt, std::ranges::end(container)); } - template + template > Predicate> void RandomResize(C& container, Predicate&& predicate, std::size_t requestedSize) { //! First use predicate filter C containerCopy; - std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate); + std::ranges::copy_if(container, std::inserter(containerCopy, std::ranges::end(containerCopy)), std::forward(predicate)); if (requestedSize) RandomResize(containerCopy, requestedSize); @@ -105,11 +107,11 @@ namespace Trinity * * Note: container cannot be empty */ - template - inline auto SelectRandomContainerElement(C const& container) -> typename std::add_const::type& + template + inline auto SelectRandomContainerElement(C const& container) -> std::add_const_t& { - auto it = std::begin(container); - std::advance(it, urand(0, uint32(std::size(container)) - 1)); + auto it = std::ranges::begin(container); + std::ranges::advance(it, urand(0, uint32(std::ranges::size(container)) - 1)); return *it; } @@ -122,11 +124,11 @@ namespace Trinity * * Note: container cannot be empty */ - template - inline auto SelectRandomWeightedContainerElement(C const& container, std::span const& weights) -> decltype(std::begin(container)) + template + inline auto SelectRandomWeightedContainerElement(C const& container, std::span const& weights) -> decltype(std::ranges::begin(container)) { - auto it = std::begin(container); - std::advance(it, urandweighted(weights.size(), weights.data())); + auto it = std::ranges::begin(container); + std::ranges::advance(it, urandweighted(weights.size(), weights.data())); return it; } @@ -138,10 +140,10 @@ namespace Trinity * * Note: container cannot be empty */ - template - inline auto SelectRandomWeightedContainerElement(C const& container, Fn weightExtractor) -> decltype(std::begin(container)) + template > Fn> + inline auto SelectRandomWeightedContainerElement(C const& container, Fn weightExtractor) -> decltype(std::ranges::begin(container)) { - std::size_t size = std::size(container); + std::size_t size = std::ranges::size(container); std::size_t i = 0; double* weights = new double[size]; double weightSum = 0.0; @@ -152,8 +154,8 @@ namespace Trinity weightSum += weight; } - auto it = std::begin(container); - std::advance(it, weightSum > 0.0 ? urandweighted(size, weights) : urand(0, uint32(std::size(container)) - 1)); + auto it = std::ranges::begin(container); + std::ranges::advance(it, weightSum > 0.0 ? urandweighted(size, weights) : urand(0, uint32(std::ranges::size(container)) - 1)); delete[] weights; return it; } @@ -166,10 +168,10 @@ namespace Trinity * @param begin Beginning of the range to reorder * @param end End of the range to reorder */ - template + template inline void RandomShuffle(Iterator begin, Iterator end) { - std::shuffle(begin, end, RandomEngine::Instance()); + std::ranges::shuffle(begin, end, RandomEngine::Instance()); } /** @@ -179,10 +181,10 @@ namespace Trinity * * @param container Container to reorder */ - template + template inline void RandomShuffle(C& container) { - RandomShuffle(std::begin(container), std::end(container)); + RandomShuffle(std::ranges::begin(container), std::ranges::end(container)); } /** @@ -197,8 +199,9 @@ namespace Trinity * * @return true if containers have a common element, false otherwise. */ - template - inline bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + template Sentinel1, + std::input_iterator Iterator2, std::sentinel_for Sentinel2> + inline constexpr bool Intersects(Iterator1 first1, Sentinel1 last1, Iterator2 first2, Sentinel2 last2) { while (first1 != last1 && first2 != last2) { @@ -226,8 +229,10 @@ namespace Trinity * * @return true if containers have a common element, false otherwise. */ - template - inline bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, Predicate&& equalPred) + template Sentinel1, + std::input_iterator Iterator2, std::sentinel_for Sentinel2, + invocable_r, std::iter_reference_t> Predicate> + inline constexpr bool Intersects(Iterator1 first1, Sentinel1 last1, Iterator2 first2, Sentinel2 last2, Predicate&& equalPred) { while (first1 != last1 && first2 != last2) { @@ -235,7 +240,7 @@ namespace Trinity ++first1; else if (*first2 < *first1) ++first2; - else if (!equalPred(*first1, *first2)) + else if (!std::invoke(std::forward(equalPred), *first1, *first2)) ++first1, ++first2; else return true; @@ -275,8 +280,8 @@ namespace Trinity } } - template - void EraseIf(Container& c, Predicate p) + template > Predicate> + inline void EraseIf(Container& c, Predicate p) requires requires { c.erase(c.begin(), c.end()); } { if constexpr (std::is_move_assignable_v) Impl::EraseIfMoveAssignable(c, std::ref(p)); @@ -291,7 +296,7 @@ namespace Trinity * This exists as separate overload instead of one function with default argument to allow using * with vectors of non-default-constructible classes */ - template + template inline decltype(auto) EnsureWritableVectorIndex(std::vector& vec, typename std::vector::size_type i) { if (i >= vec.size()) @@ -306,7 +311,7 @@ namespace Trinity * * This overload allows specifying what value to pad vector with during .resize */ - template + template inline decltype(auto) EnsureWritableVectorIndex(std::vector& vec, typename std::vector::size_type i, T const& resizeDefault) { if (i >= vec.size()) -- cgit v1.2.3