• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //-----------------------------------------------------------------------------
2 // boost-libs variant/test/recursive_variant_test.cpp source file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (c) 2003 Eric Friedman, Itay Maman
7 // Copyright (c) 2013-2020 Antony Polukhin
8 //
9 // Distributed under the Boost Software License, Version 1.0. (See
10 // accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12 
13 
14 // This file is used in two test cases:
15 //
16 // 1) recursive_variant_test.cpp that tests recursive usage of variant
17 //
18 // 2) variant_noexcept_test that tests Boost.Variant ability to compile
19 // and work with disabled exceptions
20 
21 
22 #include "boost/core/lightweight_test.hpp"
23 
24 #include "boost/variant.hpp"
25 #include "boost/mpl/vector.hpp"
26 #include "boost/mpl/copy.hpp"
27 
28 #include <iostream>
29 #include <sstream>
30 #include <vector>
31 #include <map>
32 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
33 #include <tuple>
34 #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
35 
36 struct printer
37     : boost::static_visitor<std::string>
38 {
39     template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
operator ()printer40     std::string operator()(
41             const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &var) const
42     {
43         return boost::apply_visitor( printer(), var );
44     }
45 
46     template <typename T>
operator ()printer47     std::string operator()(const std::vector<T>& vec) const
48     {
49         std::ostringstream ost;
50 
51         ost << "( ";
52 
53         typename std::vector<T>::const_iterator it = vec.begin();
54         for (; it != vec.end(); ++it)
55             ost << printer()( *it );
56 
57         ost << ") ";
58 
59         return ost.str();
60     }
61 
62 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
63     template <int...> struct indices {};
64     template <typename... Ts, int... Is>
operator ()printer65     std::string operator()(const std::tuple<Ts...>& tup, indices<Is...>) const
66     {
67         std::ostringstream ost;
68         ost << "( ";
69         int a[] = {0, (ost << printer()( std::get<Is>(tup) ), 0)... };
70         (void)a;
71         ost << ") ";
72         return ost.str();
73     }
74 
75     template <int N, int... Is>
76         struct make_indices : make_indices<N-1, N-1, Is...> {};
77     template <int... Is>
78         struct make_indices<0, Is...> : indices<Is...> {};
79     template <typename... Ts>
operator ()printer80     std::string operator()(const std::tuple<Ts...>& tup) const
81     {
82         return printer()(tup, make_indices<sizeof...(Ts)>());
83     }
84 #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
85 
86     template <typename T>
operator ()printer87     std::string operator()(const T& operand) const
88     {
89         std::ostringstream ost;
90         ost << operand << ' ';
91         return ost.str();
92     }
93 };
94 
test_recursive_variant()95 void test_recursive_variant()
96 {
97     typedef boost::make_recursive_variant<
98           int
99         , std::vector<boost::recursive_variant_>
100         >::type var1_t;
101 
102     std::vector<var1_t> vec1;
103     vec1.push_back(3);
104     vec1.push_back(5);
105     vec1.push_back(vec1);
106     vec1.push_back(7);
107 
108     var1_t var1(vec1);
109     std::string result1( printer()(var1) );
110 
111     std::cout << "result1: " << result1 << '\n';
112     BOOST_TEST(result1 == "( 3 5 ( 3 5 ) 7 ) ");
113 
114     std::vector<var1_t> vec1_copy = vec1;
115     vec1_copy.erase(vec1_copy.begin() + 2);
116     vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy);
117     var1 = vec1_copy;
118     result1 = printer()(var1);
119     std::cout << "result1+: " << result1 << '\n';
120     BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
121 
122     // Uses move construction on compilers with rvalue references support
123     result1 = printer()(
124         var1_t(
125             std::vector<var1_t>(vec1_copy)
126         )
127     );
128     std::cout << "result1++: " << result1 << '\n';
129     BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
130 
131 
132     var1_t vec1_another_copy(vec1_copy);
133     vec1_copy[2].swap(vec1_another_copy);
134     result1 = printer()(
135         var1_t(vec1_copy)
136     );
137     std::cout << "result1+++1: " << result1 << '\n';
138     BOOST_TEST(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) ");
139 
140     result1 = printer()(vec1_another_copy);
141     std::cout << "result1++2: " << result1 << '\n';
142     BOOST_TEST(result1 == "( 3 5 7 ) ");
143 
144     vec1_copy[2].swap(vec1_copy[2]);
145     result1 = printer()(
146         var1_t(vec1_copy)
147     );
148     std::cout << "result1.2: " << result1 << '\n';
149     BOOST_TEST(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) ");
150 
151     typedef boost::make_recursive_variant<
152           boost::variant<int, double>
153         , std::vector<boost::recursive_variant_>
154         >::type var2_t;
155 
156     std::vector<var2_t> vec2;
157     vec2.push_back(boost::variant<int, double>(3));
158     vec2.push_back(boost::variant<int, double>(3.5));
159     vec2.push_back(vec2);
160     vec2.push_back(boost::variant<int, double>(7));
161 
162     var2_t var2(vec2);
163     std::string result2( printer()(var2) );
164 
165     std::cout << "result2: " << result2 << '\n';
166     BOOST_TEST(result2 == "( 3 3.5 ( 3 3.5 ) 7 ) ");
167 
168     typedef boost::make_recursive_variant<
169           int
170         , std::vector<
171               boost::variant<
172                     double
173                   , std::vector<boost::recursive_variant_>
174                   >
175               >
176         >::type var3_t;
177 
178     typedef boost::variant<double, std::vector<var3_t> > var4_t;
179 
180     std::vector<var3_t> vec3;
181     vec3.push_back(3);
182     vec3.push_back(5);
183     std::vector<var4_t> vec4;
184     vec4.push_back(3.5);
185     vec4.push_back(vec3);
186     vec3.push_back(vec4);
187     vec3.push_back(7);
188 
189     var4_t var4(vec3);
190     std::string result3( printer()(var4) );
191 
192     std::cout << "result2: " << result3 << '\n';
193     BOOST_TEST(result3 == "( 3 5 ( 3.5 ( 3 5 ) ) 7 ) ");
194 
195     typedef boost::make_recursive_variant<
196           double,
197           std::vector<var1_t>
198         >::type var5_t;
199 
200     std::vector<var5_t> vec5;
201     vec5.push_back(3.5);
202     vec5.push_back(vec1);
203     vec5.push_back(17.25);
204 
205     std::string result5( printer()(vec5) );
206 
207     std::cout << "result5: " << result5 << '\n';
208     BOOST_TEST(result5 == "( 3.5 ( 3 5 ( 3 5 ) 7 ) 17.25 ) ");
209 
210     typedef boost::make_recursive_variant<
211           int,
212           std::map<int, boost::recursive_variant_>
213         >::type var6_t;
214     var6_t var6;
215 
216 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
217     typedef boost::make_recursive_variant<
218           int,
219           std::tuple<int, boost::recursive_variant_>
220         >::type var7_t;
221     var7_t var7 = 0;    // !!! Do not replace with `var7_t var7{0}` or `var7_t var7(0)` !!!
222     var7 = std::tuple<int, var7_t>(1, var7);
223     var7 = std::tuple<int, var7_t>(2, var7);
224 
225     std::string result7( printer()(var7) );
226 
227     std::cout << "result7: " << result7 << '\n';
228     BOOST_TEST(result7 == "( 2 ( 1 0 ) ) ");
229 #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
230 }
231 
test_recursive_variant_over()232 void test_recursive_variant_over()
233 {
234     typedef boost::make_recursive_variant_over<
235           boost::mpl::vector<
236               int
237             , std::vector<boost::recursive_variant_>
238           >
239         >::type var1_t;
240 
241     std::vector<var1_t> vec1;
242     vec1.push_back(3);
243     vec1.push_back(5);
244     vec1.push_back(vec1);
245     vec1.push_back(7);
246 
247     var1_t var1(vec1);
248     std::string result1( printer()(var1) );
249 
250     std::cout << "result1: " << result1 << '\n';
251     BOOST_TEST(result1 == "( 3 5 ( 3 5 ) 7 ) ");
252 
253     std::vector<var1_t> vec1_copy = vec1;
254     vec1_copy.erase(vec1_copy.begin() + 2);
255     vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy);
256     var1 = vec1_copy;
257     result1 = printer()(var1);
258     std::cout << "result1+: " << result1 << '\n';
259     BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
260 
261     // Uses move construction on compilers with rvalue references support
262     result1 = printer()(
263         var1_t(
264             std::vector<var1_t>(vec1_copy)
265         )
266     );
267     std::cout << "result1++: " << result1 << '\n';
268     BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
269 
270 
271     var1_t vec1_another_copy(vec1_copy);
272     vec1_copy[2].swap(vec1_another_copy);
273     result1 = printer()(
274         var1_t(vec1_copy)
275     );
276     std::cout << "result1+++1: " << result1 << '\n';
277     BOOST_TEST(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) ");
278 
279     result1 = printer()(vec1_another_copy);
280     std::cout << "result1++2: " << result1 << '\n';
281     BOOST_TEST(result1 == "( 3 5 7 ) ");
282 
283     typedef boost::make_recursive_variant_over<
284           boost::mpl::vector<
285               boost::make_variant_over<boost::mpl::vector<int, double> >::type
286             , std::vector<boost::recursive_variant_>
287             >
288         >::type var2_t;
289 
290     std::vector<var2_t> vec2;
291     vec2.push_back(boost::variant<int, double>(3));
292     vec2.push_back(boost::variant<int, double>(3.5));
293     vec2.push_back(vec2);
294     vec2.push_back(boost::variant<int, double>(7));
295 
296     var2_t var2(vec2);
297     std::string result2( printer()(var2) );
298 
299     std::cout << "result2: " << result2 << '\n';
300     BOOST_TEST(result2 == "( 3 3.5 ( 3 3.5 ) 7 ) ");
301 
302     typedef boost::make_recursive_variant_over<
303           boost::mpl::vector<
304               int
305             , std::vector<
306                   boost::make_variant_over<
307                       boost::mpl::vector<
308                           double
309                         , std::vector<boost::recursive_variant_>
310                         >
311                     >::type
312                 >
313             >
314         >::type var3_t;
315 
316     typedef boost::make_variant_over<
317           boost::mpl::copy<
318               boost::mpl::vector<
319                   double
320                 , std::vector<var3_t>
321                 >
322             >::type
323         >::type var4_t;
324 
325     std::vector<var3_t> vec3;
326     vec3.push_back(3);
327     vec3.push_back(5);
328     std::vector<var4_t> vec4;
329     vec4.push_back(3.5);
330     vec4.push_back(vec3);
331     vec3.push_back(vec4);
332     vec3.push_back(7);
333 
334     var4_t var3(vec3);
335     std::string result3( printer()(var3) );
336 
337     std::cout << "result2: " << result3 << '\n';
338     BOOST_TEST(result3 == "( 3 5 ( 3.5 ( 3 5 ) ) 7 ) ");
339 
340     typedef boost::make_recursive_variant_over<
341           boost::mpl::vector<
342               double
343             , std::vector<var1_t>
344             >
345         >::type var5_t;
346 
347     std::vector<var5_t> vec5;
348     vec5.push_back(3.5);
349     vec5.push_back(vec1);
350     vec5.push_back(17.25);
351 
352     std::string result5( printer()(vec5) );
353 
354     std::cout << "result5: " << result5 << '\n';
355     BOOST_TEST(result5 == "( 3.5 ( 3 5 ( 3 5 ) 7 ) 17.25 ) ");
356 }
357 
main()358 int main()
359 {
360     test_recursive_variant();
361     test_recursive_variant_over();
362 
363     return boost::report_errors();
364 }
365