Author: ericwf Date: Sun Jul 17 19:35:56 2016 New Revision: 275745 URL: http://llvm.org/viewvc/llvm-project?rev=275745&view=rev Log: Implement C++17 tuple bits. Including apply and make_from_tuple.
This patch upgrades <tuple> to be C++17 compliant by implementing: * tuple_size_v: This was forgotten when implementing the other _v traits. * std::apply: This was added via LFTS v1 in p0220r1. * std::make_from_tuple: This was added in p0209r2. Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp Modified: libcxx/trunk/include/tuple libcxx/trunk/www/cxx1z_status.html Modified: libcxx/trunk/include/tuple URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=275745&r1=275744&r2=275745&view=diff ============================================================================== --- libcxx/trunk/include/tuple (original) +++ libcxx/trunk/include/tuple Sun Jul 17 19:35:56 2016 @@ -76,10 +76,18 @@ template <class... T> tuple<V...> make_ template <class... T> tuple<ATypes...> forward_as_tuple(T&&...) noexcept; // constexpr in C++14 template <class... T> tuple<T&...> tie(T&...) noexcept; // constexpr in C++14 template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&... tpls); // constexpr in C++14 - + +// [tuple.apply], calling a function with a tuple of arguments: +template <class F, class Tuple> + constexpr decltype(auto) apply(F&& f, Tuple&& t); // C++17 +template <class T, class Tuple> + constexpr T make_from_tuple(Tuple&& t); // C++17 + // 20.4.1.4, tuple helper classes: template <class T> class tuple_size; // undefined template <class... T> class tuple_size<tuple<T...>>; +template <class T> + constexpr size_t tuple_size_v = tuple_size<T>::value; // C++17 template <size_t I, class T> class tuple_element; // undefined template <size_t I, class... T> class tuple_element<I, tuple<T...>>; template <size_t I, class T> @@ -1361,6 +1369,50 @@ pair<_T1, _T2>::pair(piecewise_construct #endif // _LIBCPP_HAS_NO_VARIADICS +#if _LIBCPP_STD_VER > 14 +template <class _Tp> +constexpr size_t tuple_size_v = tuple_size<_Tp>::value; + +#define _LIBCPP_NOEXCEPT_RETURN(...) noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; } + +template <class _Fn, class _Tuple, size_t ..._Id> +inline _LIBCPP_INLINE_VISIBILITY +constexpr decltype(auto) __apply_tuple_impl(_Fn && __f, _Tuple && __t, + __tuple_indices<_Id...>) +_LIBCPP_NOEXCEPT_RETURN( + _VSTD::__invoke_constexpr( + _VSTD::forward<_Fn>(__f), + _VSTD::get<_Id>(_VSTD::forward<_Tuple>(__t))...) +) + +template <class _Fn, class _Tuple> +inline _LIBCPP_INLINE_VISIBILITY +constexpr decltype(auto) apply(_Fn && __f, _Tuple && __t) +_LIBCPP_NOEXCEPT_RETURN( + _VSTD::__apply_tuple_impl( + _VSTD::forward<_Fn>(__f), _VSTD::forward<_Tuple>(__t), + typename __make_tuple_indices<tuple_size_v<decay_t<_Tuple>>>::type{}) +) + +template <class _Tp, class _Tuple, size_t... _Idx> +inline _LIBCPP_INLINE_VISIBILITY +constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>) +_LIBCPP_NOEXCEPT_RETURN( + _Tp(_VSTD::get<_Idx>(_VSTD::forward<_Tuple>(__t))...) +) + +template <class _Tp, class _Tuple> +inline _LIBCPP_INLINE_VISIBILITY +constexpr _Tp make_from_tuple(_Tuple&& __t) +_LIBCPP_NOEXCEPT_RETURN( + _VSTD::__make_from_tuple_impl<_Tp>(_VSTD::forward<_Tuple>(__t), + typename __make_tuple_indices<tuple_size_v<decay_t<_Tuple>>>::type{}) +) + +#undef _LIBCPP_NOEXCEPT_RETURN + +#endif // _LIBCPP_STD_VER > 14 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_TUPLE Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp?rev=275745&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply.pass.cpp Sun Jul 17 19:35:56 2016 @@ -0,0 +1,275 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <tuple> + +// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&) + +// Test with different ref/ptr/cv qualified argument types. + +#include <tuple> +#include <array> +#include <utility> +#include <cassert> + +#include "test_macros.h" +#include "type_id.h" + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + + +constexpr int constexpr_sum_fn() { return 0; } + +template <class ...Ints> +constexpr int constexpr_sum_fn(int x1, Ints... rest) { return x1 + constexpr_sum_fn(rest...); } + +struct ConstexprSumT { + constexpr ConstexprSumT() = default; + template <class ...Ints> + constexpr int operator()(Ints... values) const { + return constexpr_sum_fn(values...); + } +}; + + +void test_constexpr_evaluation() +{ + constexpr ConstexprSumT sum_obj{}; + { + using Tup = std::tuple<>; + using Fn = int(&)(); + constexpr Tup t; + static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 0, ""); + static_assert(std::apply(sum_obj, t) == 0, ""); + } + { + using Tup = std::tuple<int>; + using Fn = int(&)(int); + constexpr Tup t(42); + static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 42, ""); + static_assert(std::apply(sum_obj, t) == 42, ""); + } + { + using Tup = std::tuple<int, long>; + using Fn = int(&)(int, int); + constexpr Tup t(42, 101); + static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, ""); + static_assert(std::apply(sum_obj, t) == 143, ""); + } + { + using Tup = std::pair<int, long>; + using Fn = int(&)(int, int); + constexpr Tup t(42, 101); + static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, ""); + static_assert(std::apply(sum_obj, t) == 143, ""); + } + { + using Tup = std::tuple<int, long, int>; + using Fn = int(&)(int, int, int); + constexpr Tup t(42, 101, -1); + static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, ""); + static_assert(std::apply(sum_obj, t) == 142, ""); + } + { + using Tup = std::array<int, 3>; + using Fn = int(&)(int, int, int); + constexpr Tup t = {42, 101, -1}; + static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, ""); + static_assert(std::apply(sum_obj, t) == 142, ""); + } +} + + +enum CallQuals { + CQ_None, + CQ_LValue, + CQ_ConstLValue, + CQ_RValue, + CQ_ConstRValue +}; + +template <class Tuple> +struct CallInfo { + CallQuals quals; + TypeID const* arg_types; + Tuple args; + + template <class ...Args> + CallInfo(CallQuals q, Args&&... xargs) + : quals(q), arg_types(&makeArgumentID<Args&&...>()), args(std::forward<Args>(xargs)...) + {} +}; + +template <class ...Args> +inline CallInfo<decltype(std::forward_as_tuple(std::declval<Args>()...))> +makeCallInfo(CallQuals quals, Args&&... args) { + return {quals, std::forward<Args>(args)...}; +} + +struct TrackedCallable { + + TrackedCallable() = default; + + template <class ...Args> auto operator()(Args&&... xargs) & + { return makeCallInfo(CQ_LValue, std::forward<Args>(xargs)...); } + + template <class ...Args> auto operator()(Args&&... xargs) const& + { return makeCallInfo(CQ_ConstLValue, std::forward<Args>(xargs)...); } + + template <class ...Args> auto operator()(Args&&... xargs) && + { return makeCallInfo(CQ_RValue, std::forward<Args>(xargs)...); } + + template <class ...Args> auto operator()(Args&&... xargs) const&& + { return makeCallInfo(CQ_ConstRValue, std::forward<Args>(xargs)...); } +}; + +template <class ...ExpectArgs, class Tuple> +void check_apply_quals_and_types(Tuple&& t) { + TypeID const* const expect_args = &makeArgumentID<ExpectArgs...>(); + TrackedCallable obj; + TrackedCallable const& cobj = obj; + { + auto ret = std::apply(obj, std::forward<Tuple>(t)); + assert(ret.quals == CQ_LValue); + assert(ret.arg_types == expect_args); + assert(ret.args == t); + } + { + auto ret = std::apply(cobj, std::forward<Tuple>(t)); + assert(ret.quals == CQ_ConstLValue); + assert(ret.arg_types == expect_args); + assert(ret.args == t); + } + { + auto ret = std::apply(std::move(obj), std::forward<Tuple>(t)); + assert(ret.quals == CQ_RValue); + assert(ret.arg_types == expect_args); + assert(ret.args == t); + } + { + auto ret = std::apply(std::move(cobj), std::forward<Tuple>(t)); + assert(ret.quals == CQ_ConstRValue); + assert(ret.arg_types == expect_args); + assert(ret.args == t); + } +} + +void test_call_quals_and_arg_types() +{ + TrackedCallable obj; + using Tup = std::tuple<int, int const&, unsigned&&>; + const int x = 42; + unsigned y = 101; + Tup t(-1, x, std::move(y)); + Tup const& ct = t; + check_apply_quals_and_types<int&, int const&, unsigned&>(t); + check_apply_quals_and_types<int const&, int const&, unsigned&>(ct); + check_apply_quals_and_types<int&&, int const&, unsigned&&>(std::move(t)); + check_apply_quals_and_types<int const&&, int const&, unsigned&&>(std::move(ct)); +} + + +struct NothrowMoveable { + NothrowMoveable() noexcept = default; + NothrowMoveable(NothrowMoveable const&) noexcept(false) {} + NothrowMoveable(NothrowMoveable&&) noexcept {} +}; + +template <bool IsNoexcept> +struct TestNoexceptCallable { + template <class ...Args> + NothrowMoveable operator()(Args...) const noexcept(IsNoexcept) { return {}; } +}; + +void test_noexcept() +{ + TestNoexceptCallable<true> nec; + TestNoexceptCallable<false> tc; + { + // test that the functions noexcept-ness is propagated + using Tup = std::tuple<int, const char*, long>; + Tup t; + ASSERT_NOEXCEPT(std::apply(nec, t)); + ASSERT_NOT_NOEXCEPT(std::apply(tc, t)); + } + { + // test that the noexcept-ness of the argument conversions is checked. + using Tup = std::tuple<NothrowMoveable, int>; + Tup t; + ASSERT_NOT_NOEXCEPT(std::apply(nec, t)); + ASSERT_NOEXCEPT(std::apply(nec, std::move(t))); + } +} + +namespace ReturnTypeTest { + static int my_int = 42; + + template <int N> struct index {}; + + void f(index<0>) {} + + int f(index<1>) { return 0; } + + int & f(index<2>) { return static_cast<int &>(my_int); } + int const & f(index<3>) { return static_cast<int const &>(my_int); } + int volatile & f(index<4>) { return static_cast<int volatile &>(my_int); } + int const volatile & f(index<5>) { return static_cast<int const volatile &>(my_int); } + + int && f(index<6>) { return static_cast<int &&>(my_int); } + int const && f(index<7>) { return static_cast<int const &&>(my_int); } + int volatile && f(index<8>) { return static_cast<int volatile &&>(my_int); } + int const volatile && f(index<9>) { return static_cast<int const volatile &&>(my_int); } + + int * f(index<10>) { return static_cast<int *>(&my_int); } + int const * f(index<11>) { return static_cast<int const *>(&my_int); } + int volatile * f(index<12>) { return static_cast<int volatile *>(&my_int); } + int const volatile * f(index<13>) { return static_cast<int const volatile *>(&my_int); } + + template <int Func, class Expect> + void test() + { + using RawInvokeResult = decltype(f(index<Func>{})); + static_assert(std::is_same<RawInvokeResult, Expect>::value, ""); + using FnType = RawInvokeResult (*) (index<Func>); + FnType fn = f; + std::tuple<index<Func>> t; ((void)t); + using InvokeResult = decltype(std::apply(fn, t)); + static_assert(std::is_same<InvokeResult, Expect>::value, ""); + } +} // end namespace ReturnTypeTest + +void test_return_type() +{ + using ReturnTypeTest::test; + test<0, void>(); + test<1, int>(); + test<2, int &>(); + test<3, int const &>(); + test<4, int volatile &>(); + test<5, int const volatile &>(); + test<6, int &&>(); + test<7, int const &&>(); + test<8, int volatile &&>(); + test<9, int const volatile &&>(); + test<10, int *>(); + test<11, int const *>(); + test<12, int volatile *>(); + test<13, int const volatile *>(); +} + +int main() { + test_constexpr_evaluation(); + test_call_quals_and_arg_types(); + test_return_type(); + test_noexcept(); +} Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp?rev=275745&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_extended_types.pass.cpp Sun Jul 17 19:35:56 2016 @@ -0,0 +1,426 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <tuple> + +// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&) + +// Testing extended function types. The extended function types are those +// named by INVOKE but that are not actual callable objects. These include +// bullets 1-4 of invoke. + +#include <tuple> +#include <array> +#include <utility> +#include <cassert> + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +int count = 0; + +struct A_int_0 +{ + A_int_0() : obj1(0){} + A_int_0(int x) : obj1(x) {} + int mem1() { return ++count; } + int mem2() const { return ++count; } + int const obj1; +}; + +struct A_int_1 +{ + A_int_1() {} + A_int_1(int) {} + int mem1(int x) { return count += x; } + int mem2(int x) const { return count += x; } +}; + +struct A_int_2 +{ + A_int_2() {} + A_int_2(int) {} + int mem1(int x, int y) { return count += (x + y); } + int mem2(int x, int y) const { return count += (x + y); } +}; + +template <class A> +struct A_wrap +{ + A_wrap() {} + A_wrap(int x) : m_a(x) {} + A & operator*() { return m_a; } + A const & operator*() const { return m_a; } + A m_a; +}; + +typedef A_wrap<A_int_0> A_wrap_0; +typedef A_wrap<A_int_1> A_wrap_1; +typedef A_wrap<A_int_2> A_wrap_2; + + +template <class A> +struct A_base : public A +{ + A_base() : A() {} + A_base(int x) : A(x) {} +}; + +typedef A_base<A_int_0> A_base_0; +typedef A_base<A_int_1> A_base_1; +typedef A_base<A_int_2> A_base_2; + + +template < + class Tuple, class ConstTuple + , class TuplePtr, class ConstTuplePtr + , class TupleWrap, class ConstTupleWrap + , class TupleBase, class ConstTupleBase + > +void test_ext_int_0() +{ + count = 0; + typedef A_int_0 T; + typedef A_wrap_0 Wrap; + typedef A_base_0 Base; + + typedef int(T::*mem1_t)(); + mem1_t mem1 = &T::mem1; + + typedef int(T::*mem2_t)() const; + mem2_t mem2 = &T::mem2; + + typedef int const T::*obj1_t; + obj1_t obj1 = &T::obj1; + + // member function w/ref + { + T a; + Tuple t{a}; + assert(1 == std::apply(mem1, t)); + assert(count == 1); + } + count = 0; + // member function w/pointer + { + T a; + TuplePtr t{&a}; + assert(1 == std::apply(mem1, t)); + assert(count == 1); + } + count = 0; + // member function w/base + { + Base a; + TupleBase t{a}; + assert(1 == std::apply(mem1, t)); + assert(count == 1); + } + count = 0; + // member function w/wrap + { + Wrap a; + TupleWrap t{a}; + assert(1 == std::apply(mem1, t)); + assert(count == 1); + } + count = 0; + // const member function w/ref + { + T const a; + ConstTuple t{a}; + assert(1 == std::apply(mem2, t)); + assert(count == 1); + } + count = 0; + // const member function w/pointer + { + T const a; + ConstTuplePtr t{&a}; + assert(1 == std::apply(mem2, t)); + assert(count == 1); + } + count = 0; + // const member function w/base + { + Base const a; + ConstTupleBase t{a}; + assert(1 == std::apply(mem2, t)); + assert(count == 1); + } + count = 0; + // const member function w/wrapper + { + Wrap const a; + ConstTupleWrap t{a}; + assert(1 == std::apply(mem2, t)); + assert(1 == count); + } + // member object w/ref + { + T a{42}; + Tuple t{a}; + assert(42 == std::apply(obj1, t)); + } + // member object w/pointer + { + T a{42}; + TuplePtr t{&a}; + assert(42 == std::apply(obj1, t)); + } + // member object w/base + { + Base a{42}; + TupleBase t{a}; + assert(42 == std::apply(obj1, t)); + } + // member object w/wrapper + { + Wrap a{42}; + TupleWrap t{a}; + assert(42 == std::apply(obj1, t)); + } +} + + +template < + class Tuple, class ConstTuple + , class TuplePtr, class ConstTuplePtr + , class TupleWrap, class ConstTupleWrap + , class TupleBase, class ConstTupleBase + > +void test_ext_int_1() +{ + count = 0; + typedef A_int_1 T; + typedef A_wrap_1 Wrap; + typedef A_base_1 Base; + + typedef int(T::*mem1_t)(int); + mem1_t mem1 = &T::mem1; + + typedef int(T::*mem2_t)(int) const; + mem2_t mem2 = &T::mem2; + + // member function w/ref + { + T a; + Tuple t{a, 2}; + assert(2 == std::apply(mem1, t)); + assert(count == 2); + } + count = 0; + // member function w/pointer + { + T a; + TuplePtr t{&a, 3}; + assert(3 == std::apply(mem1, t)); + assert(count == 3); + } + count = 0; + // member function w/base + { + Base a; + TupleBase t{a, 4}; + assert(4 == std::apply(mem1, t)); + assert(count == 4); + } + count = 0; + // member function w/wrap + { + Wrap a; + TupleWrap t{a, 5}; + assert(5 == std::apply(mem1, t)); + assert(count == 5); + } + count = 0; + // const member function w/ref + { + T const a; + ConstTuple t{a, 6}; + assert(6 == std::apply(mem2, t)); + assert(count == 6); + } + count = 0; + // const member function w/pointer + { + T const a; + ConstTuplePtr t{&a, 7}; + assert(7 == std::apply(mem2, t)); + assert(count == 7); + } + count = 0; + // const member function w/base + { + Base const a; + ConstTupleBase t{a, 8}; + assert(8 == std::apply(mem2, t)); + assert(count == 8); + } + count = 0; + // const member function w/wrapper + { + Wrap const a; + ConstTupleWrap t{a, 9}; + assert(9 == std::apply(mem2, t)); + assert(9 == count); + } +} + + +template < + class Tuple, class ConstTuple + , class TuplePtr, class ConstTuplePtr + , class TupleWrap, class ConstTupleWrap + , class TupleBase, class ConstTupleBase + > +void test_ext_int_2() +{ + count = 0; + typedef A_int_2 T; + typedef A_wrap_2 Wrap; + typedef A_base_2 Base; + + typedef int(T::*mem1_t)(int, int); + mem1_t mem1 = &T::mem1; + + typedef int(T::*mem2_t)(int, int) const; + mem2_t mem2 = &T::mem2; + + // member function w/ref + { + T a; + Tuple t{a, 1, 1}; + assert(2 == std::apply(mem1, t)); + assert(count == 2); + } + count = 0; + // member function w/pointer + { + T a; + TuplePtr t{&a, 1, 2}; + assert(3 == std::apply(mem1, t)); + assert(count == 3); + } + count = 0; + // member function w/base + { + Base a; + TupleBase t{a, 2, 2}; + assert(4 == std::apply(mem1, t)); + assert(count == 4); + } + count = 0; + // member function w/wrap + { + Wrap a; + TupleWrap t{a, 2, 3}; + assert(5 == std::apply(mem1, t)); + assert(count == 5); + } + count = 0; + // const member function w/ref + { + T const a; + ConstTuple t{a, 3, 3}; + assert(6 == std::apply(mem2, t)); + assert(count == 6); + } + count = 0; + // const member function w/pointer + { + T const a; + ConstTuplePtr t{&a, 3, 4}; + assert(7 == std::apply(mem2, t)); + assert(count == 7); + } + count = 0; + // const member function w/base + { + Base const a; + ConstTupleBase t{a, 4, 4}; + assert(8 == std::apply(mem2, t)); + assert(count == 8); + } + count = 0; + // const member function w/wrapper + { + Wrap const a; + ConstTupleWrap t{a, 4, 5}; + assert(9 == std::apply(mem2, t)); + assert(9 == count); + } +} + +int main() +{ + { + test_ext_int_0< + std::tuple<A_int_0 &>, std::tuple<A_int_0 const &> + , std::tuple<A_int_0 *>, std::tuple<A_int_0 const *> + , std::tuple<A_wrap_0 &>, std::tuple<A_wrap_0 const &> + , std::tuple<A_base_0 &>, std::tuple<A_base_0 const &> + >(); + test_ext_int_0< + std::tuple<A_int_0>, std::tuple<A_int_0 const> + , std::tuple<A_int_0 *>, std::tuple<A_int_0 const *> + , std::tuple<A_wrap_0>, std::tuple<A_wrap_0 const> + , std::tuple<A_base_0>, std::tuple<A_base_0 const> + >(); + test_ext_int_0< + std::array<A_int_0, 1>, std::array<A_int_0 const, 1> + , std::array<A_int_0*, 1>, std::array<A_int_0 const*, 1> + , std::array<A_wrap_0, 1>, std::array<A_wrap_0 const, 1> + , std::array<A_base_0, 1>, std::array<A_base_0 const, 1> + >(); + } + { + test_ext_int_1< + std::tuple<A_int_1 &, int>, std::tuple<A_int_1 const &, int> + , std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int> + , std::tuple<A_wrap_1 &, int>, std::tuple<A_wrap_1 const &, int> + , std::tuple<A_base_1 &, int>, std::tuple<A_base_1 const &, int> + >(); + test_ext_int_1< + std::tuple<A_int_1, int>, std::tuple<A_int_1 const, int> + , std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int> + , std::tuple<A_wrap_1, int>, std::tuple<A_wrap_1 const, int> + , std::tuple<A_base_1, int>, std::tuple<A_base_1 const, int> + >(); + test_ext_int_1< + std::pair<A_int_1 &, int>, std::pair<A_int_1 const &, int> + , std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int> + , std::pair<A_wrap_1 &, int>, std::pair<A_wrap_1 const &, int> + , std::pair<A_base_1 &, int>, std::pair<A_base_1 const &, int> + >(); + test_ext_int_1< + std::pair<A_int_1, int>, std::pair<A_int_1 const, int> + , std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int> + , std::pair<A_wrap_1, int>, std::pair<A_wrap_1 const, int> + , std::pair<A_base_1, int>, std::pair<A_base_1 const, int> + >(); + } + { + test_ext_int_2< + std::tuple<A_int_2 &, int, int>, std::tuple<A_int_2 const &, int, int> + , std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int> + , std::tuple<A_wrap_2 &, int, int>, std::tuple<A_wrap_2 const &, int, int> + , std::tuple<A_base_2 &, int, int>, std::tuple<A_base_2 const &, int, int> + >(); + test_ext_int_2< + std::tuple<A_int_2, int, int>, std::tuple<A_int_2 const, int, int> + , std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int> + , std::tuple<A_wrap_2, int, int>, std::tuple<A_wrap_2 const, int, int> + , std::tuple<A_base_2, int, int>, std::tuple<A_base_2 const, int, int> + >(); + } +} Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp?rev=275745&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/apply_large_arity.pass.cpp Sun Jul 17 19:35:56 2016 @@ -0,0 +1,144 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <tuple> + +// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&) + +// Stress testing large arities with tuple and array. + +#include <tuple> +#include <array> +#include <utility> +#include <cassert> + +//////////////////////////////////////////////////////////////////////////////// +template <class T, std::size_t Dummy = 0> +struct always_imp +{ + typedef T type; +}; + +template <class T, std::size_t Dummy = 0> +using always_t = typename always_imp<T, Dummy>::type; + +//////////////////////////////////////////////////////////////////////////////// +template <class Tuple, class Idx> +struct make_function; + +template <class Tp, std::size_t ...Idx> +struct make_function<Tp, std::integer_sequence<std::size_t, Idx...>> +{ + using type = bool (*)(always_t<Tp, Idx>...); +}; + +template <class Tp, std::size_t Size> +using make_function_t = typename make_function<Tp, std::make_index_sequence<Size>>::type; + +//////////////////////////////////////////////////////////////////////////////// +template <class Tp, class Idx> +struct make_tuple_imp; + +//////////////////////////////////////////////////////////////////////////////// +template <class Tp, std::size_t ...Idx> +struct make_tuple_imp<Tp, std::integer_sequence<std::size_t, Idx...>> +{ + using type = std::tuple<always_t<Tp, Idx>...>; +}; + +template <class Tp, std::size_t Size> +using make_tuple_t = typename make_tuple_imp<Tp, std::make_index_sequence<Size>>::type; + +template <class ...Types> +bool test_apply_fn(Types...) { return true; } + + +template <std::size_t Size> +void test_all() +{ + + using A = std::array<int, Size>; + using ConstA = std::array<int const, Size>; + + using Tuple = make_tuple_t<int, Size>; + using CTuple = make_tuple_t<const int, Size>; + + using ValFn = make_function_t<int, Size>; + ValFn val_fn = &test_apply_fn; + + using RefFn = make_function_t<int &, Size>; + RefFn ref_fn = &test_apply_fn; + + using CRefFn = make_function_t<int const &, Size>; + CRefFn cref_fn = &test_apply_fn; + + using RRefFn = make_function_t<int &&, Size>; + RRefFn rref_fn = &test_apply_fn; + + { + A a{}; + assert(std::apply(val_fn, a)); + assert(std::apply(ref_fn, a)); + assert(std::apply(cref_fn, a)); + assert(std::apply(rref_fn, std::move(a))); + } + { + ConstA a{}; + assert(std::apply(val_fn, a)); + assert(std::apply(cref_fn, a)); + } + { + Tuple a{}; + assert(std::apply(val_fn, a)); + assert(std::apply(ref_fn, a)); + assert(std::apply(cref_fn, a)); + assert(std::apply(rref_fn, std::move(a))); + } + { + CTuple a{}; + assert(std::apply(val_fn, a)); + assert(std::apply(cref_fn, a)); + } + +} + + +template <std::size_t Size> +void test_one() +{ + using A = std::array<int, Size>; + using Tuple = make_tuple_t<int, Size>; + + using ValFn = make_function_t<int, Size>; + ValFn val_fn = &test_apply_fn; + + { + A a{}; + assert(std::apply(val_fn, a)); + } + { + Tuple a{}; + assert(std::apply(val_fn, a)); + } +} + +int main() +{ + // Instantiate with 1-5 arguments. + test_all<1>(); + test_all<2>(); + test_all<3>(); + test_all<4>(); + test_all<5>(); + + // Stress test with 256 + test_one<256>(); +} Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp?rev=275745&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp Sun Jul 17 19:35:56 2016 @@ -0,0 +1,210 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <tuple> + +// template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&); + +#include <tuple> +#include <array> +#include <utility> +#include <string> +#include <cassert> + +#include "test_macros.h" +#include "type_id.h" + +template <class Tuple> +struct ConstexprConstructibleFromTuple { + template <class ...Args> + explicit constexpr ConstexprConstructibleFromTuple(Args&&... xargs) + : args{std::forward<Args>(xargs)...} {} + Tuple args; +}; + +template <class TupleLike> +struct ConstructibleFromTuple; + +template <template <class ...> class Tuple, class ...Types> +struct ConstructibleFromTuple<Tuple<Types...>> { + template <class ...Args> + explicit ConstructibleFromTuple(Args&&... xargs) + : args(xargs...), + arg_types(&makeArgumentID<Args&&...>()) + {} + Tuple<std::decay_t<Types>...> args; + TypeID const* arg_types; +}; + +template <class Tp, size_t N> +struct ConstructibleFromTuple<std::array<Tp, N>> { +template <class ...Args> + explicit ConstructibleFromTuple(Args&&... xargs) + : args{xargs...}, + arg_types(&makeArgumentID<Args&&...>()) + {} + std::array<Tp, N> args; + TypeID const* arg_types; +}; + +template <class Tuple> +constexpr bool do_constexpr_test(Tuple&& tup) { + using RawTuple = std::decay_t<Tuple>; + using Tp = ConstexprConstructibleFromTuple<RawTuple>; + return std::make_from_tuple<Tp>(std::forward<Tuple>(tup)).args == tup; +} + +// Needed by do_forwarding_test() since it compare pairs of different types. +template <class T1, class T2, class U1, class U2> +inline bool operator==(const std::pair<T1, T2>& lhs, const std::pair<U1, U2>& rhs) { + return lhs.first == rhs.first && lhs.second == rhs.second; +} + +template <class ...ExpectTypes, class Tuple> +bool do_forwarding_test(Tuple&& tup) { + using RawTuple = std::decay_t<Tuple>; + using Tp = ConstructibleFromTuple<RawTuple>; + const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup)); + return value.args == tup + && value.arg_types == &makeArgumentID<ExpectTypes...>(); +} + +void test_constexpr_construction() { + { + constexpr std::tuple<> tup; + static_assert(do_constexpr_test(tup), ""); + } + { + constexpr std::tuple<int> tup(42); + static_assert(do_constexpr_test(tup), ""); + } + { + constexpr std::tuple<int, long, void*> tup(42, 101, nullptr); + static_assert(do_constexpr_test(tup), ""); + } + { + constexpr std::pair<int, const char*> p(42, "hello world"); + static_assert(do_constexpr_test(p), ""); + } + { + using Tuple = std::array<int, 3>; + using ValueTp = ConstexprConstructibleFromTuple<Tuple>; + constexpr Tuple arr = {42, 101, -1}; + constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr); + static_assert(value.args[0] == arr[0] && value.args[1] == arr[1] + && value.args[2] == arr[2], ""); + } +} + +void test_perfect_forwarding() { + { + using Tup = std::tuple<>; + Tup tup; + Tup const& ctup = tup; + assert(do_forwarding_test<>(tup)); + assert(do_forwarding_test<>(ctup)); + } + { + using Tup = std::tuple<int>; + Tup tup(42); + Tup const& ctup = tup; + assert(do_forwarding_test<int&>(tup)); + assert(do_forwarding_test<int const&>(ctup)); + assert(do_forwarding_test<int&&>(std::move(tup))); + assert(do_forwarding_test<int const&&>(std::move(ctup))); + } + { + using Tup = std::tuple<int&, const char*, unsigned&&>; + int x = 42; + unsigned y = 101; + Tup tup(x, "hello world", std::move(y)); + Tup const& ctup = tup; + assert((do_forwarding_test<int&, const char*&, unsigned&>(tup))); + assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup))); + assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup)))); + assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup)))); + } + // test with pair<T, U> + { + using Tup = std::pair<int&, const char*>; + int x = 42; + Tup tup(x, "hello world"); + Tup const& ctup = tup; + assert((do_forwarding_test<int&, const char*&>(tup))); + assert((do_forwarding_test<int&, const char* const&>(ctup))); + assert((do_forwarding_test<int&, const char*&&>(std::move(tup)))); + assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup)))); + } + // test with array<T, I> + { + using Tup = std::array<int, 3>; + Tup tup = {42, 101, -1}; + Tup const& ctup = tup; + assert((do_forwarding_test<int&, int&, int&>(tup))); + assert((do_forwarding_test<int const&, int const&, int const&>(ctup))); + assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup)))); + assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup)))); + } +} + +void test_noexcept() { + struct NothrowMoveable { + NothrowMoveable() = default; + NothrowMoveable(NothrowMoveable const&) {} + NothrowMoveable(NothrowMoveable&&) noexcept {} + }; + struct TestType { + TestType(int, NothrowMoveable) noexcept {} + TestType(int, int, int) noexcept(false) {} + TestType(long, long, long) noexcept {} + }; + { + using Tuple = std::tuple<int, NothrowMoveable>; + Tuple tup; ((void)tup); + Tuple const& ctup = tup; ((void)ctup); + ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup)); + ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup))); + } + { + using Tuple = std::pair<int, NothrowMoveable>; + Tuple tup; ((void)tup); + Tuple const& ctup = tup; ((void)ctup); + ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup)); + ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup))); + } + { + using Tuple = std::tuple<int, int, int>; + Tuple tup; ((void)tup); + ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); + } + { + using Tuple = std::tuple<long, long, long>; + Tuple tup; ((void)tup); + ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); + } + { + using Tuple = std::array<int, 3>; + Tuple tup; ((void)tup); + ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); + } + { + using Tuple = std::array<long, 3>; + Tuple tup; ((void)tup); + ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup)); + } +} + +int main() +{ + test_constexpr_construction(); + test_perfect_forwarding(); + test_noexcept(); +} Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp?rev=275745&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp Sun Jul 17 19:35:56 2016 @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// <tuple> + +// template <class... Types> +// class tuple_size<tuple<Types...>> +// : public integral_constant<size_t, sizeof...(Types)> { }; + +// Expect failures with a reference type, pointer type, and a non-tuple type. + +#include <tuple> + +int main() +{ + (void)std::tuple_size<std::tuple<> &>::value; // expected-error {{implicit instantiation of undefined template}} + (void)std::tuple_size<int>::value; // expected-error {{implicit instantiation of undefined template}} + (void)std::tuple_size<std::tuple<>*>::value; // expected-error {{implicit instantiation of undefined template}} +} Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp?rev=275745&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp Sun Jul 17 19:35:56 2016 @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <tuple> + +// template <class T> constexpr size_t tuple_size_v = tuple_size<T>::value; + +// Expect failures with a reference type, pointer type, and a non-tuple type. + +#include <tuple> + +int main() +{ + (void)std::tuple_size_v<std::tuple<> &>; // expected-note {{requested here}} + (void)std::tuple_size_v<int>; // expected-note {{requested here}} + (void)std::tuple_size_v<std::tuple<>*>; // expected-note {{requested here}} + // expected-error@tuple:* 3 {{implicit instantiation of undefined template}} +} Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp?rev=275745&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.pass.cpp Sun Jul 17 19:35:56 2016 @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <tuple> + +// template <class T> constexpr size_t tuple_size_v = tuple_size<T>::value; + +#include <tuple> +#include <utility> +#include <array> + +template <class Tuple, int Expect> +void test() +{ + static_assert(std::tuple_size_v<Tuple> == Expect, ""); + static_assert(std::tuple_size_v<Tuple> == std::tuple_size<Tuple>::value, ""); + static_assert(std::tuple_size_v<Tuple const> == std::tuple_size<Tuple>::value, ""); + static_assert(std::tuple_size_v<Tuple volatile> == std::tuple_size<Tuple>::value, ""); + static_assert(std::tuple_size_v<Tuple const volatile> == std::tuple_size<Tuple>::value, ""); +} + +int main() +{ + test<std::tuple<>, 0>(); + + test<std::tuple<int>, 1>(); + test<std::array<int, 1>, 1>(); + + test<std::tuple<int, int>, 2>(); + test<std::pair<int, int>, 2>(); + test<std::array<int, 2>, 2>(); + + test<std::tuple<int, int, int>, 3>(); + test<std::array<int, 3>, 3>(); +} Modified: libcxx/trunk/www/cxx1z_status.html URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=275745&r1=275744&r2=275745&view=diff ============================================================================== --- libcxx/trunk/www/cxx1z_status.html (original) +++ libcxx/trunk/www/cxx1z_status.html Sun Jul 17 19:35:56 2016 @@ -106,7 +106,7 @@ <tr><td><a href="http://wg21.link/p0175r1">p0175r1</a></td><td>LWG</td><td>Synopses for the C library</td><td>Oulu</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/p0180r2">p0180r2</a></td><td>LWG</td><td>Reserve a New Library Namespace for Future Standardization</td><td>Oulu</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/p0181r1">p0181r1</a></td><td>LWG</td><td>Ordered by Default</td><td>Oulu</td><td></td><td></td></tr> - <tr><td><a href="http://wg21.link/p0209r2">p0209r2</a></td><td>LWG</td><td>make_from_tuple: apply for construction</td><td>Oulu</td><td></td><td></td></tr> + <tr><td><a href="http://wg21.link/p0209r2">p0209r2</a></td><td>LWG</td><td>make_from_tuple: apply for construction</td><td>Oulu</td><td>Complete</td><td>3.9</td></tr> <tr><td><a href="http://wg21.link/p0219r1">p0219r1</a></td><td>LWG</td><td>Relative Paths for Filesystem</td><td>Oulu</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/p0254r2">p0254r2</a></td><td>LWG</td><td>Integrating std::string_view and std::string</td><td>Oulu</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/p0258r2">p0258r2</a></td><td>LWG</td><td>has_unique_object_representations</td><td>Oulu</td><td></td><td></td></tr> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits