diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index aedb0d57bd3..3db46dab651 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -107,6 +107,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..032e8f9a9b9 100644 --- a/benchmarks/inc/utility.hpp +++ b/benchmarks/inc/utility.hpp @@ -5,14 +5,15 @@ #include #include +#include #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..a70cc01b487 --- /dev/null +++ b/benchmarks/src/is_sorted_until.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "utility.hpp" + +enum class AlgType { Std, Rng }; + +template +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)); + + 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_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_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_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(); diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 5da863e79a1..4203359dffb 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, 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( void* _First, void* _Last, uint32_t _Old_val, uint32_t _New_val) noexcept; @@ -207,6 +218,43 @@ auto _Minmax_vectorized(_Ty* const _First, _Ty* const _Last) noexcept { } } +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_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 { @@ -8284,6 +8332,25 @@ 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 + static_cast(_Last - _First); + const auto _Result = _STD _Is_sorted_until_vectorized(_First_ptr, _Last_ptr, _Is_greater); + + if constexpr (is_pointer_v<_It>) { + return _Result; + } else { + return _First + static_cast>(_Result - _First_ptr); + } + } + } + } +#endif // _USE_STD_VECTOR_ALGORITHMS + for (auto _Prev = _First; ++_First != _Last; ++_Prev) { if (_STD invoke(_Pred, _STD invoke(_Proj, *_First), _STD invoke(_Proj, *_Prev))) { break; @@ -11152,6 +11219,29 @@ _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_vectorized(_First_ptr, _STD _To_address(_ULast), _Is_greater); + + if constexpr (is_pointer_v) { + _UFirst = _Result; + } else { + _UFirst += static_cast<_Iter_diff_t>(_Result - _First_ptr); + } + + _STD _Seek_wrapped(_Last, _UFirst); + return _Last; + } + } + } +#endif // _USE_STD_VECTOR_ALGORITHMS + if (_UFirst != _ULast) { for (auto _UNext = _UFirst; ++_UNext != _ULast; ++_UFirst) { if (_DEBUG_LT_PRED(_Pred, *_UNext, *_UFirst)) { diff --git a/stl/inc/xutility b/stl/inc/xutility index 3c68eab5f4e..1cbbc5a817f 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 = _Is_any_of_v<_Pr, +#if _HAS_CXX20 + _RANGES less, +#endif // _HAS_CXX20 + less<>, less<_Iter_value_t<_Iter>>>; + +template +constexpr bool _Is_predicate_greater = _Is_any_of_v<_Pr, #if _HAS_CXX20 - is_same<_Pr, _RANGES less>, // predicate is ranges::less + _RANGES greater, #endif // _HAS_CXX20 - is_same<_Pr, less<>>, is_same<_Pr, less<_Elem>>>>; // predicate is less + greater<>, greater<_Iter_value_t<_Iter>>>; + +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 diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 3a79345a1a9..c8135245050 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,112 @@ 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) { +#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); + 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: we just tested `if (_Mask != 0)`. + _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: we just tested `if (_Mask != 0)`. + _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 +2570,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 { 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..32eb2b455de --- /dev/null +++ b/tests/std/include/test_is_sorted_until_support.hpp @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include + +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, 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 3bbe63d8b7b..2aa4d361496 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,35 @@ 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; + + 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<>{}); + + 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) { @@ -1089,6 +1119,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 a5540f29972..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,11 +1,14 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include +#include #include #include #include +#include "test_is_sorted_until_support.hpp" #include "test_min_max_element_support.hpp" #include "test_vector_algorithms_support.hpp" @@ -25,24 +28,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(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 +93,43 @@ 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; + + 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<>{}); + 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() {