File: base.pass.cpp

package info (click to toggle)
llvm-toolchain-21 1%3A21.1.7-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,245,064 kB
  • sloc: cpp: 7,619,731; ansic: 1,434,018; asm: 1,058,748; python: 252,740; f90: 94,671; objc: 70,685; lisp: 42,813; pascal: 18,401; sh: 8,601; ml: 5,111; perl: 4,720; makefile: 3,676; awk: 3,523; javascript: 2,409; xml: 892; fortran: 770
file content (132 lines) | stat: -rw-r--r-- 5,318 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// REQUIRES: std-at-least-c++23

// <ranges>

// constexpr View base() const& requires copy_constructible<View>;
// constexpr View base() &&;

#include <ranges>

#include <cassert>
#include <utility>
#include <vector>

using InnerRange = std::vector<int>;

struct Range : std::ranges::view_base {
  constexpr explicit Range(InnerRange* b, InnerRange* e) : begin_(b), end_(e) {}
  constexpr Range(const Range& other) : begin_(other.begin_), end_(other.end_), was_copy_initialized_(true) {}
  constexpr Range(Range&& other) : begin_(other.begin_), end_(other.end_), was_move_initialized_(true) {}
  Range& operator=(const Range&) = default;
  Range& operator=(Range&&)      = default;
  constexpr InnerRange* begin() const { return begin_; }
  constexpr InnerRange* end() const { return end_; }

  InnerRange* begin_;
  InnerRange* end_;
  bool was_copy_initialized_ = false;
  bool was_move_initialized_ = false;
};

static_assert(std::ranges::view<Range>);
static_assert(std::ranges::input_range<Range>);

struct Pattern : std::ranges::view_base {
  static constexpr int pat[2] = {0, 0};
  constexpr const int* begin() const { return pat; }
  constexpr const int* end() const { return pat + 2; }
};

static_assert(std::ranges::view<Pattern>);
static_assert(std::ranges::forward_range<Pattern>);

template <class Tp>
struct NonCopyableRange : std::ranges::view_base {
  NonCopyableRange(const NonCopyableRange&)            = delete;
  NonCopyableRange(NonCopyableRange&&)                 = default;
  NonCopyableRange& operator=(const NonCopyableRange&) = default;
  NonCopyableRange& operator=(NonCopyableRange&&)      = default;
  Tp* begin() const;
  Tp* end() const;
};

static_assert(!std::copy_constructible<NonCopyableRange<InnerRange>>);
static_assert(!std::copy_constructible<NonCopyableRange<int>>);

template <typename T>
concept CanCallBaseOn = requires(T&& t) { std::forward<T>(t).base(); };

constexpr bool test() {
  InnerRange buff[3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
  Pattern pattern;

  { // Check the const& overload
    Range range(buff, buff + 3);
    std::ranges::join_with_view<Range, Pattern> view(range, pattern);
    std::same_as<Range> decltype(auto) result = view.base();
    assert(result.was_copy_initialized_);
    assert(result.begin() == buff);
    assert(result.end() == buff + 3);
  }

  { // Check the const& overload on const `view`
    Range range(buff, buff + 3);
    const std::ranges::join_with_view<Range, Pattern> view(range, pattern);
    std::same_as<Range> decltype(auto) result = view.base();
    assert(result.was_copy_initialized_);
    assert(result.begin() == buff);
    assert(result.end() == buff + 3);
  }

  { // Check the && overload
    Range range(buff, buff + 3);
    std::ranges::join_with_view<Range, Pattern> view(range, pattern);
    std::same_as<Range> decltype(auto) result = std::move(view).base();
    assert(result.was_move_initialized_);
    assert(result.begin() == buff);
    assert(result.end() == buff + 3);
  }

  { // Ensure the const& overload is not considered when the base is not copy-constructible
    static_assert(!CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&>);
    static_assert(!CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&>);
    static_assert(!CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&&>);
    static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&&>);
    static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>>);
  }

  { // Ensure the const& overload does not depend on Pattern's copy-constructability
    static_assert(CanCallBaseOn<const std::ranges::join_with_view<Range, NonCopyableRange<int>>&>);
    static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>&>);
    static_assert(CanCallBaseOn<const std::ranges::join_with_view<Range, NonCopyableRange<int>>&&>);
    static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>&&>);
    static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>>);
  }

  { // Check above two at the same time
    static_assert(
        !CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&>);
    static_assert(!CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&>);
    static_assert(
        !CanCallBaseOn<const std::ranges::join_with_view< NonCopyableRange<InnerRange>, NonCopyableRange<int>>&&>);
    static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&&>);
    static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>>);
  }

  return true;
}

int main(int, char**) {
  test();
  static_assert(test());

  return 0;
}