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