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