Skip to content

Commit 51a741c

Browse files
committed
Add new style meta-programming primatives.
Using class templates instead of alias templates causes a lot of instantiations. As part of the move away from C++03, we want to improve the efficiency of our meta-programming. This patch lays the groundwork by introducing new _If, _EnableIf, _And, _Or, and _IsValidExpansion (detect member). Future patches will replace the existing implementations after verifying there compile time differences. llvm-svn: 364114
1 parent 892f022 commit 51a741c

File tree

3 files changed

+245
-28
lines changed

3 files changed

+245
-28
lines changed

libcxx/include/type_traits

Lines changed: 87 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,93 @@ template <class _T1, class _T2> struct _LIBCPP_TEMPLATE_VIS pair;
427427
template <class _Tp> class _LIBCPP_TEMPLATE_VIS reference_wrapper;
428428
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS hash;
429429

430+
431+
template <class _Tp, _Tp __v>
432+
struct _LIBCPP_TEMPLATE_VIS integral_constant
433+
{
434+
static _LIBCPP_CONSTEXPR const _Tp value = __v;
435+
typedef _Tp value_type;
436+
typedef integral_constant type;
437+
_LIBCPP_INLINE_VISIBILITY
438+
_LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;}
439+
#if _LIBCPP_STD_VER > 11
440+
_LIBCPP_INLINE_VISIBILITY
441+
constexpr value_type operator ()() const _NOEXCEPT {return value;}
442+
#endif
443+
};
444+
445+
template <class _Tp, _Tp __v>
446+
_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value;
447+
448+
#if _LIBCPP_STD_VER > 14
449+
template <bool __b>
450+
using bool_constant = integral_constant<bool, __b>;
451+
#define _LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)>
452+
#else
453+
#define _LIBCPP_BOOL_CONSTANT(__b) integral_constant<bool,(__b)>
454+
#endif
455+
456+
typedef _LIBCPP_BOOL_CONSTANT(true) true_type;
457+
typedef _LIBCPP_BOOL_CONSTANT(false) false_type;
458+
459+
template <bool _Val>
460+
using _BoolConstant _LIBCPP_NODEBUG_TYPE = integral_constant<bool, _Val>;
461+
462+
template <bool> struct _MetaBase;
463+
template <>
464+
struct _MetaBase<true> {
465+
template <class _Tp, class _Up>
466+
using _SelectImpl _LIBCPP_NODEBUG_TYPE = _Tp;
467+
template <template <class...> class _FirstFn, template <class...> class, class ..._Args>
468+
using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _FirstFn<_Args...>;
469+
template <class _First, class...>
470+
using _FirstImpl _LIBCPP_NODEBUG_TYPE = _First;
471+
template <class, class _Second, class...>
472+
using _SecondImpl _LIBCPP_NODEBUG_TYPE = _Second;
473+
template <class _Tp = void>
474+
using _EnableIfImpl _LIBCPP_NODEBUG_TYPE = _Tp;
475+
template <class _Result, class _First, class ..._Rest>
476+
using _OrImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::type::value != true && sizeof...(_Rest) != 0>::template _OrImpl<_First, _Rest...>;
477+
template <class _Result, class _First, class ..._Rest>
478+
using _AndImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::type::value == true && sizeof...(_Rest) != 0>::template _AndImpl<_First, _Rest...>;
479+
};
480+
481+
template <>
482+
struct _MetaBase<false> {
483+
template <class _Tp, class _Up>
484+
using _SelectImpl _LIBCPP_NODEBUG_TYPE = _Up;
485+
template <template <class...> class, template <class...> class _SecondFn, class ..._Args>
486+
using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _SecondFn<_Args...>;
487+
template <class _Result, class ...>
488+
using _OrImpl _LIBCPP_NODEBUG_TYPE = _Result;
489+
template <class _Result, class ...>
490+
using _AndImpl _LIBCPP_NODEBUG_TYPE = _Result;
491+
};
492+
template <bool _Cond, class _Ret = void>
493+
using _EnableIf _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _EnableIfImpl<_Ret>;
494+
template <bool _Cond, class _IfRes, class _ElseRes>
495+
using _If _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
496+
template <class ..._Rest>
497+
using _Or _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _OrImpl<false_type, _Rest...>;
498+
template <class ..._Rest>
499+
using _And _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _AndImpl<true_type, _Rest...>;
500+
template <class _Pred>
501+
struct _Not : _BoolConstant<!_Pred::type::value> {};
502+
template <class ..._Args>
503+
using _FirstType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 1)>::template _FirstImpl<_Args...>;
504+
template <class ..._Args>
505+
using _SecondType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 2)>::template _SecondImpl<_Args...>;
506+
507+
// Member detector base
508+
509+
template <template <class...> class _Templ, class ..._Args>
510+
true_type __sfinae_test_impl(_FirstType<int, _Templ<_Args...> >);
511+
template <template <class...> class, class ...>
512+
false_type __sfinae_test_impl(...);
513+
514+
template <template <class ...> class _Templ, class ..._Args>
515+
using _IsValidExpansion _LIBCPP_NODEBUG_TYPE = decltype(std::__sfinae_test_impl<_Templ, _Args...>(0));
516+
430517
template <class>
431518
struct __void_t { typedef void type; };
432519

