1 // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
2 // Copyright (C) 2015 Andrzej Krzemienski.
4 // Use, modification, and distribution is subject to the Boost Software
5 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // See http://www.boost.org/lib/optional for documentation.
10 // You are welcome to contact the author at:
11 // fernando_cacciola@hotmail.com
14 // 12 May 2008 (added more swap tests)
17 #include "boost/optional/optional.hpp"
18 #include "boost/utility/in_place_factory.hpp"
24 #include "boost/core/lightweight_test.hpp"
26 #if __cplusplus < 201103L
32 using boost::optional
;
35 #define ARG(T) (static_cast< T const* >(0))
37 namespace optional_swap_test
39 class default_ctor_exception
: public std::exception
{} ;
40 class copy_ctor_exception
: public std::exception
{} ;
41 class assignment_exception
: public std::exception
{} ;
44 // Base class for swap test classes. Its assignment should not be called, when swapping
45 // optional<T> objects. (The default std::swap would do so.)
47 class base_class_with_forbidden_assignment
50 base_class_with_forbidden_assignment
& operator=(const base_class_with_forbidden_assignment
&)
52 BOOST_TEST(!"The assignment should not be used while swapping!");
53 throw assignment_exception();
56 virtual ~base_class_with_forbidden_assignment() {}
60 // Class without default constructor
62 class class_without_default_ctor
: public base_class_with_forbidden_assignment
66 explicit class_without_default_ctor(char arg
) : data(arg
) {}
70 // Class whose default constructor should not be used by optional::swap!
72 class class_whose_default_ctor_should_not_be_used
: public base_class_with_forbidden_assignment
76 explicit class_whose_default_ctor_should_not_be_used(char arg
) : data(arg
) {}
78 class_whose_default_ctor_should_not_be_used()
80 BOOST_TEST(!"This default constructor should not be used while swapping!");
81 throw default_ctor_exception();
86 // Class whose default constructor should be used by optional::swap.
87 // Its copy constructor should be avoided!
89 class class_whose_default_ctor_should_be_used
: public base_class_with_forbidden_assignment
93 explicit class_whose_default_ctor_should_be_used(char arg
) : data(arg
) { }
95 class_whose_default_ctor_should_be_used() : data('\0') { }
97 class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used
&)
99 BOOST_TEST(!"This copy constructor should not be used while swapping!");
100 throw copy_ctor_exception();
105 // Class template whose default constructor should be used by optional::swap.
106 // Its copy constructor should be avoided!
109 class template_whose_default_ctor_should_be_used
: public base_class_with_forbidden_assignment
113 explicit template_whose_default_ctor_should_be_used(T arg
) : data(arg
) { }
115 template_whose_default_ctor_should_be_used() : data('\0') { }
117 template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used
&)
119 BOOST_TEST(!"This copy constructor should not be used while swapping!");
120 throw copy_ctor_exception();
125 // Class whose explicit constructor should be used by optional::swap.
126 // Its other constructors should be avoided!
128 class class_whose_explicit_ctor_should_be_used
: public base_class_with_forbidden_assignment
132 explicit class_whose_explicit_ctor_should_be_used(char arg
) : data(arg
) { }
134 class_whose_explicit_ctor_should_be_used()
136 BOOST_TEST(!"This default constructor should not be used while swapping!");
137 throw default_ctor_exception();
140 class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used
&)
142 BOOST_TEST(!"This copy constructor should not be used while swapping!");
143 throw copy_ctor_exception();
147 void swap(class_whose_default_ctor_should_not_be_used
& lhs
, class_whose_default_ctor_should_not_be_used
& rhs
)
149 std::swap(lhs
.data
, rhs
.data
);
152 void swap(class_whose_default_ctor_should_be_used
& lhs
, class_whose_default_ctor_should_be_used
& rhs
)
154 std::swap(lhs
.data
, rhs
.data
);
157 void swap(class_without_default_ctor
& lhs
, class_without_default_ctor
& rhs
)
159 std::swap(lhs
.data
, rhs
.data
);
162 void swap(class_whose_explicit_ctor_should_be_used
& lhs
, class_whose_explicit_ctor_should_be_used
& rhs
)
164 std::swap(lhs
.data
, rhs
.data
);
168 void swap(template_whose_default_ctor_should_be_used
<T
> & lhs
, template_whose_default_ctor_should_be_used
<T
> & rhs
)
170 std::swap(lhs
.data
, rhs
.data
);
174 // optional<T>::swap should be customized when neither the copy constructor
175 // nor the default constructor of T are supposed to be used when swapping, e.g.,
176 // for the following type T = class_whose_explicit_ctor_should_be_used.
178 void swap(boost::optional
<class_whose_explicit_ctor_should_be_used
> & x
, boost::optional
<class_whose_explicit_ctor_should_be_used
> & y
)
183 if ( !hasX
&& !hasY
)
187 x
= boost::in_place('\0');
189 y
= boost::in_place('\0');
191 optional_swap_test::swap(*x
,*y
);
200 } // End of namespace optional_swap_test.
206 // Compile time tweaking on whether or not swap should use the default constructor:
209 template <> struct optional_swap_should_use_default_constructor
<
210 optional_swap_test::class_whose_default_ctor_should_be_used
> : true_type
{} ;
212 template <> struct optional_swap_should_use_default_constructor
<
213 optional_swap_test::class_whose_default_ctor_should_not_be_used
> : false_type
{} ;
215 template <class T
> struct optional_swap_should_use_default_constructor
<
216 optional_swap_test::template_whose_default_ctor_should_be_used
<T
> > : true_type
{} ;
220 // Specialization of boost::swap:
223 void swap(optional
<optional_swap_test::class_whose_explicit_ctor_should_be_used
> & x
, optional
<optional_swap_test::class_whose_explicit_ctor_should_be_used
> & y
)
225 optional_swap_test::swap(x
, y
);
234 // Specializations of std::swap:
238 void swap(optional_swap_test::class_whose_default_ctor_should_be_used
& x
, optional_swap_test::class_whose_default_ctor_should_be_used
& y
)
240 optional_swap_test::swap(x
, y
);
244 void swap(optional_swap_test::class_whose_default_ctor_should_not_be_used
& x
, optional_swap_test::class_whose_default_ctor_should_not_be_used
& y
)
246 optional_swap_test::swap(x
, y
);
250 void swap(optional_swap_test::class_without_default_ctor
& x
, optional_swap_test::class_without_default_ctor
& y
)
252 optional_swap_test::swap(x
, y
);
256 void swap(optional_swap_test::class_whose_explicit_ctor_should_be_used
& x
, optional_swap_test::class_whose_explicit_ctor_should_be_used
& y
)
258 optional_swap_test::swap(x
, y
);
265 // Tests whether the swap function works properly for optional<T>.
266 // Assumes that T has one data member, of type char.
267 // Returns true iff the test is passed.
270 void test_swap_function( T
const* )
275 optional
<T
> obj2('a');
277 // Self-swap should not have any effect.
281 BOOST_TEST(!!obj2
&& obj2
->data
== 'a');
283 // Call non-member swap.
286 // Test if obj1 and obj2 are really swapped.
287 BOOST_TEST(!!obj1
&& obj1
->data
== 'a');
290 // Call non-member swap one more time.
293 // Test if obj1 and obj2 are swapped back.
295 BOOST_TEST(!!obj2
&& obj2
->data
== 'a');
297 catch(const std::exception
&)
299 // The swap function should not throw, for our test cases.
300 BOOST_TEST(!"throw in swap");
305 // Tests whether the optional<T>::swap member function works properly.
306 // Assumes that T has one data member, of type char.
307 // Returns true iff the test is passed.
310 void test_swap_member_function( T
const* )
315 optional
<T
> obj2('a');
317 // Self-swap should not have any effect.
321 BOOST_TEST(!!obj2
&& obj2
->data
== 'a');
326 // Test if obj1 and obj2 are really swapped.
327 BOOST_TEST(!!obj1
&& obj1
->data
== 'a');
330 // Call member swap one more time.
333 // Test if obj1 and obj2 are swapped back.
335 BOOST_TEST(!!obj2
&& obj2
->data
== 'a');
337 catch(const std::exception
&)
339 BOOST_TEST(!"throw in swap");
345 // Tests compile time tweaking of swap, by means of
346 // optional_swap_should_use_default_constructor.
348 void test_swap_tweaking()
350 ( test_swap_function( ARG(optional_swap_test::class_without_default_ctor
) ) );
351 ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used
) ) );
352 ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used
) ) );
353 ( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used
) ) );
354 ( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used
<char>) ) );
355 ( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor
) ) );
356 ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used
) ) );
357 ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used
) ) );
358 ( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used
) ) );
359 ( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used
<char>) ) );
364 test_swap_tweaking();
365 return boost::report_errors();