1 // Copyright (C) 2018 Andrzej Krzemienski.
2 //
3 // Use, modification, and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/lib/optional for documentation.
8 //
9 // You are welcome to contact the author at:
10 //  akrzemi1@gmail.com
11 
12 #include "boost/optional/optional.hpp"
13 
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17 
18 #include "boost/core/ignore_unused.hpp"
19 #include "boost/core/is_same.hpp"
20 #include "boost/core/lightweight_test.hpp"
21 #include "boost/core/lightweight_test_trait.hpp"
22 
23 
24 using boost::optional;
25 using boost::make_optional;
26 using boost::core::is_same;
27 
28 template <typename Expected, typename Deduced>
verify_type(Deduced)29 void verify_type(Deduced)
30 {
31   BOOST_TEST_TRAIT_TRUE(( is_same<Expected, Deduced> ));
32 }
33 
34 struct Int
35 {
36   int i;
IntInt37   explicit Int(int i_) : i(i_) {}
38 };
39 
40 struct convert_t
41 {
42   typedef optional<Int> result_type;
operator ()convert_t43   optional<Int> operator()(int i) { if (i != 0) return Int(i); else return boost::none; }
44 };
45 
test_flat_map_on_mutable_optional_with_function_object()46 void test_flat_map_on_mutable_optional_with_function_object()
47 {
48   {
49     optional<int> oi (1);
50     verify_type< optional<Int> >(oi.flat_map(convert_t()));
51     optional<Int> oI = oi.flat_map(convert_t());
52     BOOST_TEST(bool(oI));
53     BOOST_TEST_EQ(1, oI->i);
54   }
55   {
56     optional<int> oi (0);
57     optional<Int> oI = oi.flat_map(convert_t());
58     BOOST_TEST(!oI);
59   }
60   {
61     optional<int> oi;
62     optional<Int> oI = oi.flat_map(convert_t());
63     BOOST_TEST(!oI);
64   }
65 }
66 
test_flat_map_on_const_optional_with_function_object()67 void test_flat_map_on_const_optional_with_function_object()
68 {
69   {
70     const optional<int> oi (1);
71     verify_type< optional<Int> >(oi.flat_map(convert_t()));
72     optional<Int> oI = oi.flat_map(convert_t());
73     BOOST_TEST(bool(oI));
74     BOOST_TEST_EQ(1, oI->i);
75   }
76   {
77     const optional<int> oi (0);
78     optional<Int> oI = oi.flat_map(convert_t());
79     BOOST_TEST(!oI);
80   }
81   {
82     const optional<int> oi;
83     optional<Int> oI = oi.flat_map(convert_t());
84     BOOST_TEST(!oI);
85   }
86 }
87 
test_flat_map_with_lambda()88 void test_flat_map_with_lambda()
89 {
90 #if !defined BOOST_NO_CXX11_LAMBDAS && !defined BOOST_NO_CXX11_DECLTYPE_N3276
91   {
92     optional<int> oi (1);
93     verify_type< optional<Int> >(oi.flat_map([](int i){ return optional<Int>(i == 0, Int(i)); }));
94     optional<Int> oI = oi.flat_map([](int i){ return optional<Int>(i != 0, Int(i)); });
95     BOOST_TEST(bool(oI));
96     BOOST_TEST_EQ(1, oI->i);
97   }
98   {
99     optional<int> oi (0);
100     optional<Int> oI = oi.flat_map([](int i){ return optional<Int>(i != 0, Int(i)); });
101     BOOST_TEST(!oI);
102   }
103   {
104     optional<int> oi;
105     optional<Int> oI = oi.flat_map([](int i){ return optional<Int>(i != 0, Int(i)); });
106     BOOST_TEST(!oI);
107   }
108 #endif // lambdas
109 }
110 
111 struct get_opt_ref
112 {
113   typedef optional<int&> result_type;
operator ()get_opt_ref114   optional<int&> operator()(int& i) { return i != 0 ? optional<int&>(i) : optional<int&>(); }
115 };
116 
test_flat_map_obj_to_ref()117 void test_flat_map_obj_to_ref()
118 {
119   {
120     optional<int> oi (2);
121     verify_type< optional<int&> >(oi.flat_map(get_opt_ref()));
122     optional<int&> ori = oi.flat_map(get_opt_ref());
123     BOOST_TEST(bool(ori));
124     BOOST_TEST_EQ(2, *ori);
125     *ori = 3;
126     BOOST_TEST(bool(oi));
127     BOOST_TEST_EQ(3, *oi);
128     BOOST_TEST_EQ(3, *ori);
129   }
130   {
131     optional<int> oi (0);
132     optional<int&> ori = oi.flat_map(get_opt_ref());
133     BOOST_TEST(!ori);
134   }
135   {
136     optional<int> oi;
137     optional<int&> ori = oi.flat_map(get_opt_ref());
138     BOOST_TEST(!ori);
139   }
140 }
141 
get_opt_int_ref(Int & i)142 optional<int&> get_opt_int_ref(Int& i)
143 {
144   return i.i ? optional<int&>(i.i) : optional<int&>();
145 }
146 
test_flat_map_ref_to_ref()147 void test_flat_map_ref_to_ref()
148 {
149   {
150     Int I (5);
151     optional<Int&> orI (I);
152     verify_type< optional<int&> >(orI.flat_map(get_opt_int_ref));
153     optional<int&> ori = orI.flat_map(get_opt_int_ref);
154     BOOST_TEST(bool(ori));
155     BOOST_TEST_EQ(5, *ori);
156     *ori = 6;
157     BOOST_TEST_EQ(6, *ori);
158     BOOST_TEST_EQ(6, I.i);
159   }
160   {
161     Int I (0);
162     optional<Int&> orI (I);
163     optional<int&> ori = orI.flat_map(get_opt_int_ref);
164     BOOST_TEST(!ori);
165   }
166   {
167     optional<Int&> orI;
168     optional<int&> ori = orI.flat_map(get_opt_int_ref);
169     BOOST_TEST(!ori);
170   }
171 }
172 
make_opt_int(int i)173 optional< optional<Int> > make_opt_int(int i)
174 {
175   if (i == 0)
176     return boost::none;
177   else if (i == 1)
178     return boost::make_optional(optional<Int>());
179   else
180     return boost::make_optional(boost::make_optional(Int(i)));
181 }
182 
test_flat_map_opt_opt()183 void test_flat_map_opt_opt()
184 {
185   {
186     optional<int> oi (9);
187     verify_type<optional<optional<Int> > >(oi.flat_map(make_opt_int));
188     optional<optional<Int> > ooI = oi.flat_map(make_opt_int);
189     BOOST_TEST(bool(ooI));
190     BOOST_TEST(bool(*ooI));
191     BOOST_TEST_EQ(9, (**ooI).i);
192   }
193   {
194     optional<int> oi (1);
195     optional<optional<Int> > ooI = oi.flat_map(make_opt_int);
196     BOOST_TEST(bool(ooI));
197     BOOST_TEST(!*ooI);
198   }
199   {
200     optional<int> oi (0);
201     optional<optional<Int> > ooI = oi.flat_map(make_opt_int);
202     BOOST_TEST(!ooI);
203   }
204   {
205     optional<int> oi;
206     optional<optional<Int> > ooI = oi.flat_map(make_opt_int);
207     BOOST_TEST(!ooI);
208   }
209 }
210 
211 #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
212 struct MoveOnly
213 {
214   int value;
MoveOnlyMoveOnly215   explicit MoveOnly(int i) : value(i) {}
MoveOnlyMoveOnly216   MoveOnly(MoveOnly && r) : value(r.value) { r.value = 0; }
operator =MoveOnly217   MoveOnly& operator=(MoveOnly && r) { value = r.value; r.value = 0; return *this; }
218 
219 private:
220   MoveOnly(MoveOnly const&);
221   void operator=(MoveOnly const&);
222 };
223 
makeMoveOnly(int i)224 MoveOnly makeMoveOnly(int i)
225 {
226   return MoveOnly(i);
227 }
228 
makeOptMoveOnly(int i)229 optional<MoveOnly> makeOptMoveOnly(int i)
230 {
231   return optional<MoveOnly>(MoveOnly(i));
232 }
233 
get_val(MoveOnly m)234 optional<int> get_val(MoveOnly m)
235 {
236   return optional<int>(m.value != 0, m.value);
237 }
238 
test_flat_map_move_only()239 void test_flat_map_move_only()
240 {
241   {
242     optional<MoveOnly> om (makeMoveOnly(1)), om2 (makeMoveOnly(2));
243     verify_type<optional<int> >(boost::move(om).flat_map(get_val));
244     optional<int> oi = boost::move(om2).flat_map(get_val);
245     BOOST_TEST(bool(oi));
246     BOOST_TEST_EQ(2, *oi);
247   }
248   {
249     optional<int> oj = makeOptMoveOnly(4).flat_map(get_val);
250     BOOST_TEST(bool(oj));
251     BOOST_TEST_EQ(4, *oj);
252   }
253   {
254     optional<int> oj = optional<MoveOnly>().flat_map(get_val);
255     BOOST_TEST(!oj);
256   }
257 }
258 
259 #endif // no rvalue refs
260 
main()261 int main()
262 {
263   test_flat_map_on_mutable_optional_with_function_object();
264   test_flat_map_on_const_optional_with_function_object();
265   test_flat_map_with_lambda();
266   test_flat_map_obj_to_ref();
267   test_flat_map_ref_to_ref();
268   test_flat_map_opt_opt();
269 
270 #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
271   test_flat_map_move_only();
272 #endif
273 
274   return boost::report_errors();
275 }
276