test_construction.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /* Copyright 2016-2019 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/poly_collection for library home page.
  7. */
  8. #include "test_construction.hpp"
  9. #include <algorithm>
  10. #include <boost/config.hpp>
  11. #include <boost/core/lightweight_test.hpp>
  12. #include <boost/detail/workaround.hpp>
  13. #include <boost/type_erasure/relaxed.hpp>
  14. #include <scoped_allocator>
  15. #include <utility>
  16. #include <vector>
  17. #include "any_types.hpp"
  18. #include "base_types.hpp"
  19. #include "function_types.hpp"
  20. #include "test_utilities.hpp"
  21. using namespace test_utilities;
  22. template<
  23. bool Propagate,bool AlwaysEqual,
  24. typename PolyCollection,typename ValueFactory,typename... Types
  25. >
  26. void test_allocator_aware_construction()
  27. {
  28. using rooted_poly_collection=realloc_poly_collection<
  29. PolyCollection,rooted_allocator,
  30. std::integral_constant<bool,Propagate>,
  31. std::integral_constant<bool,AlwaysEqual>>;
  32. using allocator_type=typename rooted_poly_collection::allocator_type;
  33. allocator_type root1{0},root2{0};
  34. rooted_poly_collection p{root1};
  35. const rooted_poly_collection& cp=p;
  36. ValueFactory v;
  37. fill<
  38. constraints<is_equality_comparable,is_copy_constructible>,
  39. Types...
  40. >(p,v,2);
  41. {
  42. rooted_poly_collection p2{cp};
  43. BOOST_TEST(p2==p);
  44. BOOST_TEST(p2.get_allocator().comes_from(root1));
  45. }
  46. {
  47. rooted_poly_collection p2{cp};
  48. auto d2=get_layout_data<Types...>(p2);
  49. rooted_poly_collection p3{std::move(p2)};
  50. auto d3=get_layout_data<Types...>(p3);
  51. BOOST_TEST(p3==p);
  52. BOOST_TEST(d2==d3);
  53. BOOST_TEST(p2.empty());
  54. do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
  55. BOOST_TEST(p2.get_allocator().comes_from(root1));
  56. }
  57. {
  58. rooted_poly_collection p2{cp,root2};
  59. BOOST_TEST(p2==p);
  60. BOOST_TEST(p2.get_allocator().comes_from(root2));
  61. }
  62. #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
  63. /* std::unordered_map allocator move ctor does not work when source and
  64. * and target allocators are not equal.
  65. */
  66. if(AlwaysEqual)
  67. #endif
  68. #if BOOST_WORKAROUND(_MSVC_STL_UPDATE,==201811L)
  69. /* This particular version of VS2019 has a bug in std::unordered_map
  70. * allocator move ctor when source and target allocators are not equal.
  71. * After private communication from Billy O'Neal.
  72. */
  73. if(AlwaysEqual)
  74. #endif
  75. {
  76. rooted_poly_collection p2{cp};
  77. auto d2=get_layout_data<Types...>(p2);
  78. rooted_poly_collection p3{std::move(p2),root2};
  79. auto d3=get_layout_data<Types...>(p3);
  80. BOOST_TEST(p3==p);
  81. #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
  82. /* Limitations from libstdc++-v3 force move construction with allocator
  83. * to decay to copy construction with allocator.
  84. */
  85. (void)(d2==d3); /* Wunused-variable */
  86. #else
  87. if(AlwaysEqual)BOOST_TEST(d2==d3);
  88. #endif
  89. BOOST_TEST(p2.empty());
  90. do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
  91. #if !defined(BOOST_MSVC)&&\
  92. BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
  93. /* Very odd behavior probably due to std::unordered_map allocator move
  94. * ctor being implemented with move assignment, as reported in
  95. * https://github.com/boostorg/poly_collection/issues/16
  96. */
  97. if(!(Propagate&&!AlwaysEqual))
  98. #endif
  99. BOOST_TEST(p3.get_allocator().comes_from(root2));
  100. }
  101. {
  102. rooted_poly_collection p2{root2};
  103. p2=cp;
  104. BOOST_TEST(p2==p);
  105. #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
  106. /* std::unordered_map copy assignment does not propagate allocators */
  107. if(!Propagate)
  108. #endif
  109. #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
  110. /* std::unordered_map copy assignment always and only propagates unequal
  111. * allocators.
  112. */
  113. if(!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual)))
  114. #endif
  115. #if !defined(BOOST_MSVC)&&\
  116. BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
  117. /* std::unordered_map copy assignment does not propagate allocators, as
  118. * reported in https://github.com/boostorg/poly_collection/issues/16
  119. */
  120. if(!Propagate)
  121. #endif
  122. BOOST_TEST(p2.get_allocator().comes_from(Propagate?root1:root2));
  123. }
  124. #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
  125. /* std::unordered_map move asignment does not propagate allocators */
  126. if(!Propagate&&AlwaysEqual)
  127. #endif
  128. {
  129. rooted_poly_collection p2{cp};
  130. auto d2=get_layout_data<Types...>(p2);
  131. rooted_poly_collection p3{root2};
  132. p3=std::move(p2);
  133. auto d3=get_layout_data<Types...>(p3);
  134. BOOST_TEST(p3==p);
  135. if(Propagate||AlwaysEqual){
  136. BOOST_TEST(d2==d3);
  137. BOOST_TEST(p2.empty());
  138. do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
  139. }
  140. #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
  141. /* std::unordered_map move assignment always and only propagates unequal
  142. * allocators.
  143. */
  144. if(!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual)))
  145. #endif
  146. #if !defined(BOOST_MSVC)&&\
  147. BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
  148. /* std::unordered_map move assignment does not propagate equal allocators,
  149. * as reported in https://github.com/boostorg/poly_collection/issues/16
  150. */
  151. if(!(Propagate&&AlwaysEqual))
  152. #endif
  153. BOOST_TEST(p3.get_allocator().comes_from(Propagate?root1:root2));
  154. }
  155. #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
  156. /* std::unordered_map::swap does not correctly swap control information when
  157. * swapping allocators, which causes crashes on "Checked Iterators" mode.
  158. */
  159. if(!(Propagate&&!AlwaysEqual))
  160. #endif
  161. {
  162. constexpr bool use_same_allocator=!Propagate&&!AlwaysEqual;
  163. rooted_poly_collection p2{cp},
  164. p3{use_same_allocator?root1:root2};
  165. auto d2=get_layout_data<Types...>(p2),
  166. d3=get_layout_data<Types...>(p3);
  167. p2.swap(p3);
  168. auto e2=get_layout_data<Types...>(p2),
  169. e3=get_layout_data<Types...>(p3);
  170. BOOST_TEST(d2==e3);
  171. BOOST_TEST(d3==e2);
  172. do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
  173. if(!use_same_allocator
  174. #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
  175. /* std::unordered_map::swap does not swap equal allocators */
  176. &&!(Propagate&&AlwaysEqual)
  177. #endif
  178. #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
  179. /* std::unordered_map::swap always and only swaps unequal allocators */
  180. &&!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual))
  181. #endif
  182. #if !defined(BOOST_MSVC)&&\
  183. BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
  184. /* std::unordered_map::swap does not swap equal allocators, as reported
  185. * in https://github.com/boostorg/poly_collection/issues/16
  186. */
  187. &&!(Propagate&&AlwaysEqual)
  188. #endif
  189. ){
  190. BOOST_TEST(p2.get_allocator().comes_from(Propagate?root2:root1));
  191. BOOST_TEST(p3.get_allocator().comes_from(Propagate?root1:root2));
  192. }
  193. using std::swap;
  194. swap(p2,p3);
  195. auto f2=get_layout_data<Types...>(p2),
  196. f3=get_layout_data<Types...>(p3);
  197. BOOST_TEST(e2==f3);
  198. BOOST_TEST(e3==f2);
  199. do_((BOOST_TEST(!p3.template is_registered<Types>()),0)...);
  200. if(!use_same_allocator){
  201. BOOST_TEST(p2.get_allocator().comes_from(root1));
  202. BOOST_TEST(p3.get_allocator().comes_from(root2));
  203. }
  204. }
  205. }
  206. template<typename PolyCollection,typename ValueFactory,typename... Types>
  207. void test_construction()
  208. {
  209. {
  210. constexpr bool propagate=true,always_equal=true;
  211. test_allocator_aware_construction<
  212. !propagate,!always_equal,PolyCollection,ValueFactory,Types...>();
  213. test_allocator_aware_construction<
  214. !propagate, always_equal,PolyCollection,ValueFactory,Types...>();
  215. test_allocator_aware_construction<
  216. propagate,!always_equal,PolyCollection,ValueFactory,Types...>();
  217. test_allocator_aware_construction<
  218. propagate, always_equal,PolyCollection,ValueFactory,Types...>();
  219. }
  220. {
  221. PolyCollection p;
  222. const PolyCollection& cp=p;
  223. ValueFactory v;
  224. fill<
  225. constraints<is_equality_comparable,is_copy_constructible>,
  226. Types...
  227. >(p,v,2);
  228. {
  229. PolyCollection p2{cp.begin(),cp.end()};
  230. BOOST_TEST(p2==p);
  231. }
  232. {
  233. using type=first_of<
  234. constraints<is_equality_comparable,is_copy_constructible>,
  235. Types...>;
  236. PolyCollection p2{cp.template begin<type>(),cp.template end<type>()};
  237. BOOST_TEST(
  238. p2.size()==cp.template size<type>()&&
  239. std::equal(
  240. p2.template begin<type>(),p2.template end<type>(),
  241. cp.template begin<type>()));
  242. }
  243. }
  244. {
  245. using not_copy_constructible=
  246. boost::poly_collection::not_copy_constructible;
  247. PolyCollection p;
  248. const PolyCollection& cp=p;
  249. ValueFactory v;
  250. fill<
  251. constraints<is_equality_comparable,is_not_copy_constructible>,
  252. Types...
  253. >(p,v,2);
  254. #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
  255. /* std::unordered_map copy construction and assigment crash when elements
  256. * throw on copy construction.
  257. */
  258. static_assert(
  259. sizeof(not_copy_constructible)>0,""); /* Wunused-local-typedefs */
  260. (void)cp; /* Wunused-variable */
  261. #else
  262. check_throw<not_copy_constructible>([&]{
  263. PolyCollection p2{cp};
  264. (void)p2;
  265. });
  266. check_throw<not_copy_constructible>([&]{
  267. PolyCollection p2;
  268. p2=cp;
  269. });
  270. #endif
  271. {
  272. PolyCollection p2{std::move(p)};
  273. BOOST_TEST(!p2.empty());
  274. BOOST_TEST(p.empty());
  275. do_((BOOST_TEST(!p.template is_registered<Types>()),0)...);
  276. p={std::move(p2)};
  277. BOOST_TEST(!p.empty());
  278. BOOST_TEST(p2.empty());
  279. do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
  280. }
  281. }
  282. }
  283. void test_scoped_allocator()
  284. {
  285. #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<50000)&&\
  286. BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,>40704)
  287. /* std::scoped_allocator_adaptor not assignable, see
  288. * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65279 .
  289. * The bug prevents poly_collection below from creating any segment.
  290. */
  291. #else
  292. using vector_allocator=rooted_allocator<char>;
  293. using vector=std::vector<char,vector_allocator>;
  294. using concept_=boost::type_erasure::relaxed;
  295. using element_allocator=rooted_allocator<
  296. boost::poly_collection::any_collection_value_type<concept_>
  297. >;
  298. using collection_allocator=std::scoped_allocator_adaptor<
  299. element_allocator,
  300. vector_allocator
  301. >;
  302. using poly_collection=
  303. boost::any_collection<concept_,collection_allocator>;
  304. element_allocator roote{0};
  305. vector_allocator rootv{0};
  306. collection_allocator al{roote,rootv};
  307. poly_collection p{al};
  308. p.emplace<vector>();
  309. auto& s=*p.begin<vector>();
  310. BOOST_TEST(p.get_allocator().comes_from(roote));
  311. #if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1916)
  312. /* https://developercommunity.visualstudio.com/content/problem/246251/
  313. * 3136309.html
  314. */
  315. #else
  316. BOOST_TEST(s.get_allocator().comes_from(rootv));
  317. #endif
  318. #endif
  319. }
  320. void test_construction()
  321. {
  322. test_construction<
  323. any_types::collection,auto_increment,
  324. any_types::t1,any_types::t2,any_types::t3,
  325. any_types::t4,any_types::t5>();
  326. test_construction<
  327. base_types::collection,auto_increment,
  328. base_types::t1,base_types::t2,base_types::t3,
  329. base_types::t4,base_types::t5>();
  330. test_construction<
  331. function_types::collection,auto_increment,
  332. function_types::t1,function_types::t2,function_types::t3,
  333. function_types::t4,function_types::t5>();
  334. test_scoped_allocator();
  335. }