xref: /llvm-project/libcxx/test/std/ranges/range.access/empty.pass.cpp (revision 6842f52a0bbf851b43b51fa8dc7dd8dfb533d0e7)
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