/* Boost.MultiIndex test for allocator awareness. * * Copyright 2003-2020 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/multi_index for library home page. */ #include "test_alloc_awareness.hpp" #include /* keep it first to prevent nasty warns in MSVC */ #include #include #include "pre_multi_index.hpp" #include #include #include #include #include #include #include #include #include struct move_tracker { move_tracker(int n):n(n),move_cted(false){} move_tracker(const move_tracker& x):n(x.n),move_cted(false){} move_tracker(BOOST_RV_REF(move_tracker) x):n(x.n),move_cted(true){} int n; bool move_cted; }; inline bool operator==(const move_tracker& x,const move_tracker& y) { return x.n==y.n; } inline bool operator<(const move_tracker& x,const move_tracker& y) { return x.n h; return h(x.n); } #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) } /* namespace boost */ #endif template< typename T, typename Propagate=boost::true_type,typename AlwaysEqual=boost::true_type > struct rooted_allocator:std::allocator { typedef Propagate propagate_on_container_copy_assignment; typedef Propagate propagate_on_container_move_assignment; typedef Propagate propagate_on_container_swap; typedef AlwaysEqual is_always_equal; template struct rebind{typedef rooted_allocator other;}; rooted_allocator():root(0){} explicit rooted_allocator(int):root(this){} template rooted_allocator(const rooted_allocator& x): root(x.root){} template bool operator==(const rooted_allocator& x)const {return AlwaysEqual::value?true:root==x.root;} template bool operator!=(const rooted_allocator& x)const {return !(*this==x);} template bool comes_from(const rooted_allocator& x)const {return root==&x;} private: template friend struct rooted_allocator; const void* root; }; #if defined(BOOST_NO_CXX17_IF_CONSTEXPR)&&defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable:4127) /* conditional expression is constant */ #endif template void test_allocator_awareness_for() { using namespace boost::multi_index; typedef rooted_allocator< move_tracker, boost::integral_constant, boost::integral_constant > allocator; typedef multi_index_container< move_tracker, indexed_by< hashed_unique >, ordered_unique >, random_access<>, ranked_unique >, sequenced<> >, allocator > container; allocator root1(0),root2(0); container c(root1); for(int i=0;i<10;++i)c.emplace(i); BOOST_TEST(c.get_allocator().comes_from(root1)); { container c2(c,root2); BOOST_TEST(c2.get_allocator().comes_from(root2)); BOOST_TEST(c2==c); } { container c2(c); const move_tracker* pfirst=&*c2.begin(); container c3(boost::move(c2),root2); BOOST_TEST(c3.get_allocator().comes_from(root2)); BOOST_TEST(c3==c); BOOST_TEST(c2.empty()); BOOST_TEST(AlwaysEqual==(&*c3.begin()==pfirst)); BOOST_TEST(!AlwaysEqual==(c3.begin()->move_cted)); } { container c2(root2); c2=c; BOOST_TEST(c2.get_allocator().comes_from(Propagate?root1:root2)); BOOST_TEST(c2==c); } { container c2(c); const move_tracker* pfirst=&*c2.begin(); container c3(root2); c3=boost::move(c2); BOOST_TEST(c3.get_allocator().comes_from(Propagate?root1:root2)); BOOST_TEST(c3==c); BOOST_TEST(c2.empty()); BOOST_TEST(AlwaysEqual==(&*c3.begin()==pfirst)); BOOST_TEST(!AlwaysEqual==(c3.begin()->move_cted)); } if(Propagate||AlwaysEqual){ container c2(c); const move_tracker* pfirst=&*c2.begin(); container c3(root2); c3.swap(c2); BOOST_TEST(c2.get_allocator().comes_from(Propagate?root2:root1)); BOOST_TEST(c3.get_allocator().comes_from(Propagate?root1:root2)); BOOST_TEST(c3==c); BOOST_TEST(c2.empty()); BOOST_TEST(&*c3.begin()==pfirst); BOOST_TEST(!c3.begin()->move_cted); } } #if defined(BOOST_NO_CXX17_IF_CONSTEXPR)&&defined(BOOST_MSVC) #pragma warning(pop) #endif void test_allocator_awareness() { test_allocator_awareness_for(); test_allocator_awareness_for(); #if !defined(BOOST_NO_CXX11_ALLOCATOR) /* only in C+11 onwards are allocators potentially expected to propagate */ test_allocator_awareness_for(); test_allocator_awareness_for(); #endif }