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// REQUIRES: std-at-least-c++2310 11// <ranges>12 13// constexpr View base() const& requires copy_constructible<View>;14// constexpr View base() &&;15 16#include <ranges>17 18#include <cassert>19#include <utility>20#include <vector>21 22using InnerRange = std::vector<int>;23 24struct Range : std::ranges::view_base {25 constexpr explicit Range(InnerRange* b, InnerRange* e) : begin_(b), end_(e) {}26 constexpr Range(const Range& other) : begin_(other.begin_), end_(other.end_), was_copy_initialized_(true) {}27 constexpr Range(Range&& other) : begin_(other.begin_), end_(other.end_), was_move_initialized_(true) {}28 Range& operator=(const Range&) = default;29 Range& operator=(Range&&) = default;30 constexpr InnerRange* begin() const { return begin_; }31 constexpr InnerRange* end() const { return end_; }32 33 InnerRange* begin_;34 InnerRange* end_;35 bool was_copy_initialized_ = false;36 bool was_move_initialized_ = false;37};38 39static_assert(std::ranges::view<Range>);40static_assert(std::ranges::input_range<Range>);41 42struct Pattern : std::ranges::view_base {43 static constexpr int pat[2] = {0, 0};44 constexpr const int* begin() const { return pat; }45 constexpr const int* end() const { return pat + 2; }46};47 48static_assert(std::ranges::view<Pattern>);49static_assert(std::ranges::forward_range<Pattern>);50 51template <class Tp>52struct NonCopyableRange : std::ranges::view_base {53 NonCopyableRange(const NonCopyableRange&) = delete;54 NonCopyableRange(NonCopyableRange&&) = default;55 NonCopyableRange& operator=(const NonCopyableRange&) = default;56 NonCopyableRange& operator=(NonCopyableRange&&) = default;57 Tp* begin() const;58 Tp* end() const;59};60 61static_assert(!std::copy_constructible<NonCopyableRange<InnerRange>>);62static_assert(!std::copy_constructible<NonCopyableRange<int>>);63 64template <typename T>65concept CanCallBaseOn = requires(T&& t) { std::forward<T>(t).base(); };66 67constexpr bool test() {68 InnerRange buff[3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};69 Pattern pattern;70 71 { // Check the const& overload72 Range range(buff, buff + 3);73 std::ranges::join_with_view<Range, Pattern> view(range, pattern);74 std::same_as<Range> decltype(auto) result = view.base();75 assert(result.was_copy_initialized_);76 assert(result.begin() == buff);77 assert(result.end() == buff + 3);78 }79 80 { // Check the const& overload on const `view`81 Range range(buff, buff + 3);82 const std::ranges::join_with_view<Range, Pattern> view(range, pattern);83 std::same_as<Range> decltype(auto) result = view.base();84 assert(result.was_copy_initialized_);85 assert(result.begin() == buff);86 assert(result.end() == buff + 3);87 }88 89 { // Check the && overload90 Range range(buff, buff + 3);91 std::ranges::join_with_view<Range, Pattern> view(range, pattern);92 std::same_as<Range> decltype(auto) result = std::move(view).base();93 assert(result.was_move_initialized_);94 assert(result.begin() == buff);95 assert(result.end() == buff + 3);96 }97 98 { // Ensure the const& overload is not considered when the base is not copy-constructible99 static_assert(!CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&>);100 static_assert(!CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&>);101 static_assert(!CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&&>);102 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&&>);103 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>>);104 }105 106 { // Ensure the const& overload does not depend on Pattern's copy-constructability107 static_assert(CanCallBaseOn<const std::ranges::join_with_view<Range, NonCopyableRange<int>>&>);108 static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>&>);109 static_assert(CanCallBaseOn<const std::ranges::join_with_view<Range, NonCopyableRange<int>>&&>);110 static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>&&>);111 static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>>);112 }113 114 { // Check above two at the same time115 static_assert(116 !CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&>);117 static_assert(!CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&>);118 static_assert(119 !CanCallBaseOn<const std::ranges::join_with_view< NonCopyableRange<InnerRange>, NonCopyableRange<int>>&&>);120 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&&>);121 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>>);122 }123 124 return true;125}126 127int main(int, char**) {128 test();129 static_assert(test());130 131 return 0;132}133