//===----------------------------------------------------------------------===// // // 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 auto end(); // constexpr auto end() const // requires forward_range && forward_range && // is_reference_v> && // input_range>; // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=10000000 #include #include #include #include #include "../types.h" #include "test_iterators.h" template concept JoinWithViewHasConstEnd = requires(const std::ranges::join_with_view jwv) { jwv.end(); }; template requires(Bits < (1 << 7)) constexpr void test_end() { constexpr bool v_models_forward_range = static_cast(Bits & (1 << 0)); constexpr bool inner_range_is_reference = static_cast(Bits & (1 << 1)); constexpr bool inner_range_models_forward_range = static_cast(Bits & (1 << 2)); constexpr bool v_models_common_range = static_cast(Bits & (1 << 3)); constexpr bool inner_range_models_common_range = static_cast(Bits & (1 << 4)); constexpr bool v_models_simple_range = static_cast(Bits & (1 << 5)); constexpr bool pattern_models_simple_range = static_cast(Bits & (1 << 6)); constexpr ViewProperties inner_range_props{.common = inner_range_models_common_range}; using InnerRange = std::conditional_t, inner_range_props, forward_iterator>, BasicView, inner_range_props, DefaultCtorInputIter>>; constexpr ViewProperties v_props{.simple = v_models_simple_range, .common = v_models_common_range}; using UnderlyingV = std::conditional_t, RvalueVector>; using V = std::conditional_t, BasicView>; using UnderlyingPattern = std::vector; using Pattern = BasicView; using JWV = std::ranges::join_with_view; using Iter = std::ranges::iterator_t; // Test when `JWV` models common range static_assert(std::same_as> == (v_models_forward_range && inner_range_is_reference && inner_range_models_forward_range && v_models_common_range && inner_range_models_common_range)); { // `V` and `Pattern` are empty V v{}; Pattern pattern{}; JWV jwv(std::move(v), std::move(pattern)); Iter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(it == se); } { // `V` is empty, `Pattern` contains some elements V v{}; Pattern pattern{std::vector{0}}; JWV jwv(std::move(v), std::move(pattern)); Iter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(it == se); } { // `V` is not empty, `Pattern is empty` V v{UnderlyingV{ std::vector{InnerRange(std::vector{1, 2, 3}), InnerRange(std::vector{4, 5, 6})}}}; Pattern pattern{}; JWV jwv(std::move(v), std::move(pattern)); Iter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(std::ranges::next(it, 6) == se); } { // `V` and `Pattern` are not empty V v{UnderlyingV{std::vector{ InnerRange(std::vector{6, 5}), InnerRange(std::vector{4, 3}), InnerRange(std::vector{2, 1, 0})}}}; Pattern pattern{std::vector{-1, -1}}; JWV jwv(std::move(v), std::move(pattern)); Iter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(std::ranges::next(it, 11) == se); } } template requires(Bits < (1 << 7)) constexpr void test_const_end() { constexpr bool const_v_models_forward_range = static_cast(Bits & (1 << 0)); constexpr bool const_pattern_models_forward_range = static_cast(Bits & (1 << 1)); constexpr bool inner_const_range_is_reference = static_cast(Bits & (1 << 2)); constexpr bool inner_const_range_models_input_range = static_cast(Bits & (1 << 3)); constexpr bool inner_const_range_models_forward_range = static_cast(Bits & (1 << 4)); constexpr bool const_v_models_common_range = static_cast(Bits & (1 << 5)); constexpr bool inner_const_range_models_common_range = static_cast(Bits & (1 << 6)); constexpr ViewProperties inner_range_props{.common = inner_const_range_models_common_range}; using InnerRange = std::conditional_t, inner_range_props, forward_iterator>, std::conditional_t, inner_range_props, DefaultCtorInputIter>, InputRangeButOutputWhenConst>>; constexpr ViewProperties v_props{.common = const_v_models_common_range}; using UnderlyingV = std::conditional_t, RvalueVector>; using V = std::conditional_t, BasicView>; using Pattern = std::conditional_t, ViewProperties{}, forward_iterator>, ForwardViewButInputWhenConst>; using JWV = std::ranges::join_with_view; static_assert(JoinWithViewHasConstEnd == (const_v_models_forward_range && const_pattern_models_forward_range && inner_const_range_is_reference && (inner_const_range_models_input_range || inner_const_range_models_forward_range))); static_assert(JoinWithViewHasConstEnd == std::ranges::range); if constexpr (std::ranges::range) { using ConstIter = std::ranges::iterator_t; // Test when `const JWV` models common range static_assert(std::same_as> == (inner_const_range_models_forward_range && const_v_models_common_range && inner_const_range_models_common_range)); { // `const V` and `const Pattern` are empty V v{}; Pattern pattern{}; const JWV jwv(std::move(v), std::move(pattern)); ConstIter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(it == se); } { // `const V` is empty, `const Pattern` contains some elements V v{}; Pattern pattern{std::vector{1}}; const JWV jwv(std::move(v), std::move(pattern)); ConstIter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(it == se); } { // `const V` is not empty, `const Pattern is empty` V v{UnderlyingV{ std::vector{InnerRange(std::vector{1, 2, 3}), InnerRange(std::vector{4, 5, 6})}}}; Pattern pattern{}; const JWV jwv(std::move(v), std::move(pattern)); ConstIter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(std::ranges::next(it, 6) == se); } { // `const V` and `const Pattern` are not empty V v{UnderlyingV{std::vector{ InnerRange(std::vector{1}), InnerRange(std::vector{2, 2}), InnerRange(std::vector{3, 3, 3})}}}; Pattern pattern{std::vector{0}}; const JWV jwv(std::move(v), std::move(pattern)); ConstIter it = jwv.begin(); std::sentinel_for decltype(auto) se = jwv.end(); assert(std::ranges::next(it, 8) == se); } } } constexpr bool test() { [](std::index_sequence) { (test_end(), ...); (test_const_end(), ...); }(std::make_index_sequence<(1 << 7)>{}); { // Check situation when iterators returned by `end()` and `end() const` are of the same type using V = BasicView, ViewProperties{.simple = true}, forward_iterator>; using Pattern = BasicView; using JWV = std::ranges::join_with_view; using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(std::input_iterator); static_assert(std::input_iterator); static_assert(std::same_as); } { // Check situation when sentinels returned by `end()` and `end() const` are of the same type using V = BasicView, ViewProperties{.simple = true, .common = false}, forward_iterator>; using Pattern = BasicView; using JWV = std::ranges::join_with_view; using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::input_iterator); static_assert(!std::input_iterator); static_assert(std::same_as); } // Check LWG-4074: compatible-joinable-ranges is underconstrained static_assert(!JoinWithViewHasConstEnd, lwg4074::PatternWithProxyConstAccess>); return true; } int main(int, char**) { test(); static_assert(test()); return 0; }