rvalue_test.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //-----------------------------------------------------------------------------
  2. // boost-libs variant/test/rvalue_test.cpp source file
  3. // See http://www.boost.org for updates, documentation, and revision history.
  4. //-----------------------------------------------------------------------------
  5. //
  6. // Copyright (c) 2012-2019 Antony Polukhin
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See
  9. // accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #include "boost/config.hpp"
  12. #include "boost/core/lightweight_test.hpp"
  13. #include "boost/variant.hpp"
  14. #include "boost/type_traits/is_nothrow_move_assignable.hpp"
  15. #include "boost/mpl/bool.hpp"
  16. #include <boost/blank.hpp>
  17. #include <boost/swap.hpp>
  18. namespace swap_ambiguouty_test_ns {
  19. struct A {};
  20. struct B {};
  21. void swap_ambiguouty_test() {
  22. // If boost::blank is not used, then it compiles.
  23. typedef boost::variant<boost::blank, A, B> Variant;
  24. Variant v1, v2;
  25. swap(v1, v2);
  26. }
  27. } // namespace swap_ambiguouty_test_ns
  28. // Most part of tests from this file require rvalue references support
  29. class move_copy_conting_class {
  30. public:
  31. static unsigned int moves_count;
  32. static unsigned int copy_count;
  33. move_copy_conting_class(){}
  34. move_copy_conting_class(BOOST_RV_REF(move_copy_conting_class) ) {
  35. ++ moves_count;
  36. }
  37. move_copy_conting_class& operator=(BOOST_RV_REF(move_copy_conting_class) ) {
  38. ++ moves_count;
  39. return *this;
  40. }
  41. move_copy_conting_class(const move_copy_conting_class&) {
  42. ++ copy_count;
  43. }
  44. move_copy_conting_class& operator=(BOOST_COPY_ASSIGN_REF(move_copy_conting_class) ) {
  45. ++ copy_count;
  46. return *this;
  47. }
  48. };
  49. unsigned int move_copy_conting_class::moves_count = 0;
  50. unsigned int move_copy_conting_class::copy_count = 0;
  51. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  52. void run()
  53. {
  54. // Making sure that internals of Boost.Move do not interfere with
  55. // internals of Boost.Variant and in case of C++03 or C++98 compilation
  56. // is still possible.
  57. typedef boost::variant<int, move_copy_conting_class> variant_I_type;
  58. variant_I_type v1, v2;
  59. v1 = move_copy_conting_class();
  60. v2 = v1;
  61. v2 = boost::move(v1);
  62. v1.swap(v2);
  63. move_copy_conting_class val;
  64. v2 = boost::move(val);
  65. v2 = 10;
  66. variant_I_type v3(boost::move(val));
  67. variant_I_type v4(boost::move(v1));
  68. }
  69. void run1()
  70. {
  71. BOOST_TEST(true);
  72. }
  73. void run_move_only()
  74. {
  75. BOOST_TEST(true);
  76. }
  77. void run_moves_are_noexcept()
  78. {
  79. BOOST_TEST(true);
  80. }
  81. void run_const_rvalues()
  82. {
  83. BOOST_TEST(true);
  84. }
  85. #else
  86. void run()
  87. {
  88. typedef boost::variant<int, move_copy_conting_class> variant_I_type;
  89. variant_I_type v1, v2;
  90. // Assuring that `move_copy_conting_class` was not created
  91. BOOST_TEST(move_copy_conting_class::copy_count == 0);
  92. BOOST_TEST(move_copy_conting_class::moves_count == 0);
  93. v1 = move_copy_conting_class();
  94. // Assuring that `move_copy_conting_class` was moved at least once
  95. BOOST_TEST(move_copy_conting_class::moves_count != 0);
  96. unsigned int total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count;
  97. move_copy_conting_class var;
  98. v1 = 0;
  99. move_copy_conting_class::moves_count = 0;
  100. move_copy_conting_class::copy_count = 0;
  101. v1 = var;
  102. // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator
  103. BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count);
  104. move_copy_conting_class::moves_count = 0;
  105. move_copy_conting_class::copy_count = 0;
  106. v2 = boost::move(v1);
  107. // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
  108. BOOST_TEST(move_copy_conting_class::moves_count != 0);
  109. BOOST_TEST(move_copy_conting_class::copy_count == 0);
  110. v1 = move_copy_conting_class();
  111. move_copy_conting_class::moves_count = 0;
  112. move_copy_conting_class::copy_count = 0;
  113. v2 = boost::move(v1);
  114. // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
  115. BOOST_TEST(move_copy_conting_class::moves_count != 0);
  116. BOOST_TEST(move_copy_conting_class::copy_count == 0);
  117. total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count;
  118. move_copy_conting_class::moves_count = 0;
  119. move_copy_conting_class::copy_count = 0;
  120. v1 = v2;
  121. // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator
  122. BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count);
  123. typedef boost::variant<move_copy_conting_class, int> variant_II_type;
  124. variant_II_type v3;
  125. move_copy_conting_class::moves_count = 0;
  126. move_copy_conting_class::copy_count = 0;
  127. v1 = boost::move(v3);
  128. // Assuring that `move_copy_conting_class` in v3 was moved at least once (v1 and v3 have different types)
  129. BOOST_TEST(move_copy_conting_class::moves_count != 0);
  130. move_copy_conting_class::moves_count = 0;
  131. move_copy_conting_class::copy_count = 0;
  132. v2 = boost::move(v1);
  133. // Assuring that `move_copy_conting_class` in v1 was moved at least once (v1 and v3 have different types)
  134. BOOST_TEST(move_copy_conting_class::moves_count != 0);
  135. move_copy_conting_class::moves_count = 0;
  136. move_copy_conting_class::copy_count = 0;
  137. variant_I_type v5(boost::move(v1));
  138. // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
  139. BOOST_TEST(move_copy_conting_class::moves_count != 0);
  140. BOOST_TEST(move_copy_conting_class::copy_count == 0);
  141. total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count;
  142. move_copy_conting_class::moves_count = 0;
  143. move_copy_conting_class::copy_count = 0;
  144. variant_I_type v6(v1);
  145. // Assuring that move constructor moves/copyes value not more times than copy constructor
  146. BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count);
  147. }
  148. void run1()
  149. {
  150. move_copy_conting_class::moves_count = 0;
  151. move_copy_conting_class::copy_count = 0;
  152. move_copy_conting_class c1;
  153. typedef boost::variant<int, move_copy_conting_class> variant_I_type;
  154. variant_I_type v1(boost::move(c1));
  155. // Assuring that `move_copy_conting_class` was not copyied
  156. BOOST_TEST(move_copy_conting_class::copy_count == 0);
  157. BOOST_TEST(move_copy_conting_class::moves_count > 0);
  158. }
  159. struct move_only_structure {
  160. move_only_structure(){}
  161. move_only_structure(move_only_structure&&){}
  162. move_only_structure& operator=(move_only_structure&&) { return *this; }
  163. private:
  164. move_only_structure(const move_only_structure&);
  165. move_only_structure& operator=(const move_only_structure&);
  166. };
  167. struct visitor_returning_move_only_type: boost::static_visitor<move_only_structure> {
  168. template <class T>
  169. move_only_structure operator()(const T&) const {
  170. return move_only_structure();
  171. }
  172. };
  173. void run_move_only()
  174. {
  175. move_only_structure mo;
  176. boost::variant<int, move_only_structure > vi, vi2(static_cast<move_only_structure&&>(mo));
  177. BOOST_TEST(vi.which() == 0);
  178. BOOST_TEST(vi2.which() == 1);
  179. vi = 10;
  180. vi2 = 10;
  181. BOOST_TEST(vi.which() == 0);
  182. BOOST_TEST(vi2.which() == 0);
  183. vi = static_cast<move_only_structure&&>(mo);
  184. vi2 = static_cast<move_only_structure&&>(mo);
  185. BOOST_TEST(vi.which() == 1);
  186. boost::variant<move_only_structure, int > rvi (1);
  187. BOOST_TEST(rvi.which() == 1);
  188. rvi = static_cast<move_only_structure&&>(mo);
  189. BOOST_TEST(rvi.which() == 0);
  190. rvi = 1;
  191. BOOST_TEST(rvi.which() == 1);
  192. rvi = static_cast<boost::variant<int, move_only_structure >&&>(vi2);
  193. BOOST_TEST(rvi.which() == 0);
  194. move_only_structure from_visitor = boost::apply_visitor(visitor_returning_move_only_type(), vi);
  195. (void)from_visitor;
  196. }
  197. void run_moves_are_noexcept() {
  198. #if !defined(BOOST_NO_CXX11_NOEXCEPT) && (!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || __GNUC_MINOR__ >= 8)
  199. typedef boost::variant<int, short, double> variant_noexcept_t;
  200. BOOST_TEST(boost::is_nothrow_move_assignable<variant_noexcept_t>::value);
  201. BOOST_TEST(boost::is_nothrow_move_constructible<variant_noexcept_t>::value);
  202. typedef boost::variant<int, short, double, move_only_structure> variant_except_t;
  203. BOOST_TEST(!boost::is_nothrow_move_assignable<variant_except_t>::value);
  204. BOOST_TEST(!boost::is_nothrow_move_constructible<variant_except_t>::value);
  205. #endif
  206. }
  207. inline const std::string get_string() { return "test"; }
  208. inline const boost::variant<int, std::string> get_variant() { return std::string("test"); }
  209. inline const boost::variant<std::string, int> get_variant2() { return std::string("test"); }
  210. void run_const_rvalues()
  211. {
  212. typedef boost::variant<int, std::string> variant_t;
  213. const variant_t v1(get_string());
  214. const variant_t v2(get_variant());
  215. const variant_t v3(get_variant2());
  216. variant_t v4, v5, v6, v7;
  217. v4 = get_string();
  218. v5 = get_variant();
  219. v6 = get_variant2();
  220. v7 = boost::move(v1);
  221. }
  222. #endif
  223. struct nothrow_copyable_throw_movable {
  224. nothrow_copyable_throw_movable(){}
  225. nothrow_copyable_throw_movable(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT {}
  226. nothrow_copyable_throw_movable& operator=(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT { return *this; }
  227. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  228. nothrow_copyable_throw_movable(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) {}
  229. nothrow_copyable_throw_movable& operator=(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) { return *this; }
  230. #endif
  231. };
  232. // This test is created to cover the following situation:
  233. // https://svn.boost.org/trac/boost/ticket/8772
  234. void run_tricky_compilation_test()
  235. {
  236. boost::variant<int, nothrow_copyable_throw_movable> v;
  237. v = nothrow_copyable_throw_movable();
  238. }
  239. template <typename T>
  240. struct is_container : boost::mpl::false_ {};
  241. template <typename T>
  242. struct is_container<boost::variant<T> > : is_container<T> {};
  243. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  244. struct is_container<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  245. : boost::mpl::bool_<is_container<T0>::value
  246. || is_container<boost::variant<BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T)> >::value>
  247. {};
  248. void run_is_container_compilation_test()
  249. {
  250. BOOST_TEST((!is_container<boost::variant<double, int> >::value));
  251. BOOST_TEST((!is_container<boost::variant<double, int, char> >::value));
  252. BOOST_TEST((!is_container<boost::variant<double, int, char, float> >::value));
  253. }
  254. int main()
  255. {
  256. swap_ambiguouty_test_ns::swap_ambiguouty_test();
  257. run();
  258. run1();
  259. run_move_only();
  260. run_moves_are_noexcept();
  261. run_tricky_compilation_test();
  262. run_const_rvalues();
  263. run_is_container_compilation_test();
  264. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6)
  265. # ifdef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
  266. BOOST_TEST(false &&
  267. "Something wrong with macro definitions. GCC-4.7+ is known to work with variadic templates"
  268. );
  269. # endif
  270. #endif
  271. return boost::report_errors();
  272. }