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 // std::ranges::empty 13 14 #include <ranges> 15 16 #include <cassert> 17 #include <utility> 18 #include "test_macros.h" 19 #include "test_iterators.h" 20 21 using RangeEmptyT = decltype(std::ranges::empty); 22 23 static_assert(!std::is_invocable_v<RangeEmptyT, int[]>); 24 static_assert(!std::is_invocable_v<RangeEmptyT, int(&)[]>); 25 static_assert(!std::is_invocable_v<RangeEmptyT, int(&&)[]>); 26 static_assert( std::is_invocable_v<RangeEmptyT, int[1]>); 27 static_assert( std::is_invocable_v<RangeEmptyT, const int[1]>); 28 static_assert( std::is_invocable_v<RangeEmptyT, int (&&)[1]>); 29 static_assert( std::is_invocable_v<RangeEmptyT, int (&)[1]>); 30 static_assert( std::is_invocable_v<RangeEmptyT, const int (&)[1]>); 31 32 struct Incomplete; 33 static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete[]>); 34 static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete(&)[]>); 35 static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete(&&)[]>); 36 37 extern Incomplete array_of_incomplete[42]; 38 static_assert(!std::ranges::empty(array_of_incomplete)); 39 static_assert(!std::ranges::empty(std::move(array_of_incomplete))); 40 static_assert(!std::ranges::empty(std::as_const(array_of_incomplete))); 41 static_assert(!std::ranges::empty(static_cast<const Incomplete(&&)[42]>(array_of_incomplete))); 42 43 struct InputRangeWithoutSize { 44 cpp17_input_iterator<int*> begin() const; 45 cpp17_input_iterator<int*> end() const; 46 }; 47 static_assert(!std::is_invocable_v<RangeEmptyT, const InputRangeWithoutSize&>); 48 49 struct NonConstEmpty { 50 bool empty(); 51 }; 52 static_assert(!std::is_invocable_v<RangeEmptyT, const NonConstEmpty&>); 53 54 struct HasMemberAndFunction { 55 constexpr bool empty() const { return true; } 56 // We should never do ADL lookup for std::ranges::empty. 57 friend bool empty(const HasMemberAndFunction&) { return false; } 58 }; 59 60 struct BadReturnType { 61 BadReturnType empty() { return {}; } 62 }; 63 static_assert(!std::is_invocable_v<RangeEmptyT, BadReturnType&>); 64 65 struct BoolConvertible { 66 constexpr explicit operator bool() noexcept(false) { return true; } 67 }; 68 struct BoolConvertibleReturnType { 69 constexpr BoolConvertible empty() noexcept { return {}; } 70 }; 71 static_assert(!noexcept(std::ranges::empty(BoolConvertibleReturnType()))); 72 73 struct InputIterators { 74 cpp17_input_iterator<int*> begin() const; 75 cpp17_input_iterator<int*> end() const; 76 }; 77 static_assert(std::is_same_v<decltype(InputIterators().begin() == InputIterators().end()), bool>); 78 static_assert(!std::is_invocable_v<RangeEmptyT, const InputIterators&>); 79 80 constexpr bool testEmptyMember() { 81 HasMemberAndFunction a; 82 assert(std::ranges::empty(a)); 83 84 BoolConvertibleReturnType b; 85 assert(std::ranges::empty(b)); 86 87 return true; 88 } 89 90 struct SizeMember { 91 size_t size_; 92 constexpr size_t size() const { return size_; } 93 }; 94 95 struct SizeFunction { 96 size_t size_; 97 friend constexpr size_t size(SizeFunction sf) { return sf.size_; } 98 }; 99 100 struct BeginEndSizedSentinel { 101 constexpr int *begin() const { return nullptr; } 102 constexpr auto end() const { return sized_sentinel<int*>(nullptr); } 103 }; 104 static_assert(std::ranges::forward_range<BeginEndSizedSentinel>); 105 static_assert(std::ranges::sized_range<BeginEndSizedSentinel>); 106 107 constexpr bool testUsingRangesSize() { 108 SizeMember a{1}; 109 assert(!std::ranges::empty(a)); 110 SizeMember b{0}; 111 assert(std::ranges::empty(b)); 112 113 SizeFunction c{1}; 114 assert(!std::ranges::empty(c)); 115 SizeFunction d{0}; 116 assert(std::ranges::empty(d)); 117 118 BeginEndSizedSentinel e; 119 assert(std::ranges::empty(e)); 120 121 return true; 122 } 123 124 struct BeginEndNotSizedSentinel { 125 constexpr int *begin() const { return nullptr; } 126 constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); } 127 }; 128 static_assert( std::ranges::forward_range<BeginEndNotSizedSentinel>); 129 static_assert(!std::ranges::sized_range<BeginEndNotSizedSentinel>); 130 131 // size is disabled here, so we have to compare begin and end. 132 struct DisabledSizeRangeWithBeginEnd { 133 constexpr int *begin() const { return nullptr; } 134 constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); } 135 size_t size() const; 136 }; 137 template<> 138 inline constexpr bool std::ranges::disable_sized_range<DisabledSizeRangeWithBeginEnd> = true; 139 static_assert(std::ranges::contiguous_range<DisabledSizeRangeWithBeginEnd>); 140 static_assert(!std::ranges::sized_range<DisabledSizeRangeWithBeginEnd>); 141 142 struct BeginEndAndEmpty { 143 constexpr int *begin() const { return nullptr; } 144 constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); } 145 constexpr bool empty() { return false; } 146 }; 147 148 struct EvilBeginEnd { 149 bool empty() &&; 150 constexpr int *begin() & { return nullptr; } 151 constexpr int *end() & { return nullptr; } 152 }; 153 154 constexpr bool testBeginEqualsEnd() { 155 BeginEndNotSizedSentinel a; 156 assert(std::ranges::empty(a)); 157 158 DisabledSizeRangeWithBeginEnd d; 159 assert(std::ranges::empty(d)); 160 161 BeginEndAndEmpty e; 162 assert(!std::ranges::empty(e)); // e.empty() 163 assert(std::ranges::empty(std::as_const(e))); // e.begin() == e.end() 164 165 assert(std::ranges::empty(EvilBeginEnd())); 166 167 return true; 168 } 169 170 // Test ADL-proofing. 171 struct Incomplete; 172 template<class T> struct Holder { T t; }; 173 static_assert(!std::is_invocable_v<RangeEmptyT, Holder<Incomplete>*>); 174 static_assert(!std::is_invocable_v<RangeEmptyT, Holder<Incomplete>*&>); 175 176 int main(int, char**) { 177 testEmptyMember(); 178 static_assert(testEmptyMember()); 179 180 testUsingRangesSize(); 181 static_assert(testUsingRangesSize()); 182 183 testBeginEqualsEnd(); 184 static_assert(testBeginEqualsEnd()); 185 186 return 0; 187 } 188