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