//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // REQUIRES: std-at-least-c++23 // // constexpr iterator& operator--() // requires ref-is-glvalue && bidirectional_range && // bidirectional-common && bidirectional-common; // constexpr iterator operator--(int) // requires ref-is-glvalue && bidirectional_range && // bidirectional-common && bidirectional-common; #include #include #include #include #include #include #include #include #include "../types.h" template concept CanPreDecrement = requires(I& i) { { --i } -> std::same_as; }; template concept CanPostDecrement = requires(I& i) { { i-- } -> std::same_as; }; template concept CanDecrement = CanPreDecrement && CanPostDecrement; constexpr bool test() { { // `V` and `Pattern` are not empty. Test return type too. using V = std::ranges::owning_view>; using Pattern = std::ranges::single_view; using JWV = std::ranges::join_with_view; using Iter = std::ranges::iterator_t; using CIter = std::ranges::iterator_t; static_assert(CanDecrement); static_assert(CanDecrement); JWV jwv(V{{"01", "23", "45"}}, Pattern{'_'}); { auto it = jwv.end(); std::same_as decltype(auto) it_ref = --it; assert(it_ref == it); assert(*it == '5'); std::same_as decltype(auto) it_copy = it--; assert(--it_copy == it); --it; assert(*it == '_'); it--; assert(*it == '3'); --it; it--; assert(*it == '_'); } { auto cit = std::as_const(jwv).end(); std::same_as decltype(auto) cit_ref = --cit; assert(cit_ref == cit); assert(*cit == '5'); std::same_as decltype(auto) cit_copy = cit--; assert(--cit_copy == cit); --cit; assert(*cit == '_'); cit--; assert(*cit == '3'); --cit; cit--; assert(*cit == '_'); } assert(std::ranges::equal(std::views::reverse(std::move(jwv)), std::string_view{"54_32_10"})); } { // `Pattern` is empty, `V` is not. using Inner = std::array; using V = std::ranges::owning_view>; using Pattern = std::ranges::owning_view>; using JWV = std::ranges::join_with_view; JWV jwv(V{{Inner{-9}, Inner{-99}, Inner{-999}}}, Pattern{}); { auto it = jwv.end(); --it; assert(*it == -999); it--; assert(*it == -99); --it; assert(*it == -9); assert(it == jwv.begin()); } { auto cit = std::as_const(jwv).end(); --cit; assert(*cit == -999); cit--; assert(*cit == -99); --cit; assert(*cit == -9); assert(cit == std::as_const(jwv).begin()); } } #if !defined(TEST_COMPILER_GCC) // GCC c++/101777 { // `V` has empty subrange in the middle, `Pattern` is not empty. Try to go back and forth. using V = std::array, 3>; using Pattern = std::ranges::single_view; using JWV = std::ranges::join_with_view, Pattern>; JWV jwv(V{{{5}, {}, {125}}}, Pattern{1}); { auto it = jwv.end(); --it; assert(*it == 125); it--; assert(*it == 1); --it; assert(*it == 1); it--; assert(*it == 5); ++it; assert(*it == 1); --it; assert(*it == 5); std::ranges::advance(it, 4); it--; assert(*it == 125); } { auto cit = std::as_const(jwv).end(); --cit; assert(*cit == 125); cit--; assert(*cit == 1); --cit; assert(*cit == 1); cit--; assert(*cit == 5); ++cit; assert(*cit == 1); --cit; assert(*cit == 5); std::ranges::advance(cit, 4); cit--; assert(*cit == 125); } } { // Only first element of `V` is not empty. `Pattern` is empty. Try to go back and forth. using Inner = std::vector; using V = std::ranges::owning_view>; using Pattern = std::ranges::empty_view; using JWV = std::ranges::join_with_view; JWV jwv(V{{Inner{999}, {}, {}}}, Pattern{}); { auto it = jwv.end(); --it; assert(*it == 999); ++it; assert(it == jwv.end()); it--; assert(*it == 999); } { auto cit = std::as_const(jwv).end(); --cit; assert(*cit == 999); ++cit; assert(cit == std::as_const(jwv).end()); cit--; assert(*cit == 999); } } #endif // !defined(TEST_COMPILER_GCC) { // `ref-is-glvalue` is false using V = RvalueVector>; using Pattern = std::ranges::empty_view; using JWV = std::ranges::join_with_view, std::ranges::owning_view>; using Iter = std::ranges::iterator_t; static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); } { // `Base` does not model bidirectional range using V = std::ranges::owning_view>>; using Pattern = std::ranges::single_view; using JWV = std::ranges::join_with_view; using Iter = std::ranges::iterator_t; using CIter = std::ranges::iterator_t; static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); } { // InnerBase does not model bidirectional-common { // InnerBase does not model bidirectional range using V = std::ranges::owning_view>>; using Pattern = std::ranges::single_view; using JWV = std::ranges::join_with_view; using Iter = std::ranges::iterator_t; using CIter = std::ranges::iterator_t; static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); } { // InnerBase does not model common range using InnerBase = BasicVectorView; using V = std::ranges::owning_view>; using Pattern = std::ranges::single_view; using JWV = std::ranges::join_with_view; using Iter = std::ranges::iterator_t; using CIter = std::ranges::iterator_t; static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); } } { // PatternBase does not model bidirectional-common { // PatternBase does not model bidirectional range using V = std::ranges::owning_view>>; using Pattern = std::ranges::owning_view>; using JWV = std::ranges::join_with_view; using Iter = std::ranges::iterator_t; using CIter = std::ranges::iterator_t; static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); } { // PatternBase does not model common range using V = std::ranges::owning_view>>; using Pattern = BasicVectorView; using JWV = std::ranges::join_with_view; using Iter = std::ranges::iterator_t; using CIter = std::ranges::iterator_t; static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); static_assert(!CanPreDecrement); static_assert(!CanPostDecrement); } } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }