[libcxx-commits] [libcxx] r364114 - Add new style meta-programming primatives.

Eric Fiselier via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 21 16:43:28 PDT 2019


Please ignore the fact I can't spell.

On Fri, Jun 21, 2019 at 7:37 PM Eric Fiselier via libcxx-commits <
libcxx-commits at lists.llvm.org> wrote:

> Author: ericwf
> Date: Fri Jun 21 16:37:52 2019
> New Revision: 364114
>
> URL: http://llvm.org/viewvc/llvm-project?rev=364114&view=rev
> Log:
> 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.
>
> Added:
>     libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp
>     libcxx/trunk/test/libcxx/utilities/meta/stress_tests/
>
> libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp
> Modified:
>     libcxx/trunk/include/type_traits
>
> Modified: libcxx/trunk/include/type_traits
> URL:
> http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=364114&r1=364113&r2=364114&view=diff
>
> ==============================================================================
> --- libcxx/trunk/include/type_traits (original)
> +++ libcxx/trunk/include/type_traits Fri Jun 21 16:37:52 2019
> @@ -427,6 +427,93 @@ template <class _T1, class _T2> struct _
>  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
>
> Added: libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp?rev=364114&view=auto
>
> ==============================================================================
> --- libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp (added)
> +++ libcxx/trunk/test/libcxx/utilities/meta/meta_base.pass.cpp Fri Jun 21
> 16:37:52 2019
> @@ -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;
> +}
>
> Added:
> libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp?rev=364114&view=auto
>
> ==============================================================================
> ---
> libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp
> (added)
> +++
> libcxx/trunk/test/libcxx/utilities/meta/stress_tests/stress_test_metafunctions.sh.cpp
> Fri Jun 21 16:37:52 2019
> @@ -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);
> +}
> +
> +
>
>
> _______________________________________________
> libcxx-commits mailing list
> libcxx-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20190621/607bbd44/attachment-0001.html>


More information about the libcxx-commits mailing list