@@ -528,34 +615,6 @@ struct __two {char __lx[2];};
528615

529616
// helper class:
530617

531-
template <class _Tp, _Tp __v>
532-
struct _LIBCPP_TEMPLATE_VIS integral_constant
533-
{
534-
static _LIBCPP_CONSTEXPR const _Tp value = __v;
535-
typedef _Tp value_type;
536-
typedef integral_constant type;
537-
_LIBCPP_INLINE_VISIBILITY
538-
_LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;}
539-
#if _LIBCPP_STD_VER > 11
540-
_LIBCPP_INLINE_VISIBILITY
541-
constexpr value_type operator ()() const _NOEXCEPT {return value;}
542-
#endif
543-
};
544-
545-
template <class _Tp, _Tp __v>
546-
_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value;
547-
548-
#if _LIBCPP_STD_VER > 14
549-
template <bool __b>
550-
using bool_constant = integral_constant<bool, __b>;
551-
#define _LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)>
552-
#else
553-
#define _LIBCPP_BOOL_CONSTANT(__b) integral_constant<bool,(__b)>
554-
#endif
555-
556-
typedef _LIBCPP_BOOL_CONSTANT(true) true_type;
557-
typedef _LIBCPP_BOOL_CONSTANT(false) false_type;
558-
559618
#if !defined(_LIBCPP_CXX03_LANG)
560619

561620
// __lazy_and
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
10+
#include <type_traits>
11+
#include <cassert>
12+
13+
#include "test_macros.h"
14+
15+
struct Bomb;
16+
template <int N, class T = Bomb >
17+
struct BOOM {
18+
using Explode = typename T::BOOMBOOM;
19+
};
20+
21+
using True = std::true_type;
22+
using False = std::false_type;
23+
24+
void test_if() {
25+
ASSERT_SAME_TYPE(std::_If<true, int, long>, int);
26+
ASSERT_SAME_TYPE(std::_If<false, int, long>, long);
27+
}
28+
29+
void test_and() {
30+
static_assert(std::_And<True>::value, "");
31+
static_assert(!std::_And<False>::value, "");
32+
static_assert(std::_And<True, True>::value, "");
33+
static_assert(!std::_And<False, BOOM<1> >::value, "");
34+
static_assert(!std::_And<True, True, True, False, BOOM<2> >::value, "");
35+
}
36+
37+
void test_or() {
38+
static_assert(std::_Or<True>::value, "");
39+
static_assert(!std::_Or<False>::value, "");
40+
static_assert(std::_Or<False, True>::value, "");
41+
static_assert(std::_Or<True, std::_Not<BOOM<3> > >::value, "");
42+
static_assert(!std::_Or<False, False>::value, "");
43+
static_assert(std::_Or<True, BOOM<1> >::value, "");
44+
static_assert(std::_Or<False, False, False, False, True, BOOM<2> >::value, "");
45+
}
46+
47+
void test_combined() {
48+
static_assert(std::_And<True, std::_Or<False, True, BOOM<4> > >::value, "");
49+
static_assert(std::_And<True, std::_Or<False, True, BOOM<4> > >::value, "");
50+
static_assert(std::_Not<std::_And<True, False, BOOM<5> > >::value, "");
51+
}
52+
53+
struct MemberTest {
54+
static int foo;
55+
using type = long;
56+
57+
void func(int);
58+
};
59+
struct Empty {};
60+
struct MemberTest2 {
61+
using foo = int;
62+
};
63+
template <class T>
64+
using HasFooData = decltype(T::foo);
65+
template <class T>
66+
using HasFooType = typename T::foo;
67+
68+
template <class T, class U>
69+
using FuncCallable = decltype(std::declval<T>().func(std::declval<U>()));
70+
template <class T>
71+
using BadCheck = typename T::DOES_NOT_EXIST;
72+
73+
void test_is_valid_trait() {
74+
static_assert(std::_IsValidExpansion<HasFooData, MemberTest>::value, "");
75+
static_assert(!std::_IsValidExpansion<HasFooType, MemberTest>::value, "");
76+
static_assert(!std::_IsValidExpansion<HasFooData, MemberTest2>::value, "");
77+
static_assert(std::_IsValidExpansion<HasFooType, MemberTest2>::value, "");
78+
static_assert(std::_IsValidExpansion<FuncCallable, MemberTest, int>::value, "");
79+
static_assert(!std::_IsValidExpansion<FuncCallable, MemberTest, void*>::value, "");
80+
}
81+
82+
void test_first_and_second_type() {
83+
ASSERT_SAME_TYPE(std::_FirstType<int, long, void*>, int);
84+
ASSERT_SAME_TYPE(std::_FirstType<char>, char);
85+
ASSERT_SAME_TYPE(std::_SecondType<char, long>, long);
86+
ASSERT_SAME_TYPE(std::_SecondType<long long, int, void*>, int);
87+
}
88+
89+
int main(int, char**) {
90+
return 0;
91+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This is a dummy feature that prevents this test from running by default.
10+
// REQUIRES: template-const-testing
11+
12+
// The table below compares the compile time and object size for each of the
13+
// variants listed in the RUN script.
14+
//
15+
// Impl Compile Time Object Size
16+
// -------------------------------------------
17+
// _And: 3,498.639 ms 158 M
18+
// __lazy_and: 10,138.982 ms 334 M
19+
// __and_: 14,181.851 ms 648 M
20+
//
21+
22+
// RUN: %cxx %flags %compile_flags -c %s -o %S/new.o -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17
23+
// RUN: %cxx %flags %compile_flags -c %s -o %S/lazy.o -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17 -DTEST_LAZY_AND
24+
// RUN: %cxx %flags %compile_flags -c %s -o %S/std.o -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17 -DTEST_STD_AND
25+
26+
#include <type_traits>
27+
#include <cassert>
28+
29+
#include "test_macros.h"
30+
#include "template_cost_testing.h"
31+
using std::true_type;
32+
using std::false_type;
33+
34+
#define FALSE_T() std::false_type,
35+
#define TRUE_T() std::true_type,
36+
37+
#ifdef TEST_LAZY_AND
38+
#define TEST_AND std::__lazy_and
39+
#define TEST_OR std::__lazy_or
40+
#elif defined(TEST_STD_AND)
41+
#define TEST_AND std::__and_
42+
#define TEST_OR std::__or_
43+
#else
44+
#define TEST_AND std::_And
45+
#define TEST_OR std::_Or
46+
#endif
47+
48+
void sink(...);
49+
50+
void Foo1(TEST_AND < REPEAT_1000(TRUE_T) true_type > t1) { sink(&t1); }
51+
void Foo2(TEST_AND < REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type > t2) { sink(&t2); }
52+
void Foo3(TEST_AND < REPEAT_1000(TRUE_T) true_type, false_type > t3) { sink(&t3); }
53+
void Foo4(TEST_AND < REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type, false_type > t4) { sink(&t4); }
54+
void Foo5(TEST_AND < false_type, REPEAT_1000(TRUE_T) true_type > t5) { sink(&t5); }
55+
void Foo6(TEST_AND < false_type, REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type > t6) { sink(&t6); }
56+
57+
void escape() {
58+
59+
sink(&Foo1);
60+
sink(&Foo2);
61+
sink(&Foo3);
62+
sink(&Foo4);
63+
sink(&Foo5);
64+
sink(&Foo6);
65+
}
66+
67+

0 commit comments

Comments
 (0)