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

source code of libcxx/test/std/ranges/range.access/empty.pass.cpp