173 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// constexpr iterator& operator--();12// requires ref-is-glvalue && bidirectional_range<Base> &&13// bidirectional_range<range_reference_t<Base>> &&14// common_range<range_reference_t<Base>>;15// constexpr iterator operator--(int);16// requires ref-is-glvalue && bidirectional_range<Base> &&17// bidirectional_range<range_reference_t<Base>> &&18// common_range<range_reference_t<Base>>;19 20#include <algorithm>21#include <array>22#include <cassert>23#include <ranges>24#include <type_traits>25#include <vector>26 27#include "../types.h"28 29template <class T>30concept CanPreDecrement = requires(T& t) { --t; };31 32template <class T>33concept CanPostDecrement = requires(T& t) { t--; };34 35constexpr void noDecrementTest(auto&& jv) {36 auto iter = jv.begin();37 static_assert(!CanPreDecrement<decltype(iter)>);38 static_assert(!CanPostDecrement<decltype(iter)>);39}40 41constexpr bool test() {42 int buffer[4][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};43 44 {45 // outer == ranges::end46 std::ranges::join_view jv(buffer);47 auto iter = std::next(jv.begin(), 16);48 for (int i = 16; i != 0; --i) {49 assert(*--iter == i);50 }51 }52 53 {54 // outer == ranges::end55 std::ranges::join_view jv(buffer);56 auto iter = std::next(jv.begin(), 13);57 for (int i = 13; i != 0; --i) {58 assert(*--iter == i);59 }60 }61 62 {63 // outer != ranges::end64 std::ranges::join_view jv(buffer);65 auto iter = std::next(jv.begin(), 12);66 for (int i = 12; i != 0; --i) {67 assert(*--iter == i);68 }69 }70 71 {72 // outer != ranges::end73 std::ranges::join_view jv(buffer);74 auto iter = std::next(jv.begin());75 for (int i = 1; i != 0; --i) {76 assert(*--iter == i);77 }78 }79 80 {81 int small[2][1] = {{1}, {2}};82 std::ranges::join_view jv(small);83 auto iter = std::next(jv.begin(), 2);84 for (int i = 2; i != 0; --i) {85 assert(*--iter == i);86 }87 }88 89 {90#if defined(__GNUG__) && !defined(__clang__)91 // This seems to be a gcc bug where evaluating the following code92 // at compile time results in wrong array index93 if (!std::is_constant_evaluated()) {94#endif95 // skip empty inner96 BidiCommonInner inners[4] = {buffer[0], {nullptr, 0}, {nullptr, 0}, buffer[1]};97 std::ranges::join_view jv(inners);98 auto iter = jv.end();99 for (int i = 8; i != 0; --i) {100 assert(*--iter == i);101 }102#if defined(__GNUG__) && !defined(__clang__)103 }104#endif105 }106 107 {108 // basic type checking109 std::ranges::join_view jv(buffer);110 auto iter1 = std::ranges::next(jv.begin(), 4);111 using iterator = decltype(iter1);112 113 decltype(auto) iter2 = --iter1;114 static_assert(std::same_as<decltype(iter2), iterator&>);115 assert(&iter1 == &iter2);116 117 std::same_as<iterator> decltype(auto) iter3 = iter1--;118 assert(iter3 == std::next(iter1));119 }120 121 {122 // !ref-is-glvalue123 BidiCommonInner inners[2] = {buffer[0], buffer[1]};124 InnerRValue<BidiCommonOuter<BidiCommonInner>> outer{inners};125 std::ranges::join_view jv(outer);126 noDecrementTest(jv);127 }128 129 {130 // !bidirectional_range<Base>131 BidiCommonInner inners[2] = {buffer[0], buffer[1]};132 SimpleForwardCommonOuter<BidiCommonInner> outer{inners};133 std::ranges::join_view jv(outer);134 noDecrementTest(jv);135 }136 137 {138 // !bidirectional_range<range_reference_t<Base>>139 ForwardCommonInner inners[2] = {buffer[0], buffer[1]};140 std::ranges::join_view jv(inners);141 noDecrementTest(jv);142 }143 144 {145 // LWG3313 `join_view::iterator::operator--` is incorrectly constrained146 // `join_view::iterator` should not have `operator--` if147 // !common_range<range_reference_t<Base>>148 BidiNonCommonInner inners[2] = {buffer[0], buffer[1]};149 std::ranges::join_view jv(inners);150 auto iter = jv.begin();151 static_assert(!CanPreDecrement<decltype(iter)>);152 static_assert(!CanPostDecrement<decltype(iter)>);153 }154 155 {156 // LWG3791: `join_view::iterator::operator--` may be ill-formed157 std::vector<std::vector<int>> vec = {{1, 2}, {3, 4}, {5, 6}};158 auto r = vec | std::views::transform([](auto& x) -> auto&& { return std::move(x); }) | std::views::join;159 auto e = --r.end();160 assert(*e == 6);161 assert(std::ranges::equal(std::views::reverse(r), std::array{6, 5, 4, 3, 2, 1}));162 }163 164 return true;165}166 167int main(int, char**) {168 test();169 static_assert(test());170 171 return 0;172}173