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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
116842f52aSArthur O'Dwyer
126842f52aSArthur O'Dwyer // std::ranges::empty
136842f52aSArthur O'Dwyer
146842f52aSArthur O'Dwyer #include <ranges>
156842f52aSArthur O'Dwyer
166842f52aSArthur O'Dwyer #include <cassert>
17a2a9a5c7SArthur O'Dwyer #include <utility>
186842f52aSArthur O'Dwyer #include "test_macros.h"
196842f52aSArthur O'Dwyer #include "test_iterators.h"
206842f52aSArthur O'Dwyer
216842f52aSArthur O'Dwyer using RangeEmptyT = decltype(std::ranges::empty);
226842f52aSArthur O'Dwyer
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(&&)[]>);
266842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, int[1]>);
276842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, const int[1]>);
286842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, int (&&)[1]>);
296842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, int (&)[1]>);
306842f52aSArthur O'Dwyer static_assert( std::is_invocable_v<RangeEmptyT, const int (&)[1]>);
316842f52aSArthur O'Dwyer
326842f52aSArthur O'Dwyer struct 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 static_assert(!std::is_invocable_v<RangeEmptyT, Incomplete(&&)[]>);
366842f52aSArthur O'Dwyer
376842f52aSArthur O'Dwyer extern Incomplete array_of_incomplete[42];
386842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(array_of_incomplete));
396842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(std::move(array_of_incomplete)));
406842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(std::as_const(array_of_incomplete)));
416842f52aSArthur O'Dwyer static_assert(!std::ranges::empty(static_cast<const Incomplete(&&)[42]>(array_of_incomplete)));
426842f52aSArthur O'Dwyer
43a2a9a5c7SArthur O'Dwyer struct InputRangeWithoutSize {
44a2a9a5c7SArthur O'Dwyer cpp17_input_iterator<int*> begin() const;
45a2a9a5c7SArthur O'Dwyer cpp17_input_iterator<int*> end() const;
46a2a9a5c7SArthur O'Dwyer };
47a2a9a5c7SArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, const InputRangeWithoutSize&>);
48a2a9a5c7SArthur O'Dwyer
49a2a9a5c7SArthur O'Dwyer struct NonConstEmpty {
506842f52aSArthur O'Dwyer bool empty();
516842f52aSArthur O'Dwyer };
52a2a9a5c7SArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, const NonConstEmpty&>);
536842f52aSArthur O'Dwyer
546842f52aSArthur O'Dwyer struct HasMemberAndFunction {
emptyHasMemberAndFunction556842f52aSArthur O'Dwyer constexpr bool empty() const { return true; }
566842f52aSArthur O'Dwyer // We should never do ADL lookup for std::ranges::empty.
empty(const HasMemberAndFunction &)576842f52aSArthur O'Dwyer friend bool empty(const HasMemberAndFunction&) { return false; }
586842f52aSArthur O'Dwyer };
596842f52aSArthur O'Dwyer
606842f52aSArthur O'Dwyer struct BadReturnType {
emptyBadReturnType616842f52aSArthur O'Dwyer BadReturnType empty() { return {}; }
626842f52aSArthur O'Dwyer };
636842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, BadReturnType&>);
646842f52aSArthur O'Dwyer
656842f52aSArthur O'Dwyer struct BoolConvertible {
operator boolBoolConvertible66a2a9a5c7SArthur O'Dwyer constexpr explicit operator bool() noexcept(false) { return true; }
676842f52aSArthur O'Dwyer };
686842f52aSArthur O'Dwyer struct BoolConvertibleReturnType {
emptyBoolConvertibleReturnType696842f52aSArthur O'Dwyer constexpr BoolConvertible empty() noexcept { return {}; }
706842f52aSArthur O'Dwyer };
716842f52aSArthur O'Dwyer static_assert(!noexcept(std::ranges::empty(BoolConvertibleReturnType())));
726842f52aSArthur O'Dwyer
736842f52aSArthur O'Dwyer struct InputIterators {
746842f52aSArthur O'Dwyer cpp17_input_iterator<int*> begin() const;
756842f52aSArthur O'Dwyer cpp17_input_iterator<int*> end() const;
766842f52aSArthur O'Dwyer };
776842f52aSArthur O'Dwyer static_assert(std::is_same_v<decltype(InputIterators().begin() == InputIterators().end()), bool>);
786842f52aSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, const InputIterators&>);
796842f52aSArthur O'Dwyer
testEmptyMember()806842f52aSArthur O'Dwyer constexpr bool testEmptyMember() {
816842f52aSArthur O'Dwyer HasMemberAndFunction a;
824191a93eSArthur O'Dwyer assert(std::ranges::empty(a));
836842f52aSArthur O'Dwyer
846842f52aSArthur O'Dwyer BoolConvertibleReturnType b;
854191a93eSArthur O'Dwyer assert(std::ranges::empty(b));
866842f52aSArthur O'Dwyer
876842f52aSArthur O'Dwyer return true;
886842f52aSArthur O'Dwyer }
896842f52aSArthur O'Dwyer
906842f52aSArthur O'Dwyer struct SizeMember {
916842f52aSArthur O'Dwyer size_t size_;
sizeSizeMember926842f52aSArthur O'Dwyer constexpr size_t size() const { return size_; }
936842f52aSArthur O'Dwyer };
946842f52aSArthur O'Dwyer
956842f52aSArthur O'Dwyer struct SizeFunction {
966842f52aSArthur O'Dwyer size_t size_;
size(SizeFunction sf)976842f52aSArthur O'Dwyer friend constexpr size_t size(SizeFunction sf) { return sf.size_; }
986842f52aSArthur O'Dwyer };
996842f52aSArthur O'Dwyer
1006842f52aSArthur O'Dwyer struct BeginEndSizedSentinel {
beginBeginEndSizedSentinel1016842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endBeginEndSizedSentinel1026842f52aSArthur O'Dwyer constexpr auto end() const { return sized_sentinel<int*>(nullptr); }
1036842f52aSArthur O'Dwyer };
1046842f52aSArthur O'Dwyer static_assert(std::ranges::forward_range<BeginEndSizedSentinel>);
1056842f52aSArthur O'Dwyer static_assert(std::ranges::sized_range<BeginEndSizedSentinel>);
1066842f52aSArthur O'Dwyer
testUsingRangesSize()1076842f52aSArthur O'Dwyer constexpr bool testUsingRangesSize() {
1086842f52aSArthur O'Dwyer SizeMember a{1};
1094191a93eSArthur O'Dwyer assert(!std::ranges::empty(a));
1106842f52aSArthur O'Dwyer SizeMember b{0};
1114191a93eSArthur O'Dwyer assert(std::ranges::empty(b));
1126842f52aSArthur O'Dwyer
1136842f52aSArthur O'Dwyer SizeFunction c{1};
1144191a93eSArthur O'Dwyer assert(!std::ranges::empty(c));
1156842f52aSArthur O'Dwyer SizeFunction d{0};
1164191a93eSArthur O'Dwyer assert(std::ranges::empty(d));
1176842f52aSArthur O'Dwyer
1186842f52aSArthur O'Dwyer BeginEndSizedSentinel e;
1194191a93eSArthur O'Dwyer assert(std::ranges::empty(e));
1206842f52aSArthur O'Dwyer
1216842f52aSArthur O'Dwyer return true;
1226842f52aSArthur O'Dwyer }
1236842f52aSArthur O'Dwyer
1246842f52aSArthur O'Dwyer struct BeginEndNotSizedSentinel {
beginBeginEndNotSizedSentinel1256842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endBeginEndNotSizedSentinel1266842f52aSArthur O'Dwyer constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); }
1276842f52aSArthur O'Dwyer };
1286842f52aSArthur O'Dwyer static_assert( std::ranges::forward_range<BeginEndNotSizedSentinel>);
1296842f52aSArthur O'Dwyer static_assert(!std::ranges::sized_range<BeginEndNotSizedSentinel>);
1306842f52aSArthur O'Dwyer
1316842f52aSArthur O'Dwyer // size is disabled here, so we have to compare begin and end.
1326842f52aSArthur O'Dwyer struct DisabledSizeRangeWithBeginEnd {
beginDisabledSizeRangeWithBeginEnd1336842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endDisabledSizeRangeWithBeginEnd1346842f52aSArthur O'Dwyer constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); }
1356842f52aSArthur O'Dwyer size_t size() const;
1366842f52aSArthur O'Dwyer };
1376842f52aSArthur O'Dwyer template<>
1386842f52aSArthur O'Dwyer inline constexpr bool std::ranges::disable_sized_range<DisabledSizeRangeWithBeginEnd> = true;
1396842f52aSArthur O'Dwyer static_assert(std::ranges::contiguous_range<DisabledSizeRangeWithBeginEnd>);
1406842f52aSArthur O'Dwyer static_assert(!std::ranges::sized_range<DisabledSizeRangeWithBeginEnd>);
1416842f52aSArthur O'Dwyer
1426842f52aSArthur O'Dwyer struct BeginEndAndEmpty {
beginBeginEndAndEmpty1436842f52aSArthur O'Dwyer constexpr int *begin() const { return nullptr; }
endBeginEndAndEmpty1446842f52aSArthur O'Dwyer constexpr auto end() const { return sentinel_wrapper<int*>(nullptr); }
emptyBeginEndAndEmpty1456842f52aSArthur O'Dwyer constexpr bool empty() { return false; }
1466842f52aSArthur O'Dwyer };
1476842f52aSArthur O'Dwyer
1486842f52aSArthur O'Dwyer struct EvilBeginEnd {
1496842f52aSArthur O'Dwyer bool empty() &&;
beginEvilBeginEnd1506842f52aSArthur O'Dwyer constexpr int *begin() & { return nullptr; }
endEvilBeginEnd1516842f52aSArthur O'Dwyer constexpr int *end() & { return nullptr; }
1526842f52aSArthur O'Dwyer };
1536842f52aSArthur O'Dwyer
testBeginEqualsEnd()1546842f52aSArthur O'Dwyer constexpr bool testBeginEqualsEnd() {
1556842f52aSArthur O'Dwyer BeginEndNotSizedSentinel a;
1564191a93eSArthur O'Dwyer assert(std::ranges::empty(a));
1576842f52aSArthur O'Dwyer
1586842f52aSArthur O'Dwyer DisabledSizeRangeWithBeginEnd d;
1594191a93eSArthur O'Dwyer assert(std::ranges::empty(d));
1606842f52aSArthur O'Dwyer
1616842f52aSArthur O'Dwyer BeginEndAndEmpty e;
1624191a93eSArthur O'Dwyer assert(!std::ranges::empty(e)); // e.empty()
1634191a93eSArthur O'Dwyer assert(std::ranges::empty(std::as_const(e))); // e.begin() == e.end()
1646842f52aSArthur O'Dwyer
1656842f52aSArthur O'Dwyer assert(std::ranges::empty(EvilBeginEnd()));
1666842f52aSArthur O'Dwyer
1676842f52aSArthur O'Dwyer return true;
1686842f52aSArthur O'Dwyer }
1696842f52aSArthur O'Dwyer
17085073836SArthur O'Dwyer // Test ADL-proofing.
17185073836SArthur O'Dwyer struct Incomplete;
17285073836SArthur O'Dwyer template<class T> struct Holder { T t; };
17385073836SArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, Holder<Incomplete>*>);
174*9be193bcSArthur O'Dwyer static_assert(!std::is_invocable_v<RangeEmptyT, Holder<Incomplete>*&>);
17585073836SArthur O'Dwyer
main(int,char **)1766842f52aSArthur O'Dwyer int main(int, char**) {
1776842f52aSArthur O'Dwyer testEmptyMember();
1786842f52aSArthur O'Dwyer static_assert(testEmptyMember());
1796842f52aSArthur O'Dwyer
1806842f52aSArthur O'Dwyer testUsingRangesSize();
1816842f52aSArthur O'Dwyer static_assert(testUsingRangesSize());
1826842f52aSArthur O'Dwyer
1836842f52aSArthur O'Dwyer testBeginEqualsEnd();
1846842f52aSArthur O'Dwyer static_assert(testBeginEqualsEnd());
1856842f52aSArthur O'Dwyer
1866842f52aSArthur O'Dwyer return 0;
1876842f52aSArthur O'Dwyer }
188