1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
17 #include "test_macros.h"
18 #include "test_iterators.h"
20 using RangeEmptyT
= decltype(std::ranges::empty
);
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]>);
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(&&)[]>);
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
)));
42 struct InputRangeWithoutSize
{
43 cpp17_input_iterator
<int*> begin() const;
44 cpp17_input_iterator
<int*> end() const;
46 static_assert(!std::is_invocable_v
<RangeEmptyT
, const InputRangeWithoutSize
&>);
48 struct NonConstEmpty
{
51 static_assert(!std::is_invocable_v
<RangeEmptyT
, const NonConstEmpty
&>);
53 struct 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; }
59 struct BadReturnType
{
60 BadReturnType
empty() { return {}; }
62 static_assert(!std::is_invocable_v
<RangeEmptyT
, BadReturnType
&>);
64 struct BoolConvertible
{
65 constexpr explicit operator bool() noexcept(false) { return true; }
67 struct BoolConvertibleReturnType
{
68 constexpr BoolConvertible
empty() noexcept
{ return {}; }
70 static_assert(!noexcept(std::ranges::empty(BoolConvertibleReturnType())));
72 struct InputIterators
{
73 cpp17_input_iterator
<int*> begin() const;
74 cpp17_input_iterator
<int*> end() const;
76 static_assert(std::is_same_v
<decltype(InputIterators().begin() == InputIterators().end()), bool>);
77 static_assert(!std::is_invocable_v
<RangeEmptyT
, const InputIterators
&>);
79 constexpr bool testEmptyMember() {
80 HasMemberAndFunction a
;
81 assert(std::ranges::empty(a
));
83 BoolConvertibleReturnType b
;
84 assert(std::ranges::empty(b
));
91 constexpr std::size_t size() const { return size_
; }
96 friend constexpr std::size_t size(SizeFunction sf
) { return sf
.size_
; }
99 struct BeginEndSizedSentinel
{
100 constexpr int *begin() const { return nullptr; }
101 constexpr auto end() const { return sized_sentinel
<int*>(nullptr); }
103 static_assert(std::ranges::forward_range
<BeginEndSizedSentinel
>);
104 static_assert(std::ranges::sized_range
<BeginEndSizedSentinel
>);
106 constexpr bool testUsingRangesSize() {
108 assert(!std::ranges::empty(a
));
110 assert(std::ranges::empty(b
));
113 assert(!std::ranges::empty(c
));
115 assert(std::ranges::empty(d
));
117 BeginEndSizedSentinel e
;
118 assert(std::ranges::empty(e
));
123 struct BeginEndNotSizedSentinel
{
124 constexpr int *begin() const { return nullptr; }
125 constexpr auto end() const { return sentinel_wrapper
<int*>(nullptr); }
127 static_assert( std::ranges::forward_range
<BeginEndNotSizedSentinel
>);
128 static_assert(!std::ranges::sized_range
<BeginEndNotSizedSentinel
>);
130 // size is disabled here, so we have to compare begin and end.
131 struct DisabledSizeRangeWithBeginEnd
{
132 constexpr int *begin() const { return nullptr; }
133 constexpr auto end() const { return sentinel_wrapper
<int*>(nullptr); }
134 std::size_t size() const;
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
>);
141 struct BeginEndAndEmpty
{
142 constexpr int *begin() const { return nullptr; }
143 constexpr auto end() const { return sentinel_wrapper
<int*>(nullptr); }
144 constexpr bool empty() { return false; }
147 struct EvilBeginEnd
{
149 constexpr int *begin() & { return nullptr; }
150 constexpr int *end() & { return nullptr; }
153 constexpr bool testBeginEqualsEnd() {
154 BeginEndNotSizedSentinel a
;
155 assert(std::ranges::empty(a
));
157 DisabledSizeRangeWithBeginEnd d
;
158 assert(std::ranges::empty(d
));
161 assert(!std::ranges::empty(e
)); // e.empty()
162 assert(std::ranges::empty(std::as_const(e
))); // e.begin() == e.end()
164 assert(std::ranges::empty(EvilBeginEnd()));
169 // Test ADL-proofing.
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
>*&>);
175 int main(int, char**) {
177 static_assert(testEmptyMember());
179 testUsingRangesSize();
180 static_assert(testUsingRangesSize());
182 testBeginEqualsEnd();
183 static_assert(testBeginEqualsEnd());