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