xref: /llvm-project/libcxx/test/std/ranges/range.access/empty.pass.cpp (revision fb855eb941b6d740cc6560297d0b4d3201dcaf9f)
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