From d51e18ecf256bca35b22cc4ff77b98e15fe532f4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 30 Mar 2025 19:32:34 +0300 Subject: [PATCH 01/26] test --- .../include/test_is_sorted_until_support.hpp | 43 +++++++++++++++++ .../VSO_0000000_vector_algorithms/test.cpp | 39 +++++++++++++++ .../test.cpp | 48 +++++++++++++++---- 3 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 tests/std/include/test_is_sorted_until_support.hpp diff --git a/tests/std/include/test_is_sorted_until_support.hpp b/tests/std/include/test_is_sorted_until_support.hpp new file mode 100644 index 00000000000..29c70a2e328 --- /dev/null +++ b/tests/std/include/test_is_sorted_until_support.hpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#if _HAS_CXX20 +#include +#endif + +template +FwdIt last_known_good_is_sorted_until(FwdIt first, FwdIt last, Comp comp) { + if (first == last) { + return last; + } + + FwdIt next = first; + for (++next; next != last; ++first, ++next) { + if (comp(*next, *first)) { + return next; + } + } + + return last; +} + +template +void test_case_is_sorted_until(const std::vector& input, Comp comp) { + auto expected = last_known_good_is_sorted_until(input.begin(), input.end(), comp); + auto actual = std::is_sorted_until(input.begin(), input.end(), comp); + assert(expected == actual); +#if _HAS_CXX20 + auto actual_r = std::ranges::is_sorted_until(input.begin(), input.end(), comp); + assert(expected == actual_r); +#endif // _HAS_CXX20 +} diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 13134bdd862..50645e4e42e 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -26,6 +26,7 @@ #include #endif // _HAS_CXX20 +#include "test_is_sorted_until_support.hpp" #include "test_min_max_element_support.hpp" #include "test_vector_algorithms_support.hpp" @@ -601,6 +602,34 @@ void test_min_max_element_special_cases() { == v.begin() + 2 * block_size_in_elements + last_vector_first_elem + 9); } +template +void test_is_sorted_until(mt19937_64& gen) { + using Limits = numeric_limits; + + uniform_int_distribution> dis(Limits::min(), Limits::max()); + + vector original_input; + vector input; + original_input.reserve(dataCount); + input.reserve(dataCount); + + test_case_is_sorted_until(input, less<>{}); + test_case_is_sorted_until(input, greater<>{}); + + for (size_t attempts = 0; attempts < dataCount; ++attempts) { + original_input.push_back(static_cast(dis(gen))); + input = original_input; + + auto it = input.begin() + uniform_int_distribution{0, static_cast(input.size() - 1)}(gen); + + sort(input.begin(), it, less<>{}); + test_case_is_sorted_until(input, less<>{}); + + reverse(input.begin(), it); + test_case_is_sorted_until(input, greater<>{}); + } +} + template void last_known_good_replace(FwdIt first, FwdIt last, const T old_val, const T new_val) { for (; first != last; ++first) { @@ -994,6 +1023,16 @@ void test_vector_algorithms(mt19937_64& gen) { test_case_min_max_element( vector{-6604286336755016904, -4365366089374418225, 6104371530830675888, -8582621853879131834}); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + test_is_sorted_until(gen); + // replace() is vectorized for 4 and 8 bytes only. test_replace(gen); test_replace(gen); diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp index 89d03bfe513..b4f7c4c7c47 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp @@ -6,6 +6,7 @@ #include #include +#include "test_is_sorted_until_support.hpp" #include "test_min_max_element_support.hpp" #include "test_vector_algorithms_support.hpp" @@ -25,24 +26,23 @@ void test_min_max_element_floating_with_values(mt19937_64& gen, const vector& } template -void test_min_max_element_floating_any(mt19937_64& gen) { +vector test_floating_input(mt19937_64& gen) { normal_distribution dis(-100000.0, 100000.0); constexpr auto input_of_input_size = dataCount / 2; - vector input_of_input(input_of_input_size); + vector result(input_of_input_size); - for (auto& element : input_of_input) { + for (auto& element : result) { element = dis(gen); } - input_of_input[0] = -0.0; - input_of_input[1] = +0.0; + result[0] = -0.0; + result[1] = +0.0; #ifndef _M_FP_FAST - input_of_input[2] = -numeric_limits::infinity(); - input_of_input[3] = +numeric_limits::infinity(); + result[2] = -numeric_limits::infinity(); + result[3] = +numeric_limits::infinity(); #endif // !defined(_M_FP_FAST) - - test_min_max_element_floating_with_values(gen, input_of_input); + return result; } template @@ -91,14 +91,42 @@ void test_min_max_element_floating_zero_predef() { template void test_min_max_element_floating(mt19937_64& gen) { - test_min_max_element_floating_any(gen); + test_min_max_element_floating_with_values(gen, test_floating_input(gen)); test_min_max_element_floating_zero(gen); test_min_max_element_floating_zero_predef(); } +template +void test_is_sorted_until_floating_with_values(mt19937_64& gen, const vector& input_of_input) { + uniform_int_distribution idx_dis(0, input_of_input.size() - 1); + + vector original_input; + vector input; + original_input.reserve(dataCount); + input.reserve(dataCount); + + test_case_is_sorted_until(input, less<>{}); + test_case_is_sorted_until(input, greater<>{}); + + for (size_t attempts = 0; attempts < dataCount; ++attempts) { + original_input.push_back(input_of_input[idx_dis(gen)]); + input = original_input; + + auto it = input.begin() + uniform_int_distribution{0, static_cast(input.size() - 1)}(gen); + sort(input.begin(), it, less<>{}); + + test_case_is_sorted_until(input, less<>{}); + reverse(input.begin(), it); + test_case_is_sorted_until(input, greater<>{}); + } +} + void test_vector_algorithms(mt19937_64& gen) { test_min_max_element_floating(gen); test_min_max_element_floating(gen); + + test_is_sorted_until_floating_with_values(gen, test_floating_input(gen)); + test_is_sorted_until_floating_with_values(gen, test_floating_input(gen)); } int main() { From e3808010aa97c265493c95a825887469c74e1ab3 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 12 Apr 2025 18:36:18 +0300 Subject: [PATCH 02/26] benchmark --- benchmarks/CMakeLists.txt | 1 + benchmarks/inc/utility.hpp | 6 +-- benchmarks/src/is_sorted_until.cpp | 62 ++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 benchmarks/src/is_sorted_until.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 10cc525b8be..9355108bf90 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -106,6 +106,7 @@ add_benchmark(find_and_count src/find_and_count.cpp) add_benchmark(find_first_of src/find_first_of.cpp) add_benchmark(has_single_bit src/has_single_bit.cpp) add_benchmark(iota src/iota.cpp) +add_benchmark(is_sorted_until src/is_sorted_until.cpp) add_benchmark(locale_classic src/locale_classic.cpp) add_benchmark(minmax_element src/minmax_element.cpp) add_benchmark(mismatch src/mismatch.cpp) diff --git a/benchmarks/inc/utility.hpp b/benchmarks/inc/utility.hpp index eacb3fc6d36..746da69dba0 100644 --- a/benchmarks/inc/utility.hpp +++ b/benchmarks/inc/utility.hpp @@ -8,11 +8,11 @@ #include #include -template -std::vector random_vector(size_t n) { +template class Alloc = std::allocator> +std::vector> random_vector(size_t n) { std::mt19937_64 prng; - std::vector res(n); + std::vector> res(n); // Here, the type Contained can be char, int, aggregate, or non_trivial where Data is char or int. // (aggregate and non_trivial are defined in udt.hpp.) diff --git a/benchmarks/src/is_sorted_until.cpp b/benchmarks/src/is_sorted_until.cpp new file mode 100644 index 00000000000..29ce55a38fb --- /dev/null +++ b/benchmarks/src/is_sorted_until.cpp @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "utility.hpp" + +enum class AlgType { Std, Rng }; + +template +void bm(benchmark::State& state) { + const std::size_t size = static_cast(state.range(0)); + const std::size_t sort_pos = static_cast(state.range(1)); + + std::vector> v; + if constexpr (std::is_integral_v) { + v = random_vector(size); + } else if constexpr (std::is_floating_point_v) { + v.resize(size, 0.0); + std::mt19937 gen; + std::normal_distribution dis(0, 100000.0); + std::generate_n(v.begin(), size, [&dis, &gen] { return dis(gen); }); + } else { + static_assert(false); + } + + std::sort(v.begin(), v.begin() + sort_pos); + + for (auto _ : state) { + benchmark::DoNotOptimize(v); + if constexpr (Alg == AlgType::Std) { + benchmark::DoNotOptimize(std::is_sorted_until(v.begin(), v.end())); + } else { + benchmark::DoNotOptimize(std::ranges::is_sorted_until(v)); + } + } +} + +void common_args(auto bm) { + bm->ArgPair(3000, 1800); +} + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK_MAIN(); From ca3eb923d4ee90a5de0e8f5f0c03b2903dd80f18 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 19 Apr 2025 08:46:10 +0300 Subject: [PATCH 03/26] Split out predicate check from other minmax checks and add greater predicate --- stl/inc/xutility | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index a7f8b8e4e14..e1102c93671 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6981,24 +6981,37 @@ namespace ranges { } // namespace ranges #endif // _HAS_CXX20 -template > -constexpr bool _Is_min_max_optimization_safe = // Activate the vector algorithms for min_/max_element? +template > +constexpr bool _Is_min_max_iterators_safe = _Iterator_is_contiguous<_Iter> // The iterator must be contiguous so we can get raw pointers. && !_Iterator_is_volatile<_Iter> // The iterator must not be volatile. - && conjunction_v, is_same<_Elem, double>, + is_same<_Elem, float>, is_same<_Elem, double>, #else // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) / 64-bit long double vvv - is_floating_point<_Elem>, // Element is floating-point or... + is_floating_point<_Elem>, // Element is floating-point or... #endif // ^^^ 64-bit long double ^^^ #endif // _USE_STD_VECTOR_FLOATING_ALGORITHMS - is_integral<_Elem>, is_pointer<_Elem>>, // ... integral or pointer type. - disjunction< // And either of the following: + is_integral<_Elem>, is_pointer<_Elem>>; // ... integral or pointer type. + +template +constexpr bool _Is_predicate_less = disjunction_v< +#if _HAS_CXX20 + is_same<_Pr, _RANGES less>, // predicate is ranges::less +#endif // _HAS_CXX20 + is_same<_Pr, less<>>, is_same<_Pr, less<_Iter_value_t<_Iter>>>>; // predicate is less + +template +constexpr bool _Is_predicate_greater = disjunction_v< #if _HAS_CXX20 - is_same<_Pr, _RANGES less>, // predicate is ranges::less + is_same<_Pr, _RANGES greater>, // predicate is ranges::greater #endif // _HAS_CXX20 - is_same<_Pr, less<>>, is_same<_Pr, less<_Elem>>>>; // predicate is less + is_same<_Pr, greater<>>, is_same<_Pr, greater<_Iter_value_t<_Iter>>>>; // predicate is greater + +template +constexpr bool _Is_min_max_optimization_safe = // Activate the vector algorithms for min_/max_element? + _Is_min_max_iterators_safe<_Iter> && _Is_predicate_less<_Iter, _Pr>; // Unlike the position-based vectorized implementation, the value-based vectorized implementation // does not always produce the expected results for floating-point types. @@ -7016,7 +7029,7 @@ constexpr bool _Is_min_max_value_optimization_safe = // Activate the vector algo #ifndef _M_FP_FAST !is_floating_point_v<_Elem> && #endif // ^^^ !defined(_M_FP_FAST) ^^^ - _Is_min_max_optimization_safe<_Iter, _Pr, _Elem>; + _Is_min_max_optimization_safe<_Iter, _Pr>; template constexpr _FwdIt _Max_element_unchecked(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find largest element From 54a44517d526b7b92e9c0459e57bbd5834b13fdf Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 19 Apr 2025 13:33:55 +0300 Subject: [PATCH 04/26] Signed benchmark --- benchmarks/src/is_sorted_until.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/benchmarks/src/is_sorted_until.cpp b/benchmarks/src/is_sorted_until.cpp index 29ce55a38fb..8d11ca3ac9f 100644 --- a/benchmarks/src/is_sorted_until.cpp +++ b/benchmarks/src/is_sorted_until.cpp @@ -45,6 +45,15 @@ void common_args(auto bm) { bm->ArgPair(3000, 1800); } +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); From d0c37204951e7c9f6e2a18f8d658f1ea8b2b45c1 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 19 Apr 2025 14:08:46 +0300 Subject: [PATCH 05/26] Unbias distribution --- tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp index b4f7c4c7c47..b7120f6d032 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp @@ -27,7 +27,7 @@ void test_min_max_element_floating_with_values(mt19937_64& gen, const vector& template vector test_floating_input(mt19937_64& gen) { - normal_distribution dis(-100000.0, 100000.0); + normal_distribution dis(0, 100000.0); constexpr auto input_of_input_size = dataCount / 2; vector result(input_of_input_size); From be4fb5ce4e32cb48e6429891cf7a03107f67bde4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 19 Apr 2025 14:09:07 +0300 Subject: [PATCH 06/26] vectorization! --- stl/inc/algorithm | 96 +++++++++++++++++++++ stl/src/vector_algorithms.cpp | 157 +++++++++++++++++++++++++++++++++- 2 files changed, 252 insertions(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index bfeed4d3cf1..7c54223aad5 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -74,6 +74,17 @@ __declspec(noalias) _Min_max_8u __stdcall __std_minmax_8u(const void* _First, co __declspec(noalias) _Min_max_f __stdcall __std_minmax_f(const void* _First, const void* _Last) noexcept; __declspec(noalias) _Min_max_d __stdcall __std_minmax_d(const void* _First, const void* _Last) noexcept; +const void* __stdcall __std_is_sorted_until_1i(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_1u(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_2i(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_2u(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_4i(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_4u(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_8i(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_8u(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_f(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_d(const void* _First, const void* _Last, const bool _Greater) noexcept; + // TRANSITION, DevCom-10610477 __declspec(noalias) void __stdcall __std_replace_4( void* _First, void* _Last, uint32_t _Old_val, uint32_t _New_val) noexcept; @@ -192,6 +203,49 @@ auto _Minmax_vectorized(_Ty* const _First, _Ty* const _Last) noexcept { } } +template +_Ty* _Is_sorted_until(_Ty* const _First, _Ty* const _Last, const bool _Greater) noexcept { + constexpr bool _Signed = is_signed_v<_Ty>; + + if constexpr (is_pointer_v<_Ty>) { +#ifdef _WIN64 + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_8u(_First, _Last, _Greater))); +#else + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_4u(_First, _Last, _Greater))); +#endif + } else if constexpr (is_same_v, float>) { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_f(_First, _Last, _Greater))); + } else if constexpr (_Is_any_of_v, double, long double>) { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_d(_First, _Last, _Greater))); + } else if constexpr (sizeof(_Ty) == 1) { + if constexpr (_Signed) { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_1i(_First, _Last, _Greater))); + } else { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_1u(_First, _Last, _Greater))); + } + } else if constexpr (sizeof(_Ty) == 2) { + if constexpr (_Signed) { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_2i(_First, _Last, _Greater))); + } else { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_2u(_First, _Last, _Greater))); + } + } else if constexpr (sizeof(_Ty) == 4) { + if constexpr (_Signed) { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_4i(_First, _Last, _Greater))); + } else { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_4u(_First, _Last, _Greater))); + } + } else if constexpr (sizeof(_Ty) == 8) { + if constexpr (_Signed) { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_8i(_First, _Last, _Greater))); + } else { + return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_8u(_First, _Last, _Greater))); + } + } else { + _STL_INTERNAL_STATIC_ASSERT(false); // unexpected size + } +} + template __declspec(noalias) void _Replace_vectorized( _Ty* const _First, _Ty* const _Last, const _TVal1 _Old_val, const _TVal2 _New_val) noexcept { @@ -8040,6 +8094,26 @@ namespace ranges { return _First; } +#if _USE_STD_VECTOR_ALGORITHMS + if constexpr (_Is_min_max_iterators_safe<_It> && sized_sentinel_for<_Se, _It> && is_same_v<_Pj, identity>) { + constexpr bool _Is_greater = _Is_predicate_greater<_It, _Pr>; + if constexpr (_Is_greater || _Is_predicate_less<_It, _Pr>) { + if (!_STD _Is_constant_evaluated()) { + const auto _First_ptr = _STD _To_address(_First); + const auto _Last_ptr = _First_ptr + (_Last - _First); + const auto _Result = _STD _Is_sorted_until(_First_ptr, _Last_ptr, _Is_greater); + + if constexpr (is_pointer_v<_It>) { + return _Result; + } else { + _First += _Result - _First_ptr; + return _First; + } + } + } + } +#endif + for (auto _Prev = _First; ++_First != _Last; ++_Prev) { if (_STD invoke(_Pred, _STD invoke(_Proj, *_First), _STD invoke(_Proj, *_Prev))) { break; @@ -10908,6 +10982,28 @@ _NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last _STD _Adl_verify_range(_First, _Last); auto _UFirst = _STD _Get_unwrapped(_First); auto _ULast = _STD _Get_unwrapped(_Last); + +#if _USE_STD_VECTOR_ALGORITHMS + if constexpr (_Is_min_max_iterators_safe) { + constexpr bool _Is_greater = _Is_predicate_greater; + if constexpr (_Is_greater || _Is_predicate_less) { + if (!_STD _Is_constant_evaluated()) { + const auto _First_ptr = _STD _To_address(_UFirst); + const auto _Result = _STD _Is_sorted_until(_First_ptr, _STD _To_address(_ULast), _Is_greater); + + if constexpr (is_pointer_v) { + _UFirst = _Result; + } else { + _UFirst += _Result - _First_ptr; + } + + _STD _Seek_wrapped(_Last, _UFirst); + return _Last; + } + } + } +#endif + if (_UFirst != _ULast) { for (auto _UNext = _UFirst; ++_UNext != _ULast; ++_UFirst) { if (_DEBUG_LT_PRED(_Pred, *_UNext, *_UFirst)) { diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 5f5584257e7..aa6b32a6c77 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -543,7 +543,8 @@ namespace { template struct _Minmax_traits_scalar : _Base { - static constexpr bool _Vectorized = false; + static constexpr bool _Vectorized = false; + static constexpr size_t _Tail_mask = 0; }; #ifndef _M_ARM64EC @@ -2249,6 +2250,110 @@ namespace { #endif // ^^^ !defined(_M_ARM64EC) ^^^ return __std_minmax_impl<_Mode, typename _Traits::_Scalar, _Sign>(_First, _Last); } + + + template + const void* __std_is_sorted_until_impl(const void* _First, const void* const _Last, const bool _Greater) noexcept { + const ptrdiff_t _Left_off = 0 - static_cast(_Greater); + const ptrdiff_t _Right_off = static_cast(_Greater) - 1; + + if constexpr (_Traits::_Vectorized) { +#ifndef _M_ARM64EC + constexpr bool _Sign_cor = static_cast<_Ty>(-1) > _Ty{0}; + + const size_t _Total_size_bytes = _Byte_length(_First, _Last); + const size_t _Vec_byte_size = _Total_size_bytes & ~_Traits::_Vec_mask; + + const void* _Stop_at = _First; + _Advance_bytes(_Stop_at, _Vec_byte_size); + + do { + auto _Left = _Traits::_Load(static_cast(_First) + _Left_off); + auto _Right = _Traits::_Load(static_cast(_First) + _Right_off); + + if constexpr (_Sign_cor) { + _Left = _Traits::_Sign_correction(_Left, false); + _Right = _Traits::_Sign_correction(_Right, false); + } + + const auto _Is_less = _Traits::_Cmp_gt(_Right, _Left); + unsigned long _Mask = _Traits::_Mask(_Traits::_Mask_cast(_Is_less)); + + if (_Mask != 0) { + unsigned long _H_pos; + + // CodeQL [SM02313] _H_pos is always initialized: element exists, so _Mask is non-zero. + _BitScanForward(&_H_pos, _Mask); + _Advance_bytes(_First, _H_pos); + return _First; + } + + _Advance_bytes(_First, _Traits::_Vec_size); + } while (_First != _Stop_at); + + if constexpr (_Traits::_Tail_mask != 0) { + const size_t _Tail_byte_size = _Total_size_bytes & _Traits::_Tail_mask; + if (_Tail_byte_size != 0) { + const auto _Tail_mask = _Avx2_tail_mask_32(_Tail_byte_size >> 2); + + auto _Left = _Traits::_Load_mask(static_cast(_First) + _Left_off, _Tail_mask); + auto _Right = _Traits::_Load_mask(static_cast(_First) + _Right_off, _Tail_mask); + + if constexpr (_Sign_cor) { + _Left = _Traits::_Sign_correction(_Left, false); + _Right = _Traits::_Sign_correction(_Right, false); + } + + const auto _Is_less = _Traits::_Cmp_gt(_Right, _Left); + unsigned long _Mask = _Traits::_Mask(_mm256_and_si256(_Traits::_Mask_cast(_Is_less), _Tail_mask)); + + if (_Mask != 0) { + unsigned long _H_pos; + + // CodeQL [SM02313] _H_pos is always initialized: element exists, so _Mask is non-zero. + _BitScanForward(&_H_pos, _Mask); + _Advance_bytes(_First, _H_pos); + return _First; + } + + _Advance_bytes(_First, _Tail_byte_size); + } + } + + _Traits::_Exit_vectorized(); // TRANSITION, DevCom-10331414 +#endif // ^^^ !defined(_M_ARM64EC) ^^^ + } + + if constexpr ((_Traits::_Tail_mask & sizeof(_Ty)) != sizeof(_Ty)) { + for (const _Ty* _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { + if (_Ptr[_Left_off] < _Ptr[_Right_off]) { + return _Ptr; + } + } + } + + return _Last; + } + + template + const void* __std_is_sorted_until_disp(const void* _First, const void* const _Last, const bool _Greater) noexcept { + if (_First == _Last) { + return _First; + } + + _Advance_bytes(_First, sizeof(_Ty)); + +#ifndef _M_ARM64EC + if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { + return __std_is_sorted_until_impl(_First, _Last, _Greater); + } + + if (_Byte_length(_First, _Last) >= 16 && _Use_sse42()) { + return __std_is_sorted_until_impl(_First, _Last, _Greater); + } +#endif // ^^^ !defined(_M_ARM64EC) ^^^ + return __std_is_sorted_until_impl(_First, _Last, _Greater); + } } // unnamed namespace extern "C" { @@ -2463,6 +2568,56 @@ __declspec(noalias) _Min_max_d __stdcall __std_minmax_d(const void* const _First return __std_minmax_disp<_Mode_both, _Minmax_traits_d, true>(_First, _Last); } +const void* __stdcall __std_is_sorted_until_1i( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_1, int8_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_1u( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_1, uint8_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_2i( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_2, int16_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_2u( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_2, uint16_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_4i( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_4, int32_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_4u( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_4, uint32_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_8i( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_8, int64_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_8u( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_8, uint64_t>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_f( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_f, float>(_First, _Last, _Greater); +} + +const void* __stdcall __std_is_sorted_until_d( + const void* const _First, const void* const _Last, const bool _Greater) noexcept { + return __std_is_sorted_until_disp<_Minmax_traits_d, double>(_First, _Last, _Greater); +} + } // extern "C" namespace { From 355b8f98eb804ee0c0f4b59b2113369172527b6b Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 19 Apr 2025 15:01:32 +0300 Subject: [PATCH 07/26] Make #2885 test pass --- stl/inc/algorithm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7c54223aad5..e84e3e89087 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -8100,14 +8100,13 @@ namespace ranges { if constexpr (_Is_greater || _Is_predicate_less<_It, _Pr>) { if (!_STD _Is_constant_evaluated()) { const auto _First_ptr = _STD _To_address(_First); - const auto _Last_ptr = _First_ptr + (_Last - _First); + const auto _Last_ptr = _First_ptr + static_cast(_Last - _First); const auto _Result = _STD _Is_sorted_until(_First_ptr, _Last_ptr, _Is_greater); if constexpr (is_pointer_v<_It>) { return _Result; } else { - _First += _Result - _First_ptr; - return _First; + return _First + static_cast>(_Result - _First_ptr); } } } From 610af8febd28fc863193a10ffbe80a3617c8ff32 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 20 Apr 2025 10:33:42 +0300 Subject: [PATCH 08/26] more concise predicate check --- stl/inc/xutility | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index e1102c93671..b924f420c0e 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6996,18 +6996,18 @@ constexpr bool _Is_min_max_iterators_safe = is_integral<_Elem>, is_pointer<_Elem>>; // ... integral or pointer type. template -constexpr bool _Is_predicate_less = disjunction_v< +constexpr bool _Is_predicate_less = _Is_any_of_v<_Pr, #if _HAS_CXX20 - is_same<_Pr, _RANGES less>, // predicate is ranges::less + _RANGES less, #endif // _HAS_CXX20 - is_same<_Pr, less<>>, is_same<_Pr, less<_Iter_value_t<_Iter>>>>; // predicate is less + less<>, less<_Iter_value_t<_Iter>>>; template -constexpr bool _Is_predicate_greater = disjunction_v< +constexpr bool _Is_predicate_greater = _Is_any_of_v<_Pr, #if _HAS_CXX20 - is_same<_Pr, _RANGES greater>, // predicate is ranges::greater + _RANGES greater, #endif // _HAS_CXX20 - is_same<_Pr, greater<>>, is_same<_Pr, greater<_Iter_value_t<_Iter>>>>; // predicate is greater + greater<>, greater<_Iter_value_t<_Iter>>>; template constexpr bool _Is_min_max_optimization_safe = // Activate the vector algorithms for min_/max_element? From 09e1fc04c719fe2767937550ab510d10e14a58c3 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 20 Apr 2025 17:59:53 +0300 Subject: [PATCH 09/26] cast here too --- stl/inc/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index e84e3e89087..cb764e45cdb 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10993,7 +10993,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last if constexpr (is_pointer_v) { _UFirst = _Result; } else { - _UFirst += _Result - _First_ptr; + _UFirst += static_cast>(_Result - _First_ptr); } _STD _Seek_wrapped(_Last, _UFirst); From 715a4ca8bbfb0f7fd21737e8eca3241ae49ab715 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 20 Apr 2025 18:23:50 +0300 Subject: [PATCH 10/26] cast here to correct type --- stl/inc/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index cb764e45cdb..6efb6963195 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10993,7 +10993,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last if constexpr (is_pointer_v) { _UFirst = _Result; } else { - _UFirst += static_cast>(_Result - _First_ptr); + _UFirst += static_cast<_Iter_diff_t>(_Result - _First_ptr); } _STD _Seek_wrapped(_Last, _UFirst); From 08e2f9ffc8723cd2f500143e209719c023a7b8b4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:00:02 +0300 Subject: [PATCH 11/26] Meow. Vectorized. --- stl/inc/algorithm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 6efb6963195..c0e67cc80d2 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -204,7 +204,7 @@ auto _Minmax_vectorized(_Ty* const _First, _Ty* const _Last) noexcept { } template -_Ty* _Is_sorted_until(_Ty* const _First, _Ty* const _Last, const bool _Greater) noexcept { +_Ty* _Is_sorted_until_vectorized(_Ty* const _First, _Ty* const _Last, const bool _Greater) noexcept { constexpr bool _Signed = is_signed_v<_Ty>; if constexpr (is_pointer_v<_Ty>) { @@ -8101,7 +8101,7 @@ namespace ranges { if (!_STD _Is_constant_evaluated()) { const auto _First_ptr = _STD _To_address(_First); const auto _Last_ptr = _First_ptr + static_cast(_Last - _First); - const auto _Result = _STD _Is_sorted_until(_First_ptr, _Last_ptr, _Is_greater); + const auto _Result = _STD _Is_sorted_until_vectorized(_First_ptr, _Last_ptr, _Is_greater); if constexpr (is_pointer_v<_It>) { return _Result; @@ -10988,7 +10988,8 @@ _NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last if constexpr (_Is_greater || _Is_predicate_less) { if (!_STD _Is_constant_evaluated()) { const auto _First_ptr = _STD _To_address(_UFirst); - const auto _Result = _STD _Is_sorted_until(_First_ptr, _STD _To_address(_ULast), _Is_greater); + const auto _Result = + _STD _Is_sorted_until_vectorized(_First_ptr, _STD _To_address(_ULast), _Is_greater); if constexpr (is_pointer_v) { _UFirst = _Result; From b95b7350f7a9e1482a0bc1f194ea953eae75046f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:03:17 +0300 Subject: [PATCH 12/26] consistent std --- benchmarks/src/is_sorted_until.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/src/is_sorted_until.cpp b/benchmarks/src/is_sorted_until.cpp index 8d11ca3ac9f..ce2cb59f4fc 100644 --- a/benchmarks/src/is_sorted_until.cpp +++ b/benchmarks/src/is_sorted_until.cpp @@ -14,8 +14,8 @@ enum class AlgType { Std, Rng }; template void bm(benchmark::State& state) { - const std::size_t size = static_cast(state.range(0)); - const std::size_t sort_pos = static_cast(state.range(1)); + const std::size_t size = static_cast(state.range(0)); + const std::size_t sort_pos = static_cast(state.range(1)); std::vector> v; if constexpr (std::is_integral_v) { From 44917c0b18daa8dfc2027e0a87741bcc1f2cd63e Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:04:06 +0300 Subject: [PATCH 13/26] includes --- benchmarks/src/is_sorted_until.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benchmarks/src/is_sorted_until.cpp b/benchmarks/src/is_sorted_until.cpp index ce2cb59f4fc..f84b2c9ca70 100644 --- a/benchmarks/src/is_sorted_until.cpp +++ b/benchmarks/src/is_sorted_until.cpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include #include "skewed_allocator.hpp" From 26434950fa8727495f8833c8c4d636453b2d7724 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:05:05 +0300 Subject: [PATCH 14/26] Avoid shadowing --- benchmarks/src/is_sorted_until.cpp | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/benchmarks/src/is_sorted_until.cpp b/benchmarks/src/is_sorted_until.cpp index f84b2c9ca70..e06c3e9c8b1 100644 --- a/benchmarks/src/is_sorted_until.cpp +++ b/benchmarks/src/is_sorted_until.cpp @@ -47,27 +47,27 @@ void common_args(auto bm) { bm->ArgPair(3000, 1800); } -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); BENCHMARK_MAIN(); From c95cc06d3863063a8752d25e3395ef32d39995ec Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:06:04 +0300 Subject: [PATCH 15/26] drop top level const on declarations --- stl/inc/algorithm | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index c0e67cc80d2..ee60403cf4e 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -74,16 +74,16 @@ __declspec(noalias) _Min_max_8u __stdcall __std_minmax_8u(const void* _First, co __declspec(noalias) _Min_max_f __stdcall __std_minmax_f(const void* _First, const void* _Last) noexcept; __declspec(noalias) _Min_max_d __stdcall __std_minmax_d(const void* _First, const void* _Last) noexcept; -const void* __stdcall __std_is_sorted_until_1i(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_1u(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_2i(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_2u(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_4i(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_4u(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_8i(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_8u(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_f(const void* _First, const void* _Last, const bool _Greater) noexcept; -const void* __stdcall __std_is_sorted_until_d(const void* _First, const void* _Last, const bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_1i(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_1u(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_2i(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_2u(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_4i(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_4u(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_8i(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_8u(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_f(const void* _First, const void* _Last, bool _Greater) noexcept; +const void* __stdcall __std_is_sorted_until_d(const void* _First, const void* _Last, bool _Greater) noexcept; // TRANSITION, DevCom-10610477 __declspec(noalias) void __stdcall __std_replace_4( From e0143d62b4730d6d6599a7f899bf8219458c4521 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:06:56 +0300 Subject: [PATCH 16/26] Pointers are just unsigned integers --- stl/inc/algorithm | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index ee60403cf4e..f87838ff69c 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -207,13 +207,7 @@ template _Ty* _Is_sorted_until_vectorized(_Ty* const _First, _Ty* const _Last, const bool _Greater) noexcept { constexpr bool _Signed = is_signed_v<_Ty>; - if constexpr (is_pointer_v<_Ty>) { -#ifdef _WIN64 - return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_8u(_First, _Last, _Greater))); -#else - return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_4u(_First, _Last, _Greater))); -#endif - } else if constexpr (is_same_v, float>) { + if constexpr (is_same_v, float>) { return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_f(_First, _Last, _Greater))); } else if constexpr (_Is_any_of_v, double, long double>) { return const_cast<_Ty*>(static_cast(::__std_is_sorted_until_d(_First, _Last, _Greater))); From a48cc6915b90739bc5db4ebaf51c9f7b69c7e03b Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:08:01 +0300 Subject: [PATCH 17/26] Preprocessor comments --- stl/inc/algorithm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index f87838ff69c..255e47880a2 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -8105,7 +8105,7 @@ namespace ranges { } } } -#endif +#endif // _USE_STD_VECTOR_ALGORITHMS for (auto _Prev = _First; ++_First != _Last; ++_Prev) { if (_STD invoke(_Pred, _STD invoke(_Proj, *_First), _STD invoke(_Proj, *_Prev))) { @@ -10996,7 +10996,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last } } } -#endif +#endif // _USE_STD_VECTOR_ALGORITHMS if (_UFirst != _ULast) { for (auto _UNext = _UFirst; ++_UNext != _ULast; ++_UFirst) { From b37d6a2998cfc19c6732cecec9e2c43422dbf4fe Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:08:49 +0300 Subject: [PATCH 18/26] C++20 --- stl/inc/algorithm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 255e47880a2..c07bda4ee7a 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -8092,7 +8092,7 @@ namespace ranges { if constexpr (_Is_min_max_iterators_safe<_It> && sized_sentinel_for<_Se, _It> && is_same_v<_Pj, identity>) { constexpr bool _Is_greater = _Is_predicate_greater<_It, _Pr>; if constexpr (_Is_greater || _Is_predicate_less<_It, _Pr>) { - if (!_STD _Is_constant_evaluated()) { + if (!_STD is_constant_evaluated()) { const auto _First_ptr = _STD _To_address(_First); const auto _Last_ptr = _First_ptr + static_cast(_Last - _First); const auto _Result = _STD _Is_sorted_until_vectorized(_First_ptr, _Last_ptr, _Is_greater); From 9a4d5287ca3683823fd9a16e781c149ea49a7993 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:11:21 +0300 Subject: [PATCH 19/26] unexpect Arm --- stl/src/vector_algorithms.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index aa6b32a6c77..b8f4ecf66e4 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -2258,7 +2258,9 @@ namespace { const ptrdiff_t _Right_off = static_cast(_Greater) - 1; if constexpr (_Traits::_Vectorized) { -#ifndef _M_ARM64EC +#ifdef _M_ARM64EC + static_assert(false, "No vectorization for _M_ARM64EC yet"); +#else // ^^^ defined(_M_ARM64EC) / !defined(_M_ARM64EC) vvv constexpr bool _Sign_cor = static_cast<_Ty>(-1) > _Ty{0}; const size_t _Total_size_bytes = _Byte_length(_First, _Last); From 516f8c0666b5c629ec5f6987306ab31d106509bc Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:15:03 +0300 Subject: [PATCH 20/26] includes --- tests/std/include/test_is_sorted_until_support.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/std/include/test_is_sorted_until_support.hpp b/tests/std/include/test_is_sorted_until_support.hpp index 29c70a2e328..d07c6e32473 100644 --- a/tests/std/include/test_is_sorted_until_support.hpp +++ b/tests/std/include/test_is_sorted_until_support.hpp @@ -5,16 +5,8 @@ #include #include -#include -#include -#include -#include #include -#if _HAS_CXX20 -#include -#endif - template FwdIt last_known_good_is_sorted_until(FwdIt first, FwdIt last, Comp comp) { if (first == last) { From 606f263031ca4ec111467d7b18aa2fe88d62dbed Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:20:27 +0300 Subject: [PATCH 21/26] named distribution --- tests/std/tests/VSO_0000000_vector_algorithms/test.cpp | 3 ++- tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 50645e4e42e..2cb675db006 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -620,7 +620,8 @@ void test_is_sorted_until(mt19937_64& gen) { original_input.push_back(static_cast(dis(gen))); input = original_input; - auto it = input.begin() + uniform_int_distribution{0, static_cast(input.size() - 1)}(gen); + uniform_int_distribution pos_dis{0, static_cast(input.size() - 1)}; + auto it = input.begin() + pos_dis(gen); sort(input.begin(), it, less<>{}); test_case_is_sorted_until(input, less<>{}); diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp index b7120f6d032..9e560c23239 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp @@ -112,7 +112,8 @@ void test_is_sorted_until_floating_with_values(mt19937_64& gen, const vector& original_input.push_back(input_of_input[idx_dis(gen)]); input = original_input; - auto it = input.begin() + uniform_int_distribution{0, static_cast(input.size() - 1)}(gen); + uniform_int_distribution pos_dis{0, static_cast(input.size() - 1)}; + auto it = input.begin() + pos_dis(gen); sort(input.begin(), it, less<>{}); test_case_is_sorted_until(input, less<>{}); From aff7b41a602d3e3c0ae7b8ec8a7d42d26c37c45a Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:22:46 +0300 Subject: [PATCH 22/26] rename benchmark function itself --- benchmarks/src/is_sorted_until.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/src/is_sorted_until.cpp b/benchmarks/src/is_sorted_until.cpp index e06c3e9c8b1..a70cc01b487 100644 --- a/benchmarks/src/is_sorted_until.cpp +++ b/benchmarks/src/is_sorted_until.cpp @@ -15,7 +15,7 @@ enum class AlgType { Std, Rng }; template -void bm(benchmark::State& state) { +void bm_is_sorted_until(benchmark::State& state) { const std::size_t size = static_cast(state.range(0)); const std::size_t sort_pos = static_cast(state.range(1)); From 896ced293a28393896f8c0ff99a30ed0bc9069e7 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Tue, 22 Apr 2025 16:24:00 +0300 Subject: [PATCH 23/26] includes --- tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp index 9e560c23239..ba8f7e80277 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_floats/test.cpp @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include +#include #include #include #include From 61fde12d9bad6c2caaa5368ae99950e0b36e1d19 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 22 Apr 2025 21:02:09 -0700 Subject: [PATCH 24/26] `` for `allocator`. --- benchmarks/inc/utility.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/inc/utility.hpp b/benchmarks/inc/utility.hpp index 746da69dba0..032e8f9a9b9 100644 --- a/benchmarks/inc/utility.hpp +++ b/benchmarks/inc/utility.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include From 1f4661dba3a1415c96e1241102d41804ce53dcb3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 22 Apr 2025 21:53:45 -0700 Subject: [PATCH 25/26] Adjust CodeQL suppression reasons. --- stl/src/vector_algorithms.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 15090cb1627..c8135245050 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -2284,7 +2284,7 @@ namespace { if (_Mask != 0) { unsigned long _H_pos; - // CodeQL [SM02313] _H_pos is always initialized: element exists, so _Mask is non-zero. + // CodeQL [SM02313] _H_pos is always initialized: we just tested `if (_Mask != 0)`. _BitScanForward(&_H_pos, _Mask); _Advance_bytes(_First, _H_pos); return _First; @@ -2312,7 +2312,7 @@ namespace { if (_Mask != 0) { unsigned long _H_pos; - // CodeQL [SM02313] _H_pos is always initialized: element exists, so _Mask is non-zero. + // CodeQL [SM02313] _H_pos is always initialized: we just tested `if (_Mask != 0)`. _BitScanForward(&_H_pos, _Mask); _Advance_bytes(_First, _H_pos); return _First; From 2d1385e7f886a52abdac0c2f8a55d67e48731022 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 22 Apr 2025 22:06:18 -0700 Subject: [PATCH 26/26] Pass `input` as a single range to `std::ranges::is_sorted_until`. --- tests/std/include/test_is_sorted_until_support.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/include/test_is_sorted_until_support.hpp b/tests/std/include/test_is_sorted_until_support.hpp index d07c6e32473..32eb2b455de 100644 --- a/tests/std/include/test_is_sorted_until_support.hpp +++ b/tests/std/include/test_is_sorted_until_support.hpp @@ -29,7 +29,7 @@ void test_case_is_sorted_until(const std::vector& input, Comp comp) { auto actual = std::is_sorted_until(input.begin(), input.end(), comp); assert(expected == actual); #if _HAS_CXX20 - auto actual_r = std::ranges::is_sorted_until(input.begin(), input.end(), comp); + auto actual_r = std::ranges::is_sorted_until(input, comp); assert(expected == actual_r); #endif // _HAS_CXX20 }