//===----------------------------------------------------------------------===// // // 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, c++20 // constexpr auto end() // constexpr auto end() const #include #include #include #include "test_iterators.h" struct DefaultConstructibleView : std::ranges::view_base { int* begin() const; int* end() const; }; struct CVCallView : std::ranges::view_base { mutable bool const_called = false; mutable int i[1]; constexpr int* begin() { const_called = false; return i; } constexpr int* begin() const { const_called = true; return i; } constexpr int* end() { const_called = false; return i + 1; } constexpr int* end() const { const_called = true; return i + 1; } }; struct NonConstCommonRange : std::ranges::view_base { int* begin(); int* end(); int* begin() const; sentinel_wrapper end() const; }; struct NonConstView : std::ranges::view_base { int* begin(); int* end(); }; template concept HasEnd = requires(T t) { t.end(); }; static_assert(HasEnd>); static_assert(HasEnd>); static_assert(HasEnd>); static_assert(!HasEnd>); static_assert(std::is_same_v>().end()), std::move_iterator>); static_assert(std::is_same_v>().end()), std::move_sentinel>>); template constexpr void test_range() { using Expected = std::conditional_t, std::move_sentinel>; int a[] = {1, 2}; std::ranges::subrange range(Iter(std::begin(a)), Sent(Iter(std::end(a)))); std::ranges::as_rvalue_view view(std::move(range)); std::same_as decltype(auto) iter = view.end(); assert(base(base(iter.base())) == std::end(a)); } template class WrapRange { Iter iter_; Sent sent_; public: constexpr WrapRange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {} constexpr Iter begin() const { return iter_; } constexpr Sent end() const { return sent_; } }; template WrapRange(Iter, Sent) -> WrapRange; template constexpr void test_const_range() { using Expected = std::conditional_t, std::move_sentinel>; int a[] = {1, 2}; auto range = WrapRange{Iter(a), Sent(Iter(a + 2))}; const std::ranges::as_rvalue_view view(std::move(range)); std::same_as decltype(auto) iter = view.end(); assert(base(base(iter.base())) == std::end(a)); } struct move_iterator_view : std::ranges::view_base { constexpr std::move_iterator begin() const { return {}; } constexpr std::move_iterator end() const { return {}; } }; constexpr bool test() { test_range, sentinel_wrapper>, false>(); test_range, sized_sentinel>, false>(); test_range, sentinel_wrapper>, false>(); test_range, sized_sentinel>, false>(); types::for_each(types::forward_iterator_list{}, [] { test_range(); test_range, false>(); test_range, false>(); }); { std::ranges::as_rvalue_view view(CVCallView{}); (void)view.end(); assert(view.base().const_called); } { // check that with a std::move_iterator begin() doesn't return move_iterator> std::ranges::as_rvalue_view view{move_iterator_view{}}; std::same_as> decltype(auto) it = view.end(); assert(it == std::move_iterator{}); } return true; } int main(int, char**) { test(); // gcc cannot have mutable member in constant expression #if !defined(TEST_COMPILER_GCC) static_assert(test()); #endif return 0; }