133 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 12// constexpr iterator_t<R> begin();13// constexpr sentinel_t<R> end();14// constexpr auto begin() const requires range<const R>;15// constexpr auto end() const requires range<const R>;16 17#include <ranges>18 19#include <array>20#include <cassert>21#include <concepts>22#include <memory>23 24#include "test_iterators.h"25#include "test_macros.h"26 27struct Base {28 constexpr int *begin() { return nullptr; }29 constexpr auto end() { return sentinel_wrapper<int*>(nullptr); }30 constexpr char *begin() const { return nullptr; }31 constexpr auto end() const { return sentinel_wrapper<char*>(nullptr); }32};33static_assert(std::same_as<std::ranges::iterator_t<Base>, int*>);34static_assert(std::same_as<std::ranges::sentinel_t<Base>, sentinel_wrapper<int*>>);35static_assert(std::same_as<std::ranges::iterator_t<const Base>, char*>);36static_assert(std::same_as<std::ranges::sentinel_t<const Base>, sentinel_wrapper<char*>>);37 38struct NoConst {39 int* begin();40 sentinel_wrapper<int*> end();41};42 43struct DecayChecker {44 int*& begin() const;45 int*& end() const;46};47 48template <class T>49concept HasBegin = requires (T t) {50 t.begin();51};52 53template <class T>54concept HasEnd = requires (T t) {55 t.end();56};57 58constexpr bool test()59{60 {61 using OwningView = std::ranges::owning_view<Base>;62 OwningView ov;63 std::same_as<int*> decltype(auto) b1 = static_cast<OwningView&>(ov).begin();64 std::same_as<int*> decltype(auto) b2 = static_cast<OwningView&&>(ov).begin();65 std::same_as<char*> decltype(auto) b3 = static_cast<const OwningView&>(ov).begin();66 std::same_as<char*> decltype(auto) b4 = static_cast<const OwningView&&>(ov).begin();67 68 std::same_as<sentinel_wrapper<int*>> decltype(auto) e1 = static_cast<OwningView&>(ov).end();69 std::same_as<sentinel_wrapper<int*>> decltype(auto) e2 = static_cast<OwningView&&>(ov).end();70 std::same_as<sentinel_wrapper<char*>> decltype(auto) e3 = static_cast<const OwningView&>(ov).end();71 std::same_as<sentinel_wrapper<char*>> decltype(auto) e4 = static_cast<const OwningView&&>(ov).end();72 73 assert(b1 == e1);74 assert(b2 == e2);75 assert(b3 == e3);76 assert(b4 == e4);77 }78 {79 // NoConst has non-const begin() and end(); so does the owning_view.80 using OwningView = std::ranges::owning_view<NoConst>;81 static_assert(HasBegin<OwningView&>);82 static_assert(HasBegin<OwningView&&>);83 static_assert(!HasBegin<const OwningView&>);84 static_assert(!HasBegin<const OwningView&&>);85 static_assert(HasEnd<OwningView&>);86 static_assert(HasEnd<OwningView&&>);87 static_assert(!HasEnd<const OwningView&>);88 static_assert(!HasEnd<const OwningView&&>);89 }90 {91 // DecayChecker's begin() and end() return references; make sure the owning_view decays them.92 using OwningView = std::ranges::owning_view<DecayChecker>;93 OwningView ov;94 ASSERT_SAME_TYPE(decltype(ov.begin()), int*);95 ASSERT_SAME_TYPE(decltype(ov.end()), int*);96 }97 {98 // Test an empty view.99 int a[] = {1};100 auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));101 assert(ov.begin() == a);102 assert(std::as_const(ov).begin() == a);103 assert(ov.end() == a);104 assert(std::as_const(ov).end() == a);105 }106 {107 // Test a non-empty view.108 int a[] = {1};109 auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1));110 assert(ov.begin() == a);111 assert(std::as_const(ov).begin() == a);112 assert(ov.end() == a+1);113 assert(std::as_const(ov).end() == a+1);114 }115 {116 // Test a non-view.117 std::array<int, 2> a = {1, 2};118 auto ov = std::ranges::owning_view(std::move(a));119 assert(std::to_address(ov.begin()) != std::to_address(a.begin())); // because it points into the copy120 assert(std::to_address(std::as_const(ov).begin()) != std::to_address(a.begin()));121 assert(std::to_address(ov.end()) != std::to_address(a.end()));122 assert(std::to_address(std::as_const(ov).end()) != std::to_address(a.end()));123 }124 return true;125}126 127int main(int, char**) {128 test();129 static_assert(test());130 131 return 0;132}133