diff options
-rw-r--r-- | libcxx/include/type_traits | 115 | ||||
-rw-r--r-- | libcxx/test/libcxx/utilities/meta/meta_base.pass.cpp | 91 | ||||
-rw-r--r-- | libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp | 67 |
3 files changed, 245 insertions, 28 deletions
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index 21494920713..05405c96e56 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -427,6 +427,93 @@ template <class _T1, class _T2> struct _LIBCPP_TEMPLATE_VIS pair; template <class _Tp> class _LIBCPP_TEMPLATE_VIS reference_wrapper; template <class _Tp> struct _LIBCPP_TEMPLATE_VIS hash; + +template <class _Tp, _Tp __v> +struct _LIBCPP_TEMPLATE_VIS integral_constant +{ + static _LIBCPP_CONSTEXPR const _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant type; + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;} +#if _LIBCPP_STD_VER > 11 + _LIBCPP_INLINE_VISIBILITY + constexpr value_type operator ()() const _NOEXCEPT {return value;} +#endif +}; + +template <class _Tp, _Tp __v> +_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value; + +#if _LIBCPP_STD_VER > 14 +template <bool __b> +using bool_constant = integral_constant<bool, __b>; +#define _LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)> +#else +#define _LIBCPP_BOOL_CONSTANT(__b) integral_constant<bool,(__b)> +#endif + +typedef _LIBCPP_BOOL_CONSTANT(true) true_type; +typedef _LIBCPP_BOOL_CONSTANT(false) false_type; + +template <bool _Val> +using _BoolConstant _LIBCPP_NODEBUG_TYPE = integral_constant<bool, _Val>; + +template <bool> struct _MetaBase; +template <> +struct _MetaBase<true> { + template <class _Tp, class _Up> + using _SelectImpl _LIBCPP_NODEBUG_TYPE = _Tp; + template <template <class...> class _FirstFn, template <class...> class, class ..._Args> + using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _FirstFn<_Args...>; + template <class _First, class...> + using _FirstImpl _LIBCPP_NODEBUG_TYPE = _First; + template <class, class _Second, class...> + using _SecondImpl _LIBCPP_NODEBUG_TYPE = _Second; + template <class _Tp = void> + using _EnableIfImpl _LIBCPP_NODEBUG_TYPE = _Tp; + template <class _Result, class _First, class ..._Rest> + using _OrImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::type::value != true && sizeof...(_Rest) != 0>::template _OrImpl<_First, _Rest...>; + template <class _Result, class _First, class ..._Rest> + using _AndImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::type::value == true && sizeof...(_Rest) != 0>::template _AndImpl<_First, _Rest...>; +}; + +template <> +struct _MetaBase<false> { + template <class _Tp, class _Up> + using _SelectImpl _LIBCPP_NODEBUG_TYPE = _Up; + template <template <class...> class, template <class...> class _SecondFn, class ..._Args> + using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _SecondFn<_Args...>; + template <class _Result, class ...> + using _OrImpl _LIBCPP_NODEBUG_TYPE = _Result; + template <class _Result, class ...> + using _AndImpl _LIBCPP_NODEBUG_TYPE = _Result; +}; +template <bool _Cond, class _Ret = void> +using _EnableIf _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _EnableIfImpl<_Ret>; +template <bool _Cond, class _IfRes, class _ElseRes> +using _If _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>; +template <class ..._Rest> +using _Or _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _OrImpl<false_type, _Rest...>; +template <class ..._Rest> +using _And _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _AndImpl<true_type, _Rest...>; +template <class _Pred> +struct _Not : _BoolConstant<!_Pred::type::value> {}; +template <class ..._Args> +using _FirstType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 1)>::template _FirstImpl<_Args...>; +template <class ..._Args> +using _SecondType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 2)>::template _SecondImpl<_Args...>; + +// Member detector base + +template <template <class...> class _Templ, class ..._Args> +true_type __sfinae_test_impl(_FirstType<int, _Templ<_Args...> >); +template <template <class...> class, class ...> +false_type __sfinae_test_impl(...); + +template <template <class ...> class _Templ, class ..._Args> +using _IsValidExpansion _LIBCPP_NODEBUG_TYPE = decltype(std::__sfinae_test_impl<_Templ, _Args...>(0)); + template <class> struct __void_t { typedef void type; }; @@ -528,34 +615,6 @@ struct __two {char __lx[2];}; // helper class: -template <class _Tp, _Tp __v> -struct _LIBCPP_TEMPLATE_VIS integral_constant -{ - static _LIBCPP_CONSTEXPR const _Tp value = __v; - typedef _Tp value_type; - typedef integral_constant type; - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;} -#if _LIBCPP_STD_VER > 11 - _LIBCPP_INLINE_VISIBILITY - constexpr value_type operator ()() const _NOEXCEPT {return value;} -#endif -}; - -template <class _Tp, _Tp __v> -_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value; - -#if _LIBCPP_STD_VER > 14 -template <bool __b> -using bool_constant = integral_constant<bool, __b>; -#define _LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)> -#else -#define _LIBCPP_BOOL_CONSTANT(__b) integral_constant<bool,(__b)> -#endif - -typedef _LIBCPP_BOOL_CONSTANT(true) true_type; -typedef _LIBCPP_BOOL_CONSTANT(false) false_type; - #if !defined(_LIBCPP_CXX03_LANG) // __lazy_and diff --git a/libcxx/test/libcxx/utilities/meta/meta_base.pass.cpp b/libcxx/test/libcxx/utilities/meta/meta_base.pass.cpp new file mode 100644 index 00000000000..f04ae608614 --- /dev/null +++ b/libcxx/test/libcxx/utilities/meta/meta_base.pass.cpp @@ -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; +} diff --git a/libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp b/libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp new file mode 100644 index 00000000000..559759bf698 --- /dev/null +++ b/libcxx/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp @@ -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); +} + + |