1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9#ifndef _LIBCPP___RANGES_EMPTY_H
10#define _LIBCPP___RANGES_EMPTY_H
11
12#include <__config>
13#include <__iterator/concepts.h>
14#include <__ranges/size.h>
15#include <type_traits>
16
17#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
18#pragma GCC system_header
19#endif
20
21_LIBCPP_PUSH_MACROS
22#include <__undef_macros>
23
24_LIBCPP_BEGIN_NAMESPACE_STD
25
26#if !defined(_LIBCPP_HAS_NO_RANGES)
27
28// clang-format off
29namespace ranges {
30// [range.prim.empty]
31namespace __empty {
32  template <class _Tp>
33  concept __member_empty = requires(_Tp&& __t) {
34    bool(_VSTD::forward<_Tp>(__t).empty());
35  };
36
37  template<class _Tp>
38  concept __can_invoke_size =
39    !__member_empty<_Tp> &&
40    requires(_Tp&& __t) { ranges::size(_VSTD::forward<_Tp>(__t)); };
41
42  template <class _Tp>
43  concept __can_compare_begin_end =
44    !__member_empty<_Tp> &&
45    !__can_invoke_size<_Tp> &&
46    requires(_Tp&& __t) {
47      bool(ranges::begin(__t) == ranges::end(__t));
48      { ranges::begin(__t) } -> forward_iterator;
49    };
50
51  struct __fn {
52    template <__member_empty _Tp>
53    [[nodiscard]] constexpr bool operator()(_Tp&& __t) const
54        noexcept(noexcept(bool(__t.empty()))) {
55      return __t.empty();
56    }
57
58    template <__can_invoke_size _Tp>
59    [[nodiscard]] constexpr bool operator()(_Tp&& __t) const
60        noexcept(noexcept(ranges::size(_VSTD::forward<_Tp>(__t)))) {
61      return ranges::size(_VSTD::forward<_Tp>(__t)) == 0;
62    }
63
64    template<__can_compare_begin_end _Tp>
65    [[nodiscard]] constexpr bool operator()(_Tp&& __t) const
66        noexcept(noexcept(bool(ranges::begin(__t) == ranges::end(__t)))) {
67      return ranges::begin(__t) == ranges::end(__t);
68    }
69  };
70}
71
72inline namespace __cpo {
73  inline constexpr auto empty = __empty::__fn{};
74} // namespace __cpo
75} // namespace ranges
76// clang-format off
77
78#endif // !defined(_LIBCPP_HAS_NO_RANGES)
79
80_LIBCPP_END_NAMESPACE_STD
81
82_LIBCPP_POP_MACROS
83
84#endif // _LIBCPP___RANGES_EMPTY_H
85