187 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// std::ranges::empty12 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{1};108 assert(!std::ranges::empty(a));109 SizeMember b{0};110 assert(std::ranges::empty(b));111 112 SizeFunction c{1};113 assert(!std::ranges::empty(c));114 SizeFunction d{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