diff --git a/libcxx/include/__ranges/empty.h b/libcxx/include/__ranges/empty.h --- a/libcxx/include/__ranges/empty.h +++ b/libcxx/include/__ranges/empty.h @@ -14,7 +14,7 @@ #include <__ranges/access.h> #include <__ranges/size.h> #include <__utility/forward.h> -#include +#include <__utility/priority_tag.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -24,47 +24,39 @@ #if !defined(_LIBCPP_HAS_NO_RANGES) -// clang-format off -namespace ranges { // [range.prim.empty] -namespace __empty { - template - concept __member_empty = requires(_Tp&& __t) { - bool(_VSTD::forward<_Tp>(__t).empty()); - }; - - template - concept __can_invoke_size = - !__member_empty<_Tp> && - requires(_Tp&& __t) { ranges::size(_VSTD::forward<_Tp>(__t)); }; - - template - concept __can_compare_begin_end = - !__member_empty<_Tp> && - !__can_invoke_size<_Tp> && - requires(_Tp&& __t) { - bool(ranges::begin(__t) == ranges::end(__t)); - { ranges::begin(__t) } -> forward_iterator; - }; +namespace ranges { +namespace __empty { struct __fn { - template <__member_empty _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t) const - noexcept(noexcept(bool(__t.empty()))) { - return __t.empty(); - } + template + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<2>) + noexcept(noexcept(bool(__t.empty()))) + -> decltype( bool(__t.empty())) + { return bool(__t.empty()); } + + template + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<1>) + noexcept(noexcept(ranges::size(__t) == 0)) + -> decltype( ranges::size(__t) == 0) + { return ranges::size(__t) == 0; } - template <__can_invoke_size _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t) const - noexcept(noexcept(ranges::size(_VSTD::forward<_Tp>(__t)))) { - return ranges::size(_VSTD::forward<_Tp>(__t)) == 0; - } + template + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<0>) + noexcept(noexcept(bool(ranges::begin(__t) == ranges::end(__t)))) + -> decltype( bool(ranges::begin(__t) == ranges::end(__t))) + requires forward_iterator + { return bool(ranges::begin(__t) == ranges::end(__t)); } - template<__can_compare_begin_end _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t) const - noexcept(noexcept(bool(ranges::begin(__t) == ranges::end(__t)))) { - return ranges::begin(__t) == ranges::end(__t); - } + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), __priority_tag<2>()))) + -> decltype( __go(_VSTD::forward<_Tp>(__t), __priority_tag<2>())) + { return __go(_VSTD::forward<_Tp>(__t), __priority_tag<2>()); } }; } @@ -72,7 +64,6 @@ inline constexpr auto empty = __empty::__fn{}; } // namespace __cpo } // namespace ranges -// clang-format off #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp b/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp --- a/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/empty.pass.cpp @@ -49,7 +49,7 @@ static_assert(!std::is_invocable_v); struct BoolConvertible { - constexpr /*TODO: explicit*/ operator bool() noexcept(false) { return true; } + constexpr explicit operator bool() noexcept(false) { return true; } }; struct BoolConvertibleReturnType { constexpr BoolConvertible empty() noexcept { return {}; } @@ -148,9 +148,7 @@ assert(std::ranges::empty(e) == false); // e.empty() assert(std::ranges::empty(std::as_const(e)) == true); // e.begin() == e.end() -#if 0 // TODO FIXME assert(std::ranges::empty(EvilBeginEnd())); -#endif return true; }