libs/multi_index/test/test_alloc_awareness.cpp
/* 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 <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/lightweight_test.hpp>
#include <boost/move/core.hpp>
#include <boost/move/utility_core.hpp>
#include "pre_multi_index.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/ranked_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include "rooted_allocator.hpp"
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){}
move_tracker& operator=(BOOST_COPY_ASSIGN_REF(move_tracker) x)
{n=x.n;return *this;}
move_tracker& operator=(BOOST_RV_REF(move_tracker) x){n=x.n;return *this;}
int n;
bool move_cted;
private:
BOOST_COPYABLE_AND_MOVABLE(move_tracker)
};
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<y.n;
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost{
#endif
inline std::size_t hash_value(const move_tracker& x)
{
boost::hash<int> h;
return h(x.n);
}
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
} /* namespace boost */
#endif
#if defined(BOOST_NO_CXX17_IF_CONSTEXPR)&&defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) /* conditional expression is constant */
#endif
template<bool Propagate,bool AlwaysEqual>
void test_allocator_awareness_for()
{
using namespace boost::multi_index;
typedef rooted_allocator<move_tracker,Propagate,AlwaysEqual> allocator;
typedef multi_index_container<
move_tracker,
indexed_by<
hashed_unique<identity<move_tracker> >,
ordered_unique<identity<move_tracker> >,
random_access<>,
ranked_unique<identity<move_tracker> >,
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);
}
{
const bool element_transfer=Propagate||AlwaysEqual;
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(element_transfer==(&*c3.begin()==pfirst));
BOOST_TEST(!element_transfer==(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) /* C4127 */
#endif
void test_allocator_awareness()
{
test_allocator_awareness_for<false,false>();
test_allocator_awareness_for<false,true>();
#if !defined(BOOST_NO_CXX11_ALLOCATOR)
/* only in C+11 onwards are allocators potentially expected to propagate */
test_allocator_awareness_for<true,false>();
test_allocator_awareness_for<true,true>();
#endif
}