• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Louis Dionne 2013-2017
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
4 
5 #include <boost/hana/assert.hpp>
6 #include <boost/hana/equal.hpp>
7 #include <boost/hana/functional/apply.hpp>
8 
9 #include <laws/base.hpp>
10 #include <support/tracked.hpp>
11 
12 #include <type_traits>
13 #include <utility>
14 namespace hana = boost::hana;
15 
16 
17 template <int i = 0>
18 struct nonpod : Tracked {
nonpodnonpod19     nonpod() : Tracked{i} { }
20 };
21 
22 struct NonCopyable {
23     NonCopyable() = default;
24     NonCopyable(NonCopyable const&) = delete;
25     NonCopyable& operator=(NonCopyable const&) = delete;
26 };
27 
28 struct TestClass {
TestClassTestClass29     explicit TestClass(int x) : data(x) { }
30     TestClass(TestClass const&) = delete;
31     TestClass& operator=(TestClass const&) = delete;
32 
operator ()TestClass33     int& operator()(NonCopyable&&) & { return data; }
operator ()TestClass34     int const& operator()(NonCopyable&&) const & { return data; }
operator ()TestClass35     int volatile& operator()(NonCopyable&&) volatile & { return data; }
operator ()TestClass36     int const volatile& operator()(NonCopyable&&) const volatile & { return data; }
37 
operator ()TestClass38     int&& operator()(NonCopyable&&) && { return std::move(data); }
operator ()TestClass39     int const&& operator()(NonCopyable&&) const && { return std::move(data); }
operator ()TestClass40     int volatile&& operator()(NonCopyable&&) volatile && { return std::move(data); }
operator ()TestClass41     int const volatile&& operator()(NonCopyable&&) const volatile && { return std::move(data); }
42 
43     int data;
44 };
45 
46 struct DerivedFromTestClass : TestClass {
DerivedFromTestClassDerivedFromTestClass47     explicit DerivedFromTestClass(int x) : TestClass(x) { }
48 };
49 
50 
51 template <typename Signature,  typename Expect, typename Functor>
test_b12(Functor && f)52 void test_b12(Functor&& f) {
53     // Create the callable object.
54     using ClassFunc = Signature TestClass::*;
55     ClassFunc func_ptr = &TestClass::operator();
56 
57     // Create the dummy arg.
58     NonCopyable arg;
59 
60     // Check that the deduced return type of invoke is what is expected.
61     using DeducedReturnType = decltype(
62         hana::apply(func_ptr, std::forward<Functor>(f), std::move(arg))
63     );
64     static_assert(std::is_same<DeducedReturnType, Expect>::value, "");
65 
66     // Check that result_of_t matches Expect.
67     using ResultOfReturnType = typename std::result_of<ClassFunc&&(Functor&&, NonCopyable&&)>::type;
68     static_assert(std::is_same<ResultOfReturnType, Expect>::value, "");
69 
70     // Run invoke and check the return value.
71     DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f), std::move(arg));
72     BOOST_HANA_RUNTIME_CHECK(ret == 42);
73 }
74 
75 template <typename Expect, typename Functor>
test_b34(Functor && f)76 void test_b34(Functor&& f) {
77     // Create the callable object.
78     using ClassFunc = int TestClass::*;
79     ClassFunc func_ptr = &TestClass::data;
80 
81     // Check that the deduced return type of invoke is what is expected.
82     using DeducedReturnType = decltype(
83         hana::apply(func_ptr, std::forward<Functor>(f))
84     );
85     static_assert(std::is_same<DeducedReturnType, Expect>::value, "");
86 
87     // Check that result_of_t matches Expect.
88     using ResultOfReturnType = typename std::result_of<ClassFunc&&(Functor&&)>::type;
89     static_assert(std::is_same<ResultOfReturnType, Expect>::value, "");
90 
91     // Run invoke and check the return value.
92     DeducedReturnType ret = hana::apply(func_ptr, std::forward<Functor>(f));
93     BOOST_HANA_RUNTIME_CHECK(ret == 42);
94 }
95 
96 template <typename Expect, typename Functor>
test_b5(Functor && f)97 void test_b5(Functor&& f) {
98     NonCopyable arg;
99 
100     // Check that the deduced return type of invoke is what is expected.
101     using DeducedReturnType = decltype(
102         hana::apply(std::forward<Functor>(f), std::move(arg))
103     );
104     static_assert(std::is_same<DeducedReturnType, Expect>::value, "");
105 
106     // Check that result_of_t matches Expect.
107     using ResultOfReturnType = typename std::result_of<Functor&&(NonCopyable&&)>::type;
108     static_assert(std::is_same<ResultOfReturnType, Expect>::value, "");
109 
110     // Run invoke and check the return value.
111     DeducedReturnType ret = hana::apply(std::forward<Functor>(f), std::move(arg));
112     BOOST_HANA_RUNTIME_CHECK(ret == 42);
113 }
114 
foo(NonCopyable &&)115 int& foo(NonCopyable&&) {
116     static int data = 42;
117     return data;
118 }
119 
main()120 int main() {
121     // Test normal usage with a function object
122     {
123         hana::test::_injection<0> f{};
124         using hana::test::ct_eq;
125 
126         BOOST_HANA_CONSTANT_CHECK(hana::equal(
127             hana::apply(f),
128             f()
129         ));
130         BOOST_HANA_CONSTANT_CHECK(hana::equal(
131             hana::apply(f, ct_eq<0>{}),
132             f(ct_eq<0>{})
133         ));
134         BOOST_HANA_CONSTANT_CHECK(hana::equal(
135             hana::apply(f, ct_eq<0>{}, ct_eq<1>{}),
136             f(ct_eq<0>{}, ct_eq<1>{})
137         ));
138         BOOST_HANA_CONSTANT_CHECK(hana::equal(
139             hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
140             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
141         ));
142         BOOST_HANA_CONSTANT_CHECK(hana::equal(
143             hana::apply(f, ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
144             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
145         ));
146 
147         // Make sure we can use apply with non-PODs
148         hana::apply(f, nonpod<>{});
149     }
150 
151     // Bullets 1 & 2 in the standard
152     {
153         TestClass cl(42);
154         test_b12<int&(NonCopyable&&) &, int&>(cl);
155         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
156         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
157         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
158 
159         test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
160         test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
161         test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));
162         test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));
163     }
164     {
165         DerivedFromTestClass cl(42);
166         test_b12<int&(NonCopyable&&) &, int&>(cl);
167         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
168         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
169         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
170 
171         test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
172         test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
173         test_b12<int volatile&&(NonCopyable&&) volatile &&, int volatile&&>(std::move(cl));
174         test_b12<int const volatile&&(NonCopyable&&) const volatile &&, int const volatile&&>(std::move(cl));
175     }
176     {
177         TestClass cl_obj(42);
178         TestClass *cl = &cl_obj;
179         test_b12<int&(NonCopyable&&) &, int&>(cl);
180         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
181         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
182         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
183     }
184     {
185         DerivedFromTestClass cl_obj(42);
186         DerivedFromTestClass *cl = &cl_obj;
187         test_b12<int&(NonCopyable&&) &, int&>(cl);
188         test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
189         test_b12<int volatile&(NonCopyable&&) volatile &, int volatile&>(cl);
190         test_b12<int const volatile&(NonCopyable&&) const volatile &, int const volatile&>(cl);
191     }
192 
193     // Bullets 3 & 4 in the standard
194     {
195         using Fn = TestClass;
196         Fn cl(42);
197         test_b34<int&>(cl);
198         test_b34<int const&>(static_cast<Fn const&>(cl));
199         test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
200         test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
201 
202         test_b34<int&&>(static_cast<Fn &&>(cl));
203         test_b34<int const&&>(static_cast<Fn const&&>(cl));
204         test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));
205         test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
206     }
207     {
208         using Fn = DerivedFromTestClass;
209         Fn cl(42);
210         test_b34<int&>(cl);
211         test_b34<int const&>(static_cast<Fn const&>(cl));
212         test_b34<int volatile&>(static_cast<Fn volatile&>(cl));
213         test_b34<int const volatile&>(static_cast<Fn const volatile &>(cl));
214 
215         test_b34<int&&>(static_cast<Fn &&>(cl));
216         test_b34<int const&&>(static_cast<Fn const&&>(cl));
217         test_b34<int volatile&&>(static_cast<Fn volatile&&>(cl));
218         test_b34<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
219     }
220     {
221         using Fn = TestClass;
222         Fn cl_obj(42);
223         Fn* cl = &cl_obj;
224         test_b34<int&>(cl);
225         test_b34<int const&>(static_cast<Fn const*>(cl));
226         test_b34<int volatile&>(static_cast<Fn volatile*>(cl));
227         test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));
228     }
229     {
230         using Fn = DerivedFromTestClass;
231         Fn cl_obj(42);
232         Fn* cl = &cl_obj;
233         test_b34<int&>(cl);
234         test_b34<int const&>(static_cast<Fn const*>(cl));
235         test_b34<int volatile&>(static_cast<Fn volatile*>(cl));
236         test_b34<int const volatile&>(static_cast<Fn const volatile *>(cl));
237     }
238 
239     // Bullet 5 in the standard
240     using FooType = int&(NonCopyable&&);
241     {
242         FooType& fn = foo;
243         test_b5<int &>(fn);
244     }
245     {
246         FooType* fn = foo;
247         test_b5<int &>(fn);
248     }
249     {
250         using Fn = TestClass;
251         Fn cl(42);
252         test_b5<int&>(cl);
253         test_b5<int const&>(static_cast<Fn const&>(cl));
254         test_b5<int volatile&>(static_cast<Fn volatile&>(cl));
255         test_b5<int const volatile&>(static_cast<Fn const volatile &>(cl));
256 
257         test_b5<int&&>(static_cast<Fn &&>(cl));
258         test_b5<int const&&>(static_cast<Fn const&&>(cl));
259         test_b5<int volatile&&>(static_cast<Fn volatile&&>(cl));
260         test_b5<int const volatile&&>(static_cast<Fn const volatile&&>(cl));
261     }
262 }
263