Skip to content

Commit 2696e4f

Browse files
authored
[libc++] Reduce std::conjunction overhead (#124259)
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.
1 parent 7974f12 commit 2696e4f

File tree

1 file changed

+18
-24
lines changed

1 file changed

+18
-24
lines changed

libcxx/include/__type_traits/conjunction.h

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
#define _LIBCPP___TYPE_TRAITS_CONJUNCTION_H
1111

1212
#include <__config>
13-
#include <__type_traits/conditional.h>
14-
#include <__type_traits/enable_if.h>
1513
#include <__type_traits/integral_constant.h>
1614
#include <__type_traits/is_same.h>
1715

@@ -21,22 +19,29 @@
2119

2220
_LIBCPP_BEGIN_NAMESPACE_STD
2321

24-
template <class...>
25-
using __expand_to_true _LIBCPP_NODEBUG = true_type;
22+
template <bool>
23+
struct _AndImpl;
2624

27-
template <class... _Pred>
28-
__expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
25+
template <>
26+
struct _AndImpl<true> {
27+
template <class _Res, class _First, class... _Rest>
28+
using _Result _LIBCPP_NODEBUG =
29+
typename _AndImpl<bool(_First::value) && sizeof...(_Rest) != 0>::template _Result<_First, _Rest...>;
30+
};
2931

30-
template <class...>
31-
false_type __and_helper(...);
32+
template <>
33+
struct _AndImpl<false> {
34+
template <class _Res, class...>
35+
using _Result _LIBCPP_NODEBUG = _Res;
36+
};
3237

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

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

4752
#if _LIBCPP_STD_VER >= 17
4853

49-
template <class...>
50-
struct _LIBCPP_NO_SPECIALIZATIONS conjunction : true_type {};
51-
52-
_LIBCPP_DIAGNOSTIC_PUSH
53-
# if __has_warning("-Winvalid-specialization")
54-
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization")
55-
# endif
56-
template <class _Arg>
57-
struct conjunction<_Arg> : _Arg {};
58-
59-
template <class _Arg, class... _Args>
60-
struct conjunction<_Arg, _Args...> : conditional_t<!bool(_Arg::value), _Arg, conjunction<_Args...>> {};
61-
_LIBCPP_DIAGNOSTIC_POP
54+
template <class... _Args>
55+
struct _LIBCPP_NO_SPECIALIZATIONS conjunction : _And<_Args...> {};
6256

6357
template <class... _Args>
64-
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool conjunction_v = conjunction<_Args...>::value;
58+
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool conjunction_v = _And<_Args...>::value;
6559

6660
#endif // _LIBCPP_STD_VER >= 17
6761

0 commit comments

Comments
 (0)