1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// UNSUPPORTED: c++98, c++03, c++11
11
12// <experimental/tuple>
13
14// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
15
16// Stress testing large arities with tuple and array.
17
18#include <experimental/tuple>
19#include <array>
20#include <utility>
21#include <cassert>
22
23////////////////////////////////////////////////////////////////////////////////
24template <class T, std::size_t Dummy = 0>
25struct always_imp
26{
27    typedef T type;
28};
29
30template <class T, std::size_t Dummy = 0>
31using always_t = typename always_imp<T, Dummy>::type;
32
33////////////////////////////////////////////////////////////////////////////////
34template <class Tuple, class Idx>
35struct make_function;
36
37template <class Tp, std::size_t ...Idx>
38struct make_function<Tp, std::integer_sequence<std::size_t, Idx...>>
39{
40    using type = bool (*)(always_t<Tp, Idx>...);
41};
42
43template <class Tp, std::size_t Size>
44using make_function_t = typename make_function<Tp, std::make_index_sequence<Size>>::type;
45
46////////////////////////////////////////////////////////////////////////////////
47template <class Tp, class Idx>
48struct make_tuple_imp;
49
50////////////////////////////////////////////////////////////////////////////////
51template <class Tp, std::size_t ...Idx>
52struct make_tuple_imp<Tp, std::integer_sequence<std::size_t, Idx...>>
53{
54    using type = std::tuple<always_t<Tp, Idx>...>;
55};
56
57template <class Tp, std::size_t Size>
58using make_tuple_t = typename make_tuple_imp<Tp, std::make_index_sequence<Size>>::type;
59
60template <class ...Types>
61bool test_apply_fn(Types...) { return true; }
62
63namespace ex = std::experimental;
64
65template <std::size_t Size>
66void test_all()
67{
68
69    using A = std::array<int, Size>;
70    using ConstA = std::array<int const, Size>;
71
72    using Tuple = make_tuple_t<int, Size>;
73    using CTuple = make_tuple_t<const int, Size>;
74
75    using ValFn  = make_function_t<int, Size>;
76    ValFn val_fn = &test_apply_fn;
77
78    using RefFn  = make_function_t<int &, Size>;
79    RefFn ref_fn = &test_apply_fn;
80
81    using CRefFn = make_function_t<int const &, Size>;
82    CRefFn cref_fn = &test_apply_fn;
83
84    using RRefFn = make_function_t<int &&, Size>;
85    RRefFn rref_fn = &test_apply_fn;
86
87    {
88        A a{};
89        assert(ex::apply(val_fn, a));
90        assert(ex::apply(ref_fn, a));
91        assert(ex::apply(cref_fn, a));
92        assert(ex::apply(rref_fn, std::move(a)));
93    }
94    {
95        ConstA a{};
96        assert(ex::apply(val_fn, a));
97        assert(ex::apply(cref_fn, a));
98    }
99    {
100        Tuple a{};
101        assert(ex::apply(val_fn, a));
102        assert(ex::apply(ref_fn, a));
103        assert(ex::apply(cref_fn, a));
104        assert(ex::apply(rref_fn, std::move(a)));
105    }
106    {
107        CTuple a{};
108        assert(ex::apply(val_fn, a));
109        assert(ex::apply(cref_fn, a));
110    }
111
112}
113
114
115template <std::size_t Size>
116void test_one()
117{
118    using A = std::array<int, Size>;
119    using Tuple = make_tuple_t<int, Size>;
120
121    using ValFn  = make_function_t<int, Size>;
122    ValFn val_fn = &test_apply_fn;
123
124    {
125        A a{};
126        assert(ex::apply(val_fn, a));
127    }
128    {
129        Tuple a{};
130        assert(ex::apply(val_fn, a));
131    }
132}
133
134int main()
135{
136    // Instantiate with 1-5 arguments.
137    test_all<1>();
138    test_all<2>();
139    test_all<3>();
140    test_all<4>();
141    test_all<5>();
142
143    // Stress test with 128.
144    test_one<128>();
145    //test_one<256>();
146}
147