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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11 
12 // template <input_range Range>
13 //   requires constructible_from<View, views::all_t<Range>> &&
14 //             constructible_from<Pattern, single_view<range_value_t<Range>>>
15 // constexpr lazy_split_view(Range&& r, range_value_t<Range> e);
16 
17 #include <ranges>
18 
19 #include <cassert>
20 #include <string_view>
21 #include <type_traits>
22 #include <utility>
23 #include "small_string.h"
24 #include "types.h"
25 
26 struct ElementWithCounting {
27   int* times_copied = nullptr;
28   int* times_moved = nullptr;
29 
30   constexpr ElementWithCounting(int& copies_ctr, int& moves_ctr) : times_copied(&copies_ctr), times_moved(&moves_ctr) {}
31 
32   constexpr ElementWithCounting(const ElementWithCounting& rhs)
33       : times_copied(rhs.times_copied)
34       , times_moved(rhs.times_moved) {
35     ++(*times_copied);
36   }
37   constexpr ElementWithCounting(ElementWithCounting&& rhs)
38       : times_copied(rhs.times_copied)
39       , times_moved(rhs.times_moved) {
40     ++(*times_moved);
41   }
42 
43   constexpr bool operator==(const ElementWithCounting&) const { return true; }
44 };
45 
46 struct RangeWithCounting {
47   using value_type = ElementWithCounting;
48 
49   int* times_copied = nullptr;
50   int* times_moved = nullptr;
51 
52   constexpr RangeWithCounting(int& copies_ctr, int& moves_ctr) : times_copied(&copies_ctr), times_moved(&moves_ctr) {}
53 
54   constexpr RangeWithCounting(const RangeWithCounting& rhs)
55     : times_copied(rhs.times_copied)
56     , times_moved(rhs.times_moved) {
57     ++(*times_copied);
58   }
59   constexpr RangeWithCounting(RangeWithCounting&& rhs)
60     : times_copied(rhs.times_copied)
61     , times_moved(rhs.times_moved) {
62     ++(*times_moved);
63   }
64 
65   constexpr const ElementWithCounting* begin() const { return nullptr; }
66   constexpr const ElementWithCounting* end() const { return nullptr; }
67 
68   constexpr RangeWithCounting& operator=(const RangeWithCounting&) = default;
69   constexpr RangeWithCounting& operator=(RangeWithCounting&&) = default;
70   constexpr bool operator==(const RangeWithCounting&) const { return true; }
71 };
72 static_assert( std::ranges::forward_range<RangeWithCounting>);
73 static_assert(!std::ranges::view<RangeWithCounting>);
74 
75 struct StrRange {
76   SmallString buffer_;
77   constexpr explicit StrRange() = default;
78   constexpr StrRange(const char* ptr) : buffer_(ptr) {}
79   constexpr const char* begin() const { return buffer_.begin(); }
80   constexpr const char* end() const { return buffer_.end(); }
81   constexpr bool operator==(const StrRange& rhs) const { return buffer_ == rhs.buffer_; }
82 };
83 static_assert( std::ranges::random_access_range<StrRange>);
84 static_assert(!std::ranges::view<StrRange>);
85 static_assert( std::is_copy_constructible_v<StrRange>);
86 
87 struct StrView : std::ranges::view_base {
88   SmallString buffer_;
89   constexpr explicit StrView() = default;
90   constexpr StrView(const char* ptr) : buffer_(ptr) {}
91   template <std::ranges::range R>
92   constexpr StrView(R&& r) : buffer_(std::forward<R>(r)) {}
93   constexpr const char* begin() const { return buffer_.begin(); }
94   constexpr const char* end() const { return buffer_.end(); }
95   constexpr bool operator==(const StrView& rhs) const { return buffer_ == rhs.buffer_; }
96 };
97 static_assert( std::ranges::random_access_range<StrView>);
98 static_assert( std::ranges::view<StrView>);
99 static_assert( std::is_copy_constructible_v<StrView>);
100 
101 constexpr bool test() {
102   {
103     using V = std::ranges::lazy_split_view<StrView, StrView>;
104 
105     // Calling the constructor with `(StrRange, range_value_t)`.
106     {
107       StrRange input;
108       V v(input, ' ');
109       assert(v.base() == input);
110     }
111 
112     // Calling the constructor with `(StrView, range_value_t)`.
113     {
114       StrView input("abc def");
115       V v(input, ' ');
116       assert(v.base() == input);
117     }
118 
119     struct Empty {};
120     static_assert(!std::is_constructible_v<V, Empty, std::string_view>);
121     static_assert(!std::is_constructible_v<V, std::string_view, Empty>);
122   }
123 
124   // Make sure the arguments are moved, not copied.
125   {
126     using Range = RangeWithCounting;
127     using Element = ElementWithCounting;
128     // TODO(varconst): use `views::single` once it's implemented.
129     using Pattern = std::ranges::single_view<Element>;
130 
131     // Arguments are lvalues.
132     {
133       using View = std::ranges::ref_view<Range>;
134 
135       int range_copied = 0, range_moved = 0, element_copied = 0, element_moved = 0;
136       Range range(range_copied, range_moved);
137       Element element(element_copied, element_moved);
138 
139       std::ranges::lazy_split_view<View, Pattern> v(range, element);
140       assert(range_copied == 0); // `ref_view` does neither copy...
141       assert(range_moved == 0); // ...nor move the element.
142       assert(element_copied == 1); // The element is copied into the argument...
143       assert(element_moved == 1); // ...and moved into the member variable.
144     }
145 
146     // Arguments are rvalues.
147     {
148       using View = std::ranges::owning_view<Range>;
149 
150       int range_copied = 0, range_moved = 0, element_copied = 0, element_moved = 0;
151       std::ranges::lazy_split_view<View, Pattern> v(
152           Range(range_copied, range_moved), Element(element_copied, element_moved));
153       assert(range_copied == 0);
154       assert(range_moved == 1); // `owning_view` moves the given argument.
155       assert(element_copied == 0);
156       assert(element_moved == 1);
157     }
158   }
159 
160   return true;
161 }
162 
163 int main(int, char**) {
164   test();
165   static_assert(test());
166 
167   return 0;
168 }
169