16842f52aSArthur O'Dwyer //===----------------------------------------------------------------------===//
26842f52aSArthur O'Dwyer //
36842f52aSArthur O'Dwyer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46842f52aSArthur O'Dwyer // See https://llvm.org/LICENSE.txt for license information.
56842f52aSArthur O'Dwyer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66842f52aSArthur O'Dwyer //
76842f52aSArthur O'Dwyer //===----------------------------------------------------------------------===//
86842f52aSArthur O'Dwyer
96842f52aSArthur O'Dwyer // UNSUPPORTED: c++03, c++11, c++14, c++17
106842f52aSArthur O'Dwyer
116842f52aSArthur O'Dwyer // std::ranges::empty
126842f52aSArthur O'Dwyer
136842f52aSArthur O'Dwyer #include <ranges>
146842f52aSArthur O'Dwyer
156842f52aSArthur O'Dwyer #include <cassert>
16a2a9a5c7SArthur O'Dwyer #include <utility>
176842f52aSArthur O'Dwyer #include "test_macros.h"
186842f52aSArthur O'Dwyer #include "test_iterators.h"
196842f52aSArthur O'Dwyer
206842f52aSArthur O'Dwyer using RangeEmptyT = decltype(std::ranges::empty);
216842f52aSArthur O'Dwyer
226842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, int[]>);
236842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, int(&)[]>);
246842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, int(&&)[]>);
256842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, int[1]>);
266842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, const int[1]>);
276842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, int (&&)[1]>);
286842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, int (&)[1]>);
296842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, const int (&)[1]>);
306842f52aSArthur O'Dwyer
316842f52aSArthur O'Dwyer struct Incomplete;
326842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete[]>);
336842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete(&)[]>);
346842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete(&&)[]>);
356842f52aSArthur O'Dwyer
366842f52aSArthur O'Dwyer extern Incomplete array_of_incomplete[42];
376842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(array_of_incomplete));
386842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(std::move(array_of_incomplete)));
396842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(std::as_const(array_of_incomplete)));
406842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(static_cast<const Incomplete(&&)[42]>(array_of_incomplete)));
416842f52aSArthur O'Dwyer
42a2a9a5c7SArthur O'Dwyer struct InputRangeWithoutSize {
43a2a9a5c7SArthur O'Dwyer cpp17_input_iterator<int*> begin() const;
44a2a9a5c7SArthur O'Dwyer cpp17_input_iterator<int*> end() const;
45a2a9a5c7SArthur O'Dwyer };
46a2a9a5c7SArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, const InputRangeWithoutSize&>);
47a2a9a5c7SArthur O'Dwyer
48a2a9a5c7SArthur O'Dwyer struct NonConstEmpty {
496842f52aSArthur O'Dwyer bool empty();
506842f52aSArthur O'Dwyer };
51a2a9a5c7SArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, const NonConstEmpty&>);
526842f52aSArthur O'Dwyer
536842f52aSArthur O'Dwyer struct HasMemberAndFunction {
emptyHasMemberAndFunction546842f52aSArthur O'Dwyer constexpr bool empty() const { return true; }
556842f52aSArthur O'Dwyer // We should never do ADL lookup for std::ranges::empty.
empty(const HasMemberAndFunction &)566842f52aSArthur O'Dwyer friend bool empty(const HasMemberAndFunction&) { return false; }
576842f52aSArthur O'Dwyer };
586842f52aSArthur O'Dwyer
596842f52aSArthur O'Dwyer struct BadReturnType {
emptyBadReturnType606842f52aSArthur O'Dwyer BadReturnType empty() { return {}; }
616842f52aSArthur O'Dwyer };
626842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, BadReturnType&>);
636842f52aSArthur O'Dwyer
646842f52aSArthur O'Dwyer struct BoolConvertible {
operator boolBoolConvertible65a2a9a5c7SArthur O'Dwyer constexpr explicit operator bool() noexcept(false) { return true; }
666842f52aSArthur O'Dwyer };
676842f52aSArthur O'Dwyer struct BoolConvertibleReturnType {
emptyBoolConvertibleReturnType686842f52aSArthur O'Dwyer constexpr BoolConvertible empty() noexcept { return {}; }
696842f52aSArthur O'Dwyer };
706842f52aSArthur O'Dwyer static_assert(!noexcept(std::ranges::empty(BoolConvertibleReturnType())));
716842f52aSArthur O'Dwyer
726842f52aSArthur O'Dwyer struct InputIterators {
736842f52aSArthur O'Dwyer cpp17_input_iterator<int*> begin() const;
746842f52aSArthur O'Dwyer cpp17_input_iterator<int*> end() const;
756842f52aSArthur O'Dwyer };
766842f52aSArthur O'Dwyer static_assert(std::is_same_v<decltype(InputIterators().begin() == InputIterators().end()), bool>);
776842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, const InputIterators&>);
786842f52aSArthur O'Dwyer
testEmptyMember()796842f52aSArthur O'Dwyer constexpr bool testEmptyMember() {
806842f52aSArthur O'Dwyer HasMemberAndFunction a;
814191a93eSArthur O'Dwyer assert(std::ranges::empty(a));
826842f52aSArthur O'Dwyer
836842f52aSArthur O'Dwyer BoolConvertibleReturnType b;
844191a93eSArthur O'Dwyer assert(std::ranges::empty(b));
856842f52aSArthur O'Dwyer
866842f52aSArthur O'Dwyer return true;
876842f52aSArthur O'Dwyer }
886842f52aSArthur O'Dwyer
896842f52aSArthur O'Dwyer struct SizeMember {
90*fb855eb9SMark de Wever std::size_t size_;
sizeSizeMember91*fb855eb9SMark de Wever constexpr std::size_t size() const { return size_; }
926842f52aSArthur O'Dwyer };
936842f52aSArthur O'Dwyer
946842f52aSArthur O'Dwyer struct SizeFunction {
95*fb855eb9SMark de Wever std::size_t size_;
size(SizeFunction sf)96*fb855eb9SMark de Wever friend constexpr std::size_t size(SizeFunction sf) { return sf.size_; }
976842f52aSArthur O'Dwyer };
986842f52aSArthur O'Dwyer
996842f52aSArthur O'Dwyer struct BeginEndSizedSentinel {
beginBeginEndSizedSentinel1006842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endBeginEndSizedSentinel1016842f52aSArthur O'Dwyer constexpr auto end() const { return sized_sentinel<int*>(nullptr); }
1026842f52aSArthur O'Dwyer };
1036842f52aSArthur O'Dwyer static_assert(std::ranges::forward_range<BeginEndSizedSentinel>);
1046842f52aSArthur O'Dwyer static_assert(std::ranges::sized_range<BeginEndSizedSentinel>);
1056842f52aSArthur O'Dwyer
testUsingRangesSize()1066842f52aSArthur O'Dwyer constexpr bool testUsingRangesSize() {
1076842f52aSArthur O'Dwyer SizeMember a{1};
1084191a93eSArthur O'Dwyer assert(!std::ranges::empty(a));
1096842f52aSArthur O'Dwyer SizeMember b{0};
1104191a93eSArthur O'Dwyer assert(std::ranges::empty(b));
1116842f52aSArthur O'Dwyer
1126842f52aSArthur O'Dwyer SizeFunction c{1};
1134191a93eSArthur O'Dwyer assert(!std::ranges::empty(c));
1146842f52aSArthur O'Dwyer SizeFunction d{0};
1154191a93eSArthur O'Dwyer assert(std::ranges::empty(d));
1166842f52aSArthur O'Dwyer
1176842f52aSArthur O'Dwyer BeginEndSizedSentinel e;
1184191a93eSArthur O'Dwyer assert(std::ranges::empty(e));
1196842f52aSArthur O'Dwyer
1206842f52aSArthur O'Dwyer return true;
1216842f52aSArthur O'Dwyer }
1226842f52aSArthur O'Dwyer
1236842f52aSArthur O'Dwyer struct BeginEndNotSizedSentinel {
beginBeginEndNotSizedSentinel1246842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endBeginEndNotSizedSentinel1256842f52aSArthur O'Dwyer constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); }
1266842f52aSArthur O'Dwyer };
1276842f52aSArthur O'Dwyer static_assert( std::ranges::forward_range<BeginEndNotSizedSentinel>);
1286842f52aSArthur O'Dwyer static_assert(!std::ranges::sized_range<BeginEndNotSizedSentinel>);
1296842f52aSArthur O'Dwyer
1306842f52aSArthur O'Dwyer // size is disabled here, so we have to compare begin and end.
1316842f52aSArthur O'Dwyer struct DisabledSizeRangeWithBeginEnd {
beginDisabledSizeRangeWithBeginEnd1326842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endDisabledSizeRangeWithBeginEnd1336842f52aSArthur O'Dwyer constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); }
134*fb855eb9SMark de Wever std::size_t size() const;
1356842f52aSArthur O'Dwyer };
1366842f52aSArthur O'Dwyer template<>
1376842f52aSArthur O'Dwyer inline constexpr bool std::ranges::disable_sized_range<DisabledSizeRangeWithBeginEnd> = true;
1386842f52aSArthur O'Dwyer static_assert(std::ranges::contiguous_range<DisabledSizeRangeWithBeginEnd>);
1396842f52aSArthur O'Dwyer static_assert(!std::ranges::sized_range<DisabledSizeRangeWithBeginEnd>);
1406842f52aSArthur O'Dwyer
1416842f52aSArthur O'Dwyer struct BeginEndAndEmpty {
beginBeginEndAndEmpty1426842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endBeginEndAndEmpty1436842f52aSArthur O'Dwyer constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); }
emptyBeginEndAndEmpty1446842f52aSArthur O'Dwyer constexpr bool empty() { return false; }
1456842f52aSArthur O'Dwyer };
1466842f52aSArthur O'Dwyer
1476842f52aSArthur O'Dwyer struct EvilBeginEnd {
1486842f52aSArthur O'Dwyer bool empty() &&;
beginEvilBeginEnd1496842f52aSArthur O'Dwyer constexpr int *begin() & { return nullptr; }
endEvilBeginEnd1506842f52aSArthur O'Dwyer constexpr int *end() & { return nullptr; }
1516842f52aSArthur O'Dwyer };
1526842f52aSArthur O'Dwyer
testBeginEqualsEnd()1536842f52aSArthur O'Dwyer constexpr bool testBeginEqualsEnd() {
1546842f52aSArthur O'Dwyer BeginEndNotSizedSentinel a;
1554191a93eSArthur O'Dwyer assert(std::ranges::empty(a));
1566842f52aSArthur O'Dwyer
1576842f52aSArthur O'Dwyer DisabledSizeRangeWithBeginEnd d;
1584191a93eSArthur O'Dwyer assert(std::ranges::empty(d));
1596842f52aSArthur O'Dwyer
1606842f52aSArthur O'Dwyer BeginEndAndEmpty e;
1614191a93eSArthur O'Dwyer assert(!std::ranges::empty(e)); // e.empty()
1624191a93eSArthur O'Dwyer assert(std::ranges::empty(std::as_const(e))); // e.begin() == e.end()
1636842f52aSArthur O'Dwyer
1646842f52aSArthur O'Dwyer assert(std::ranges::empty(EvilBeginEnd()));
1656842f52aSArthur O'Dwyer
1666842f52aSArthur O'Dwyer return true;
1676842f52aSArthur O'Dwyer }
1686842f52aSArthur O'Dwyer
16985073836SArthur O'Dwyer // Test ADL-proofing.
17085073836SArthur O'Dwyer struct Incomplete;
17185073836SArthur O'Dwyer template<class T> struct Holder { T t; };
17285073836SArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, Holder<Incomplete>*>);
1739be193bcSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, Holder<Incomplete>*&>);
17485073836SArthur O'Dwyer
main(int,char **)1756842f52aSArthur O'Dwyer int main(int, char**) {
1766842f52aSArthur O'Dwyer testEmptyMember();
1776842f52aSArthur O'Dwyer static_assert(testEmptyMember());
1786842f52aSArthur O'Dwyer
1796842f52aSArthur O'Dwyer testUsingRangesSize();
1806842f52aSArthur O'Dwyer static_assert(testUsingRangesSize());
1816842f52aSArthur O'Dwyer
1826842f52aSArthur O'Dwyer testBeginEqualsEnd();
1836842f52aSArthur O'Dwyer static_assert(testBeginEqualsEnd());
1846842f52aSArthur O'Dwyer
1856842f52aSArthur O'Dwyer return 0;
1866842f52aSArthur O'Dwyer }
187