123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /* Copyright 2016-2019 Joaquin M Lopez Munoz.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * See http://www.boost.org/libs/poly_collection for library home page.
- */
- #include "test_construction.hpp"
- #include <algorithm>
- #include <boost/config.hpp>
- #include <boost/core/lightweight_test.hpp>
- #include <boost/detail/workaround.hpp>
- #include <boost/type_erasure/relaxed.hpp>
- #include <scoped_allocator>
- #include <utility>
- #include <vector>
- #include "any_types.hpp"
- #include "base_types.hpp"
- #include "function_types.hpp"
- #include "test_utilities.hpp"
- using namespace test_utilities;
- template<
- bool Propagate,bool AlwaysEqual,
- typename PolyCollection,typename ValueFactory,typename... Types
- >
- void test_allocator_aware_construction()
- {
- using rooted_poly_collection=realloc_poly_collection<
- PolyCollection,rooted_allocator,
- std::integral_constant<bool,Propagate>,
- std::integral_constant<bool,AlwaysEqual>>;
- using allocator_type=typename rooted_poly_collection::allocator_type;
- allocator_type root1{0},root2{0};
- rooted_poly_collection p{root1};
- const rooted_poly_collection& cp=p;
- ValueFactory v;
- fill<
- constraints<is_equality_comparable,is_copy_constructible>,
- Types...
- >(p,v,2);
- {
- rooted_poly_collection p2{cp};
- BOOST_TEST(p2==p);
- BOOST_TEST(p2.get_allocator().comes_from(root1));
- }
- {
- rooted_poly_collection p2{cp};
- auto d2=get_layout_data<Types...>(p2);
- rooted_poly_collection p3{std::move(p2)};
- auto d3=get_layout_data<Types...>(p3);
- BOOST_TEST(p3==p);
- BOOST_TEST(d2==d3);
- BOOST_TEST(p2.empty());
- do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
- BOOST_TEST(p2.get_allocator().comes_from(root1));
- }
- {
- rooted_poly_collection p2{cp,root2};
- BOOST_TEST(p2==p);
- BOOST_TEST(p2.get_allocator().comes_from(root2));
- }
- #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
- /* std::unordered_map allocator move ctor does not work when source and
- * and target allocators are not equal.
- */
- if(AlwaysEqual)
- #endif
- #if BOOST_WORKAROUND(_MSVC_STL_UPDATE,==201811L)
- /* This particular version of VS2019 has a bug in std::unordered_map
- * allocator move ctor when source and target allocators are not equal.
- * After private communication from Billy O'Neal.
- */
- if(AlwaysEqual)
- #endif
- {
- rooted_poly_collection p2{cp};
- auto d2=get_layout_data<Types...>(p2);
- rooted_poly_collection p3{std::move(p2),root2};
- auto d3=get_layout_data<Types...>(p3);
- BOOST_TEST(p3==p);
- #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
- /* Limitations from libstdc++-v3 force move construction with allocator
- * to decay to copy construction with allocator.
- */
- (void)(d2==d3); /* Wunused-variable */
- #else
- if(AlwaysEqual)BOOST_TEST(d2==d3);
- #endif
- BOOST_TEST(p2.empty());
- do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
- #if !defined(BOOST_MSVC)&&\
- BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
- /* Very odd behavior probably due to std::unordered_map allocator move
- * ctor being implemented with move assignment, as reported in
- * https://github.com/boostorg/poly_collection/issues/16
- */
- if(!(Propagate&&!AlwaysEqual))
- #endif
- BOOST_TEST(p3.get_allocator().comes_from(root2));
- }
- {
- rooted_poly_collection p2{root2};
- p2=cp;
- BOOST_TEST(p2==p);
- #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
- /* std::unordered_map copy assignment does not propagate allocators */
-
- if(!Propagate)
- #endif
- #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
- /* std::unordered_map copy assignment always and only propagates unequal
- * allocators.
- */
- if(!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual)))
- #endif
- #if !defined(BOOST_MSVC)&&\
- BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
- /* std::unordered_map copy assignment does not propagate allocators, as
- * reported in https://github.com/boostorg/poly_collection/issues/16
- */
- if(!Propagate)
- #endif
- BOOST_TEST(p2.get_allocator().comes_from(Propagate?root1:root2));
- }
- #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
- /* std::unordered_map move asignment does not propagate allocators */
- if(!Propagate&&AlwaysEqual)
- #endif
- {
- rooted_poly_collection p2{cp};
- auto d2=get_layout_data<Types...>(p2);
- rooted_poly_collection p3{root2};
- p3=std::move(p2);
- auto d3=get_layout_data<Types...>(p3);
- BOOST_TEST(p3==p);
- if(Propagate||AlwaysEqual){
- BOOST_TEST(d2==d3);
- BOOST_TEST(p2.empty());
- do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
- }
- #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
- /* std::unordered_map move assignment always and only propagates unequal
- * allocators.
- */
- if(!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual)))
- #endif
- #if !defined(BOOST_MSVC)&&\
- BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
- /* std::unordered_map move assignment does not propagate equal allocators,
- * as reported in https://github.com/boostorg/poly_collection/issues/16
- */
- if(!(Propagate&&AlwaysEqual))
- #endif
- BOOST_TEST(p3.get_allocator().comes_from(Propagate?root1:root2));
- }
- #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
- /* std::unordered_map::swap does not correctly swap control information when
- * swapping allocators, which causes crashes on "Checked Iterators" mode.
- */
- if(!(Propagate&&!AlwaysEqual))
- #endif
- {
- constexpr bool use_same_allocator=!Propagate&&!AlwaysEqual;
- rooted_poly_collection p2{cp},
- p3{use_same_allocator?root1:root2};
- auto d2=get_layout_data<Types...>(p2),
- d3=get_layout_data<Types...>(p3);
- p2.swap(p3);
- auto e2=get_layout_data<Types...>(p2),
- e3=get_layout_data<Types...>(p3);
- BOOST_TEST(d2==e3);
- BOOST_TEST(d3==e2);
- do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
- if(!use_same_allocator
- #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
- /* std::unordered_map::swap does not swap equal allocators */
- &&!(Propagate&&AlwaysEqual)
- #endif
- #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
- /* std::unordered_map::swap always and only swaps unequal allocators */
- &&!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual))
- #endif
- #if !defined(BOOST_MSVC)&&\
- BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
- /* std::unordered_map::swap does not swap equal allocators, as reported
- * in https://github.com/boostorg/poly_collection/issues/16
- */
- &&!(Propagate&&AlwaysEqual)
- #endif
- ){
- BOOST_TEST(p2.get_allocator().comes_from(Propagate?root2:root1));
- BOOST_TEST(p3.get_allocator().comes_from(Propagate?root1:root2));
- }
- using std::swap;
- swap(p2,p3);
- auto f2=get_layout_data<Types...>(p2),
- f3=get_layout_data<Types...>(p3);
- BOOST_TEST(e2==f3);
- BOOST_TEST(e3==f2);
- do_((BOOST_TEST(!p3.template is_registered<Types>()),0)...);
- if(!use_same_allocator){
- BOOST_TEST(p2.get_allocator().comes_from(root1));
- BOOST_TEST(p3.get_allocator().comes_from(root2));
- }
- }
- }
- template<typename PolyCollection,typename ValueFactory,typename... Types>
- void test_construction()
- {
- {
- constexpr bool propagate=true,always_equal=true;
- test_allocator_aware_construction<
- !propagate,!always_equal,PolyCollection,ValueFactory,Types...>();
- test_allocator_aware_construction<
- !propagate, always_equal,PolyCollection,ValueFactory,Types...>();
- test_allocator_aware_construction<
- propagate,!always_equal,PolyCollection,ValueFactory,Types...>();
- test_allocator_aware_construction<
- propagate, always_equal,PolyCollection,ValueFactory,Types...>();
- }
- {
- PolyCollection p;
- const PolyCollection& cp=p;
- ValueFactory v;
- fill<
- constraints<is_equality_comparable,is_copy_constructible>,
- Types...
- >(p,v,2);
- {
- PolyCollection p2{cp.begin(),cp.end()};
- BOOST_TEST(p2==p);
- }
- {
- using type=first_of<
- constraints<is_equality_comparable,is_copy_constructible>,
- Types...>;
- PolyCollection p2{cp.template begin<type>(),cp.template end<type>()};
- BOOST_TEST(
- p2.size()==cp.template size<type>()&&
- std::equal(
- p2.template begin<type>(),p2.template end<type>(),
- cp.template begin<type>()));
- }
- }
- {
- using not_copy_constructible=
- boost::poly_collection::not_copy_constructible;
- PolyCollection p;
- const PolyCollection& cp=p;
- ValueFactory v;
- fill<
- constraints<is_equality_comparable,is_not_copy_constructible>,
- Types...
- >(p,v,2);
- #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
- /* std::unordered_map copy construction and assigment crash when elements
- * throw on copy construction.
- */
- static_assert(
- sizeof(not_copy_constructible)>0,""); /* Wunused-local-typedefs */
- (void)cp; /* Wunused-variable */
- #else
- check_throw<not_copy_constructible>([&]{
- PolyCollection p2{cp};
- (void)p2;
- });
- check_throw<not_copy_constructible>([&]{
- PolyCollection p2;
- p2=cp;
- });
- #endif
- {
- PolyCollection p2{std::move(p)};
- BOOST_TEST(!p2.empty());
- BOOST_TEST(p.empty());
- do_((BOOST_TEST(!p.template is_registered<Types>()),0)...);
- p={std::move(p2)};
- BOOST_TEST(!p.empty());
- BOOST_TEST(p2.empty());
- do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
- }
- }
- }
- void test_scoped_allocator()
- {
- #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<50000)&&\
- BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,>40704)
- /* std::scoped_allocator_adaptor not assignable, see
- * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65279 .
- * The bug prevents poly_collection below from creating any segment.
- */
- #else
- using vector_allocator=rooted_allocator<char>;
- using vector=std::vector<char,vector_allocator>;
- using concept_=boost::type_erasure::relaxed;
- using element_allocator=rooted_allocator<
- boost::poly_collection::any_collection_value_type<concept_>
- >;
- using collection_allocator=std::scoped_allocator_adaptor<
- element_allocator,
- vector_allocator
- >;
- using poly_collection=
- boost::any_collection<concept_,collection_allocator>;
- element_allocator roote{0};
- vector_allocator rootv{0};
- collection_allocator al{roote,rootv};
- poly_collection p{al};
- p.emplace<vector>();
- auto& s=*p.begin<vector>();
- BOOST_TEST(p.get_allocator().comes_from(roote));
- #if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1916)
- /* https://developercommunity.visualstudio.com/content/problem/246251/
- * 3136309.html
- */
- #else
- BOOST_TEST(s.get_allocator().comes_from(rootv));
- #endif
- #endif
- }
- void test_construction()
- {
- test_construction<
- any_types::collection,auto_increment,
- any_types::t1,any_types::t2,any_types::t3,
- any_types::t4,any_types::t5>();
- test_construction<
- base_types::collection,auto_increment,
- base_types::t1,base_types::t2,base_types::t3,
- base_types::t4,base_types::t5>();
- test_construction<
- function_types::collection,auto_increment,
- function_types::t1,function_types::t2,function_types::t3,
- function_types::t4,function_types::t5>();
- test_scoped_allocator();
- }
|