//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // constexpr iterator_t begin(); // constexpr sentinel_t end(); // constexpr auto begin() const requires range; // constexpr auto end() const requires range; #include #include #include #include #include #include "test_iterators.h" #include "test_macros.h" struct Base { constexpr int *begin() { return nullptr; } constexpr auto end() { return sentinel_wrapper(nullptr); } constexpr char *begin() const { return nullptr; } constexpr auto end() const { return sentinel_wrapper(nullptr); } }; static_assert(std::same_as, int*>); static_assert(std::same_as, sentinel_wrapper>); static_assert(std::same_as, char*>); static_assert(std::same_as, sentinel_wrapper>); struct NoConst { int* begin(); sentinel_wrapper end(); }; struct DecayChecker { int*& begin() const; int*& end() const; }; template concept HasBegin = requires (T t) { t.begin(); }; template concept HasEnd = requires (T t) { t.end(); }; constexpr bool test() { { using OwningView = std::ranges::owning_view; OwningView ov; std::same_as decltype(auto) b1 = static_cast(ov).begin(); std::same_as decltype(auto) b2 = static_cast(ov).begin(); std::same_as decltype(auto) b3 = static_cast(ov).begin(); std::same_as decltype(auto) b4 = static_cast(ov).begin(); std::same_as> decltype(auto) e1 = static_cast(ov).end(); std::same_as> decltype(auto) e2 = static_cast(ov).end(); std::same_as> decltype(auto) e3 = static_cast(ov).end(); std::same_as> decltype(auto) e4 = static_cast(ov).end(); assert(b1 == e1); assert(b2 == e2); assert(b3 == e3); assert(b4 == e4); } { // NoConst has non-const begin() and end(); so does the owning_view. using OwningView = std::ranges::owning_view; static_assert(HasBegin); static_assert(HasBegin); static_assert(!HasBegin); static_assert(!HasBegin); static_assert(HasEnd); static_assert(HasEnd); static_assert(!HasEnd); static_assert(!HasEnd); } { // DecayChecker's begin() and end() return references; make sure the owning_view decays them. using OwningView = std::ranges::owning_view; OwningView ov; ASSERT_SAME_TYPE(decltype(ov.begin()), int*); ASSERT_SAME_TYPE(decltype(ov.end()), int*); } { // Test an empty view. int a[] = {1}; auto ov = std::ranges::owning_view(std::ranges::subrange(a, a)); assert(ov.begin() == a); assert(std::as_const(ov).begin() == a); assert(ov.end() == a); assert(std::as_const(ov).end() == a); } { // Test a non-empty view. int a[] = {1}; auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1)); assert(ov.begin() == a); assert(std::as_const(ov).begin() == a); assert(ov.end() == a+1); assert(std::as_const(ov).end() == a+1); } { // Test a non-view. std::array a = {1, 2}; auto ov = std::ranges::owning_view(std::move(a)); assert(std::to_address(ov.begin()) != std::to_address(a.begin())); // because it points into the copy assert(std::to_address(std::as_const(ov).begin()) != std::to_address(a.begin())); assert(std::to_address(ov.end()) != std::to_address(a.end())); assert(std::to_address(std::as_const(ov).end()) != std::to_address(a.end())); } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }