-
Notifications
You must be signed in to change notification settings - Fork 12.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
3 changed files
with
245 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
|
|
||
| #include <type_traits> | ||
| #include <cassert> | ||
|
|
||
| #include "test_macros.h" | ||
|
|
||
| struct Bomb; | ||
| template <int N, class T = Bomb > | ||
| struct BOOM { | ||
| using Explode = typename T::BOOMBOOM; | ||
| }; | ||
|
|
||
| using True = std::true_type; | ||
| using False = std::false_type; | ||
|
|
||
| void test_if() { | ||
| ASSERT_SAME_TYPE(std::_If<true, int, long>, int); | ||
| ASSERT_SAME_TYPE(std::_If<false, int, long>, long); | ||
| } | ||
|
|
||
| void test_and() { | ||
| static_assert(std::_And<True>::value, ""); | ||
| static_assert(!std::_And<False>::value, ""); | ||
| static_assert(std::_And<True, True>::value, ""); | ||
| static_assert(!std::_And<False, BOOM<1> >::value, ""); | ||
| static_assert(!std::_And<True, True, True, False, BOOM<2> >::value, ""); | ||
| } | ||
|
|
||
| void test_or() { | ||
| static_assert(std::_Or<True>::value, ""); | ||
| static_assert(!std::_Or<False>::value, ""); | ||
| static_assert(std::_Or<False, True>::value, ""); | ||
| static_assert(std::_Or<True, std::_Not<BOOM<3> > >::value, ""); | ||
| static_assert(!std::_Or<False, False>::value, ""); | ||
| static_assert(std::_Or<True, BOOM<1> >::value, ""); | ||
| static_assert(std::_Or<False, False, False, False, True, BOOM<2> >::value, ""); | ||
| } | ||
|
|
||
| void test_combined() { | ||
| static_assert(std::_And<True, std::_Or<False, True, BOOM<4> > >::value, ""); | ||
| static_assert(std::_And<True, std::_Or<False, True, BOOM<4> > >::value, ""); | ||
| static_assert(std::_Not<std::_And<True, False, BOOM<5> > >::value, ""); | ||
| } | ||
|
|
||
| struct MemberTest { | ||
| static int foo; | ||
| using type = long; | ||
|
|
||
| void func(int); | ||
| }; | ||
| struct Empty {}; | ||
| struct MemberTest2 { | ||
| using foo = int; | ||
| }; | ||
| template <class T> | ||
| using HasFooData = decltype(T::foo); | ||
| template <class T> | ||
| using HasFooType = typename T::foo; | ||
|
|
||
| template <class T, class U> | ||
| using FuncCallable = decltype(std::declval<T>().func(std::declval<U>())); | ||
| template <class T> | ||
| using BadCheck = typename T::DOES_NOT_EXIST; | ||
|
|
||
| void test_is_valid_trait() { | ||
| static_assert(std::_IsValidExpansion<HasFooData, MemberTest>::value, ""); | ||
| static_assert(!std::_IsValidExpansion<HasFooType, MemberTest>::value, ""); | ||
| static_assert(!std::_IsValidExpansion<HasFooData, MemberTest2>::value, ""); | ||
| static_assert(std::_IsValidExpansion<HasFooType, MemberTest2>::value, ""); | ||
| static_assert(std::_IsValidExpansion<FuncCallable, MemberTest, int>::value, ""); | ||
| static_assert(!std::_IsValidExpansion<FuncCallable, MemberTest, void*>::value, ""); | ||
| } | ||
|
|
||
| void test_first_and_second_type() { | ||
| ASSERT_SAME_TYPE(std::_FirstType<int, long, void*>, int); | ||
| ASSERT_SAME_TYPE(std::_FirstType<char>, char); | ||
| ASSERT_SAME_TYPE(std::_SecondType<char, long>, long); | ||
| ASSERT_SAME_TYPE(std::_SecondType<long long, int, void*>, int); | ||
| } | ||
|
|
||
| int main(int, char**) { | ||
| return 0; | ||
| } |
67 changes: 67 additions & 0 deletions
67
libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This is a dummy feature that prevents this test from running by default. | ||
| // REQUIRES: template-const-testing | ||
|
|
||
| // The table below compares the compile time and object size for each of the | ||
| // variants listed in the RUN script. | ||
| // | ||
| // Impl Compile Time Object Size | ||
| // ------------------------------------------- | ||
| // _And: 3,498.639 ms 158 M | ||
| // __lazy_and: 10,138.982 ms 334 M | ||
| // __and_: 14,181.851 ms 648 M | ||
| // | ||
|
|
||
| // RUN: %cxx %flags %compile_flags -c %s -o %S/new.o -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17 | ||
| // 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 | ||
| // 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 | ||
|
|
||
| #include <type_traits> | ||
| #include <cassert> | ||
|
|
||
| #include "test_macros.h" | ||
| #include "template_cost_testing.h" | ||
| using std::true_type; | ||
| using std::false_type; | ||
|
|
||
| #define FALSE_T() std::false_type, | ||
| #define TRUE_T() std::true_type, | ||
|
|
||
| #ifdef TEST_LAZY_AND | ||
| #define TEST_AND std::__lazy_and | ||
| #define TEST_OR std::__lazy_or | ||
| #elif defined(TEST_STD_AND) | ||
| #define TEST_AND std::__and_ | ||
| #define TEST_OR std::__or_ | ||
| #else | ||
| #define TEST_AND std::_And | ||
| #define TEST_OR std::_Or | ||
| #endif | ||
|
|
||
| void sink(...); | ||
|
|
||
| void Foo1(TEST_AND < REPEAT_1000(TRUE_T) true_type > t1) { sink(&t1); } | ||
| void Foo2(TEST_AND < REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type > t2) { sink(&t2); } | ||
| void Foo3(TEST_AND < REPEAT_1000(TRUE_T) true_type, false_type > t3) { sink(&t3); } | ||
| void Foo4(TEST_AND < REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type, false_type > t4) { sink(&t4); } | ||
| void Foo5(TEST_AND < false_type, REPEAT_1000(TRUE_T) true_type > t5) { sink(&t5); } | ||
| void Foo6(TEST_AND < false_type, REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type > t6) { sink(&t6); } | ||
|
|
||
| void escape() { | ||
|
|
||
| sink(&Foo1); | ||
| sink(&Foo2); | ||
| sink(&Foo3); | ||
| sink(&Foo4); | ||
| sink(&Foo5); | ||
| sink(&Foo6); | ||
| } | ||
|
|
||
|
|