<div dir="ltr">Please ignore the fact I can't spell.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jun 21, 2019 at 7:37 PM Eric Fiselier via libcxx-commits <<a href="mailto:libcxx-commits@lists.llvm.org">libcxx-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: ericwf<br>
Date: Fri Jun 21 16:37:52 2019<br>
New Revision: 364114<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=364114&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=364114&view=rev</a><br>
Log:<br>
Add new style meta-programming primatives.<br>
<br>
Using class templates instead of alias templates causes a lot of<br>
instantiations. As part of the move away from C++03, we want to<br>
improve the efficiency of our meta-programming.<br>
<br>
This patch lays the groundwork by introducing new _If, _EnableIf,<br>
_And, _Or, and _IsValidExpansion (detect member). Future patches<br>
will replace the existing implementations after verifying there<br>
compile time differences.<br>
<br>
Added:<br>
libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp<br>
libcxx/trunk/test/libcxx/utilities/meta/stress_tests/<br>
libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp<br>
Modified:<br>
libcxx/trunk/include/type_traits<br>
<br>
Modified: libcxx/trunk/include/type_traits<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=364114&r1=364113&r2=364114&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=364114&r1=364113&r2=364114&view=diff</a><br>
==============================================================================<br>
--- libcxx/trunk/include/type_traits (original)<br>
+++ libcxx/trunk/include/type_traits Fri Jun 21 16:37:52 2019<br>
@@ -427,6 +427,93 @@ template <class _T1, class _T2> struct _<br>
template <class _Tp> class _LIBCPP_TEMPLATE_VIS reference_wrapper;<br>
template <class _Tp> struct _LIBCPP_TEMPLATE_VIS hash;<br>
<br>
+<br>
+template <class _Tp, _Tp __v><br>
+struct _LIBCPP_TEMPLATE_VIS integral_constant<br>
+{<br>
+ static _LIBCPP_CONSTEXPR const _Tp value = __v;<br>
+ typedef _Tp value_type;<br>
+ typedef integral_constant type;<br>
+ _LIBCPP_INLINE_VISIBILITY<br>
+ _LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;}<br>
+#if _LIBCPP_STD_VER > 11<br>
+ _LIBCPP_INLINE_VISIBILITY<br>
+ constexpr value_type operator ()() const _NOEXCEPT {return value;}<br>
+#endif<br>
+};<br>
+<br>
+template <class _Tp, _Tp __v><br>
+_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value;<br>
+<br>
+#if _LIBCPP_STD_VER > 14<br>
+template <bool __b><br>
+using bool_constant = integral_constant<bool, __b>;<br>
+#define _LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)><br>
+#else<br>
+#define _LIBCPP_BOOL_CONSTANT(__b) integral_constant<bool,(__b)><br>
+#endif<br>
+<br>
+typedef _LIBCPP_BOOL_CONSTANT(true) true_type;<br>
+typedef _LIBCPP_BOOL_CONSTANT(false) false_type;<br>
+<br>
+template <bool _Val><br>
+using _BoolConstant _LIBCPP_NODEBUG_TYPE = integral_constant<bool, _Val>;<br>
+<br>
+template <bool> struct _MetaBase;<br>
+template <><br>
+struct _MetaBase<true> {<br>
+ template <class _Tp, class _Up><br>
+ using _SelectImpl _LIBCPP_NODEBUG_TYPE = _Tp;<br>
+ template <template <class...> class _FirstFn, template <class...> class, class ..._Args><br>
+ using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _FirstFn<_Args...>;<br>
+ template <class _First, class...><br>
+ using _FirstImpl _LIBCPP_NODEBUG_TYPE = _First;<br>
+ template <class, class _Second, class...><br>
+ using _SecondImpl _LIBCPP_NODEBUG_TYPE = _Second;<br>
+ template <class _Tp = void><br>
+ using _EnableIfImpl _LIBCPP_NODEBUG_TYPE = _Tp;<br>
+ template <class _Result, class _First, class ..._Rest><br>
+ using _OrImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::type::value != true && sizeof...(_Rest) != 0>::template _OrImpl<_First, _Rest...>;<br>
+ template <class _Result, class _First, class ..._Rest><br>
+ using _AndImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::type::value == true && sizeof...(_Rest) != 0>::template _AndImpl<_First, _Rest...>;<br>
+};<br>
+<br>
+template <><br>
+struct _MetaBase<false> {<br>
+ template <class _Tp, class _Up><br>
+ using _SelectImpl _LIBCPP_NODEBUG_TYPE = _Up;<br>
+ template <template <class...> class, template <class...> class _SecondFn, class ..._Args><br>
+ using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _SecondFn<_Args...>;<br>
+ template <class _Result, class ...><br>
+ using _OrImpl _LIBCPP_NODEBUG_TYPE = _Result;<br>
+ template <class _Result, class ...><br>
+ using _AndImpl _LIBCPP_NODEBUG_TYPE = _Result;<br>
+};<br>
+template <bool _Cond, class _Ret = void><br>
+using _EnableIf _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _EnableIfImpl<_Ret>;<br>
+template <bool _Cond, class _IfRes, class _ElseRes><br>
+using _If _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;<br>
+template <class ..._Rest><br>
+using _Or _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _OrImpl<false_type, _Rest...>;<br>
+template <class ..._Rest><br>
+using _And _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _AndImpl<true_type, _Rest...>;<br>
+template <class _Pred><br>
+struct _Not : _BoolConstant<!_Pred::type::value> {};<br>
+template <class ..._Args><br>
+using _FirstType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 1)>::template _FirstImpl<_Args...>;<br>
+template <class ..._Args><br>
+using _SecondType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 2)>::template _SecondImpl<_Args...>;<br>
+<br>
+// Member detector base<br>
+<br>
+template <template <class...> class _Templ, class ..._Args><br>
+true_type __sfinae_test_impl(_FirstType<int, _Templ<_Args...> >);<br>
+template <template <class...> class, class ...><br>
+false_type __sfinae_test_impl(...);<br>
+<br>
+template <template <class ...> class _Templ, class ..._Args><br>
+using _IsValidExpansion _LIBCPP_NODEBUG_TYPE = decltype(std::__sfinae_test_impl<_Templ, _Args...>(0));<br>
+<br>
template <class><br>
struct __void_t { typedef void type; };<br>
<br>
@@ -528,34 +615,6 @@ struct __two {char __lx[2];};<br>
<br>
// helper class:<br>
<br>
-template <class _Tp, _Tp __v><br>
-struct _LIBCPP_TEMPLATE_VIS integral_constant<br>
-{<br>
- static _LIBCPP_CONSTEXPR const _Tp value = __v;<br>
- typedef _Tp value_type;<br>
- typedef integral_constant type;<br>
- _LIBCPP_INLINE_VISIBILITY<br>
- _LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;}<br>
-#if _LIBCPP_STD_VER > 11<br>
- _LIBCPP_INLINE_VISIBILITY<br>
- constexpr value_type operator ()() const _NOEXCEPT {return value;}<br>
-#endif<br>
-};<br>
-<br>
-template <class _Tp, _Tp __v><br>
-_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value;<br>
-<br>
-#if _LIBCPP_STD_VER > 14<br>
-template <bool __b><br>
-using bool_constant = integral_constant<bool, __b>;<br>
-#define _LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)><br>
-#else<br>
-#define _LIBCPP_BOOL_CONSTANT(__b) integral_constant<bool,(__b)><br>
-#endif<br>
-<br>
-typedef _LIBCPP_BOOL_CONSTANT(true) true_type;<br>
-typedef _LIBCPP_BOOL_CONSTANT(false) false_type;<br>
-<br>
#if !defined(_LIBCPP_CXX03_LANG)<br>
<br>
// __lazy_and<br>
<br>
Added: libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp?rev=364114&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp?rev=364114&view=auto</a><br>
==============================================================================<br>
--- libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp (added)<br>
+++ libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp Fri Jun 21 16:37:52 2019<br>
@@ -0,0 +1,91 @@<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+<br>
+#include <type_traits><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+<br>
+struct Bomb;<br>
+template <int N, class T = Bomb ><br>
+struct BOOM {<br>
+ using Explode = typename T::BOOMBOOM;<br>
+};<br>
+<br>
+using True = std::true_type;<br>
+using False = std::false_type;<br>
+<br>
+void test_if() {<br>
+ ASSERT_SAME_TYPE(std::_If<true, int, long>, int);<br>
+ ASSERT_SAME_TYPE(std::_If<false, int, long>, long);<br>
+}<br>
+<br>
+void test_and() {<br>
+ static_assert(std::_And<True>::value, "");<br>
+ static_assert(!std::_And<False>::value, "");<br>
+ static_assert(std::_And<True, True>::value, "");<br>
+ static_assert(!std::_And<False, BOOM<1> >::value, "");<br>
+ static_assert(!std::_And<True, True, True, False, BOOM<2> >::value, "");<br>
+}<br>
+<br>
+void test_or() {<br>
+ static_assert(std::_Or<True>::value, "");<br>
+ static_assert(!std::_Or<False>::value, "");<br>
+ static_assert(std::_Or<False, True>::value, "");<br>
+ static_assert(std::_Or<True, std::_Not<BOOM<3> > >::value, "");<br>
+ static_assert(!std::_Or<False, False>::value, "");<br>
+ static_assert(std::_Or<True, BOOM<1> >::value, "");<br>
+ static_assert(std::_Or<False, False, False, False, True, BOOM<2> >::value, "");<br>
+}<br>
+<br>
+void test_combined() {<br>
+ static_assert(std::_And<True, std::_Or<False, True, BOOM<4> > >::value, "");<br>
+ static_assert(std::_And<True, std::_Or<False, True, BOOM<4> > >::value, "");<br>
+ static_assert(std::_Not<std::_And<True, False, BOOM<5> > >::value, "");<br>
+}<br>
+<br>
+struct MemberTest {<br>
+ static int foo;<br>
+ using type = long;<br>
+<br>
+ void func(int);<br>
+};<br>
+struct Empty {};<br>
+struct MemberTest2 {<br>
+ using foo = int;<br>
+};<br>
+template <class T><br>
+using HasFooData = decltype(T::foo);<br>
+template <class T><br>
+using HasFooType = typename T::foo;<br>
+<br>
+template <class T, class U><br>
+using FuncCallable = decltype(std::declval<T>().func(std::declval<U>()));<br>
+template <class T><br>
+using BadCheck = typename T::DOES_NOT_EXIST;<br>
+<br>
+void test_is_valid_trait() {<br>
+ static_assert(std::_IsValidExpansion<HasFooData, MemberTest>::value, "");<br>
+ static_assert(!std::_IsValidExpansion<HasFooType, MemberTest>::value, "");<br>
+ static_assert(!std::_IsValidExpansion<HasFooData, MemberTest2>::value, "");<br>
+ static_assert(std::_IsValidExpansion<HasFooType, MemberTest2>::value, "");<br>
+ static_assert(std::_IsValidExpansion<FuncCallable, MemberTest, int>::value, "");<br>
+ static_assert(!std::_IsValidExpansion<FuncCallable, MemberTest, void*>::value, "");<br>
+}<br>
+<br>
+void test_first_and_second_type() {<br>
+ ASSERT_SAME_TYPE(std::_FirstType<int, long, void*>, int);<br>
+ ASSERT_SAME_TYPE(std::_FirstType<char>, char);<br>
+ ASSERT_SAME_TYPE(std::_SecondType<char, long>, long);<br>
+ ASSERT_SAME_TYPE(std::_SecondType<long long, int, void*>, int);<br>
+}<br>
+<br>
+int main(int, char**) {<br>
+ return 0;<br>
+}<br>
<br>
Added: libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp?rev=364114&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp?rev=364114&view=auto</a><br>
==============================================================================<br>
--- libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp (added)<br>
+++ libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp Fri Jun 21 16:37:52 2019<br>
@@ -0,0 +1,67 @@<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This is a dummy feature that prevents this test from running by default.<br>
+// REQUIRES: template-const-testing<br>
+<br>
+// The table below compares the compile time and object size for each of the<br>
+// variants listed in the RUN script.<br>
+//<br>
+// Impl Compile Time Object Size<br>
+// -------------------------------------------<br>
+// _And: 3,498.639 ms 158 M<br>
+// __lazy_and: 10,138.982 ms 334 M<br>
+// __and_: 14,181.851 ms 648 M<br>
+//<br>
+<br>
+// RUN: %cxx %flags %compile_flags -c %s -o %S/new.o -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -std=c++17<br>
+// 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<br>
+// 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<br>
+<br>
+#include <type_traits><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+#include "template_cost_testing.h"<br>
+using std::true_type;<br>
+using std::false_type;<br>
+<br>
+#define FALSE_T() std::false_type,<br>
+#define TRUE_T() std::true_type,<br>
+<br>
+#ifdef TEST_LAZY_AND<br>
+#define TEST_AND std::__lazy_and<br>
+#define TEST_OR std::__lazy_or<br>
+#elif defined(TEST_STD_AND)<br>
+#define TEST_AND std::__and_<br>
+#define TEST_OR std::__or_<br>
+#else<br>
+#define TEST_AND std::_And<br>
+#define TEST_OR std::_Or<br>
+#endif<br>
+<br>
+void sink(...);<br>
+<br>
+void Foo1(TEST_AND < REPEAT_1000(TRUE_T) true_type > t1) { sink(&t1); }<br>
+void Foo2(TEST_AND < REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type > t2) { sink(&t2); }<br>
+void Foo3(TEST_AND < REPEAT_1000(TRUE_T) true_type, false_type > t3) { sink(&t3); }<br>
+void Foo4(TEST_AND < REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type, false_type > t4) { sink(&t4); }<br>
+void Foo5(TEST_AND < false_type, REPEAT_1000(TRUE_T) true_type > t5) { sink(&t5); }<br>
+void Foo6(TEST_AND < false_type, REPEAT_1000(TRUE_T) REPEAT_1000(TRUE_T) true_type > t6) { sink(&t6); }<br>
+<br>
+void escape() {<br>
+<br>
+sink(&Foo1);<br>
+sink(&Foo2);<br>
+sink(&Foo3);<br>
+sink(&Foo4);<br>
+sink(&Foo5);<br>
+sink(&Foo6);<br>
+}<br>
+<br>
+<br>
<br>
<br>
_______________________________________________<br>
libcxx-commits mailing list<br>
<a href="mailto:libcxx-commits@lists.llvm.org" target="_blank">libcxx-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-commits</a><br>
</blockquote></div>