233 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// REQUIRES: std-at-least-c++2310 11// <ranges>12 13// constexpr auto end();14// constexpr auto end() const15// requires forward_range<const V> && forward_range<const Pattern> &&16// is_reference_v<range_reference_t<const V>> &&17// input_range<range_reference_t<const V>>;18 19// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=1000000020 21#include <ranges>22 23#include <algorithm>24#include <string>25#include <vector>26 27#include "../types.h"28#include "test_iterators.h"29 30template <class V, class Pattern>31concept JoinWithViewHasConstEnd = requires(const std::ranges::join_with_view<V, Pattern> jwv) { jwv.end(); };32 33template <size_t Bits>34 requires(Bits < (1 << 7))35constexpr void test_end() {36 constexpr bool v_models_forward_range = static_cast<bool>(Bits & (1 << 0));37 constexpr bool inner_range_is_reference = static_cast<bool>(Bits & (1 << 1));38 constexpr bool inner_range_models_forward_range = static_cast<bool>(Bits & (1 << 2));39 constexpr bool v_models_common_range = static_cast<bool>(Bits & (1 << 3));40 constexpr bool inner_range_models_common_range = static_cast<bool>(Bits & (1 << 4));41 constexpr bool v_models_simple_range = static_cast<bool>(Bits & (1 << 5));42 constexpr bool pattern_models_simple_range = static_cast<bool>(Bits & (1 << 6));43 44 constexpr ViewProperties inner_range_props{.common = inner_range_models_common_range};45 using InnerRange =46 std::conditional_t<inner_range_models_forward_range,47 BasicView<std::vector<int>, inner_range_props, forward_iterator>,48 BasicView<std::vector<int>, inner_range_props, DefaultCtorInputIter>>;49 50 constexpr ViewProperties v_props{.simple = v_models_simple_range, .common = v_models_common_range};51 using UnderlyingV = std::conditional_t<inner_range_is_reference, std::vector<InnerRange>, RvalueVector<InnerRange>>;52 using V = std::conditional_t<v_models_forward_range,53 BasicView<UnderlyingV, v_props, forward_iterator>,54 BasicView<UnderlyingV, v_props, DefaultCtorInputIter>>;55 56 using UnderlyingPattern = std::vector<int>;57 using Pattern = BasicView<UnderlyingPattern, ViewProperties{.simple = pattern_models_simple_range}, forward_iterator>;58 59 using JWV = std::ranges::join_with_view<V, Pattern>;60 using Iter = std::ranges::iterator_t<JWV>;61 62 // Test when `JWV` models common range63 static_assert(std::same_as<Iter, std::ranges::sentinel_t<JWV>> ==64 (v_models_forward_range && inner_range_is_reference && inner_range_models_forward_range &&65 v_models_common_range && inner_range_models_common_range));66 67 { // `V` and `Pattern` are empty68 V v{};69 Pattern pattern{};70 JWV jwv(std::move(v), std::move(pattern));71 Iter it = jwv.begin();72 std::sentinel_for<Iter> decltype(auto) se = jwv.end();73 assert(it == se);74 }75 76 { // `V` is empty, `Pattern` contains some elements77 V v{};78 Pattern pattern{std::vector<int>{0}};79 JWV jwv(std::move(v), std::move(pattern));80 Iter it = jwv.begin();81 std::sentinel_for<Iter> decltype(auto) se = jwv.end();82 assert(it == se);83 }84 85 { // `V` is not empty, `Pattern is empty`86 V v{UnderlyingV{87 std::vector<InnerRange>{InnerRange(std::vector<int>{1, 2, 3}), InnerRange(std::vector<int>{4, 5, 6})}}};88 Pattern pattern{};89 JWV jwv(std::move(v), std::move(pattern));90 Iter it = jwv.begin();91 std::sentinel_for<Iter> decltype(auto) se = jwv.end();92 assert(std::ranges::next(it, 6) == se);93 }94 95 { // `V` and `Pattern` are not empty96 V v{UnderlyingV{std::vector<InnerRange>{97 InnerRange(std::vector<int>{6, 5}),98 InnerRange(std::vector<int>{4, 3}),99 InnerRange(std::vector<int>{2, 1, 0})}}};100 Pattern pattern{std::vector<int>{-1, -1}};101 JWV jwv(std::move(v), std::move(pattern));102 Iter it = jwv.begin();103 std::sentinel_for<Iter> decltype(auto) se = jwv.end();104 assert(std::ranges::next(it, 11) == se);105 }106}107 108template <std::size_t Bits>109 requires(Bits < (1 << 7))110constexpr void test_const_end() {111 constexpr bool const_v_models_forward_range = static_cast<bool>(Bits & (1 << 0));112 constexpr bool const_pattern_models_forward_range = static_cast<bool>(Bits & (1 << 1));113 constexpr bool inner_const_range_is_reference = static_cast<bool>(Bits & (1 << 2));114 constexpr bool inner_const_range_models_input_range = static_cast<bool>(Bits & (1 << 3));115 constexpr bool inner_const_range_models_forward_range = static_cast<bool>(Bits & (1 << 4));116 constexpr bool const_v_models_common_range = static_cast<bool>(Bits & (1 << 5));117 constexpr bool inner_const_range_models_common_range = static_cast<bool>(Bits & (1 << 6));118 119 constexpr ViewProperties inner_range_props{.common = inner_const_range_models_common_range};120 using InnerRange =121 std::conditional_t<inner_const_range_models_forward_range,122 BasicView<std::vector<int>, inner_range_props, forward_iterator>,123 std::conditional_t<inner_const_range_models_input_range,124 BasicView<std::vector<int>, inner_range_props, DefaultCtorInputIter>,125 InputRangeButOutputWhenConst<int>>>;126 127 constexpr ViewProperties v_props{.common = const_v_models_common_range};128 using UnderlyingV =129 std::conditional_t<inner_const_range_is_reference, std::vector<InnerRange>, RvalueVector<InnerRange>>;130 using V = std::conditional_t<const_v_models_forward_range,131 BasicView<UnderlyingV, v_props, forward_iterator>,132 BasicView<UnderlyingV, v_props, DefaultCtorInputIter>>;133 using Pattern =134 std::conditional_t<const_pattern_models_forward_range,135 BasicView<std::vector<int>, ViewProperties{}, forward_iterator>,136 ForwardViewButInputWhenConst<int>>;137 138 using JWV = std::ranges::join_with_view<V, Pattern>;139 static_assert(JoinWithViewHasConstEnd<V, Pattern> ==140 (const_v_models_forward_range && const_pattern_models_forward_range && inner_const_range_is_reference &&141 (inner_const_range_models_input_range || inner_const_range_models_forward_range)));142 static_assert(JoinWithViewHasConstEnd<V, Pattern> == std::ranges::range<const JWV>);143 144 if constexpr (std::ranges::range<const JWV>) {145 using ConstIter = std::ranges::iterator_t<const JWV>;146 147 // Test when `const JWV` models common range148 static_assert(std::same_as<ConstIter, std::ranges::sentinel_t<const JWV>> ==149 (inner_const_range_models_forward_range && const_v_models_common_range &&150 inner_const_range_models_common_range));151 152 { // `const V` and `const Pattern` are empty153 V v{};154 Pattern pattern{};155 const JWV jwv(std::move(v), std::move(pattern));156 ConstIter it = jwv.begin();157 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();158 assert(it == se);159 }160 161 { // `const V` is empty, `const Pattern` contains some elements162 V v{};163 Pattern pattern{std::vector<int>{1}};164 const JWV jwv(std::move(v), std::move(pattern));165 ConstIter it = jwv.begin();166 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();167 assert(it == se);168 }169 170 { // `const V` is not empty, `const Pattern is empty`171 V v{UnderlyingV{172 std::vector<InnerRange>{InnerRange(std::vector<int>{1, 2, 3}), InnerRange(std::vector<int>{4, 5, 6})}}};173 Pattern pattern{};174 const JWV jwv(std::move(v), std::move(pattern));175 ConstIter it = jwv.begin();176 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();177 assert(std::ranges::next(it, 6) == se);178 }179 180 { // `const V` and `const Pattern` are not empty181 V v{UnderlyingV{std::vector<InnerRange>{182 InnerRange(std::vector<int>{1}), InnerRange(std::vector<int>{2, 2}), InnerRange(std::vector<int>{3, 3, 3})}}};183 Pattern pattern{std::vector<int>{0}};184 const JWV jwv(std::move(v), std::move(pattern));185 ConstIter it = jwv.begin();186 std::sentinel_for<ConstIter> decltype(auto) se = jwv.end();187 assert(std::ranges::next(it, 8) == se);188 }189 }190}191 192constexpr bool test() {193 []<std::size_t... Bits>(std::index_sequence<Bits...>) {194 (test_end<Bits>(), ...);195 (test_const_end<Bits>(), ...);196 }(std::make_index_sequence<(1 << 7)>{});197 198 { // Check situation when iterators returned by `end()` and `end() const` are of the same type199 using V = BasicView<std::vector<std::string>, ViewProperties{.simple = true}, forward_iterator>;200 using Pattern = BasicView<std::string, ViewProperties{.simple = true}, forward_iterator>;201 using JWV = std::ranges::join_with_view<V, Pattern>;202 using Sentinel = std::ranges::sentinel_t<JWV&>;203 using ConstSentinel = std::ranges::sentinel_t<const JWV&>;204 static_assert(std::input_iterator<Sentinel>);205 static_assert(std::input_iterator<ConstSentinel>);206 static_assert(std::same_as<Sentinel, ConstSentinel>);207 }208 209 { // Check situation when sentinels returned by `end()` and `end() const` are of the same type210 using V = BasicView<std::vector<std::string>, ViewProperties{.simple = true, .common = false}, forward_iterator>;211 using Pattern = BasicView<std::string, ViewProperties{.simple = true}, forward_iterator>;212 using JWV = std::ranges::join_with_view<V, Pattern>;213 using Sentinel = std::ranges::sentinel_t<JWV&>;214 using ConstSentinel = std::ranges::sentinel_t<const JWV&>;215 static_assert(!std::input_iterator<Sentinel>);216 static_assert(!std::input_iterator<ConstSentinel>);217 static_assert(std::same_as<Sentinel, ConstSentinel>);218 }219 220 // Check LWG-4074: compatible-joinable-ranges is underconstrained221 static_assert(!JoinWithViewHasConstEnd<BasicVectorView<int, ViewProperties{}, forward_iterator>,222 lwg4074::PatternWithProxyConstAccess>);223 224 return true;225}226 227int main(int, char**) {228 test();229 static_assert(test());230 231 return 0;232}233