152 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++17, c++2010 11// constexpr auto end()12// constexpr auto end() const13 14#include <array>15#include <cassert>16#include <ranges>17 18#include "test_iterators.h"19 20struct DefaultConstructibleView : std::ranges::view_base {21 int* begin() const;22 int* end() const;23};24 25struct CVCallView : std::ranges::view_base {26 mutable bool const_called = false;27 mutable int i[1];28 constexpr int* begin() {29 const_called = false;30 return i;31 }32 33 constexpr int* begin() const {34 const_called = true;35 return i;36 }37 38 constexpr int* end() {39 const_called = false;40 return i + 1;41 }42 43 constexpr int* end() const {44 const_called = true;45 return i + 1;46 }47};48 49struct NonConstCommonRange : std::ranges::view_base {50 int* begin();51 int* end();52 53 int* begin() const;54 sentinel_wrapper<int*> end() const;55};56 57struct NonConstView : std::ranges::view_base {58 int* begin();59 int* end();60};61 62template <class T>63concept HasEnd = requires(T t) { t.end(); };64 65static_assert(HasEnd<std::ranges::as_rvalue_view<DefaultConstructibleView>>);66static_assert(HasEnd<const std::ranges::as_rvalue_view<DefaultConstructibleView>>);67static_assert(HasEnd<std::ranges::as_rvalue_view<NonConstView>>);68static_assert(!HasEnd<const std::ranges::as_rvalue_view<NonConstView>>);69 70static_assert(std::is_same_v<decltype(std::declval<std::ranges::as_rvalue_view<DefaultConstructibleView>>().end()),71 std::move_iterator<int*>>);72static_assert(std::is_same_v<decltype(std::declval<const std::ranges::as_rvalue_view<NonConstCommonRange>>().end()),73 std::move_sentinel<sentinel_wrapper<int*>>>);74 75template <class Iter, class Sent, bool is_common>76constexpr void test_range() {77 using Expected = std::conditional_t<is_common, std::move_iterator<Sent>, std::move_sentinel<Sent>>;78 int a[] = {1, 2};79 std::ranges::subrange range(Iter(std::begin(a)), Sent(Iter(std::end(a))));80 std::ranges::as_rvalue_view view(std::move(range));81 std::same_as<Expected> decltype(auto) iter = view.end();82 assert(base(base(iter.base())) == std::end(a));83}84 85template <class Iter, class Sent>86class WrapRange {87 Iter iter_;88 Sent sent_;89 90public:91 constexpr WrapRange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {}92 93 constexpr Iter begin() const { return iter_; }94 constexpr Sent end() const { return sent_; }95};96 97template <class Iter, class Sent>98WrapRange(Iter, Sent) -> WrapRange<Iter, Sent>;99 100template <class Iter, class Sent, bool is_common>101constexpr void test_const_range() {102 using Expected = std::conditional_t<is_common, std::move_iterator<Sent>, std::move_sentinel<Sent>>;103 int a[] = {1, 2};104 auto range = WrapRange{Iter(a), Sent(Iter(a + 2))};105 const std::ranges::as_rvalue_view view(std::move(range));106 std::same_as<Expected> decltype(auto) iter = view.end();107 assert(base(base(iter.base())) == std::end(a));108}109 110struct move_iterator_view : std::ranges::view_base {111 constexpr std::move_iterator<int*> begin() const { return {}; }112 constexpr std::move_iterator<int*> end() const { return {}; }113};114 115constexpr bool test() {116 test_range<cpp17_input_iterator<int*>, sentinel_wrapper<cpp17_input_iterator<int*>>, false>();117 test_range<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>, false>();118 test_range<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>, false>();119 test_range<cpp20_input_iterator<int*>, sized_sentinel<cpp20_input_iterator<int*>>, false>();120 121 types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {122 test_range<Iter, Iter, true>();123 test_range<Iter, sentinel_wrapper<Iter>, false>();124 test_range<Iter, sized_sentinel<Iter>, false>();125 });126 127 {128 std::ranges::as_rvalue_view view(CVCallView{});129 (void)view.end();130 assert(view.base().const_called);131 }132 133 { // check that with a std::move_iterator begin() doesn't return move_iterator<move_iterator<T>>134 std::ranges::as_rvalue_view view{move_iterator_view{}};135 std::same_as<std::move_iterator<int*>> decltype(auto) it = view.end();136 assert(it == std::move_iterator<int*>{});137 }138 139 return true;140}141 142int main(int, char**) {143 test();144 145// gcc cannot have mutable member in constant expression146#if !defined(TEST_COMPILER_GCC)147 static_assert(test());148#endif149 150 return 0;151}152