Skip to content

Commit

Permalink
[libc++] Reduce std::conjunction overhead (#124259)
Browse files Browse the repository at this point in the history
The old and new implementation of `_And` are very close in terms of
performance according to my testing, but the new implementation can also
be used to implement `conjunction`, which make that ~50% faster.
  • Loading branch information
philnik777 authored Jan 25, 2025
1 parent 7974f12 commit 2696e4f
Showing 1 changed file with 18 additions and 24 deletions.
42 changes: 18 additions & 24 deletions libcxx/include/__type_traits/conjunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
#define _LIBCPP___TYPE_TRAITS_CONJUNCTION_H

#include <__config>
#include <__type_traits/conditional.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_same.h>

Expand All @@ -21,22 +19,29 @@

_LIBCPP_BEGIN_NAMESPACE_STD

template <class...>
using __expand_to_true _LIBCPP_NODEBUG = true_type;
template <bool>
struct _AndImpl;

template <class... _Pred>
__expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
template <>
struct _AndImpl<true> {
template <class _Res, class _First, class... _Rest>
using _Result _LIBCPP_NODEBUG =
typename _AndImpl<bool(_First::value) && sizeof...(_Rest) != 0>::template _Result<_First, _Rest...>;
};

template <class...>
false_type __and_helper(...);
template <>
struct _AndImpl<false> {
template <class _Res, class...>
using _Result _LIBCPP_NODEBUG = _Res;
};

// _And always performs lazy evaluation of its arguments.
//
// However, `_And<_Pred...>` itself will evaluate its result immediately (without having to
// be instantiated) since it is an alias, unlike `conjunction<_Pred...>`, which is a struct.
// If you want to defer the evaluation of `_And<_Pred...>` itself, use `_Lazy<_And, _Pred...>`.
template <class... _Pred>
using _And _LIBCPP_NODEBUG = decltype(std::__and_helper<_Pred...>(0));
template <class... _Args>
using _And _LIBCPP_NODEBUG = typename _AndImpl<sizeof...(_Args) != 0>::template _Result<true_type, _Args...>;

template <bool... _Preds>
struct __all_dummy;
Expand All @@ -46,22 +51,11 @@ struct __all : _IsSame<__all_dummy<_Pred...>, __all_dummy<((void)_Pred, true)...

#if _LIBCPP_STD_VER >= 17

template <class...>
struct _LIBCPP_NO_SPECIALIZATIONS conjunction : true_type {};

_LIBCPP_DIAGNOSTIC_PUSH
# if __has_warning("-Winvalid-specialization")
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization")
# endif
template <class _Arg>
struct conjunction<_Arg> : _Arg {};

template <class _Arg, class... _Args>
struct conjunction<_Arg, _Args...> : conditional_t<!bool(_Arg::value), _Arg, conjunction<_Args...>> {};
_LIBCPP_DIAGNOSTIC_POP
template <class... _Args>
struct _LIBCPP_NO_SPECIALIZATIONS conjunction : _And<_Args...> {};

template <class... _Args>
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool conjunction_v = conjunction<_Args...>::value;
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool conjunction_v = _And<_Args...>::value;

#endif // _LIBCPP_STD_VER >= 17

Expand Down

0 comments on commit 2696e4f

Please sign in to comment.