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