diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7ca53f3719d..c035796ec0e 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -179,13 +179,16 @@ namespace ranges { } }; - template _Se> + // clang-format off + template + requires sentinel_for, _Wrapped> _NODISCARD constexpr auto _Get_final_iterator_unwrapped(const _Unwrapped_t<_Wrapped>& _UFirst, _Se&& _Last) { + // clang-format on // find the iterator in [_UFirst, _Get_unwrapped(_Last)) which equals _Get_unwrapped(_Last) [possibly O(N)] - auto _ULast = _Get_unwrapped(_STD move(_Last)); - if constexpr (is_same_v<_Se, _Wrapped>) { + auto _ULast = _Get_unwrapped(_STD forward<_Se>(_Last)); + if constexpr (is_same_v, _Wrapped>) { return _ULast; - } else if constexpr (sized_sentinel_for<_Se, _Wrapped>) { + } else if constexpr (sized_sentinel_for, _Wrapped>) { return _RANGES next(_UFirst, _ULast - _UFirst); } else { return _RANGES next(_UFirst, _STD move(_ULast)); @@ -196,7 +199,11 @@ namespace ranges { _NODISCARD constexpr auto _Get_final_iterator_unwrapped(_Rng& _Range) { // find the (unwrapped) iterator in _Range which equals _Uend(_Range) [possibly O(N)] if constexpr (common_range<_Rng>) { - return _Uend(_Range); + if constexpr (same_as<_Unwrapped_t<_RANGES iterator_t<_Rng>>, decltype(_Uend(_Range))>) { + return _Uend(_Range); + } else { + return _Get_unwrapped(_RANGES end(_Range)); + } } else if constexpr (sized_range<_Rng>) { return _RANGES next(_Ubegin(_Range), _RANGES distance(_Range)); } else { @@ -4920,9 +4927,11 @@ template constexpr _FwdIt shift_left(_FwdIt _First, const _FwdIt _Last, _Iter_diff_t<_FwdIt> _Pos_to_shift) { // shift [_First, _Last) left by _Pos_to_shift // positions; returns the end of the resulting range + _STL_ASSERT(_Pos_to_shift >= 0, "shift count must be non-negative (N4910 [alg.shift]/1)"); + _Adl_verify_range(_First, _Last); - if (_Pos_to_shift <= 0) { + if (_Pos_to_shift == 0) { return _Last; } @@ -4959,9 +4968,11 @@ template constexpr _FwdIt shift_right(_FwdIt _First, const _FwdIt _Last, _Iter_diff_t<_FwdIt> _Pos_to_shift) { // shift [_First, _Last) right by _Pos_to_shift // positions; returns the beginning of the resulting range + _STL_ASSERT(_Pos_to_shift >= 0, "shift count must be non-negative (N4910 [alg.shift]/5)"); + _Adl_verify_range(_First, _Last); - if (_Pos_to_shift <= 0) { + if (_Pos_to_shift == 0) { return _First; } @@ -5035,6 +5046,236 @@ _FwdIt shift_right(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Iter_diff_t<_FwdIt> _P } #endif // _HAS_CXX20 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +namespace ranges { + class _Shift_left_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _Se> + constexpr subrange<_It> operator()(_It _First, const _Se _Last, iter_difference_t<_It> _Pos_to_shift) const { + _STL_ASSERT(_Pos_to_shift >= 0, "shift count must be non-negative (N4910 [alg.shift]/1)"); + + _Adl_verify_range(_First, _Last); + auto _Result = _First; + _Unwrapped_t<_It> _UResult; + + if (_Pos_to_shift == 0) { + _UResult = _Get_final_iterator_unwrapped<_It>(_Get_unwrapped(_Result), _Last); + } else { + _UResult = _Shift_left_impl(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pos_to_shift); + } + _Seek_wrapped(_Result, _UResult); + return {_STD move(_First), _STD move(_Result)}; + } + + template + requires permutable> + constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, range_difference_t<_Rng> _Pos_to_shift) const { + _STL_ASSERT(_Pos_to_shift >= 0, "shift count must be non-negative (N4910 [alg.shift]/1)"); + + if (_Pos_to_shift == 0) { + auto _Last = _Rewrap_iterator(_Range, _Get_final_iterator_unwrapped(_Range)); + return {_RANGES begin(_Range), _STD move(_Last)}; + } + + if constexpr (sized_range<_Rng>) { + auto _First = _RANGES begin(_Range); + if (_RANGES distance(_Range) <= _Pos_to_shift) { + return {_First, _First}; + } + + auto _UFirst = _Get_unwrapped(_First); + auto _Start_at = _RANGES next(_UFirst, _Pos_to_shift); + auto _Result = _RANGES _Move_unchecked(_STD move(_Start_at), _Uend(_Range), _UFirst).out; + return {_STD move(_First), _Rewrap_iterator(_Range, _STD move(_Result))}; + } else { + auto _Result = _Shift_left_impl(_Ubegin(_Range), _Uend(_Range), _Pos_to_shift); + return {_RANGES begin(_Range), _Rewrap_iterator(_Range, _STD move(_Result))}; + } + } + + private: + template + _NODISCARD static constexpr _It _Shift_left_impl(_It _First, _Se _Last, iter_difference_t<_It> _Pos_to_shift) { + _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_CHECK(_Pos_to_shift > 0); + + auto _Start_at = _First; + if (_RANGES advance(_Start_at, _Pos_to_shift, _Last) != 0) { + return _First; + } + + return _RANGES _Move_unchecked(_STD move(_Start_at), _STD move(_Last), _STD move(_First)).out; + } + }; + + inline constexpr _Shift_left_fn shift_left{_Not_quite_object::_Construct_tag{}}; + + class _Shift_right_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _Se> + constexpr subrange<_It> operator()(_It _First, const _Se _Last, iter_difference_t<_It> _Pos_to_shift) const { + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_First); + auto _ULast = _Get_unwrapped(_Last); + const auto _Size = _Size_helper(_UFirst, _ULast); + auto _Result = _Shift_right_impl(_STD move(_UFirst), _STD move(_ULast), _Pos_to_shift, _Size); + _Seek_wrapped(_First, _Result.begin()); + auto _Final = _First; + _Seek_wrapped(_Final, _Result.end()); + return {_STD move(_First), _STD move(_Final)}; + } + + template + requires permutable> + constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, range_difference_t<_Rng> _Pos_to_shift) const { + const auto _Size = _Size_helper(_Range); + auto _Result = _Shift_right_impl(_Ubegin(_Range), _Uend(_Range), _Pos_to_shift, _Size); + auto _First = _Rewrap_iterator(_Range, _Result.begin()); + auto _Final = _Rewrap_iterator(_Range, _Result.end()); + return {_STD move(_First), _STD move(_Final)}; + } + + private: + struct _Unsized {}; + + template + _NODISCARD static constexpr auto _Size_helper(_Rng&& _Range) { + if constexpr (sized_range<_Rng>) { + return _RANGES distance(_Range); + } else { + return _Unsized{}; + } + } + + template _Se> + _NODISCARD static constexpr auto _Size_helper(const _It& _First, const _Se& _Last) { + if constexpr (sized_sentinel_for<_Se, _It>) { + return _Last - _First; + } else { + return _Unsized{}; + } + } + + // clang-format off + template + requires indirectly_movable<_It, _Out> + _NODISCARD static constexpr _Out _Move_n_helper(_It _First, iter_difference_t<_It> _Count, _Out _Result) { + // clang-format on + for (; _Count > 0; ++_First, (void) --_Count, ++_Result) { + *_Result = _RANGES iter_move(_First); + } + + return _Result; + } + + template + _NODISCARD static constexpr subrange<_It> _Shift_right_impl( + _It _First, _Se _Last, iter_difference_t<_It> _Pos_to_shift, const _SizeTy _Size) { + _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_ASSERT(_Pos_to_shift >= 0, "shift count must be non-negative (N4910 [alg.shift]/5)"); + + if (_Pos_to_shift == 0) { + return {_First, _RANGES next(_First, _Last)}; + } + + constexpr bool _Is_sized = !same_as<_SizeTy, _Unsized>; + + if constexpr (_Is_sized) { + if (_Pos_to_shift >= _Size) { + if constexpr (same_as<_It, _Se>) { + return {_Last, _Last}; + } else if constexpr (random_access_iterator<_It>) { + _First += _Size; + return {_First, _First}; + } else { + _RANGES advance(_First, _Last); + return {_First, _First}; + } + } + } + + if constexpr (_Bidi_common<_It, _Se>) { + auto _Mid = _Last; + if constexpr (_Is_sized) { + // We validated above that the length of the range is more than _Pos_to_shift + _RANGES advance(_Mid, -_Pos_to_shift); + } else { + if (_RANGES advance(_Mid, -_Pos_to_shift, _First) != 0) { + return {_Last, _Last}; + } + } + return {_RANGES _Move_backward_common(_STD move(_First), _STD move(_Mid), _Last), _Last}; + } else if constexpr (_Is_sized && random_access_iterator<_It>) { + auto _Final = _First + _Size; + auto _Mid = _Final - _Pos_to_shift; + return {_RANGES _Move_backward_common(_STD move(_First), _STD move(_Mid), _Final), _Final}; + } else { + auto _Buf = _First; + if constexpr (_Is_sized) { + _RANGES advance(_Buf, _Pos_to_shift); + } else { + if (_RANGES advance(_Buf, _Pos_to_shift, _Last) != 0) { + return {_Buf, _Buf}; + } + } + + if constexpr (_Is_sized) { + if (_Size < 2 * _Pos_to_shift) { + return {_Buf, _Move_n_helper(_First, _Size - _Pos_to_shift, _Buf)}; + } + } + + auto _Lead = _Buf; + if constexpr (_Is_sized) { + // We validated above that the length of the range is at least 2 * _Pos_to_shift + _RANGES advance(_Lead, _Pos_to_shift); + } else { + if (auto _Rem = _RANGES advance(_Lead, _Pos_to_shift, _Last); _Rem != 0) { + return {_Buf, _Move_n_helper(_First, _Pos_to_shift - _Rem, _Buf)}; + } + } + + auto _Trail = _Buf; + + // The range is now partitioned like: + // + // | _Pos_to_shift elements | | _Pos_to_shift elements | + // |------------------------|-----------|------------------------|------------| + // ^_First _Buf^ _Trail^ _Lead^ _Last^ + // + // From now on, _Mid repeatedly cycles through the [_First, _Buf) window while the + // [_Trail, _Lead) window advances toward _Last. + + for (;;) { + for (auto _Mid = _First; _Mid != _Buf; ++_Mid, (void) ++_Trail, ++_Lead) { + if (_Lead == _Last) { + // The leading edge of the [_Trail, _Lead) window has hit the end of + // the range, so we have only the final _Pos_to_shift elements to process. + // Their original values are lost - shifted off the end of the range - + // so we only need to fill them with new values from [_First, _Buf). + _Trail = _RANGES _Move_unchecked(_Mid, _Buf, _STD move(_Trail)).out; + _Trail = _RANGES _Move_unchecked(_First, _Mid, _STD move(_Trail)).out; + _STL_INTERNAL_CHECK(_Trail == _Lead); + return {_STD move(_Buf), _STD move(_Trail)}; + } + + _RANGES iter_swap(_Mid, _Trail); + } + } + } + } + }; + + inline constexpr _Shift_right_fn shift_right{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + template _CONSTEXPR20 _FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { // move elements satisfying _Pred to beginning of sequence @@ -7736,7 +7977,6 @@ void stable_sort(_ExPo&& _Exec, _BidIt _First, _BidIt _Last) noexcept /* termina } #endif // _HAS_CXX17 - #ifdef __cpp_lib_concepts namespace ranges { class _Stable_sort_fn : private _Not_quite_object { diff --git a/stl/inc/numeric b/stl/inc/numeric index 44c62bda57b..43e3638012d 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -523,6 +523,50 @@ _CONSTEXPR20 void iota(_FwdIt _First, _FwdIt _Last, _Ty _Val) { } } +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +namespace ranges { + template + using iota_result = out_value_result<_Out, _Ty>; + + class _Iota_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _Se, weakly_incrementable _Ty> + requires indirectly_writable<_It, const _Ty&> + constexpr iota_result<_It, _Ty> operator()(_It _First, _Se _Last, _Ty _Val) const { + _Adl_verify_range(_First, _Last); + _Seek_wrapped( + _First, _Iota_impl(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val)); + return {_STD move(_First), _STD move(_Val)}; + } + + template _Rng> + constexpr iota_result, _Ty> operator()(_Rng&& _Range, _Ty _Val) const { + auto _First = _RANGES begin(_Range); + _Seek_wrapped(_First, _Iota_impl(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Val)); + return {_STD move(_First), _STD move(_Val)}; + } + + private: + template + _NODISCARD static constexpr _It _Iota_impl(_It _First, const _Se _Last, _Ty& _Val) { + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Ty>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_writable<_It, const _Ty&>); + + const _Ty& _Const_val = _Val; + for (; _First != _Last; ++_First, (void) ++_Val) { + *_First = _Const_val; + } + return _First; + } + }; + + inline constexpr _Iota_fn iota{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + #if _HAS_CXX17 template _NODISCARD constexpr auto _Abs_u(const _Integral _Val) noexcept { diff --git a/stl/inc/xutility b/stl/inc/xutility index 132dddb48be..6a198cd1931 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1856,8 +1856,6 @@ namespace ranges { _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { _STL_INTERNAL_STATIC_ASSERT(is_lvalue_reference_v<_Ty>); if constexpr (_Has_member<_Ty>) { - _STL_INTERNAL_STATIC_ASSERT(same_as()._Unchecked_end()), - decltype(_Get_unwrapped(_RANGES end(_STD declval<_Ty>())))>); return {_St::_Member, noexcept(_STD declval<_Ty>()._Unchecked_end())}; } else if constexpr (_Can_end<_Ty>) { return {_St::_Unwrap, noexcept(_Get_unwrapped(_RANGES end(_STD declval<_Ty>())))}; @@ -3706,6 +3704,24 @@ namespace ranges { } }; +#if _HAS_CXX23 + template + struct out_value_result { + /* [[no_unique_address]] */ _Out out; + /* [[no_unique_address]] */ _Ty value; + + template <_Convertible_from _OOut, _Convertible_from _TTy> + constexpr operator out_value_result<_OOut, _TTy>() const& { + return {out, value}; + } + + template <_Convertible_from<_Out> _OOut, _Convertible_from<_Ty> _TTy> + constexpr operator out_value_result<_OOut, _TTy>() && { + return {_STD move(out), _STD move(value)}; + } + }; +#endif // _HAS_CXX23 + template using copy_result = in_out_result<_In, _Out>; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 40d7a928a07..aaf6307da5b 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -306,6 +306,7 @@ // P2273R3 constexpr unique_ptr // P2321R2 zip // (changes to pair, tuple, and vector::reference only) +// P2440R1 ranges::iota, ranges::shift_left, ranges::shift_right // P2442R1 Windowing Range Adaptors: views::chunk, views::slide // P2443R1 views::chunk_by // P2549R0 unexpected::error() @@ -1412,7 +1413,6 @@ #define __cpp_lib_remove_cvref 201711L #define __cpp_lib_semaphore 201907L -#define __cpp_lib_shift 201806L #define __cpp_lib_smart_ptr_for_overwrite 202002L #ifdef __cpp_consteval @@ -1457,6 +1457,7 @@ #define __cpp_lib_out_ptr 202106L #define __cpp_lib_ranges_chunk 202202L #define __cpp_lib_ranges_chunk_by 202202L +#define __cpp_lib_ranges_iota 202202L #define __cpp_lib_ranges_slide 202202L #define __cpp_lib_ranges_starts_ends_with 202106L #endif // __cpp_lib_concepts @@ -1512,6 +1513,12 @@ #define __cpp_lib_shared_ptr_arrays 201611L // P0497R0 Fixing shared_ptr For Arrays #endif // _HAS_CXX20 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +#define __cpp_lib_shift 202202L // P2440R1 ranges::shift_left, ranges::shift_right +#elif _HAS_CXX20 // ^^^ _HAS_CXX23 / _HAS_CXX20 vvv +#define __cpp_lib_shift 201806L // P0769R2 shift_left(), shift_right() +#endif // _HAS_CXX20 + #if _HAS_CXX20 #define __cpp_lib_variant 202106L // P2231R1 Completing constexpr In optional And variant #elif _HAS_CXX17 // ^^^ _HAS_CXX20 / _HAS_CXX17 vvv diff --git a/tests/std/test.lst b/tests/std/test.lst index 03282d2299b..658f11a7f7a 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -483,6 +483,9 @@ tests\P2273R3_constexpr_unique_ptr tests\P2321R2_proxy_reference tests\P2401R0_conditional_noexcept_for_exchange tests\P2415R2_owning_view +tests\P2440R1_ranges_alg_shift_left +tests\P2440R1_ranges_alg_shift_right +tests\P2440R1_ranges_numeric_iota tests\P2442R1_views_chunk tests\P2442R1_views_chunk_death tests\P2442R1_views_slide diff --git a/tests/std/tests/P0769R2_shift_left_shift_right/test.cpp b/tests/std/tests/P0769R2_shift_left_shift_right/test.cpp index 57a311df531..b7c702b420c 100644 --- a/tests/std/tests/P0769R2_shift_left_shift_right/test.cpp +++ b/tests/std/tests/P0769R2_shift_left_shift_right/test.cpp @@ -101,17 +101,47 @@ void test_case_shift_left(const ptrdiff_t tmpSize) { Container tmp; fill_iota(tmp, tmpSize); - test_iota(tmp.begin(), shift_left(tmp.begin(), tmp.end(), -1), 1, tmpSize); - for (ptrdiff_t pos_to_shift = 0; pos_to_shift < tmpSize; ++pos_to_shift) { fill_iota(tmp, tmpSize); test_iota(tmp.begin(), shift_left(tmp.begin(), tmp.end(), pos_to_shift), pos_to_shift + 1, tmpSize); + +#if __cpp_lib_shift >= 202202L + { + fill_iota(tmp, tmpSize); + auto [first, last] = ranges::shift_left(tmp.begin(), tmp.end(), pos_to_shift); + assert(first == tmp.begin()); + test_iota(first, last, pos_to_shift + 1, tmpSize); + } + + { + fill_iota(tmp, tmpSize); + auto [first, last] = ranges::shift_left(tmp, pos_to_shift); + assert(first == tmp.begin()); + test_iota(first, last, pos_to_shift + 1, tmpSize); + } +#endif // __cpp_lib_shift >= 202202L } fill_iota(tmp, tmpSize); for (int i = 0; i < 3; ++i) { test_iota(shift_left(tmp.begin(), tmp.end(), tmpSize + i), tmp.end(), 1, tmpSize); } + +#if __cpp_lib_shift >= 202202L + fill_iota(tmp, tmpSize); + for (int i = 0; i < 3; ++i) { + auto [first, last] = ranges::shift_left(tmp.begin(), tmp.end(), tmpSize + i); + assert(first == tmp.begin()); + test_iota(last, tmp.end(), 1, tmpSize); + } + + fill_iota(tmp, tmpSize); + for (int i = 0; i < 3; ++i) { + auto [first, last] = ranges::shift_left(tmp, tmpSize + i); + assert(first == tmp.begin()); + test_iota(last, tmp.end(), 1, tmpSize); + } +#endif // __cpp_lib_shift >= 202202L } template @@ -119,17 +149,47 @@ void test_case_shift_right(const ptrdiff_t tmpSize) { Container tmp; fill_iota(tmp, tmpSize); - test_iota(shift_right(tmp.begin(), tmp.end(), -1), tmp.end(), 1, tmpSize); - for (ptrdiff_t pos_to_shift = 0; pos_to_shift < tmpSize; ++pos_to_shift) { fill_iota(tmp, tmpSize); test_iota(shift_right(tmp.begin(), tmp.end(), pos_to_shift), tmp.end(), 1, tmpSize - pos_to_shift); + +#if __cpp_lib_shift >= 202202L + { + fill_iota(tmp, tmpSize); + auto [first, last] = ranges::shift_right(tmp.begin(), tmp.end(), pos_to_shift); + assert(last == tmp.end()); + test_iota(first, last, 1, tmpSize - pos_to_shift); + } + + { + fill_iota(tmp, tmpSize); + auto [first, last] = ranges::shift_right(tmp, pos_to_shift); + assert(last == tmp.end()); + test_iota(first, last, 1, tmpSize - pos_to_shift); + } +#endif // __cpp_lib_shift >= 202202L } fill_iota(tmp, tmpSize); for (int i = 0; i < 3; ++i) { test_iota(tmp.begin(), shift_right(tmp.begin(), tmp.end(), tmpSize + i), 1, tmpSize); } + +#if __cpp_lib_shift >= 202202L + fill_iota(tmp, tmpSize); + for (int i = 0; i < 3; ++i) { + auto [first, last] = ranges::shift_right(tmp.begin(), tmp.end(), tmpSize + i); + assert(last == tmp.end()); + test_iota(tmp.begin(), first, 1, tmpSize); + } + + fill_iota(tmp, tmpSize); + for (int i = 0; i < 3; ++i) { + auto [first, last] = ranges::shift_right(tmp, tmpSize + i); + assert(last == tmp.end()); + test_iota(tmp.begin(), first, 1, tmpSize); + } +#endif // __cpp_lib_shift >= 202202L } int main() { diff --git a/tests/std/tests/P2440R1_ranges_alg_shift_left/env.lst b/tests/std/tests/P2440R1_ranges_alg_shift_left/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2440R1_ranges_alg_shift_left/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2440R1_ranges_alg_shift_left/test.cpp b/tests/std/tests/P2440R1_ranges_alg_shift_left/test.cpp new file mode 100644 index 00000000000..0193d40158a --- /dev/null +++ b/tests/std/tests/P2440R1_ranges_alg_shift_left/test.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + constexpr int_wrapper() = default; + constexpr int_wrapper(int x) : val{x} {} + constexpr int_wrapper(int_wrapper&& that) : val{exchange(that.val, -1)} {} + constexpr int_wrapper& operator=(int_wrapper&& that) { + val = exchange(that.val, -1); + return *this; + } + auto operator<=>(const int_wrapper&) const = default; +}; + +// Validate dangling story +STATIC_ASSERT(same_as{}, 1)), ranges::dangling>); +STATIC_ASSERT(same_as{}, 1)), ranges::subrange>); + +struct instantiator { + static constexpr int_wrapper expected_result[2] = {12345, 3333}; + static constexpr int_wrapper expected_io[5] = {12345, 3333, 44, -1, -1}; + + template + static constexpr void call() { + if constexpr (permutable>) { + using ranges::equal, ranges::iterator_t, ranges::begin, ranges::end; + { + int_wrapper io[5] = {13, 55, 44, 12345, 3333}; + Rng range(io); + + auto result = ranges::shift_left(range, 3); + STATIC_ASSERT(same_as>>); + assert(equal(result, expected_result)); + assert(equal(io, expected_io)); + } + { + int_wrapper io[5] = {13, 55, 44, 12345, 3333}; + Rng range(io); + + auto result = ranges::shift_left(begin(range), end(range), 3); + STATIC_ASSERT(same_as>>); + assert(equal(begin(result), end(result), begin(expected_result), end(expected_result))); + assert(equal(io, expected_io)); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_fwd(), true)); + test_fwd(); +} diff --git a/tests/std/tests/P2440R1_ranges_alg_shift_right/env.lst b/tests/std/tests/P2440R1_ranges_alg_shift_right/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2440R1_ranges_alg_shift_right/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2440R1_ranges_alg_shift_right/test.cpp b/tests/std/tests/P2440R1_ranges_alg_shift_right/test.cpp new file mode 100644 index 00000000000..836e246f9b2 --- /dev/null +++ b/tests/std/tests/P2440R1_ranges_alg_shift_right/test.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + int val = 10; + constexpr int_wrapper() = default; + constexpr int_wrapper(int x) : val{x} {} + constexpr int_wrapper(int_wrapper&& that) : val{exchange(that.val, -1)} {} + constexpr int_wrapper& operator=(int_wrapper&& that) { + val = exchange(that.val, -1); + return *this; + } + auto operator<=>(const int_wrapper&) const = default; +}; + +// Validate dangling story +STATIC_ASSERT(same_as{}, 1)), ranges::dangling>); +STATIC_ASSERT(same_as{}, 1)), ranges::subrange>); + +struct instantiator { + template + static constexpr void call() { + if constexpr (permutable>) { + using ranges::equal, ranges::iterator_t, ranges::begin, ranges::end; + { + int_wrapper io[5] = {13, 55, 44, 12345, 3333}; + Rng range(io); + + auto result = ranges::shift_right(range, 2); + STATIC_ASSERT(same_as>>); + + int_wrapper expected_result[3] = {13, 55, 44}; + int_wrapper expected_io[5] = {-1, -1, 13, 55, 44}; + assert(equal(result, expected_result)); + assert(equal(io, expected_io)); + } + { + int_wrapper io[5] = {13, 55, 44, 12345, 3333}; + Rng range(io); + + auto result = ranges::shift_right(begin(range), end(range), 2); + STATIC_ASSERT(same_as>>); + + int_wrapper expected_result[3] = {13, 55, 44}; + int_wrapper expected_io[5] = {-1, -1, 13, 55, 44}; + assert(equal(result, expected_result)); + assert(equal(io, expected_io)); + } + { + int_wrapper io[5] = {13, 55, 44, 12345, 3333}; + Rng range(io); + + auto result = ranges::shift_right(begin(range), end(range), 5); + + int_wrapper expected_io[5] = {13, 55, 44, 12345, 3333}; + assert(equal(result, ranges::empty_view{})); + assert(equal(io, expected_io)); + } + { + int_wrapper io[7] = {13, 55, 44, 12345, 3333, 5555, 7777}; + Rng range(io); + + auto result = ranges::shift_right(begin(range), end(range), 2); + + int_wrapper expected_result[5] = {13, 55, 44, 12345, 3333}; + assert(equal(result, expected_result)); + assert(equal(begin(io) + 2, end(io), begin(expected_result), end(expected_result))); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_fwd(), true)); + test_fwd(); +} diff --git a/tests/std/tests/P2440R1_ranges_numeric_iota/env.lst b/tests/std/tests/P2440R1_ranges_numeric_iota/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2440R1_ranges_numeric_iota/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2440R1_ranges_numeric_iota/test.cpp b/tests/std/tests/P2440R1_ranges_numeric_iota/test.cpp new file mode 100644 index 00000000000..3852be2878e --- /dev/null +++ b/tests/std/tests/P2440R1_ranges_numeric_iota/test.cpp @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that iota_result aliases out_value_result +STATIC_ASSERT(same_as, ranges::out_value_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, 0L)), ranges::iota_result>); +STATIC_ASSERT(same_as{}, 0L)), ranges::iota_result>); + +struct instantiator { + template Out> + static constexpr void call() { + using ranges::iterator_t, ranges::iota, ranges::iota_result; + + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + same_as, long>> auto result = iota(out_wrapper, 0L); + assert(result.out == out_wrapper.end()); + assert(result.value == 3L); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + same_as, long>> auto result = iota(out_wrapper.begin(), out_wrapper.end(), 0L); + assert(result.out == out_wrapper.end()); + assert(result.value == 3L); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_out(), true)); + test_out(); +} diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 83f3c86bf29..e693ad2d767 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1394,6 +1394,20 @@ STATIC_ASSERT(__cpp_lib_ranges_chunk_by == 202202L); #endif #endif +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +#ifndef __cpp_lib_ranges_iota +#error __cpp_lib_ranges_iota is not defined +#elif __cpp_lib_ranges_iota != 202202L +#error __cpp_lib_ranges_iota is not 202202L +#else +STATIC_ASSERT(__cpp_lib_ranges_iota == 202202L); +#endif +#else +#ifdef __cpp_lib_ranges_iota +#error __cpp_lib_ranges_iota is defined +#endif +#endif + #if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support #ifndef __cpp_lib_ranges_slide #error __cpp_lib_ranges_slide is not defined @@ -1560,7 +1574,19 @@ STATIC_ASSERT(__cpp_lib_shared_timed_mutex == 201402L); #endif #endif -#if _HAS_CXX20 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +#ifndef __cpp_lib_shift +#error __cpp_lib_shift is not defined +#elif __cpp_lib_shift != 202202L +#if __cpp_lib_shift == 201806L +#error __cpp_lib_shift is 201806L when it should be 202202L +#else +#error __cpp_lib_shift is not 202202L +#endif +#else +STATIC_ASSERT(__cpp_lib_shift == 202202L); +#endif +#elif _HAS_CXX20 #ifndef __cpp_lib_shift #error __cpp_lib_shift is not defined #elif __cpp_lib_shift != 201806L