optional_test_swap.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
  2. // Copyright (C) 2015 Andrzej Krzemienski.
  3. //
  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)
  7. //
  8. // See http://www.boost.org/lib/optional for documentation.
  9. //
  10. // You are welcome to contact the author at:
  11. // fernando_cacciola@hotmail.com
  12. //
  13. // Revisions:
  14. // 12 May 2008 (added more swap tests)
  15. //
  16. #include "boost/optional/optional.hpp"
  17. #include "boost/utility/in_place_factory.hpp"
  18. #ifdef __BORLANDC__
  19. #pragma hdrstop
  20. #endif
  21. #include "boost/core/lightweight_test.hpp"
  22. #if __cplusplus < 201103L
  23. #include <algorithm>
  24. #else
  25. #include <utility>
  26. #endif
  27. using boost::optional;
  28. using boost::none;
  29. #define ARG(T) (static_cast< T const* >(0))
  30. namespace optional_swap_test
  31. {
  32. class default_ctor_exception : public std::exception {} ;
  33. class copy_ctor_exception : public std::exception {} ;
  34. class assignment_exception : public std::exception {} ;
  35. //
  36. // Base class for swap test classes. Its assignment should not be called, when swapping
  37. // optional<T> objects. (The default std::swap would do so.)
  38. //
  39. class base_class_with_forbidden_assignment
  40. {
  41. public:
  42. base_class_with_forbidden_assignment & operator=(const base_class_with_forbidden_assignment &)
  43. {
  44. BOOST_TEST(!"The assignment should not be used while swapping!");
  45. throw assignment_exception();
  46. }
  47. virtual ~base_class_with_forbidden_assignment() {}
  48. };
  49. //
  50. // Class without default constructor
  51. //
  52. class class_without_default_ctor : public base_class_with_forbidden_assignment
  53. {
  54. public:
  55. char data;
  56. explicit class_without_default_ctor(char arg) : data(arg) {}
  57. };
  58. //
  59. // Class whose default constructor should not be used by optional::swap!
  60. //
  61. class class_whose_default_ctor_should_not_be_used : public base_class_with_forbidden_assignment
  62. {
  63. public:
  64. char data;
  65. explicit class_whose_default_ctor_should_not_be_used(char arg) : data(arg) {}
  66. class_whose_default_ctor_should_not_be_used()
  67. {
  68. BOOST_TEST(!"This default constructor should not be used while swapping!");
  69. throw default_ctor_exception();
  70. }
  71. };
  72. //
  73. // Class whose default constructor should be used by optional::swap.
  74. // Its copy constructor should be avoided!
  75. //
  76. class class_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment
  77. {
  78. public:
  79. char data;
  80. explicit class_whose_default_ctor_should_be_used(char arg) : data(arg) { }
  81. class_whose_default_ctor_should_be_used() : data('\0') { }
  82. class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used &)
  83. {
  84. BOOST_TEST(!"This copy constructor should not be used while swapping!");
  85. throw copy_ctor_exception();
  86. }
  87. };
  88. //
  89. // Class template whose default constructor should be used by optional::swap.
  90. // Its copy constructor should be avoided!
  91. //
  92. template <class T>
  93. class template_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment
  94. {
  95. public:
  96. T data;
  97. explicit template_whose_default_ctor_should_be_used(T arg) : data(arg) { }
  98. template_whose_default_ctor_should_be_used() : data('\0') { }
  99. template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used &)
  100. {
  101. BOOST_TEST(!"This copy constructor should not be used while swapping!");
  102. throw copy_ctor_exception();
  103. }
  104. };
  105. //
  106. // Class whose explicit constructor should be used by optional::swap.
  107. // Its other constructors should be avoided!
  108. //
  109. class class_whose_explicit_ctor_should_be_used : public base_class_with_forbidden_assignment
  110. {
  111. public:
  112. char data;
  113. explicit class_whose_explicit_ctor_should_be_used(char arg) : data(arg) { }
  114. class_whose_explicit_ctor_should_be_used()
  115. {
  116. BOOST_TEST(!"This default constructor should not be used while swapping!");
  117. throw default_ctor_exception();
  118. }
  119. class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used &)
  120. {
  121. BOOST_TEST(!"This copy constructor should not be used while swapping!");
  122. throw copy_ctor_exception();
  123. }
  124. };
  125. void swap(class_whose_default_ctor_should_not_be_used & lhs, class_whose_default_ctor_should_not_be_used & rhs)
  126. {
  127. std::swap(lhs.data, rhs.data);
  128. }
  129. void swap(class_whose_default_ctor_should_be_used & lhs, class_whose_default_ctor_should_be_used & rhs)
  130. {
  131. std::swap(lhs.data, rhs.data);
  132. }
  133. void swap(class_without_default_ctor & lhs, class_without_default_ctor & rhs)
  134. {
  135. std::swap(lhs.data, rhs.data);
  136. }
  137. void swap(class_whose_explicit_ctor_should_be_used & lhs, class_whose_explicit_ctor_should_be_used & rhs)
  138. {
  139. std::swap(lhs.data, rhs.data);
  140. }
  141. template <class T>
  142. void swap(template_whose_default_ctor_should_be_used<T> & lhs, template_whose_default_ctor_should_be_used<T> & rhs)
  143. {
  144. std::swap(lhs.data, rhs.data);
  145. }
  146. //
  147. // optional<T>::swap should be customized when neither the copy constructor
  148. // nor the default constructor of T are supposed to be used when swapping, e.g.,
  149. // for the following type T = class_whose_explicit_ctor_should_be_used.
  150. //
  151. void swap(boost::optional<class_whose_explicit_ctor_should_be_used> & x, boost::optional<class_whose_explicit_ctor_should_be_used> & y)
  152. {
  153. bool hasX(x);
  154. bool hasY(y);
  155. if ( !hasX && !hasY )
  156. return;
  157. if( !hasX )
  158. x = boost::in_place('\0');
  159. else if ( !hasY )
  160. y = boost::in_place('\0');
  161. optional_swap_test::swap(*x,*y);
  162. if( !hasX )
  163. y = boost::none ;
  164. else if( !hasY )
  165. x = boost::none ;
  166. }
  167. } // End of namespace optional_swap_test.
  168. namespace boost {
  169. //
  170. // Compile time tweaking on whether or not swap should use the default constructor:
  171. //
  172. template <> struct optional_swap_should_use_default_constructor<
  173. optional_swap_test::class_whose_default_ctor_should_be_used> : true_type {} ;
  174. template <> struct optional_swap_should_use_default_constructor<
  175. optional_swap_test::class_whose_default_ctor_should_not_be_used> : false_type {} ;
  176. template <class T> struct optional_swap_should_use_default_constructor<
  177. optional_swap_test::template_whose_default_ctor_should_be_used<T> > : true_type {} ;
  178. //
  179. // Specialization of boost::swap:
  180. //
  181. template <>
  182. 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)
  183. {
  184. optional_swap_test::swap(x, y);
  185. }
  186. } // namespace boost
  187. namespace std {
  188. //
  189. // Specializations of std::swap:
  190. //
  191. template <>
  192. void swap(optional_swap_test::class_whose_default_ctor_should_be_used & x, optional_swap_test::class_whose_default_ctor_should_be_used & y)
  193. {
  194. optional_swap_test::swap(x, y);
  195. }
  196. template <>
  197. 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)
  198. {
  199. optional_swap_test::swap(x, y);
  200. }
  201. template <>
  202. void swap(optional_swap_test::class_without_default_ctor & x, optional_swap_test::class_without_default_ctor & y)
  203. {
  204. optional_swap_test::swap(x, y);
  205. }
  206. template <>
  207. void swap(optional_swap_test::class_whose_explicit_ctor_should_be_used & x, optional_swap_test::class_whose_explicit_ctor_should_be_used & y)
  208. {
  209. optional_swap_test::swap(x, y);
  210. }
  211. } // namespace std
  212. //
  213. // Tests whether the swap function works properly for optional<T>.
  214. // Assumes that T has one data member, of type char.
  215. // Returns true iff the test is passed.
  216. //
  217. template <class T>
  218. void test_swap_function( T const* )
  219. {
  220. try
  221. {
  222. optional<T> obj1;
  223. optional<T> obj2('a');
  224. // Self-swap should not have any effect.
  225. swap(obj1, obj1);
  226. swap(obj2, obj2);
  227. BOOST_TEST(!obj1);
  228. BOOST_TEST(!!obj2 && obj2->data == 'a');
  229. // Call non-member swap.
  230. swap(obj1, obj2);
  231. // Test if obj1 and obj2 are really swapped.
  232. BOOST_TEST(!!obj1 && obj1->data == 'a');
  233. BOOST_TEST(!obj2);
  234. // Call non-member swap one more time.
  235. swap(obj1, obj2);
  236. // Test if obj1 and obj2 are swapped back.
  237. BOOST_TEST(!obj1);
  238. BOOST_TEST(!!obj2 && obj2->data == 'a');
  239. }
  240. catch(const std::exception &)
  241. {
  242. // The swap function should not throw, for our test cases.
  243. BOOST_TEST(!"throw in swap");
  244. }
  245. }
  246. //
  247. // Tests whether the optional<T>::swap member function works properly.
  248. // Assumes that T has one data member, of type char.
  249. // Returns true iff the test is passed.
  250. //
  251. template <class T>
  252. void test_swap_member_function( T const* )
  253. {
  254. try
  255. {
  256. optional<T> obj1;
  257. optional<T> obj2('a');
  258. // Self-swap should not have any effect.
  259. obj1.swap(obj1);
  260. obj2.swap(obj2);
  261. BOOST_TEST(!obj1);
  262. BOOST_TEST(!!obj2 && obj2->data == 'a');
  263. // Call member swap.
  264. obj1.swap(obj2);
  265. // Test if obj1 and obj2 are really swapped.
  266. BOOST_TEST(!!obj1 && obj1->data == 'a');
  267. BOOST_TEST(!obj2);
  268. // Call member swap one more time.
  269. obj1.swap(obj2);
  270. // Test if obj1 and obj2 are swapped back.
  271. BOOST_TEST(!obj1);
  272. BOOST_TEST(!!obj2 && obj2->data == 'a');
  273. }
  274. catch(const std::exception &)
  275. {
  276. BOOST_TEST(!"throw in swap");
  277. }
  278. }
  279. //
  280. // Tests compile time tweaking of swap, by means of
  281. // optional_swap_should_use_default_constructor.
  282. //
  283. void test_swap_tweaking()
  284. {
  285. ( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) );
  286. ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) );
  287. ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) );
  288. ( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
  289. ( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) );
  290. ( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) );
  291. ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) );
  292. ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) );
  293. ( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) );
  294. ( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used<char>) ) );
  295. }
  296. int main()
  297. {
  298. test_swap_tweaking();
  299. return boost::report_errors();
  300. }