• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2005-2006 Joao Abecasis
3     Copyright (c) 2006-2007 Tobias Schwinger
4 
5     Use modification and distribution are subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt).
8 ==============================================================================*/
9 
10 #include <boost/fusion/functional/invocation/invoke_function_object.hpp>
11 #include <boost/detail/lightweight_test.hpp>
12 
13 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
14 #include <functional>
15 #endif
16 
17 #include <boost/type_traits/is_same.hpp>
18 
19 #include <memory>
20 #include <boost/noncopyable.hpp>
21 
22 #include <boost/mpl/int.hpp>
23 
24 #include <boost/fusion/container/vector.hpp>
25 #include <boost/fusion/container/list.hpp>
26 #include <boost/fusion/sequence/intrinsic/size.hpp>
27 #include <boost/fusion/sequence/intrinsic/begin.hpp>
28 #include <boost/fusion/view/single_view.hpp>
29 #include <boost/fusion/view/iterator_range.hpp>
30 #include <boost/fusion/iterator/advance.hpp>
31 #include <boost/fusion/algorithm/transformation/join.hpp>
32 
33 #include "../compile_time/sfinae_friendly.hpp"
34 
35 namespace mpl = boost::mpl;
36 namespace fusion = boost::fusion;
37 
38 template <typename T>
const_(T const & t)39 inline T const & const_(T const & t)
40 {
41     return t;
42 }
43 
44 struct object {};
45 struct object_nc : boost::noncopyable {};
46 
47 struct fobj
48 {
49     // Handle nullary separately to exercise result_of support
50     template <typename Sig>
51     struct result;
52 
53     template <class Self, typename T0>
54     struct result< Self(T0) >
55     {
56         typedef int type;
57     };
58 
59     template <class Self, typename T0, typename T1>
60     struct result< Self(T0, T1) >
61     {
62         typedef int type;
63     };
64 
65     template <class Self, typename T0, typename T1, typename T2>
66     struct result< Self(T0, T1, T2) >
67     {
68         typedef int type;
69     };
70 
operator ()fobj71     int operator()()       { return 0; }
operator ()fobj72     int operator()() const { return 1; }
73 
operator ()fobj74     int operator()(int i)       { return 2 + i; }
operator ()fobj75     int operator()(int i) const { return 3 + i; }
76 
operator ()fobj77     int operator()(int i, object &)             { return 4 + i; }
operator ()fobj78     int operator()(int i, object &) const       { return 5 + i; }
operator ()fobj79     int operator()(int i, object const &)       { return 6 + i; }
operator ()fobj80     int operator()(int i, object const &) const { return 7 + i; }
81 
operator ()fobj82     int operator()(int i, object &, object_nc &)       { return 10 + i; }
operator ()fobj83     int operator()(int i, object &, object_nc &) const { return 11 + i; }
84     int operator()(int i, object const &, object_nc &);
85     int operator()(int i, object const &, object_nc &) const;
86 };
87 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj, sfinae_friendly::v1>));
88 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj, sfinae_friendly::v2>));
89 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj, sfinae_friendly::v3>));
90 
91 struct nullary_fobj
92 {
93     typedef int result_type;
94 
operator ()nullary_fobj95     int operator()()       { return 0; }
operator ()nullary_fobj96     int operator()() const { return 1; }
97 };
98 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj, sfinae_friendly::v1>));
99 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj, sfinae_friendly::v2>));
100 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj, sfinae_friendly::v3>));
101 
102 struct fobj_nc
103       : boost::noncopyable
104 {
105     // Handle nullary separately to exercise result_of support
106     template <typename T>
107     struct result;
108 
109     template <class Self, typename T0>
110     struct result< Self(T0) >
111     {
112         typedef int type;
113     };
114 
operator ()fobj_nc115     int operator()(int i)       { return 14 + i; }
operator ()fobj_nc116     int operator()(int i) const { return 15 + i; }
117 };
118 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v0>));
119 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v1>));
120 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v2>));
121 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<fobj_nc, sfinae_friendly::v3>));
122 
123 struct nullary_fobj_nc
124       : boost::noncopyable
125 {
126     typedef int result_type;
127 
operator ()nullary_fobj_nc128     int operator()()       { return 12; }
operator ()nullary_fobj_nc129     int operator()() const { return 13; }
130 };
131 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj_nc, sfinae_friendly::v1>));
132 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj_nc, sfinae_friendly::v2>));
133 SFINAE_FRIENDLY_ASSERT((fusion::result_of::invoke_function_object<nullary_fobj_nc, sfinae_friendly::v3>));
134 
135 
136 typedef int         element1_type;
137 typedef object      element2_type;
138 typedef object_nc & element3_type;
139 
140 int         element1 = 100;
141 object      element2 = object();
142 object_nc   element3;
143 
144 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<0>)145 void test_sequence_n(Sequence & seq, mpl::int_<0>)
146 {
147     // Function Objects
148 
149     nullary_fobj f;
150     BOOST_TEST(f () == fusion::invoke_function_object(f ,        seq ));
151     BOOST_TEST(f () == fusion::invoke_function_object(f , const_(seq)));
152 
153     // Note: The function object is taken by value, so we request the copy
154     // to be const with an explicit template argument. We can also request
155     // the function object to be pased by reference...
156     BOOST_TEST(const_(f)() == fusion::invoke_function_object<nullary_fobj const  >(const_(f),        seq ));
157     BOOST_TEST(const_(f)() == fusion::invoke_function_object<nullary_fobj const &>(const_(f), const_(seq)));
158 
159     nullary_fobj_nc nc_f;
160     // ...and we further ensure there is no copying in this case, using a
161     // noncopyable function object.
162     BOOST_TEST(nc_f () == fusion::invoke_function_object<nullary_fobj_nc &>(nc_f ,        seq ));
163     BOOST_TEST(nc_f () == fusion::invoke_function_object<nullary_fobj_nc &>(nc_f , const_(seq)));
164     BOOST_TEST(const_(nc_f)() == fusion::invoke_function_object<nullary_fobj_nc const &>(const_(nc_f),        seq ));
165     BOOST_TEST(const_(nc_f)() == fusion::invoke_function_object<nullary_fobj_nc const &>(const_(nc_f), const_(seq)));
166 }
167 
168 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<1>)169 void test_sequence_n(Sequence & seq, mpl::int_<1>)
170 {
171     fobj f;
172     BOOST_TEST(f(element1) == fusion::invoke_function_object(f , seq ));
173     BOOST_TEST(f(element1) == fusion::invoke_function_object(f , const_(seq)));
174     BOOST_TEST(const_(f)(element1) == fusion::invoke_function_object<fobj const  >(const_(f), seq ));
175     BOOST_TEST(const_(f)(element1) == fusion::invoke_function_object<fobj const &>(const_(f), const_(seq)));
176 
177     fobj_nc nc_f;
178     BOOST_TEST(nc_f(element1) == fusion::invoke_function_object<fobj_nc &>(nc_f, seq ));
179     BOOST_TEST(nc_f(element1) == fusion::invoke_function_object<fobj_nc &>(nc_f, const_(seq)));
180     BOOST_TEST(const_(nc_f)(element1) == fusion::invoke_function_object<fobj_nc const &>(const_(nc_f), seq ));
181     BOOST_TEST(const_(nc_f)(element1) == fusion::invoke_function_object<fobj_nc const &>(const_(nc_f), const_(seq)));
182 }
183 
184 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<2>)185 void test_sequence_n(Sequence & seq, mpl::int_<2>)
186 {
187     fobj f;
188     BOOST_TEST(f (element1, element2) == fusion::invoke_function_object(f , seq));
189     BOOST_TEST(f (element1, const_(element2)) == fusion::invoke_function_object(f , const_(seq)));
190     BOOST_TEST(const_(f)(element1, element2) == fusion::invoke_function_object<fobj const>(const_(f), seq));
191     BOOST_TEST(const_(f)(element1, const_(element2)) == fusion::invoke_function_object<fobj const>(const_(f), const_(seq)));
192 }
193 
194 template <class Sequence>
test_sequence_n(Sequence & seq,mpl::int_<3>)195 void test_sequence_n(Sequence & seq, mpl::int_<3>)
196 {
197     fobj f;
198 
199     BOOST_TEST(f(element1, element2, element3) == fusion::invoke_function_object(f, seq));
200     BOOST_TEST(const_(f)(element1, element2, element3) == fusion::invoke_function_object<fobj const>(const_(f), seq));
201 }
202 
203 template <class Sequence>
test_sequence(Sequence & seq)204 void test_sequence(Sequence & seq)
205 {
206     test_sequence_n(seq, mpl::int_<boost::fusion::result_of::size<Sequence>::value>());
207 }
208 
result_type_tests()209 void result_type_tests()
210 {
211     using boost::is_same;
212 
213     BOOST_TEST(( is_same< boost::fusion::result_of::invoke_function_object< nullary_fobj, fusion::vector<> >::type, int >::value ));
214     BOOST_TEST(( is_same< boost::fusion::result_of::invoke_function_object< fobj, fusion::vector<element1_type> >::type, int >::value ));
215     BOOST_TEST(( is_same< boost::fusion::result_of::invoke_function_object< fobj, fusion::vector<element1_type,element2_type> >::type, int >::value ));
216 }
217 
218 
main()219 int main()
220 {
221     result_type_tests();
222 
223     typedef fusion::vector<> vector0;
224     typedef fusion::vector<element1_type> vector1;
225     typedef fusion::vector<element1_type, element2_type> vector2;
226     typedef fusion::vector<element1_type, element2_type, element3_type> vector3;
227 
228     vector0 v0;
229     vector1 v1(element1);
230     vector2 v2(element1, element2);
231 
232 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
233     // Note: C++11 will pickup the rvalue overload for the d argument
234     // since we do not have all permutations (expensive!) for all const&
235     // and && arguments. We either have all && or all const& arguments only.
236     // For that matter, use std::ref to disambiguate the call.
237 
238     vector3 v3(element1, element2, std::ref(element3));
239 #else
240     vector3 v3(element1, element2, element3);
241 #endif
242 
243     test_sequence(v0);
244     test_sequence(v1);
245     test_sequence(v2);
246     test_sequence(v3);
247 
248     typedef fusion::list<> list0;
249     typedef fusion::list<element1_type> list1;
250     typedef fusion::list<element1_type, element2_type> list2;
251     typedef fusion::list<element1_type, element2_type, element3_type> list3;
252 
253     list0 l0;
254     list1 l1(element1);
255     list2 l2(element1, element2);
256     list3 l3(element1, element2, element3);
257 
258     test_sequence(l0);
259     test_sequence(l1);
260     test_sequence(l2);
261     test_sequence(l3);
262 
263     return boost::report_errors();
264 }
265 
266