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