Author: ericwf Date: Thu Jun 30 22:54:54 2016 New Revision: 274330 URL: http://llvm.org/viewvc/llvm-project?rev=274330&view=rev Log: Flatten the tuple_element and __make_tuple_types implementations.
This patch attempts to improve the QoI of std::tuples tuple_element and __make_tuple_types helpers. Previously they required O(N) instantiations, one for every element in the tuple The new implementations are O(1) after __tuple_indices<Id...> is created. Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp Modified: libcxx/trunk/include/__tuple Modified: libcxx/trunk/include/__tuple URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__tuple?rev=274330&r1=274329&r2=274330&view=diff ============================================================================== --- libcxx/trunk/include/__tuple (original) +++ libcxx/trunk/include/__tuple Thu Jun 30 22:54:54 2016 @@ -228,26 +228,42 @@ get(const array<_Tp, _Size>&&) _NOEXCEPT template <class ..._Tp> struct __tuple_types {}; -template <size_t _Ip> -class _LIBCPP_TYPE_VIS_ONLY tuple_element<_Ip, __tuple_types<> > -{ -public: - static_assert(_Ip == 0, "tuple_element index out of range"); - static_assert(_Ip != 0, "tuple_element index out of range"); -}; +#if !__has_builtin(__type_pack_element) -template <class _Hp, class ..._Tp> -class _LIBCPP_TYPE_VIS_ONLY tuple_element<0, __tuple_types<_Hp, _Tp...> > -{ -public: - typedef _Hp type; -}; +namespace __indexer_detail { + +template <size_t _Idx, class _Tp> +struct __indexed { using type = _Tp; }; + +template <class _Types, class _Indexes> struct __indexer; + +template <class ..._Types, size_t ..._Idx> +struct __indexer<__tuple_types<_Types...>, __tuple_indices<_Idx...>> + : __indexed<_Idx, _Types>... +{}; + +template <size_t _Idx, class _Tp> +__indexed<_Idx, _Tp> __at_index(__indexed<_Idx, _Tp> const&); -template <size_t _Ip, class _Hp, class ..._Tp> -class _LIBCPP_TYPE_VIS_ONLY tuple_element<_Ip, __tuple_types<_Hp, _Tp...> > +} // namespace __indexer_detail + +template <size_t _Idx, class ..._Types> +using __type_pack_element = typename decltype( + __indexer_detail::__at_index<_Idx>( + __indexer_detail::__indexer< + __tuple_types<_Types...>, + typename __make_tuple_indices<sizeof...(_Types)>::type + >{}) + )::type; + +#endif + +template <size_t _Ip, class ..._Types> +class _LIBCPP_TYPE_VIS_ONLY tuple_element<_Ip, __tuple_types<_Types...>> { public: - typedef typename tuple_element<_Ip-1, __tuple_types<_Tp...> >::type type; + static_assert(_Ip < sizeof...(_Types), "tuple_element index out of range"); + typedef __type_pack_element<_Ip, _Types...> type; }; template <class ..._Tp> @@ -258,6 +274,46 @@ class _LIBCPP_TYPE_VIS_ONLY tuple_size<_ template <class... _Tp> struct __tuple_like<__tuple_types<_Tp...> > : true_type {}; +template <bool _ApplyLV, bool _ApplyConst, bool _ApplyVolatile> +struct __apply_cv_mf; +template <> +struct __apply_cv_mf<false, false, false> { + template <class _Tp> using __apply = _Tp; +}; +template <> +struct __apply_cv_mf<false, true, false> { + template <class _Tp> using __apply = const _Tp; +}; +template <> +struct __apply_cv_mf<false, false, true> { + template <class _Tp> using __apply = volatile _Tp; +}; +template <> +struct __apply_cv_mf<false, true, true> { + template <class _Tp> using __apply = const volatile _Tp; +}; +template <> +struct __apply_cv_mf<true, false, false> { + template <class _Tp> using __apply = _Tp&; +}; +template <> +struct __apply_cv_mf<true, true, false> { + template <class _Tp> using __apply = const _Tp&; +}; +template <> +struct __apply_cv_mf<true, false, true> { + template <class _Tp> using __apply = volatile _Tp&; +}; +template <> +struct __apply_cv_mf<true, true, true> { + template <class _Tp> using __apply = const volatile _Tp&; +}; +template <class _Tp, class _RawTp = typename remove_reference<_Tp>::type> +using __apply_cv_t = __apply_cv_mf< + is_lvalue_reference<_Tp>::value, + is_const<_RawTp>::value, + is_volatile<_RawTp>::value>; + // __make_tuple_types // __make_tuple_types<_Tuple<_Types...>, _Ep, _Sp>::type is a @@ -265,31 +321,47 @@ template <class... _Tp> struct __tuple_l // _Sp defaults to 0 and _Ep defaults to tuple_size<_Tuple>. If _Tuple is a // lvalue_reference type, then __tuple_types<_Types&...> is the result. -template <class _TupleTypes, class _Tp, size_t _Sp, size_t _Ep> -struct __make_tuple_types_imp; +template <class _TupleTypes, class _TupleIndices> +struct __make_tuple_types_flat; -template <class ..._Types, class _Tp, size_t _Sp, size_t _Ep> -struct __make_tuple_types_imp<__tuple_types<_Types...>, _Tp, _Sp, _Ep> +template <template <class...> class _Tuple, class ..._Types, size_t ..._Idx> +struct __make_tuple_types_flat<_Tuple<_Types...>, __tuple_indices<_Idx...>> { + // Specialization for pair, tuple, and __tuple_types + template <class _Tp, class _ApplyFn = __apply_cv_t<_Tp>> + using __apply_quals = __tuple_types< + typename _ApplyFn::template __apply<__type_pack_element<_Idx, _Types...>>... + >; +}; + +template <class _Vt, size_t _Np, size_t ..._Idx> +struct __make_tuple_types_flat<array<_Vt, _Np>, __tuple_indices<_Idx...>> { + using _Array = array<_Vt, _Np>; + + template <class _Tp, class _ApplyFn = __apply_cv_t<_Tp>> + using __apply_quals = __tuple_types< + typename _ApplyFn::template __apply<typename tuple_element<_Idx, _Array>::type>... + >; +}; + +template <class _Tp, size_t _Ep = tuple_size<typename remove_reference<_Tp>::type>::value, + size_t _Sp = 0, + bool _SameSize = (_Ep == tuple_size<typename remove_reference<_Tp>::type>::value)> +struct __make_tuple_types { - typedef typename remove_reference<_Tp>::type _Tpr; - typedef typename __make_tuple_types_imp<__tuple_types<_Types..., - typename conditional<is_lvalue_reference<_Tp>::value, - typename tuple_element<_Sp, _Tpr>::type&, - typename tuple_element<_Sp, _Tpr>::type>::type>, - _Tp, _Sp+1, _Ep>::type type; + static_assert(_Sp <= _Ep, "__make_tuple_types input error"); + using _RawTp = typename remove_cv<typename remove_reference<_Tp>::type>::type; + using _Maker = __make_tuple_types_flat<_RawTp, typename __make_tuple_indices<_Ep, _Sp>::type>; + using type = typename _Maker::template __apply_quals<_Tp>; }; -template <class ..._Types, class _Tp, size_t _Ep> -struct __make_tuple_types_imp<__tuple_types<_Types...>, _Tp, _Ep, _Ep> -{ - typedef __tuple_types<_Types...> type; +template <class ..._Types, size_t _Ep> +struct __make_tuple_types<tuple<_Types...>, _Ep, 0, true> { + typedef __tuple_types<_Types...> type; }; -template <class _Tp, size_t _Ep = tuple_size<typename remove_reference<_Tp>::type>::value, size_t _Sp = 0> -struct __make_tuple_types -{ - static_assert(_Sp <= _Ep, "__make_tuple_types input error"); - typedef typename __make_tuple_types_imp<__tuple_types<>, _Tp, _Sp, _Ep>::type type; +template <class ..._Types, size_t _Ep> +struct __make_tuple_types<__tuple_types<_Types...>, _Ep, 0, true> { + typedef __tuple_types<_Types...> type; }; // __tuple_convertible Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp?rev=274330&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp Thu Jun 30 22:54:54 2016 @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <tuple> + +// template <class... Types> class tuple; + +// template <size_t I, class... Types> +// class tuple_element<I, tuple<Types...> > +// { +// public: +// typedef Ti type; +// }; + +// UNSUPPORTED: c++98, c++03 + +#include <tuple> +#include <type_traits> + +int main() +{ + using T = std::tuple<int, long, void*>; + using E1 = typename std::tuple_element<1, T &>::type; // expected-error{{undefined template}} + using E2 = typename std::tuple_element<3, T>::type; + using E3 = typename std::tuple_element<4, T const>::type; + // expected-error@__tuple:* 2 {{static_assert failed}} + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits