1 /*=============================================================================
2 Copyright (c) 2017 Paul Fultz II
3 unpack.cpp
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 #include <boost/hof/unpack.hpp>
8 #include <boost/hof/static.hpp>
9 #include <boost/hof/lambda.hpp>
10 #include "test.hpp"
11
12 #include <memory>
13
14 static constexpr boost::hof::static_<boost::hof::unpack_adaptor<unary_class> > unary_unpack = {};
15 static constexpr boost::hof::static_<boost::hof::unpack_adaptor<binary_class> > binary_unpack = {};
16
17 BOOST_HOF_STATIC_AUTO unary_unpack_constexpr = boost::hof::unpack_adaptor<unary_class>();
18 #if BOOST_HOF_HAS_CONSTEXPR_TUPLE
19 BOOST_HOF_STATIC_AUTO binary_unpack_constexpr = boost::hof::unpack_adaptor<binary_class>();
20 #endif
21
22 BOOST_HOF_STATIC_AUTO unary_unpack_reveal = boost::hof::reveal_adaptor<boost::hof::unpack_adaptor<unary_class>>();
23 BOOST_HOF_STATIC_AUTO binary_unpack_reveal = boost::hof::reveal_adaptor<boost::hof::unpack_adaptor<binary_class>>();
24
25 #if BOOST_HOF_HAS_NOEXCEPT_DEDUCTION
BOOST_HOF_TEST_CASE()26 BOOST_HOF_TEST_CASE()
27 {
28 static_assert(noexcept(boost::hof::unpack(unary_class())(boost::hof::pack(3))), "noexcept unpack");
29 static_assert(noexcept(unary_unpack(boost::hof::pack(3))), "noexcept unpack");
30 static_assert(noexcept(binary_unpack(boost::hof::pack(3), boost::hof::pack(2))), "noexcept unpack");
31 }
32 #endif
33
BOOST_HOF_TEST_CASE()34 BOOST_HOF_TEST_CASE()
35 {
36 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(unary_class())(std::make_tuple(3)));
37 BOOST_HOF_TEST_CHECK(3 == unary_unpack(std::make_tuple(3)));
38 BOOST_HOF_TEST_CHECK(3 == unary_unpack_reveal(std::make_tuple(3)));
39 int ifu = 3;
40 BOOST_HOF_TEST_CHECK(3 == unary_unpack(std::tuple<int&>(ifu)));
41
42 #if BOOST_HOF_HAS_CONSTEXPR_TUPLE
43 BOOST_HOF_STATIC_TEST_CHECK(3 == boost::hof::unpack(unary_class())(std::make_tuple(3)));
44 BOOST_HOF_STATIC_TEST_CHECK(3 == unary_unpack_constexpr(std::make_tuple(3)));
45 BOOST_HOF_STATIC_TEST_CHECK(3 == unary_unpack_reveal(std::make_tuple(3)));
46 #endif
47 }
48
BOOST_HOF_TEST_CASE()49 BOOST_HOF_TEST_CASE()
50 {
51 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(unary_class())(boost::hof::pack(3)));
52 BOOST_HOF_TEST_CHECK(3 == unary_unpack(boost::hof::pack(3)));
53 BOOST_HOF_TEST_CHECK(3 == unary_unpack_reveal(boost::hof::pack(3)));
54 int ifu = 3;
55 BOOST_HOF_TEST_CHECK(3 == unary_unpack(boost::hof::pack_forward(ifu)));
56
57 BOOST_HOF_STATIC_TEST_CHECK(3 == boost::hof::unpack(unary_class())(boost::hof::pack(3)));
58 BOOST_HOF_STATIC_TEST_CHECK(3 == unary_unpack_constexpr(boost::hof::pack(3)));
59 BOOST_HOF_STATIC_TEST_CHECK(3 == unary_unpack_reveal(boost::hof::pack(3)));
60 }
61
BOOST_HOF_TEST_CASE()62 BOOST_HOF_TEST_CASE()
63 {
64 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1, 2)));
65 BOOST_HOF_TEST_CHECK(3 == binary_unpack(std::make_tuple(1, 2)));
66 BOOST_HOF_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1, 2)));
67
68 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1), std::make_tuple(2)));
69 BOOST_HOF_TEST_CHECK(3 == binary_unpack(std::make_tuple(1), std::make_tuple(2)));
70 BOOST_HOF_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(2)));
71
72 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
73 BOOST_HOF_TEST_CHECK(3 == binary_unpack(std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
74 BOOST_HOF_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
75
76 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
77 BOOST_HOF_TEST_CHECK(3 == binary_unpack(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
78 BOOST_HOF_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
79
80 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple()));
81 BOOST_HOF_TEST_CHECK(3 == binary_unpack(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple()));
82 BOOST_HOF_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple()));
83
84 #if BOOST_HOF_HAS_CONSTEXPR_TUPLE
85 BOOST_HOF_STATIC_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1, 2)));
86 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1, 2)));
87 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1, 2)));
88
89 BOOST_HOF_STATIC_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1), std::make_tuple(2)));
90 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1), std::make_tuple(2)));
91 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(2)));
92
93 BOOST_HOF_STATIC_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
94 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
95 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
96
97 BOOST_HOF_STATIC_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
98 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
99 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(), std::make_tuple(1), std::make_tuple(), std::make_tuple(2)));
100
101 BOOST_HOF_STATIC_TEST_CHECK(3 == boost::hof::unpack(binary_class())(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple()));
102 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_constexpr(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple()));
103 BOOST_HOF_STATIC_TEST_CHECK(3 == binary_unpack_reveal(std::make_tuple(1), std::make_tuple(), std::make_tuple(2), std::make_tuple()));
104 #endif
105 }
106
BOOST_HOF_TEST_CASE()107 BOOST_HOF_TEST_CASE()
108 {
109 auto p1 = boost::hof::pack_basic(1, 2);
110 static_assert(boost::hof::is_unpackable<decltype(p1)>::value, "Not unpackable");
111 static_assert(boost::hof::is_unpackable<decltype((p1))>::value, "Not unpackable");
112
113 auto p2 = boost::hof::pack_forward(1, 2);
114 static_assert(boost::hof::is_unpackable<decltype(p2)>::value, "Not unpackable");
115 static_assert(boost::hof::is_unpackable<decltype((p2))>::value, "Not unpackable");
116
117 auto p3 = boost::hof::pack(1, 2);
118 static_assert(boost::hof::is_unpackable<decltype(p3)>::value, "Not unpackable");
119 static_assert(boost::hof::is_unpackable<decltype((p3))>::value, "Not unpackable");
120
121 static_assert(boost::hof::is_unpackable<std::tuple<int>>::value, "Not unpackable");
122
123 static_assert(!boost::hof::is_unpackable<int>::value, "Unpackable");
124 static_assert(!boost::hof::is_unpackable<void>::value, "Unpackable");
125 }
126
BOOST_HOF_TEST_CASE()127 BOOST_HOF_TEST_CASE()
128 {
129 typedef std::tuple<int, int> tuple_type;
130 static_assert(boost::hof::is_unpackable<tuple_type>::value, "Not unpackable");
131 static_assert(boost::hof::is_unpackable<tuple_type&>::value, "Not unpackable");
132 static_assert(boost::hof::is_unpackable<const tuple_type&>::value, "Not unpackable");
133 static_assert(boost::hof::is_unpackable<tuple_type&&>::value, "Not unpackable");
134
135 }
136
137 BOOST_HOF_STATIC_AUTO lambda_unary_unpack = boost::hof::unpack(BOOST_HOF_STATIC_LAMBDA(int x)
138 {
139 return x;
140 });
141
BOOST_HOF_TEST_CASE()142 BOOST_HOF_TEST_CASE()
143 {
144 BOOST_HOF_TEST_CHECK(3 == lambda_unary_unpack(std::make_tuple(3)));
145 }
146
BOOST_HOF_TEST_CASE()147 BOOST_HOF_TEST_CASE()
148 {
149 BOOST_HOF_TEST_CHECK(3 == lambda_unary_unpack(boost::hof::pack(3)));
150 }
151
152 struct unary_move
153 {
154 std::unique_ptr<int> i;
unary_moveunary_move155 unary_move()
156 : i(new int(2))
157 {}
158
159 template<class T>
operator ()unary_move160 T operator()(T x) const
161 {
162 return x + *i;
163 }
164 };
165
166 static constexpr boost::hof::static_<boost::hof::unpack_adaptor<unary_move> > unary_move_unpack = {};
167
BOOST_HOF_TEST_CASE()168 BOOST_HOF_TEST_CASE()
169 {
170 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(unary_move())(std::make_tuple(1)));
171 BOOST_HOF_TEST_CHECK(3 == unary_move_unpack(std::make_tuple(1)));
172 }
173
BOOST_HOF_TEST_CASE()174 BOOST_HOF_TEST_CASE()
175 {
176 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(unary_move())(boost::hof::pack(1)));
177 BOOST_HOF_TEST_CHECK(3 == unary_move_unpack(boost::hof::pack(1)));
178 }
179
180 struct indirect_sum_f
181 {
182 template<class T, class U>
183 auto operator()(T x, U y) const
184 BOOST_HOF_RETURNS(*x + *y);
185 };
186
187 #define MAKE_UNIQUE_PTR(x) std::unique_ptr<int>(new int(x))
188
BOOST_HOF_TEST_CASE()189 BOOST_HOF_TEST_CASE()
190 {
191 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(indirect_sum_f())(boost::hof::pack_basic(MAKE_UNIQUE_PTR(1), MAKE_UNIQUE_PTR(2))));
192 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(indirect_sum_f())(boost::hof::pack_forward(MAKE_UNIQUE_PTR(1), MAKE_UNIQUE_PTR(2))));
193 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(indirect_sum_f())(boost::hof::pack(MAKE_UNIQUE_PTR(1), MAKE_UNIQUE_PTR(2))));
194 BOOST_HOF_TEST_CHECK(3 == boost::hof::unpack(indirect_sum_f())(std::make_tuple(MAKE_UNIQUE_PTR(1), MAKE_UNIQUE_PTR(2))));
195 }
196
197 template<class...>
198 struct deduce_types
199 {};
200
201 struct deducer
202 {
203 template<class... Ts>
204 deduce_types<Ts...> operator()(Ts&&...) const;
205 };
206
207 static constexpr boost::hof::unpack_adaptor<deducer> deduce = {};
208
BOOST_HOF_TEST_CASE()209 BOOST_HOF_TEST_CASE()
210 {
211 STATIC_ASSERT_SAME(deduce_types<int, int>, decltype(deduce(std::make_tuple(1, 2))));
212 STATIC_ASSERT_SAME(deduce_types<int, int>, decltype(deduce(std::make_tuple(1), std::make_tuple(2))));
213 STATIC_ASSERT_SAME(deduce_types<int, int, int>, decltype(deduce(std::make_tuple(1), std::make_tuple(2), std::make_tuple(3))));
214 STATIC_ASSERT_SAME(std::tuple<int&&, int&&>, decltype(std::forward_as_tuple(1, 2)));
215 // Disable this test, it seems that rvalue references get swalllowed by type deduction
216 // STATIC_ASSERT_SAME(deduce_types<int&&, int&&>, decltype(deduce(std::forward_as_tuple(1, 2))));
217
218
219 STATIC_ASSERT_SAME(deduce_types<int, int>, decltype(deduce(boost::hof::pack_basic(1, 2))));
220 STATIC_ASSERT_SAME(deduce_types<int, int>, decltype(deduce(boost::hof::pack_basic(1), boost::hof::pack_basic(2))));
221 STATIC_ASSERT_SAME(deduce_types<int, int, int>, decltype(deduce(boost::hof::pack_basic(1), boost::hof::pack_basic(2), boost::hof::pack_basic(3))));
222 // STATIC_ASSERT_SAME(deduce_types<int&&, int&&>, decltype(deduce(boost::hof::pack_forward(1, 2))));
223 }
224
225 struct not_unpackable
226 {};
227
BOOST_HOF_TEST_CASE()228 BOOST_HOF_TEST_CASE()
229 {
230 auto f = boost::hof::unpack(boost::hof::always(1));
231
232 static_assert(!boost::hof::is_invocable<decltype(f), not_unpackable>::value, "SFINAE for unpack failed");
233 }
234
235 struct simple_unpackable
236 {};
237
238 namespace boost { namespace hof {
239
240 template<>
241 struct unpack_sequence<simple_unpackable>
242 {
243 template<class F, class S>
244 constexpr static auto apply(F&& f, S&&) BOOST_HOF_RETURNS
245 (
246 f(1)
247 );
248 };
249 }} // namespace boost::hof
250
BOOST_HOF_TEST_CASE()251 BOOST_HOF_TEST_CASE()
252 {
253 BOOST_HOF_TEST_CHECK(boost::hof::unpack(boost::hof::identity)(simple_unpackable{}) == 1);
254 BOOST_HOF_STATIC_TEST_CHECK(boost::hof::unpack(boost::hof::identity)(simple_unpackable{}) == 1);
255 }
256