diff --git a/.github/workflows/cmake_eastl.yml b/.github/workflows/cmake_eastl.yml index f601ab5..4ce8f81 100644 --- a/.github/workflows/cmake_eastl.yml +++ b/.github/workflows/cmake_eastl.yml @@ -31,6 +31,10 @@ jobs: repository: electronicarts/EASTL path: eastl submodules: true + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.31.x' - name: Configure CMake EASTL working-directory: ${{github.workspace}}/eastl run: cmake -B ${{github.workspace}}/eastl/build -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}} -DCMAKE_CXX_STANDARD=${{matrix.cppstd}} -D CMAKE_C_COMPILER=${{matrix.compiler.c}} -D CMAKE_CXX_COMPILER=${{matrix.compiler.cpp}} diff --git a/includes/rah2/algo_sort.hpp b/includes/rah2/algo_sort.hpp index 23828ab..855580e 100644 --- a/includes/rah2/algo_sort.hpp +++ b/includes/rah2/algo_sort.hpp @@ -29,20 +29,21 @@ namespace RAH2_NS typename Sentinel, RAH2_STD::enable_if_t< forward_iterator && sentinel_for>* = nullptr> - ForwardIterator operator()(ForwardIterator first, Sentinel last) const + constexpr ForwardIterator operator()(ForwardIterator first, Sentinel last) const { if (first == last) { return first; } ForwardIterator next = first; - - while (++next != last) + ++next; + while (next != last) { if (*next < *first) return next; - first = next; + ++first; + ++next; } return next; } @@ -53,7 +54,7 @@ namespace RAH2_NS typename Compare, typename Proj = RAH2_NS::details::identity, RAH2_STD::enable_if_t>* = nullptr> - ForwardIterator + constexpr ForwardIterator operator()(ForwardIterator first, Sentinel last, Compare compare, Proj proj = {}) const { auto pred_proj = @@ -83,7 +84,7 @@ namespace RAH2_NS typename Compare, typename Proj = RAH2_NS::details::identity, RAH2_STD::enable_if_t>* = nullptr> - auto operator()(ForwardRange&& r, Compare compare, Proj proj = {}) const + constexpr auto operator()(ForwardRange&& r, Compare compare, Proj proj = {}) const { return (*this)( RAH2_NS::ranges::begin(r), @@ -93,7 +94,7 @@ namespace RAH2_NS } template - auto operator()(ForwardRange&& r) const + constexpr auto operator()(ForwardRange&& r) const { return (*this)(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::end(r)); } @@ -111,7 +112,7 @@ namespace RAH2_NS typename Comp = RAH2_NS::ranges::less, // RAH2_STD::indirect_strict_weak_order> typename Proj = RAH2_NS::details::identity, RAH2_STD::enable_if_t && sentinel_for>* = nullptr> - constexpr bool operator()(I first, S last, Comp comp = {}, Proj proj = {}) const + constexpr bool operator()(I first, S last, Comp comp, Proj proj = {}) const { return RAH2_NS::ranges::is_sorted_until( RAH2_STD::move(first), @@ -126,7 +127,7 @@ namespace RAH2_NS typename Comp = RAH2_NS::ranges::less, // RAH2_STD::indirect_strict_weak_order, Proj>> typename Proj = RAH2_NS::details::identity, RAH2_STD::enable_if_t>* = nullptr> - constexpr bool operator()(R&& r, Comp comp = {}, Proj proj = {}) const + constexpr bool operator()(R&& r, Comp comp, Proj proj = {}) const { return (*this)( RAH2_NS::ranges::begin(r), @@ -134,6 +135,29 @@ namespace RAH2_NS RAH2_STD::move(comp), RAH2_STD::move(proj)); } + + template < + typename I, // RAH2_STD::forward_iterator + typename S, // RAH2_STD::sentinel_for + typename Comp = RAH2_NS::ranges::less, // RAH2_STD::indirect_strict_weak_order> + typename Proj = RAH2_NS::details::identity, + RAH2_STD::enable_if_t && sentinel_for>* = nullptr> + constexpr bool operator()(I first, S last) const + { + return RAH2_NS::ranges::is_sorted_until( + RAH2_STD::move(first), RAH2_STD::move(last)) + == last; + } + + template < + typename R, // ranges::forward_range + typename Comp = RAH2_NS::ranges::less, // RAH2_STD::indirect_strict_weak_order, Proj>> + typename Proj = RAH2_NS::details::identity, + RAH2_STD::enable_if_t>* = nullptr> + constexpr bool operator()(R&& r) const + { + return (*this)(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::end(r)); + } }; } // namespace niebloids @@ -1044,8 +1068,9 @@ namespace RAH2_NS auto lasti = result; while ((lasti - first) > 5) { - auto&& midValue(RAH2_NS::ranges::median( - *first, *(first + (lasti - first) / 2), *(lasti - 1))); + auto&& midValue( + RAH2_NS::ranges::median( + *first, *(first + (lasti - first) / 2), *(lasti - 1))); RandomAccessIterator const midPos( RAH2_NS::ranges::get_partition(first, lasti, RAH2_STD::move(midValue))); @@ -1088,8 +1113,9 @@ namespace RAH2_NS auto lasti = result; while ((lasti - first) > 5) { - auto const midValue(RAH2_NS::ranges::median( - *first, *(first + (lasti - first) / 2), *(lasti - 1), pred_proj)); + auto const midValue( + RAH2_NS::ranges::median( + *first, *(first + (lasti - first) / 2), *(lasti - 1), pred_proj)); RandomAccessIterator const midPos( RAH2_NS::ranges::get_partition(first, lasti, midValue, pred_proj)); @@ -1136,11 +1162,12 @@ namespace RAH2_NS { while (((last - first) > details::kQuickSortLimit) && (kRecursionCount > 0)) { - RandomAccessIterator const position(RAH2_NS::ranges::get_partition( - first, - last, - RAH2_STD::forward(RAH2_NS::ranges::median( - *first, *(first + (last - first) / 2), *(last - 1))))); + RandomAccessIterator const position( + RAH2_NS::ranges::get_partition( + first, + last, + RAH2_STD::forward(RAH2_NS::ranges::median( + *first, *(first + (last - first) / 2), *(last - 1))))); quick_sort_impl_helper( position, last, --kRecursionCount); @@ -1157,12 +1184,13 @@ namespace RAH2_NS { while (((last - first) > details::kQuickSortLimit) && (kRecursionCount > 0)) { - RandomAccessIterator const position(RAH2_NS::ranges::get_partition( - first, - last, - RAH2_STD::forward(RAH2_NS::ranges::median( - *first, *(first + (last - first) / 2), *(last - 1), compare)), - compare)); + RandomAccessIterator const position( + RAH2_NS::ranges::get_partition( + first, + last, + RAH2_STD::forward(RAH2_NS::ranges::median( + *first, *(first + (last - first) / 2), *(last - 1), compare)), + compare)); quick_sort_impl_helper( position, last, --kRecursionCount, compare); diff --git a/includes/rah2/algorithm.hpp b/includes/rah2/algorithm.hpp index 1e37bab..0fc2677 100644 --- a/includes/rah2/algorithm.hpp +++ b/includes/rah2/algorithm.hpp @@ -1102,10 +1102,10 @@ namespace RAH2_NS S last, RAH2_NS::iter_difference_t input_size, O out, - RAH2_NS::iter_difference_t n, + RAH2_NS::iter_difference_t output_size, Gen&& gen) const { - if (n == 0 or input_size == 0) + if (output_size == 0 or input_size == 0) { return out; } @@ -1116,7 +1116,7 @@ namespace RAH2_NS auto out_iter = details::unwrap_begin(RAH2_STD::move(out)); auto out2 = out_iter.iterator; - n = std::min(n, input_size); + auto n = RAH2_STD::min(output_size, input_size); for (; input_size > 0; ++first2, (void)--input_size) { uniform_int_distrib distrib( @@ -1132,7 +1132,13 @@ namespace RAH2_NS return out_iter.wrap_iterator(RAH2_STD::move(out2)); } - template + template < + typename DistibType, + typename I, + typename S, + typename O, + class Gen, + RAH2_STD::enable_if_t>* = nullptr> inline constexpr O sample_unsized_impl( I first, S last, O out, RAH2_NS::iter_difference_t n, Gen&& gen) const { @@ -1165,13 +1171,38 @@ namespace RAH2_NS return out + sample_size; } + template < + typename DistibType, + typename I, + typename S, + typename O, + class Gen, + RAH2_STD::enable_if_t< + !RAH2_NS::random_access_iterator && RAH2_NS::forward_iterator>* = nullptr> + inline constexpr O sample_unsized_impl( + I first, S last, O out, RAH2_NS::iter_difference_t n, Gen&& gen) const + { + auto last1 = first; + auto const input_size = details::advance_and_count(last1, last); + if (input_size < RAH2_STD::numeric_limits::max()) + { + return this->sample_sized_impl( + first, RAH2_MOV(last1), input_size, RAH2_MOV(out), n, RAH2_MOV(gen)); + } + else + { + return this->sample_sized_impl( + first, RAH2_MOV(last1), input_size, RAH2_MOV(out), n, RAH2_MOV(gen)); + } + } + template < typename I, typename S, typename O, class Gen, RAH2_STD::enable_if_t || RAH2_NS::sized_sentinel_for)>* = nullptr> + RAH2_NS::sized_sentinel_for && !RAH2_NS::random_access_iterator)>* = nullptr> inline constexpr O operator()(I first, S last, O out, RAH2_NS::iter_difference_t n, Gen&& gen) const { @@ -1193,37 +1224,72 @@ namespace RAH2_NS typename O, class Gen, RAH2_STD::enable_if_t< - RAH2_NS::forward_iterator || RAH2_NS::sized_sentinel_for>* = nullptr> + RAH2_NS::sized_sentinel_for && !RAH2_NS::random_access_iterator>* = nullptr> inline constexpr O operator()(I first, S last, O out, RAH2_NS::iter_difference_t n, Gen&& gen) const { - auto input_size = RAH2_NS::ranges::distance(first, last); - return this->sample_sized_impl( - RAH2_MOV(first), RAH2_MOV(last), input_size, RAH2_MOV(out), n, RAH2_MOV(gen)); + auto last1 = first; + size_t const input_size = details::advance_and_count(last1, last); + if (input_size < RAH2_STD::numeric_limits::max()) + { + return this->sample_sized_impl( + RAH2_MOV(first), + RAH2_MOV(last1), + input_size, + RAH2_MOV(out), + n, + RAH2_FWD(gen)); + } + else + { + return this->sample_sized_impl( + RAH2_MOV(first), + RAH2_MOV(last1), + input_size, + RAH2_MOV(out), + n, + RAH2_FWD(gen)); + } } template < typename R, typename O, class Gen, - RAH2_STD::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t< + RAH2_NS::ranges::sized_range && !RAH2_NS::random_access_iterator>* = nullptr> inline constexpr O operator()(R&& r, O out, range_difference_t n, Gen&& gen) const { - auto input_size = RAH2_NS::ranges::size(r); - return this->sample_sized_impl( - RAH2_NS::ranges::begin(r), - RAH2_NS::ranges::end(r), - input_size, - RAH2_MOV(out), - n, - RAH2_MOV(gen)); + auto const input_size = RAH2_NS::ranges::size(r); + auto const last1 = RAH2_NS::ranges::next(RAH2_NS::ranges::begin(r), input_size); + if (input_size < RAH2_STD::numeric_limits::max()) + { + return this->sample_sized_impl( + RAH2_NS::ranges::begin(r), + RAH2_MOV(last1), + input_size, + RAH2_MOV(out), + n, + RAH2_FWD(gen)); + } + else + { + return this->sample_sized_impl( + RAH2_NS::ranges::begin(r), + RAH2_MOV(last1), + input_size, + RAH2_MOV(out), + n, + RAH2_FWD(gen)); + } } template < typename R, typename O, class Gen, - RAH2_STD::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t && !RAH2_NS::random_access_iterator)>* = nullptr> inline constexpr O operator()(R&& r, O out, range_difference_t n, Gen&& gen) const { return (*this)( @@ -1231,7 +1297,7 @@ namespace RAH2_NS RAH2_NS::ranges::end(r), RAH2_MOV(out), n, - RAH2_MOV(gen)); + RAH2_FWD(gen)); } }; } // namespace niebloids @@ -1410,25 +1476,18 @@ namespace RAH2_NS { struct partition_point_fn { - template < - typename ForwardIt, - typename Sentinel, - typename UnaryPredicate, - typename Proj = RAH2_NS::details::identity, - RAH2_STD::enable_if_t>* = nullptr> - constexpr ForwardIt - operator()(ForwardIt first, Sentinel last, UnaryPredicate pred, Proj proj = {}) const + template + inline constexpr ForwardIt impl(ForwardIt first, N length, UnaryPredicate pred) const { - auto pred_proj = - details::wrap_pred_proj(RAH2_STD::move(pred), RAH2_STD::move(proj)); - - for (auto length = RAH2_NS::ranges::distance(first, last); 0 < length;) + while (length > 0) { - auto half = length / 2; - auto middle = RAH2_STD::next(first, half); - if (pred_proj(*middle)) + auto const half = length / 2; + auto middle = first; + RAH2_NS::ranges::advance(middle, half); + if (pred(*middle)) { - first = RAH2_STD::next(middle); + first = middle; + ++first; length -= (half + 1); } else @@ -1438,12 +1497,29 @@ namespace RAH2_NS return first; } + template < + typename ForwardIt, + typename Sentinel, + typename UnaryPredicate, + typename Proj = RAH2_NS::details::identity, + RAH2_STD::enable_if_t>* = nullptr> + inline constexpr ForwardIt + operator()(ForwardIt first, Sentinel last, UnaryPredicate pred, Proj proj = {}) const + { + auto pred_proj = + details::wrap_pred_proj(RAH2_STD::move(pred), RAH2_STD::move(proj)); + auto length = RAH2_NS::ranges::distance(first, last); + return impl(RAH2_STD::move(first), length, RAH2_STD::move(pred_proj)); + } + template < typename ForwardRange, typename UnaryPredicate, typename Proj = RAH2_NS::details::identity, - RAH2_STD::enable_if_t>* = nullptr> - constexpr borrowed_iterator_t + RAH2_STD::enable_if_t< + RAH2_NS::ranges::range + && !RAH2_NS::ranges::sized_range>* = nullptr> + inline constexpr borrowed_iterator_t operator()(ForwardRange&& range, UnaryPredicate pred, Proj proj = {}) const { return (*this)( @@ -1452,6 +1528,22 @@ namespace RAH2_NS RAH2_STD::move(pred), RAH2_STD::move(proj)); } + + template < + typename ForwardRange, + typename UnaryPredicate, + typename Proj = RAH2_NS::details::identity, + RAH2_STD::enable_if_t< + RAH2_NS::ranges::range + && RAH2_NS::ranges::sized_range>* = nullptr> + inline constexpr borrowed_iterator_t + operator()(ForwardRange&& range, UnaryPredicate pred, Proj proj = {}) const + { + auto pred_proj = + details::wrap_pred_proj(RAH2_STD::move(pred), RAH2_STD::move(proj)); + auto length = RAH2_NS::ranges::size(range); + return impl(RAH2_NS::ranges::begin(range), length, RAH2_STD::move(pred_proj)); + } }; } // namespace niebloids @@ -1853,9 +1945,9 @@ namespace RAH2_NS { V new_val(*first); if (pred_proj(new_val, result.min)) - result.min = std::move(new_val); + result.min = RAH2_MOV(new_val); else if (pred_proj(result.max, new_val)) - result.max = std::move(new_val); + result.max = RAH2_MOV(new_val); } return result; } @@ -2674,7 +2766,8 @@ namespace RAH2_NS typename RandomAccessIterator, typename Sentinel, typename UniformRandomNumberGenerator, - std::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t< + not RAH2_NS::sized_sentinel_for>* = nullptr> void operator()( RandomAccessIterator first, Sentinel last, UniformRandomNumberGenerator&& urng) const { @@ -2684,7 +2777,7 @@ namespace RAH2_NS typename RandomAccessIterator, typename Sentinel, typename UniformRandomNumberGenerator, - std::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t>* = nullptr> void operator()( RandomAccessIterator first, Sentinel last, UniformRandomNumberGenerator&& urng) const { @@ -2695,7 +2788,7 @@ namespace RAH2_NS template < typename RandomRange, typename UniformRandomNumberGenerator, - std::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t>* = nullptr> void operator()(RandomRange&& range, UniformRandomNumberGenerator&& urng) const { dispatch_n( @@ -2704,7 +2797,7 @@ namespace RAH2_NS template < typename RandomRange, typename UniformRandomNumberGenerator, - std::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t>* = nullptr> void operator()(RandomRange&& range, UniformRandomNumberGenerator&& urng) const { (*this)( diff --git a/includes/rah2/base_algorithm.hpp b/includes/rah2/base_algorithm.hpp index bd3edc7..0f35dc6 100644 --- a/includes/rah2/base_algorithm.hpp +++ b/includes/rah2/base_algorithm.hpp @@ -137,7 +137,8 @@ namespace RAH2_NS RAH2_STD::enable_if_t && RAH2_NS::contiguous_iterator && RAH2_NS::is_same_v, RAH2_NS::iter_value_t> - and std::is_trivially_move_assignable>::value)>* = nullptr> + and RAH2_STD::is_trivially_move_assignable>::value + and RAH2_NS::is_trivially_copyable_v>)>* = nullptr> constexpr RAH2_NS::ranges::move_result impl_n(I first, N len, O result) const { RAH2_FOR_N(len, { @@ -154,7 +155,8 @@ namespace RAH2_NS RAH2_STD::enable_if_t< RAH2_NS::contiguous_iterator && RAH2_NS::contiguous_iterator && RAH2_NS::is_same_v, RAH2_NS::iter_value_t> - and std::is_trivially_move_assignable>::value>* = nullptr> + and RAH2_STD::is_trivially_move_assignable>::value + and RAH2_NS::is_trivially_copyable_v>>* = nullptr> constexpr RAH2_NS::ranges::move_result impl_n(I first, N len, O result) const { memcpy(&(*result), &(*first), len * sizeof(RAH2_NS::iter_value_t)); @@ -1186,6 +1188,35 @@ namespace RAH2_NS /// constexpr niebloids::copy_n_fn copy_n{}; + namespace details + { + template < + typename It, + typename Sent, + RAH2_STD::enable_if_t>* = nullptr> + static auto advance_and_count(It& it, Sent sent) + { + auto dist = RAH2_NS::ranges::distance(it, sent); + RAH2_NS::ranges::advance(it, sent); + return dist; + } + + template < + typename It, + typename Sent, + RAH2_STD::enable_if_t>* = nullptr> + static auto advance_and_count(It& it, Sent sent) + { + RAH2_NS::iter_difference_t dist = 0; + while (it != sent) + { + ++it; + ++dist; + } + return dist; + } + } // namespace details + template using move_backward_result = RAH2_NS::ranges::in_out_result; @@ -1193,38 +1224,61 @@ namespace RAH2_NS { struct move_backward_fn { - - RAH2_EXT_WARNING_PUSH - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic ignored "-Wstringop-overflow" -#endif template < typename I1, typename S1, typename I2, RAH2_STD::enable_if_t and RAH2_NS::contiguous_iterator - and RAH2_NS::contiguous_iterator - and RAH2_STD::is_trivially_copyable>::value + RAH2_NS::contiguous_iterator and RAH2_NS::contiguous_iterator + and RAH2_STD::is_trivially_move_assignable>::value + and RAH2_NS::is_trivially_copyable_v> and RAH2_NS::is_same_v, RAH2_NS::iter_value_t>)>* = nullptr> constexpr move_backward_result impl(I1 first, S1 last, I2 result) const { - I1 const last1{RAH2_NS::ranges::next(first, RAH2_STD::move(last))}; - for (I1 i{last1}; i != first;) + I1 last1 = first; + size_t const item_count = details::advance_and_count(last1, last); + I1 i = last1; + for (auto u = item_count / 4; u != 0; --u) + { + *--result = RAH2_MOV(*--i); + *--result = RAH2_MOV(*--i); *--result = RAH2_MOV(*--i); + *--result = RAH2_MOV(*--i); + } + for (auto u = item_count % 4; u != 0; --u) + { + *--result = RAH2_MOV(*--i); + } return {RAH2_STD::move(last1), RAH2_STD::move(result)}; } + template < + typename I1, + typename S1, + typename I2, + RAH2_STD::enable_if_t< + not(RAH2_NS::sized_sentinel_for) + and (RAH2_NS::contiguous_iterator and RAH2_NS::contiguous_iterator and RAH2_NS::is_same_v, RAH2_NS::iter_value_t> and RAH2_STD::is_trivially_move_assignable>::value and RAH2_NS::is_trivially_copyable_v>)>* = + nullptr> + constexpr move_backward_result impl(I1 first, S1 last, I2 result) const + { + I1 last1 = first; + size_t const item_count = details::advance_and_count(last1, last); + memmove( + &(*(result - item_count)), + &(*first), + item_count * sizeof(RAH2_NS::iter_value_t)); + return {last1, result - item_count}; + } + template < typename I1, typename S1, typename I2, RAH2_STD::enable_if_t<( - RAH2_NS::sized_sentinel_for and RAH2_NS::contiguous_iterator - and RAH2_NS::contiguous_iterator - and RAH2_STD::is_trivially_copyable>::value - and RAH2_NS::is_same_v, RAH2_NS::iter_value_t>)>* = nullptr> + RAH2_NS::sized_sentinel_for + and (RAH2_NS::contiguous_iterator and RAH2_NS::contiguous_iterator and RAH2_STD::is_trivially_move_assignable>::value and RAH2_NS::is_trivially_copyable_v> and RAH2_NS::is_same_v, RAH2_NS::iter_value_t>))>* = + nullptr> constexpr move_backward_result impl(I1 first, S1 last, I2 result) const { auto const item_count = RAH2_NS::ranges::distance(first, last); @@ -1256,15 +1310,11 @@ namespace RAH2_NS unwraped_out.wrap_iterator(RAH2_STD::move(ret.out))}; } - RAH2_EXT_WARNING_POP - template < typename R, typename I, - RAH2_STD::enable_if_t< - RAH2_NS::ranges::bidirectional_range && RAH2_NS::bidirectional_iterator>* = nullptr> - constexpr RAH2_NS::ranges::move_backward_result, I> - operator()(R&& r, I result) const + RAH2_STD::enable_if_t && bidirectional_iterator>* = nullptr> + constexpr move_backward_result, I> operator()(R&& r, I result) const { return (*this)( RAH2_NS::ranges::begin(r), RAH2_NS::ranges::end(r), RAH2_STD::move(result)); @@ -1305,27 +1355,59 @@ namespace RAH2_NS typename S1, typename I2, RAH2_STD::enable_if_t and RAH2_NS::contiguous_iterator - and RAH2_NS::contiguous_iterator + RAH2_NS::contiguous_iterator and RAH2_NS::contiguous_iterator and RAH2_STD::is_trivially_copyable>::value and RAH2_NS::is_same_v, RAH2_NS::iter_value_t>)>* = nullptr> constexpr copy_backward_result impl(I1 first, S1 last, I2 result) const { - I1 const last1{RAH2_NS::ranges::next(first, RAH2_STD::move(last))}; - for (I1 i{last1}; i != first;) + size_t item_count = 0; + I1 last1 = first; + for (; last1 != last; ++last1, ++item_count) + ; + I1 i = last1; + for (auto u = item_count / 4; u != 0; --u) + { + *--result = *--i; + *--result = *--i; + *--result = *--i; + *--result = *--i; + } + for (auto u = item_count % 4; u != 0; --u) + { *--result = *--i; + } return {RAH2_STD::move(last1), RAH2_STD::move(result)}; } + template < + typename I1, + typename S1, + typename I2, + RAH2_STD::enable_if_t< + not(RAH2_NS::sized_sentinel_for) + and (RAH2_NS::contiguous_iterator and RAH2_NS::contiguous_iterator and RAH2_STD::is_trivially_copyable>::value and RAH2_NS::is_same_v, RAH2_NS::iter_value_t>)>* = + nullptr> + constexpr copy_backward_result impl(I1 first, S1 last, I2 result) const + { + size_t item_count = 0; + I1 last1 = first; + for (; last1 != last; ++last1, ++item_count) + ; + memmove( + &(*(result - item_count)), + &(*first), + item_count * sizeof(RAH2_NS::iter_value_t)); + return {last1, result - item_count}; + } + template < typename I1, typename S1, typename I2, RAH2_STD::enable_if_t<( - RAH2_NS::sized_sentinel_for and RAH2_NS::contiguous_iterator - and RAH2_NS::contiguous_iterator - and RAH2_STD::is_trivially_copyable>::value - and RAH2_NS::is_same_v, RAH2_NS::iter_value_t>)>* = nullptr> + RAH2_NS::sized_sentinel_for + and (RAH2_NS::contiguous_iterator and RAH2_NS::contiguous_iterator and RAH2_STD::is_trivially_copyable>::value and RAH2_NS::is_same_v, RAH2_NS::iter_value_t>))>* = + nullptr> constexpr copy_backward_result impl(I1 first, S1 last, I2 result) const { auto const item_count = RAH2_NS::ranges::distance(first, last); @@ -1389,14 +1471,9 @@ namespace RAH2_NS { struct count_fn { - template < - typename I, - typename S, - class T, - class Proj = RAH2_NS::details::identity, - RAH2_STD::enable_if_t && sentinel_for>* = nullptr> + template constexpr RAH2_NS::iter_difference_t - operator()(I first_w, S last_w, T const& value, Proj proj) const + impl(I first_w, S last_w, T const& value, Proj proj) const { auto first_last = details::unwrap(RAH2_STD::move(first_w), RAH2_STD::move(last_w)); @@ -1411,43 +1488,123 @@ namespace RAH2_NS return counter; } + template + constexpr RAH2_NS::iter_difference_t + impl_n(I first_w, N len, T const& value, Proj proj) const + { + auto first_last = details::unwrap_begin(RAH2_STD::move(first_w)); + auto first = RAH2_STD::move(first_last.iterator); + RAH2_NS::iter_difference_t counter = 0; + RAH2_FOR_N(len, { + if (RAH2_INVOKE_1(proj, *first) == value) + ++counter; + ++first; + }); + return counter; + } + + template + constexpr RAH2_NS::iter_difference_t impl(I first_w, S last_w, T const& value) const + { + auto first_last = + details::unwrap(RAH2_STD::move(first_w), RAH2_STD::move(last_w)); + auto first = RAH2_STD::move(first_last.iterator); + auto last = RAH2_STD::move(first_last.sentinel); + RAH2_NS::iter_difference_t counter = 0; + for (; first != last; ++first) + counter += (*first == value); + return counter; + } + + template + constexpr RAH2_NS::iter_difference_t impl_n(I first_w, N len, T const& value) const + { + auto first_last = details::unwrap_begin(RAH2_STD::move(first_w)); + auto first = RAH2_STD::move(first_last.iterator); + RAH2_NS::iter_difference_t counter = 0; + RAH2_FOR_N(len, { + counter += (*first == value); + ++first; + }); + return counter; + } + + template < + typename I, + typename S, + class T, + class Proj = RAH2_NS::details::identity, + RAH2_STD::enable_if_t< + input_iterator && sentinel_for && !sized_sentinel_for>* = nullptr> + constexpr RAH2_NS::iter_difference_t + operator()(I first_w, S last_w, T const& value, Proj proj) const + { + return impl(first_w, last_w, value, proj); + } + + template < + typename I, + typename S, + class T, + class Proj = RAH2_NS::details::identity, + RAH2_STD::enable_if_t && sized_sentinel_for>* = nullptr> + constexpr RAH2_NS::iter_difference_t + operator()(I first_w, S last_w, T const& value, Proj proj) const + { + return impl_n(first_w, RAH2_NS::ranges::distance(first_w, last_w), value, proj); + } + template < typename R, class T, class Proj = RAH2_NS::details::identity, - RAH2_STD::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t && sized_range>* = nullptr> constexpr range_difference_t operator()(R&& r, T const& value, Proj proj) const { - return (*this)( - RAH2_NS::ranges::begin(r), - RAH2_NS::ranges::end(r), - value, - RAH2_STD::move(proj)); + return impl_n(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::size(r), value, proj); + } + template < + typename R, + class T, + class Proj = RAH2_NS::details::identity, + RAH2_STD::enable_if_t && !sized_range>* = nullptr> + constexpr range_difference_t operator()(R&& r, T const& value, Proj proj) const + { + return impl(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::end(r), value, proj); } template < typename I, typename S, class T, - RAH2_STD::enable_if_t && sentinel_for>* = nullptr> + RAH2_STD::enable_if_t< + input_iterator && sentinel_for && !sized_sentinel_for>* = nullptr> constexpr RAH2_NS::iter_difference_t operator()(I first_w, S last_w, T const& value) const { - auto first_last = - details::unwrap(RAH2_STD::move(first_w), RAH2_STD::move(last_w)); - auto first = RAH2_STD::move(first_last.iterator); - auto last = RAH2_STD::move(first_last.sentinel); - RAH2_NS::iter_difference_t counter = 0; - for (; first != last; ++first) - if (*first == value) - ++counter; - return counter; + return impl(first_w, last_w, value); + } + + template < + typename I, + typename S, + class T, + RAH2_STD::enable_if_t && sized_sentinel_for>* = nullptr> + constexpr RAH2_NS::iter_difference_t + operator()(I first_w, S last_w, T const& value) const + { + return impl_n(first_w, RAH2_NS::ranges::distance(first_w, last_w), value); } - template >* = nullptr> + template && sized_range>* = nullptr> constexpr range_difference_t operator()(R&& r, T const& value) const { - return (*this)(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::end(r), value); + return impl_n(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::size(r), value); + } + template && !sized_range>* = nullptr> + constexpr range_difference_t operator()(R&& r, T const& value) const + { + return impl(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::end(r), value); } }; } // namespace niebloids @@ -2077,7 +2234,7 @@ namespace RAH2_NS typename O, typename S, typename F, - std::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t>* = nullptr> constexpr O operator()(O first, S last, F&& gen) const { return generate_n(first, RAH2_NS::ranges::distance(first, last), RAH2_FWD(gen)); @@ -2087,7 +2244,7 @@ namespace RAH2_NS typename O, typename S, typename F, - std::enable_if_t>* = nullptr> + RAH2_STD::enable_if_t>* = nullptr> constexpr O operator()(O first, S last, F&& gen) const { for (; first != last; ++first) @@ -2097,13 +2254,13 @@ namespace RAH2_NS return first; } - template >* = nullptr> + template >* = nullptr> constexpr borrowed_iterator_t operator()(R&& r, F&& gen) const { return (*this)(RAH2_NS::ranges::begin(r), RAH2_NS::ranges::end(r), RAH2_FWD(gen)); } - template >* = nullptr> + template >* = nullptr> constexpr borrowed_iterator_t operator()(R&& r, F&& gen) const { return generate_n( @@ -4365,7 +4522,7 @@ namespace RAH2_NS operator()(ForwardIterator first, Sentinel last, T const& value) const { // To do: This can be made slightly faster by not using lower_bound. - ForwardIterator i(RAH2_NS::ranges::lower_bound(first, last, value)); + auto i = RAH2_NS::ranges::lower_bound(first, last, value); // Note that we always express value comparisons in terms of < or ==. return ((i != last) && !(value < *i)); } @@ -4373,7 +4530,11 @@ namespace RAH2_NS template RAH2_NODISCARD constexpr bool operator()(Range&& range, T const& value) const { - return (*this)(RAH2_NS::ranges::begin(range), RAH2_NS::ranges::end(range), value); + auto last = RAH2_NS::ranges::end(range); + // To do: This can be made slightly faster by not using lower_bound. + auto i = RAH2_NS::ranges::lower_bound(range, value); + // Note that we always express value comparisons in terms of < or ==. + return ((i != last) && !(value < *i)); } /// binary_search @@ -4400,29 +4561,24 @@ namespace RAH2_NS Compare compare, Proj proj = {}) const { - auto pred_proj = - details::wrap_pred_value_proj(RAH2_STD::move(compare), RAH2_STD::move(proj)); - // To do: This can be made slightly faster by not using lower_bound. - ForwardIterator i(RAH2_NS::ranges::lower_bound(first, last, value, compare, proj)); - return ((i != last) && !pred_proj(value, *i)); + auto i = RAH2_NS::ranges::lower_bound(first, last, value, compare, proj); + return ((i != last) && !compare(value, RAH2_STD::ref(proj)(*i))); } template < typename Range, typename T, typename Compare, - class Proj = RAH2_NS::details::identity, + typename Proj = RAH2_NS::details::identity, RAH2_STD::enable_if_t>* = nullptr> RAH2_NODISCARD constexpr bool operator()(Range&& range, T const& value, Compare compare, Proj proj = {}) const { - return (*this)( - RAH2_NS::ranges::begin(range), - RAH2_NS::ranges::end(range), - value, - RAH2_STD::move(compare), - RAH2_STD::move(proj)); + auto last = RAH2_NS::ranges::end(range); + // To do: This can be made slightly faster by not using lower_bound. + auto i = RAH2_NS::ranges::lower_bound(range, value, compare, proj); + return (i != last) && !compare(value, RAH2_STD::ref(proj)(*i)); } }; } // namespace niebloids @@ -5775,7 +5931,7 @@ namespace RAH2_NS { template subrange - operator()(ForwardIterator first, ForwardIterator middle, ForwardSentinel last) const + impl(ForwardIterator first, ForwardIterator middle, ForwardSentinel last) const { if (middle != first) { @@ -5816,6 +5972,25 @@ namespace RAH2_NS return {last_it, last_it}; } + template + subrange + operator()(ForwardIterator first, ForwardIterator middle, ForwardSentinel last) const + { + auto last2 = RAH2_NS::ranges::next(first, last); + if (middle == last) + { + return {first, last2}; + } + auto middle_u = details::unwrap(RAH2_STD::move(middle), last2); + auto first_last = details::unwrap(RAH2_STD::move(first), RAH2_STD::move(last2)); + auto res = impl( + RAH2_MOV(first_last.iterator), + RAH2_MOV(middle_u.iterator), + RAH2_MOV(first_last.sentinel)); + return { + first_last.wrap_iterator(res.begin()), first_last.wrap_iterator(res.end())}; + } + template borrowed_subrange_t operator()(ForwardRange&& range, iterator_t middle) const diff --git a/includes/rah2/ranges.hpp b/includes/rah2/ranges.hpp index 7d7bd5f..6960456 100644 --- a/includes/rah2/ranges.hpp +++ b/includes/rah2/ranges.hpp @@ -914,7 +914,7 @@ namespace RAH2_NS { return range_.begin(); } - template >* = nullptr> + template >* = nullptr> auto begin() const { return range_.begin(); @@ -923,7 +923,7 @@ namespace RAH2_NS { return range_.end(); } - template >* = nullptr> + template >* = nullptr> auto end() const { return range_.end(); diff --git a/test/TestSuite.hpp b/test/TestSuite.hpp index 329f32e..1b85629 100644 --- a/test/TestSuite.hpp +++ b/test/TestSuite.hpp @@ -42,7 +42,7 @@ struct TestSuite void addTest(RAH2_STD::string const& group, RAH2_STD::string const& name, std::function test) { - testMap.emplace(group + " - " + name, std::move(test)); + testMap.emplace(group + " - " + name, RAH2_MOV(test)); } char const* currentTest = nullptr; diff --git a/test/test_algo3.cpp b/test/test_algo3.cpp index ddea29b..943257f 100644 --- a/test/test_algo3.cpp +++ b/test/test_algo3.cpp @@ -175,13 +175,13 @@ struct test_search_ assert(RAH2_STD::distance(haystack.begin(), found5.end()) == 4); } - template >>* = nullptr> + template >>* = nullptr> static auto get_begin(I&& i) -> decltype(std::forward(i)) { return std::forward(i); } - template >>* = nullptr> + template >>* = nullptr> static auto get_begin(I&& i) -> decltype(i.begin()) { return i.begin(); @@ -2943,6 +2943,19 @@ struct test_swap_ CHECK(out == (RAH2_STD::vector{1, 2, 3, 4, 5})); CHECK(in_ == (RAH2_STD::vector{10, 11, 12})); } + { + RAH2_STD::vector in_(1000); + in_[3] = 12; + auto in = make_test_view_adapter(in_); + RAH2_STD::vector out(1000); + out[4] = 79; + auto result = RAH2_NS::ranges::swap_ranges( + RAH2_NS::ranges::begin(in), RAH2_NS::ranges::end(in), out.begin(), out.end()); + CHECK(result.in2 == out.begin() + in_.size()); + CHECK(result.in1 == in.end()); + CHECK_EQUAL(out[3], 12); + CHECK_EQUAL(in_[4], 79); + } { testSuite.test_case("range"); diff --git a/test/test_algo4.cpp b/test/test_algo4.cpp index 82b8400..d3dd8b5 100644 --- a/test/test_algo4.cpp +++ b/test/test_algo4.cpp @@ -565,6 +565,11 @@ void test_shift_right() template struct test_sample_ { + using OutTag = typename RAH2_STD::conditional< + RAH2_NS::derived_from, + Tag, + RAH2_NS::random_access_iterator_tag>::type; + template void test() { @@ -579,8 +584,8 @@ struct test_sample_ auto result = RAH2_NS::ranges::sample( RAH2_NS::ranges::begin(in), RAH2_NS::ranges::end(in), out.begin(), 3, g); CHECK(result == out.begin() + 3); - CHECK(RAH2_NS::ranges::none_of( - out.begin(), out.begin() + 3, [](auto v) { return v == 0; })); + CHECK( + RAH2_NS::ranges::none_of(out.begin(), out.begin() + 3, [](auto v) { return v == 0; })); } { @@ -588,8 +593,8 @@ struct test_sample_ RAH2_STD::vector out{0, 0, 0, 0, 0, 0, 4, 5}; auto result = RAH2_NS::ranges::sample(in, out.begin(), 3, g); CHECK(result == out.begin() + 3); - CHECK(RAH2_NS::ranges::none_of( - out.begin(), out.begin() + 3, [](auto v) { return v == 0; })); + CHECK( + RAH2_NS::ranges::none_of(out.begin(), out.begin() + 3, [](auto v) { return v == 0; })); } testSuite.test_case("empty"); @@ -621,10 +626,11 @@ struct test_sample_ in_.push_back(i % 15); } auto in = make_test_view_adapter(in_); - RAH2_STD::vector out; - out.resize(1000000 * RELEASE_MULTIPLIER); - out.emplace_back(); - out.emplace_back(); + RAH2_STD::vector out_; + out_.resize(1000000 * RELEASE_MULTIPLIER); + out_.emplace_back(); + out_.emplace_back(); + auto out = make_test_view_adapter(out_); COMPARE_DURATION_TO_STD_ALGO_17_AND_RANGES( CS == Common, @@ -640,6 +646,20 @@ struct test_sample_ g); DONT_OPTIM(result); }); + COMPARE_DURATION_TO_STD_ALGO_17_AND_RANGES( + CS == Common, + "sample_iter_smallout", + range_type, + [&] + { + auto result = STD::sample( + fwd(RAH2_NS::ranges::begin(in)), + RAH2_NS::ranges::end(in), + out.begin(), + 100 * RELEASE_MULTIPLIER, + g); + DONT_OPTIM(result); + }); } #endif @@ -651,10 +671,11 @@ struct test_sample_ } auto in2 = make_test_view_adapter(in2_); - RAH2_STD::vector out2; - out2.resize(1000000 * RELEASE_MULTIPLIER); - out2.emplace_back(); - out2.emplace_back(); + RAH2_STD::vector out2_; + out2_.resize(1000000 * RELEASE_MULTIPLIER); + out2_.emplace_back(); + out2_.emplace_back(); + auto out2 = make_test_view_adapter(out2_); COMPARE_DURATION_TO_STD_RANGES( "sample_range", @@ -666,6 +687,15 @@ struct test_sample_ STD::sample(in2, out2.begin(), 1000000 * RELEASE_MULTIPLIER, g); DONT_OPTIM(result2); })); + COMPARE_DURATION_TO_STD_RANGES( + "sample_range_smallout", + range_type, + ( + [&] + { + auto result2 = STD::sample(in2, out2.begin(), 100 * RELEASE_MULTIPLIER, g); + DONT_OPTIM(result2); + })); } } static constexpr bool do_test = true; @@ -1681,12 +1711,26 @@ struct test_partition_point_ template void test_perf(char const* range_type) { - size_t PerfMultiplier = - (RAH2_NS::derived_from && Sized) ? 100llu : - 10llu; + auto const IterSized = + (CS == Common && RAH2_NS::derived_from) + || (CS == Sentinel && Sized); + +#ifdef _DEBUG + auto const IterSizedMultiplier = + IterSized && RAH2_NS::derived_from ? + 1000 * RELEASE_MULTIPLIER : + 1; + auto const RangeSizedMultiplier = + Sized && RAH2_NS::derived_from ? + 1000 * RELEASE_MULTIPLIER : + 1; +#else + auto const IterSizedMultiplier = IterSized ? 1000 * RELEASE_MULTIPLIER : 1; + auto const RangeSizedMultiplier = Sized ? 1000 * RELEASE_MULTIPLIER : 1; +#endif testSuite.test_case("perf"); - RAH2_STD::vector in(10000000llu * RELEASE_MULTIPLIER, Coord{1, 2}); + RAH2_STD::vector in(1000000llu * RELEASE_MULTIPLIER, Coord{1, 2}); in.push_back(Coord{3, 4}); auto r1 = make_test_view_adapter(in); @@ -1696,7 +1740,7 @@ struct test_partition_point_ range_type, [&] { - for (size_t i = 0; i < PerfMultiplier; ++i) + for (int i = 0; i < IterSizedMultiplier; ++i) { auto iter = STD::partition_point( fwd(r1.begin()), r1.end(), [](auto c) { return c.x < 3; }); @@ -1708,7 +1752,7 @@ struct test_partition_point_ range_type, [&] { - for (size_t i = 0; i < PerfMultiplier; ++i) + for (int i = 0; i < RangeSizedMultiplier; ++i) { auto iter = STD::partition_point(r1, [](int64_t c) { return c < 3; }, &Coord::x); assert((*iter == Coord{3, 4})); @@ -2839,8 +2883,8 @@ struct test_nth_element_ CHECK(RAH2_NS::ranges::all_of(out.begin(), midle, [](auto const& v) { return v < 5; })); auto after_middle = midle; ++after_middle; - CHECK(RAH2_NS::ranges::all_of( - after_middle, out.end(), [](auto const& v) { return v > 5; })); + CHECK( + RAH2_NS::ranges::all_of(after_middle, out.end(), [](auto const& v) { return v > 5; })); CHECK_EQUAL(midle->i, 5); } @@ -2880,12 +2924,12 @@ struct test_nth_element_ auto midle = RAH2_NS::ranges::next(out.begin(), 2); auto result = RAH2_NS::ranges::nth_element(out, midle, comp_64, &Coord::x); CHECK(result == out.end()); - CHECK(RAH2_NS::ranges::all_of( - out.begin(), midle, [](auto v) { return v > 3; }, &Coord::x)); + CHECK(RAH2_NS::ranges::all_of(out.begin(), midle, [](auto v) { return v > 3; }, &Coord::x)); auto after_middle = midle; ++after_middle; - CHECK(RAH2_NS::ranges::all_of( - after_middle, out.end(), [](auto v) { return v < 3; }, &Coord::x)); + CHECK( + RAH2_NS::ranges::all_of( + after_middle, out.end(), [](auto v) { return v < 3; }, &Coord::x)); CHECK(midle->x == 3); } } @@ -3048,10 +3092,23 @@ struct test_lower_bound_ in2.push_back(Coord{1, 3}); auto r2 = make_test_view_adapter(in2); - auto const RangeTypeMultiplier = - RAH2_NS::derived_from ? 100 : 1; + auto const IterSized = + (CS == Common && RAH2_NS::derived_from) + || (CS == Sentinel && Sized); - auto const RangeSizedMultiplier = Sized ? 10 : 1; +#ifdef _DEBUG + auto const IterSizedMultiplier = + IterSized && RAH2_NS::derived_from ? + 1000 * RELEASE_MULTIPLIER : + 1; + auto const RangeSizedMultiplier = + Sized && RAH2_NS::derived_from ? + 1000 * RELEASE_MULTIPLIER : + 1; +#else + auto const IterSizedMultiplier = IterSized ? 1000 * RELEASE_MULTIPLIER : 1; + auto const RangeSizedMultiplier = Sized ? 1000 * RELEASE_MULTIPLIER : 1; +#endif COMPARE_DURATION_TO_STD_ALGO_AND_RANGES( CS == Common, @@ -3059,7 +3116,7 @@ struct test_lower_bound_ range_type, [&] { - for (auto i = 0; i < RangeTypeMultiplier * RangeSizedMultiplier; ++i) + for (auto i = 0; i < IterSizedMultiplier; ++i) { auto iter = STD::lower_bound(fwd(r1.begin()), r1.end(), Coord{3, 4}); assert((*iter == Coord{3, 4})); @@ -3070,7 +3127,7 @@ struct test_lower_bound_ range_type, [&] { - for (auto i = 0; i < RangeTypeMultiplier * RangeSizedMultiplier; ++i) + for (auto i = 0; i < RangeSizedMultiplier; ++i) { auto iter = STD::lower_bound(r2, 1, comp_64, &Coord::x); assert((*iter == Coord{1, 4})); @@ -3294,13 +3351,23 @@ struct test_binary_search_ } auto r2 = make_test_view_adapter(in2); - auto const RangeMultiplier = Sized ? 50 * RELEASE_MULTIPLIER : 1; + auto const IterSized = + (CS == Common && RAH2_NS::derived_from) + || (CS == Sentinel && Sized); - auto const IterMultiplier = - (Sized - and (CS == CommonOrSent::Sentinel or RAH2_NS::derived_from)) ? - 50 * (RELEASE_MULTIPLIER > 1 ? 10 : 1) : +#ifdef _DEBUG + auto const IterSizedMultiplier = + IterSized && RAH2_NS::derived_from ? + 1000 * RELEASE_MULTIPLIER : + 1; + auto const RangeSizedMultiplier = + Sized && RAH2_NS::derived_from ? + 1000 * RELEASE_MULTIPLIER : 1; +#else + auto const IterSizedMultiplier = IterSized ? 1000 * RELEASE_MULTIPLIER : 1; + auto const RangeSizedMultiplier = Sized ? 1000 * RELEASE_MULTIPLIER : 1; +#endif COMPARE_DURATION_TO_STD_ALGO_AND_RANGES( CS == Common, @@ -3308,7 +3375,7 @@ struct test_binary_search_ range_type, [&] { - for (auto i = 0; i < IterMultiplier; ++i) + for (auto i = 0; i < IterSizedMultiplier; ++i) { auto found = STD::binary_search(fwd(r1.begin()), r1.end(), Coord{3, 4}); CHECK(found); @@ -3319,7 +3386,7 @@ struct test_binary_search_ range_type, [&] { - for (auto i = 0; i < RangeMultiplier; ++i) + for (auto i = 0; i < RangeSizedMultiplier; ++i) { auto found = STD::binary_search(r2, 1, comp_64, &Coord::x); CHECK(found); diff --git a/test/test_helpers.hpp b/test/test_helpers.hpp index bf0d1eb..4f4dd78 100644 --- a/test/test_helpers.hpp +++ b/test/test_helpers.hpp @@ -459,7 +459,7 @@ class test_view_adapter test_view_adapter() = default; explicit test_view_adapter(Range r) - : base_(std::move(r)) + : base_(RAH2_MOV(r)) { } @@ -797,7 +797,7 @@ struct check_size } static intptr_t get_stop_iter() { - return std::numeric_limits::max(); + return RAH2_STD::numeric_limits::max(); } }; @@ -1308,7 +1308,7 @@ std::chrono::nanoseconds compute_duration( #endif } -constexpr static auto PerfTolerency = 5.; +constexpr static auto PerfTolerency = 4.; template auto compare_duration(