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