xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.lazy.split/ctor.range.pass.cpp (revision 120b0bfbf0bade430fa9b19d78025ccd1d6148d0)
1e53c461bSKonstantin Varlamov //===----------------------------------------------------------------------===//
2e53c461bSKonstantin Varlamov //
3e53c461bSKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e53c461bSKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
5e53c461bSKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e53c461bSKonstantin Varlamov //
7e53c461bSKonstantin Varlamov //===----------------------------------------------------------------------===//
8e53c461bSKonstantin Varlamov 
9e53c461bSKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
10e53c461bSKonstantin Varlamov 
11e53c461bSKonstantin Varlamov // template <input_range Range>
12e53c461bSKonstantin Varlamov //   requires constructible_from<View, views::all_t<Range>> &&
13e53c461bSKonstantin Varlamov //             constructible_from<Pattern, single_view<range_value_t<Range>>>
1440aaa272SHristo Hristov // constexpr lazy_split_view(Range&& r, range_value_t<Range> e); // explicit since C++23
15e53c461bSKonstantin Varlamov 
16e53c461bSKonstantin Varlamov #include <ranges>
17e53c461bSKonstantin Varlamov 
18e53c461bSKonstantin Varlamov #include <cassert>
19ae2ae84fSJoe Loser #include <string>
20e53c461bSKonstantin Varlamov #include <string_view>
21e53c461bSKonstantin Varlamov #include <type_traits>
22e53c461bSKonstantin Varlamov #include <utility>
2340aaa272SHristo Hristov 
2440aaa272SHristo Hristov #include "test_convertible.h"
25*120b0bfbSHui #include "test_macros.h"
26e53c461bSKonstantin Varlamov #include "types.h"
27e53c461bSKonstantin Varlamov 
28e53c461bSKonstantin Varlamov struct ElementWithCounting {
29e53c461bSKonstantin Varlamov   int* times_copied = nullptr;
30e53c461bSKonstantin Varlamov   int* times_moved  = nullptr;
31e53c461bSKonstantin Varlamov 
ElementWithCountingElementWithCounting32e53c461bSKonstantin Varlamov   constexpr ElementWithCounting(int& copies_ctr, int& moves_ctr) : times_copied(&copies_ctr), times_moved(&moves_ctr) {}
33e53c461bSKonstantin Varlamov 
ElementWithCountingElementWithCounting34e53c461bSKonstantin Varlamov   constexpr ElementWithCounting(const ElementWithCounting& rhs)
35*120b0bfbSHui       : times_copied(rhs.times_copied), times_moved(rhs.times_moved) {
36e53c461bSKonstantin Varlamov     ++(*times_copied);
37e53c461bSKonstantin Varlamov   }
ElementWithCountingElementWithCounting38e53c461bSKonstantin Varlamov   constexpr ElementWithCounting(ElementWithCounting&& rhs)
39*120b0bfbSHui       : times_copied(rhs.times_copied), times_moved(rhs.times_moved) {
40e53c461bSKonstantin Varlamov     ++(*times_moved);
41e53c461bSKonstantin Varlamov   }
42e53c461bSKonstantin Varlamov 
operator ==ElementWithCounting43e53c461bSKonstantin Varlamov   constexpr bool operator==(const ElementWithCounting&) const { return true; }
44e53c461bSKonstantin Varlamov };
45e53c461bSKonstantin Varlamov 
46e53c461bSKonstantin Varlamov struct RangeWithCounting {
47e53c461bSKonstantin Varlamov   using value_type = ElementWithCounting;
48e53c461bSKonstantin Varlamov 
49e53c461bSKonstantin Varlamov   int* times_copied = nullptr;
50e53c461bSKonstantin Varlamov   int* times_moved  = nullptr;
51e53c461bSKonstantin Varlamov 
RangeWithCountingRangeWithCounting52e53c461bSKonstantin Varlamov   constexpr RangeWithCounting(int& copies_ctr, int& moves_ctr) : times_copied(&copies_ctr), times_moved(&moves_ctr) {}
53e53c461bSKonstantin Varlamov 
RangeWithCountingRangeWithCounting54e53c461bSKonstantin Varlamov   constexpr RangeWithCounting(const RangeWithCounting& rhs)
55*120b0bfbSHui       : times_copied(rhs.times_copied), times_moved(rhs.times_moved) {
56e53c461bSKonstantin Varlamov     ++(*times_copied);
57e53c461bSKonstantin Varlamov   }
RangeWithCountingRangeWithCounting58*120b0bfbSHui   constexpr RangeWithCounting(RangeWithCounting&& rhs) : times_copied(rhs.times_copied), times_moved(rhs.times_moved) {
59e53c461bSKonstantin Varlamov     ++(*times_moved);
60e53c461bSKonstantin Varlamov   }
61e53c461bSKonstantin Varlamov 
beginRangeWithCounting62e53c461bSKonstantin Varlamov   constexpr const ElementWithCounting* begin() const { return nullptr; }
endRangeWithCounting63e53c461bSKonstantin Varlamov   constexpr const ElementWithCounting* end() const { return nullptr; }
64e53c461bSKonstantin Varlamov 
65e53c461bSKonstantin Varlamov   constexpr RangeWithCounting& operator=(const RangeWithCounting&) = default;
66e53c461bSKonstantin Varlamov   constexpr RangeWithCounting& operator=(RangeWithCounting&&)      = default;
operator ==RangeWithCounting67e53c461bSKonstantin Varlamov   constexpr bool operator==(const RangeWithCounting&) const { return true; }
68e53c461bSKonstantin Varlamov };
69e53c461bSKonstantin Varlamov static_assert(std::ranges::forward_range<RangeWithCounting>);
70e53c461bSKonstantin Varlamov static_assert(!std::ranges::view<RangeWithCounting>);
71e53c461bSKonstantin Varlamov 
72e53c461bSKonstantin Varlamov struct StrView : std::ranges::view_base {
73ae2ae84fSJoe Loser   std::string_view buffer_;
74e53c461bSKonstantin Varlamov   constexpr explicit StrView() = default;
StrViewStrView75e53c461bSKonstantin Varlamov   constexpr StrView(const char* ptr) : buffer_(ptr) {}
76ae2ae84fSJoe Loser   // Intentionally don't forward to range constructor for std::string_view since
77ae2ae84fSJoe Loser   // this test needs to work on C++20 as well and the range constructor is only for
78ae2ae84fSJoe Loser   // C++23 and later.
79e53c461bSKonstantin Varlamov   template <std::ranges::range R>
StrViewStrView80ae2ae84fSJoe Loser   constexpr StrView(R&& r) : buffer_(r.begin(), r.end()) {}
beginStrView81a845b5b4SLouis Dionne   constexpr std::string_view::const_iterator begin() const { return buffer_.begin(); }
endStrView82a845b5b4SLouis Dionne   constexpr std::string_view::const_iterator end() const { return buffer_.end(); }
operator ==StrView83e53c461bSKonstantin Varlamov   constexpr bool operator==(const StrView& rhs) const { return buffer_ == rhs.buffer_; }
84e53c461bSKonstantin Varlamov };
85e53c461bSKonstantin Varlamov static_assert(std::ranges::random_access_range<StrView>);
86e53c461bSKonstantin Varlamov static_assert(std::ranges::view<StrView>);
87e53c461bSKonstantin Varlamov static_assert(std::is_copy_constructible_v<StrView>);
88e53c461bSKonstantin Varlamov 
8940aaa272SHristo Hristov // SFINAE tests.
9040aaa272SHristo Hristov 
9140aaa272SHristo Hristov #if TEST_STD_VER >= 23
9240aaa272SHristo Hristov 
9340aaa272SHristo Hristov static_assert(
9440aaa272SHristo Hristov     !test_convertible<std::ranges::lazy_split_view<StrView, StrView>, StrView, std::ranges::range_value_t<StrView>>(),
9540aaa272SHristo Hristov     "This constructor must be explicit");
9640aaa272SHristo Hristov 
9740aaa272SHristo Hristov #else
9840aaa272SHristo Hristov 
9940aaa272SHristo Hristov static_assert(
10040aaa272SHristo Hristov     test_convertible<std::ranges::lazy_split_view<StrView, StrView>, StrView, std::ranges::range_value_t<StrView>>(),
10140aaa272SHristo Hristov     "This constructor must not be explicit");
10240aaa272SHristo Hristov 
10340aaa272SHristo Hristov #endif // TEST_STD_VER >= 23
10440aaa272SHristo Hristov 
test()105e53c461bSKonstantin Varlamov constexpr bool test() {
106e53c461bSKonstantin Varlamov   {
107e53c461bSKonstantin Varlamov     using V = std::ranges::lazy_split_view<StrView, StrView>;
108e53c461bSKonstantin Varlamov 
109ae2ae84fSJoe Loser     // Calling the constructor with `(std::string, range_value_t)`.
110e53c461bSKonstantin Varlamov     {
111ae2ae84fSJoe Loser       std::string input;
112e53c461bSKonstantin Varlamov       V v(input, ' ');
113e53c461bSKonstantin Varlamov       assert(v.base() == input);
114e53c461bSKonstantin Varlamov     }
115e53c461bSKonstantin Varlamov 
116e53c461bSKonstantin Varlamov     // Calling the constructor with `(StrView, range_value_t)`.
117e53c461bSKonstantin Varlamov     {
118e53c461bSKonstantin Varlamov       StrView input("abc def");
119e53c461bSKonstantin Varlamov       V v(input, ' ');
120e53c461bSKonstantin Varlamov       assert(v.base() == input);
121e53c461bSKonstantin Varlamov     }
122e53c461bSKonstantin Varlamov 
123e53c461bSKonstantin Varlamov     struct Empty {};
124e53c461bSKonstantin Varlamov     static_assert(!std::is_constructible_v<V, Empty, std::string_view>);
125e53c461bSKonstantin Varlamov     static_assert(!std::is_constructible_v<V, std::string_view, Empty>);
126e53c461bSKonstantin Varlamov   }
127e53c461bSKonstantin Varlamov 
128e53c461bSKonstantin Varlamov   // Make sure the arguments are moved, not copied.
129e53c461bSKonstantin Varlamov   {
130e53c461bSKonstantin Varlamov     using Range   = RangeWithCounting;
131e53c461bSKonstantin Varlamov     using Element = ElementWithCounting;
132e53c461bSKonstantin Varlamov     using Pattern = std::ranges::single_view<Element>;
133e53c461bSKonstantin Varlamov 
134e53c461bSKonstantin Varlamov     // Arguments are lvalues.
135e53c461bSKonstantin Varlamov     {
136e53c461bSKonstantin Varlamov       using View = std::ranges::ref_view<Range>;
137e53c461bSKonstantin Varlamov 
138e53c461bSKonstantin Varlamov       int range_copied = 0, range_moved = 0, element_copied = 0, element_moved = 0;
139e53c461bSKonstantin Varlamov       Range range(range_copied, range_moved);
140e53c461bSKonstantin Varlamov       Element element(element_copied, element_moved);
141e53c461bSKonstantin Varlamov 
142e53c461bSKonstantin Varlamov       std::ranges::lazy_split_view<View, Pattern> v(range, element);
143e53c461bSKonstantin Varlamov       assert(range_copied == 0);   // `ref_view` does neither copy...
144e53c461bSKonstantin Varlamov       assert(range_moved == 0);    // ...nor move the element.
145e53c461bSKonstantin Varlamov       assert(element_copied == 1); // The element is copied into the argument...
146*120b0bfbSHui #ifndef TEST_COMPILER_GCC
147*120b0bfbSHui       //https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995
148e53c461bSKonstantin Varlamov       assert(element_moved == 1); // ...and moved into the member variable.
149*120b0bfbSHui #endif
150e53c461bSKonstantin Varlamov     }
151e53c461bSKonstantin Varlamov 
152e53c461bSKonstantin Varlamov     // Arguments are rvalues.
153e53c461bSKonstantin Varlamov     {
154e53c461bSKonstantin Varlamov       using View = std::ranges::owning_view<Range>;
155e53c461bSKonstantin Varlamov 
156e53c461bSKonstantin Varlamov       int range_copied = 0, range_moved = 0, element_copied = 0, element_moved = 0;
157e53c461bSKonstantin Varlamov       std::ranges::lazy_split_view<View, Pattern> v(
158e53c461bSKonstantin Varlamov           Range(range_copied, range_moved), Element(element_copied, element_moved));
159e53c461bSKonstantin Varlamov       assert(range_copied == 0);
160e53c461bSKonstantin Varlamov       assert(range_moved == 1); // `owning_view` moves the given argument.
161e53c461bSKonstantin Varlamov       assert(element_copied == 0);
162*120b0bfbSHui #ifndef TEST_COMPILER_GCC
163*120b0bfbSHui       //https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995
164e53c461bSKonstantin Varlamov       assert(element_moved == 1);
165*120b0bfbSHui #endif
166e53c461bSKonstantin Varlamov     }
167e53c461bSKonstantin Varlamov   }
168e53c461bSKonstantin Varlamov 
169e53c461bSKonstantin Varlamov   return true;
170e53c461bSKonstantin Varlamov }
171e53c461bSKonstantin Varlamov 
main(int,char **)172e53c461bSKonstantin Varlamov int main(int, char**) {
173e53c461bSKonstantin Varlamov   test();
174e53c461bSKonstantin Varlamov   static_assert(test());
175e53c461bSKonstantin Varlamov 
176e53c461bSKonstantin Varlamov   return 0;
177e53c461bSKonstantin Varlamov }
178