Swapping of internal KeyFromValue
, Compare
, Hash
and Pred
objects now selects the appropriate swap
function between std::swap
and ADL candidates,
@@ -654,7 +657,7 @@ Acknowledgements
-Revised January 21st 2020
+Revised January 25th 2020
© Copyright 2003-2020 Joaquín M López Muñoz.
Distributed under the Boost Software
diff --git a/doc/tests.html b/doc/tests.html
index 26d3122..2161904 100644
--- a/doc/tests.html
+++ b/doc/tests.html
@@ -43,100 +43,105 @@ with some of the least common features offered by Boost.MultiIndex.
Description |
+ test_alloc_awareness.cpp |
+ Checks allocator
+ awareness. |
+
+
test_basic.cpp |
Simple program along the lines of the employees example studied in the
tutorial. |
-
+
test_capacity.cpp |
empty , size , resize
(non key-based indices) and reserve /capacity
(random access indices only). |
-
+
test_comparison.cpp |
Comparison between indices. |
-
+
test_composite_key.cpp |
composite_key and composite_key_compare . |
-
+
test_conv_iterators.cpp |
Checks convertibility of non-constant to constant iterators. |
-
+
test_copy_assignment.cpp |
Various forms of assignment: copy, operator = , insertion,
(non key-based indices only) assign .
|
-
+
test_hash_ops.cpp |
Hashing operations. |
-
+
test_iterators.cpp |
Constant and non-constant iterators and their reverse variants. |
-
+
test_key.cpp |
Terse key specification syntax. |
-
+
test_key_extractors.cpp |
Covers all use cases of key extractors shipped with the library. |
-
+
test_list_ops.cpp |
List-like operations particular to sequenced and random access indices. |
-
+
test_modifiers.cpp |
Checks the family of insertion and erasing operations. |
-
+
test_mpl_ops.cpp |
Metaprogramming manipulations of multi_index_container types. |
-
+
test_observers.cpp |
Checks observer member functions of ordered and hashed indices. |
-
+
test_projection.cpp |
Projection of iterators among indices. |
-
+
test_range.cpp |
Exercises the range facility (ordered indices only). |
-
+
test_rank_ops.cpp |
Specific operations of ranked indices. |
-
+
test_rearrange.cpp |
Rearrange functions of sequenced and random access indices. |
-
+
test_safe_mode.cpp |
Comprehensive coverage of all conditions checked in safe mode. |
-
+
test_serialization1.cpp
test_serialization2.cpp
test_serialization3.cpp |
Serialization support. |
-
+
test_set_ops.cpp |
Set-like operations particular to ordered indices. |
-
+
test_special_set_ops.cpp |
Checks special lookup operations using compatible sorting criteria. |
-
+
test_update.cpp |
replace , modify and modify_key . |
@@ -157,9 +162,9 @@ Future work
-Revised August 17th 2018
+Revised January 25th 2020
-© Copyright 2003-2018 Joaquín M López Muñoz.
+
© Copyright 2003-2020 Joaquín M López Muñoz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at
diff --git a/include/boost/multi_index/detail/allocator_traits.hpp b/include/boost/multi_index/detail/allocator_traits.hpp
index 63fce6a..f3c8ef5 100644
--- a/include/boost/multi_index/detail/allocator_traits.hpp
+++ b/include/boost/multi_index/detail/allocator_traits.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2018 Joaquin M Lopez Munoz.
+/* 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)
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#endif
@@ -75,6 +76,10 @@ struct allocator_traits
typedef typename Allocator::difference_type difference_type;
typedef typename Allocator::size_type size_type;
+ typedef boost::false_type propagate_on_container_copy_assignment;
+ typedef boost::false_type propagate_on_container_move_assignment;
+ typedef boost::false_type propagate_on_container_swap;
+
template
struct rebind_alloc
{
@@ -123,6 +128,11 @@ struct allocator_traits
#endif
static size_type max_size(Allocator& a)BOOST_NOEXCEPT{return a.max_size();}
+
+ static Allocator select_on_container_copy_construction(const Allocator& a)
+ {
+ return a;
+ }
};
#endif
diff --git a/include/boost/multi_index/detail/auto_space.hpp b/include/boost/multi_index/detail/auto_space.hpp
index ca19b32..4df875b 100644
--- a/include/boost/multi_index/detail/auto_space.hpp
+++ b/include/boost/multi_index/detail/auto_space.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2018 Joaquin M Lopez Munoz.
+/* 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)
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
namespace boost{
@@ -64,11 +65,25 @@ struct auto_space:private noncopyable
void swap(auto_space& x)
{
- if(al_!=x.al_)adl_swap(al_,x.al_);
+ swap(
+ x,
+ boost::integral_constant<
+ bool,alloc_traits::propagate_on_container_swap::value>());
+ }
+
+ void swap(auto_space& x,boost::true_type /* swap_allocators */)
+ {
+ adl_swap(al_,x.al_);
std::swap(n_,x.n_);
std::swap(data_,x.data_);
}
+ void swap(auto_space& x,boost::false_type /* swap_allocators */)
+ {
+ std::swap(n_,x.n_);
+ std::swap(data_,x.data_);
+ }
+
private:
allocator al_;
size_type n_;
diff --git a/include/boost/multi_index/detail/bucket_array.hpp b/include/boost/multi_index/detail/bucket_array.hpp
index 149addf..1faf821 100644
--- a/include/boost/multi_index/detail/bucket_array.hpp
+++ b/include/boost/multi_index/detail/bucket_array.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2018 Joaquin M Lopez Munoz.
+/* 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)
@@ -173,6 +173,13 @@ public:
spc.swap(x.spc);
}
+ template
+ void swap(bucket_array& x,BoolConstant swap_allocators)
+ {
+ std::swap(size_index_,x.size_index_);
+ spc.swap(x.spc,swap_allocators);
+ }
+
private:
typedef auto_space auto_space_type;
typedef typename auto_space_type::size_type auto_space_size_type;
diff --git a/include/boost/multi_index/detail/copy_map.hpp b/include/boost/multi_index/detail/copy_map.hpp
index d5806ad..6414942 100644
--- a/include/boost/multi_index/detail/copy_map.hpp
+++ b/include/boost/multi_index/detail/copy_map.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2018 Joaquin M Lopez Munoz.
+/* 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)
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -55,6 +56,18 @@ struct copy_map_entry
}
};
+struct copy_map_value_copier
+{
+ template
+ const Value& operator()(Value& x)const{return x;}
+};
+
+struct copy_map_value_mover
+{
+ template
+ BOOST_RV_REF(Value) operator()(Value& x)const{return boost::move(x);}
+};
+
template
class copy_map:private noncopyable
{
@@ -88,27 +101,8 @@ public:
const_iterator begin()const{return raw_ptr(spc.data());}
const_iterator end()const{return raw_ptr(spc.data()+n);}
- void clone(Node* node)
- {
- (spc.data()+n)->first=node;
- (spc.data()+n)->second=raw_ptr(allocate());
- BOOST_TRY{
- alloc_traits::construct(
- al_,boost::addressof((spc.data()+n)->second->value()),node->value());
- }
- BOOST_CATCH(...){
- deallocate((spc.data()+n)->second);
- BOOST_RETHROW;
- }
- BOOST_CATCH_END
- ++n;
-
- if(n==size_){
- std::sort(
- raw_ptr*>(spc.data()),
- raw_ptr*>(spc.data())+size_);
- }
- }
+ void copy_clone(Node* node){clone(node,copy_map_value_copier());}
+ void move_clone(Node* node){clone(node,copy_map_value_mover());}
Node* find(Node* node)const
{
@@ -140,6 +134,30 @@ private:
{
alloc_traits::deallocate(al_,static_cast(node),1);
}
+
+ template
+ void clone(Node* node,ValueAccess access)
+ {
+ (spc.data()+n)->first=node;
+ (spc.data()+n)->second=raw_ptr(allocate());
+ BOOST_TRY{
+ alloc_traits::construct(
+ al_,boost::addressof((spc.data()+n)->second->value()),
+ access(node->value()));
+ }
+ BOOST_CATCH(...){
+ deallocate((spc.data()+n)->second);
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+ ++n;
+
+ if(n==size_){
+ std::sort(
+ raw_ptr*>(spc.data()),
+ raw_ptr*>(spc.data())+size_);
+ }
+ }
};
} /* namespace multi_index::detail */
diff --git a/include/boost/multi_index/detail/index_base.hpp b/include/boost/multi_index/detail/index_base.hpp
index 1748a8f..65e279f 100644
--- a/include/boost/multi_index/detail/index_base.hpp
+++ b/include/boost/multi_index/detail/index_base.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2018 Joaquin M Lopez Munoz.
+/* 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)
@@ -162,7 +162,11 @@ protected:
void clear_(){}
- void swap_(index_base&){}
+ template
+ void swap_(
+ index_base&,
+ BoolConstant /* swap_allocators */)
+ {}
void swap_elements_(index_base&){}
diff --git a/include/boost/multi_index/detail/ord_index_impl.hpp b/include/boost/multi_index/detail/ord_index_impl.hpp
index 6efab3c..ec6be72 100644
--- a/include/boost/multi_index/detail/ord_index_impl.hpp
+++ b/include/boost/multi_index/detail/ord_index_impl.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2019 Joaquin M Lopez Munoz.
+/* 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)
@@ -771,9 +771,11 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
#endif
}
+ template
void swap_(
ordered_index_impl<
- KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy>& x)
+ KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy>& x,
+ BoolConstant swap_allocators)
{
adl_swap(key,x.key);
adl_swap(comp_,x.comp_);
@@ -782,7 +784,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
safe_super::swap(x);
#endif
- super::swap_(x);
+ super::swap_(x,swap_allocators);
}
void swap_elements_(
diff --git a/include/boost/multi_index/detail/rnd_index_ptr_array.hpp b/include/boost/multi_index/detail/rnd_index_ptr_array.hpp
index 495bad8..0a1be70 100644
--- a/include/boost/multi_index/detail/rnd_index_ptr_array.hpp
+++ b/include/boost/multi_index/detail/rnd_index_ptr_array.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2018 Joaquin M Lopez Munoz.
+/* 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)
@@ -110,6 +110,14 @@ public:
spc.swap(x.spc);
}
+ template
+ void swap(random_access_index_ptr_array& x,BoolConstant swap_allocators)
+ {
+ std::swap(size_,x.size_);
+ std::swap(capacity_,x.capacity_);
+ spc.swap(x.spc,swap_allocators);
+ }
+
private:
size_type size_;
size_type capacity_;
diff --git a/include/boost/multi_index/hashed_index.hpp b/include/boost/multi_index/hashed_index.hpp
index 5b1b487..fae4ae9 100644
--- a/include/boost/multi_index/hashed_index.hpp
+++ b/include/boost/multi_index/hashed_index.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2019 Joaquin M Lopez Munoz.
+/* 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)
@@ -876,13 +876,15 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
#endif
}
+ template
void swap_(
- hashed_index& x)
+ hashed_index& x,
+ BoolConstant swap_allocators)
{
adl_swap(key,x.key);
adl_swap(hash_,x.hash_);
adl_swap(eq_,x.eq_);
- buckets.swap(x.buckets);
+ buckets.swap(x.buckets,swap_allocators);
std::swap(mlf,x.mlf);
std::swap(max_load,x.max_load);
@@ -890,7 +892,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
safe_super::swap(x);
#endif
- super::swap_(x);
+ super::swap_(x,swap_allocators);
}
void swap_elements_(
diff --git a/include/boost/multi_index/random_access_index.hpp b/include/boost/multi_index/random_access_index.hpp
index 8f5e90b..f1a090b 100644
--- a/include/boost/multi_index/random_access_index.hpp
+++ b/include/boost/multi_index/random_access_index.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2018 Joaquin M Lopez Munoz.
+/* 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)
@@ -823,15 +823,17 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
#endif
}
- void swap_(random_access_index& x)
+ template
+ void swap_(
+ random_access_index& x,BoolConstant swap_allocators)
{
- ptrs.swap(x.ptrs);
+ ptrs.swap(x.ptrs,swap_allocators);
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
safe_super::swap(x);
#endif
- super::swap_(x);
+ super::swap_(x,swap_allocators);
}
void swap_elements_(random_access_index& x)
diff --git a/include/boost/multi_index/sequenced_index.hpp b/include/boost/multi_index/sequenced_index.hpp
index 6db2f24..1555a4d 100644
--- a/include/boost/multi_index/sequenced_index.hpp
+++ b/include/boost/multi_index/sequenced_index.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2003-2019 Joaquin M Lopez Munoz.
+/* 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)
@@ -720,13 +720,15 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
#endif
}
- void swap_(sequenced_index& x)
+ template
+ void swap_(
+ sequenced_index& x,BoolConstant swap_allocators)
{
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
safe_super::swap(x);
#endif
- super::swap_(x);
+ super::swap_(x,swap_allocators);
}
void swap_elements_(sequenced_index& x)
diff --git a/include/boost/multi_index_container.hpp b/include/boost/multi_index_container.hpp
index 72e4233..63cb524 100644
--- a/include/boost/multi_index_container.hpp
+++ b/include/boost/multi_index_container.hpp
@@ -1,6 +1,6 @@
/* Multiply indexed container.
*
- * Copyright 2003-2018 Joaquin M Lopez Munoz.
+ * 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)
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include
#include
@@ -77,6 +78,12 @@ namespace boost{
namespace multi_index{
+namespace detail{
+
+struct unequal_alloc_move_ctor_tag{};
+
+} /* namespace multi_index::detail */
+
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1500))
#pragma warning(push)
#pragma warning(disable:4522) /* spurious warning on multiple operator=()'s */
@@ -123,7 +130,7 @@ private:
#endif
typedef typename detail::multi_index_base_type<
- Value,IndexSpecifierList,Allocator>::type super;
+ Value,IndexSpecifierList,Allocator>::type super;
typedef typename detail::rebind_alloc_for<
Allocator,
typename super::node_type
@@ -271,28 +278,18 @@ public:
multi_index_container(
const multi_index_container& x):
- bfm_allocator(x.bfm_allocator::member),
+ bfm_allocator(
+ node_alloc_traits::select_on_container_copy_construction(
+ x.bfm_allocator::member)),
bfm_header(),
super(x),
node_count(0)
{
- copy_map_type map(bfm_allocator::member,x.size(),x.header(),header());
- for(const_iterator it=x.begin(),it_end=x.end();it!=it_end;++it){
- map.clone(it.get_node());
- }
- super::copy_(x,map);
- map.release();
- node_count=x.size();
-
- /* Not until this point are the indices required to be consistent,
- * hence the position of the invariant checker.
- */
-
- BOOST_MULTI_INDEX_CHECK_INVARIANT;
+ copy_construct_from(x);
}
multi_index_container(BOOST_RV_REF(multi_index_container) x):
- bfm_allocator(x.bfm_allocator::member),
+ bfm_allocator(boost::move(x.bfm_allocator::member)),
bfm_header(),
super(x,detail::do_not_copy_elements_tag()),
node_count(0)
@@ -302,6 +299,36 @@ public:
swap_elements_(x);
}
+ multi_index_container(
+ const multi_index_container& x,
+ const allocator_type& al):
+ bfm_allocator(al),
+ bfm_header(),
+ super(x),
+ node_count(0)
+ {
+ copy_construct_from(x);
+ }
+
+ multi_index_container(
+ BOOST_RV_REF(multi_index_container) x,const allocator_type& al):
+ bfm_allocator(al),
+ bfm_header(),
+ super(x,detail::do_not_copy_elements_tag()),
+ node_count(0)
+ {
+ BOOST_MULTI_INDEX_CHECK_INVARIANT;
+ BOOST_MULTI_INDEX_CHECK_INVARIANT_OF(x);
+
+ if(al==x.get_allocator()){
+ swap_elements_(x);
+ }
+ else{
+ multi_index_container y(x,al,detail::unequal_alloc_move_ctor_tag());
+ swap_elements_(y);
+ }
+ }
+
~multi_index_container()
{
delete_all_nodes_();
@@ -315,8 +342,11 @@ public:
multi_index_container& operator=(
const multi_index_container& x)
{
- multi_index_container y(x);
- this->swap(y);
+ multi_index_container y(
+ x,
+ node_alloc_traits::propagate_on_container_copy_assignment::value?
+ x.get_allocator():this->get_allocator());
+ swap_(y,boost::true_type() /* swap_allocators */);
return *this;
}
#endif
@@ -324,16 +354,44 @@ public:
multi_index_container& operator=(
BOOST_COPY_ASSIGN_REF(multi_index_container) x)
{
- multi_index_container y(x);
- this->swap(y);
+ multi_index_container y(
+ x,
+ node_alloc_traits::propagate_on_container_copy_assignment::value?
+ x.get_allocator():this->get_allocator());
+ swap_(y,boost::true_type() /* swap_allocators */);
return *this;
}
multi_index_container& operator=(
BOOST_RV_REF(multi_index_container) x)
{
- this->swap(x);
+#if !defined(BOOST_NO_CXX17_IF_CONSTEXPR)
+#define BOOST_MULTI_INDEX_IF_CONSTEXPR if constexpr
+#else
+#define BOOST_MULTI_INDEX_IF_CONSTEXPR if
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+#pragma warning(disable:4127) /* conditional expression is constant */
+#endif
+#endif
+
+ BOOST_MULTI_INDEX_IF_CONSTEXPR(
+ node_alloc_traits::propagate_on_container_move_assignment::value){
+ swap_(x,boost::true_type() /* swap_allocators */);
+ }
+ else if(this->get_allocator()==x.get_allocator()){
+ swap_(x,boost::false_type() /* swap_allocators */);
+ }
+ else{
+ multi_index_container y(boost::move(x),this->get_allocator());
+ swap_(y,boost::true_type() /* swap_allocators */);
+ }
return *this;
+
+#undef BOOST_MULTI_INDEX_IF_CONSTEXPR
+#if defined(BOOST_NO_CXX17_IF_CONSTEXPR)&&defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
}
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
@@ -518,6 +576,39 @@ public:
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
typedef typename super::copy_map_type copy_map_type;
+ multi_index_container(
+ multi_index_container& x,
+ const allocator_type& al,
+ detail::unequal_alloc_move_ctor_tag):
+ bfm_allocator(al),
+ bfm_header(),
+ super(x),
+ node_count(0)
+ {
+ BOOST_MULTI_INDEX_CHECK_INVARIANT_OF(x);
+ BOOST_TRY{
+ copy_map_type map(bfm_allocator::member,x.size(),x.header(),header());
+ for(const_iterator it=x.begin(),it_end=x.end();it!=it_end;++it){
+ map.move_clone(it.get_node());
+ }
+ super::copy_(x,map);
+ map.release();
+ node_count=x.size();
+ x.clear();
+ }
+ BOOST_CATCH(...){
+ x.clear();
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+
+ /* Not until this point are the indices required to be consistent,
+ * hence the position of the invariant checker.
+ */
+
+ BOOST_MULTI_INDEX_CHECK_INVARIANT;
+ }
+
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
multi_index_container(
const multi_index_container& x,
@@ -531,6 +622,24 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
}
#endif
+ void copy_construct_from(
+ const multi_index_container& x)
+ {
+ copy_map_type map(bfm_allocator::member,x.size(),x.header(),header());
+ for(const_iterator it=x.begin(),it_end=x.end();it!=it_end;++it){
+ map.copy_clone(it.get_node());
+ }
+ super::copy_(x,map);
+ map.release();
+ node_count=x.size();
+
+ /* Not until this point are the indices required to be consistent,
+ * hence the position of the invariant checker.
+ */
+
+ BOOST_MULTI_INDEX_CHECK_INVARIANT;
+ }
+
node_type* header()const
{
return &*bfm_header::member;
@@ -811,11 +920,28 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
void swap_(multi_index_container& x)
{
- if(bfm_allocator::member!=x.bfm_allocator::member){
- detail::adl_swap(bfm_allocator::member,x.bfm_allocator::member);
- }
+ swap_(
+ x,
+ boost::integral_constant<
+ bool,node_alloc_traits::propagate_on_container_swap::value>());
+ }
+
+ void swap_(
+ multi_index_container& x,
+ boost::true_type swap_allocators)
+ {
+ detail::adl_swap(bfm_allocator::member,x.bfm_allocator::member);
std::swap(bfm_header::member,x.bfm_header::member);
- super::swap_(x);
+ super::swap_(x,swap_allocators);
+ std::swap(node_count,x.node_count);
+ }
+
+ void swap_(
+ multi_index_container& x,
+ boost::false_type swap_allocators)
+ {
+ std::swap(bfm_header::member,x.bfm_header::member);
+ super::swap_(x,swap_allocators);
std::swap(node_count,x.node_count);
}
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 36da215..405dc76 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -1,6 +1,6 @@
# Boost.MultiIndex tests Jamfile
#
-# Copyright 2003-2018 Joaquín M López Muñoz.
+# Copyright 2003-2020 Joaquín M López Muñoz.
# 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)
@@ -38,6 +38,7 @@ obj boost_multi_index_key_supported : check_bmi_key_supported.cpp ;
explicit boost_multi_index_key_supported ;
test-suite "multi_index" :
+ [ run test_alloc_awareness.cpp test_alloc_awareness_main.cpp ]
[ run test_basic.cpp test_basic_main.cpp ]
[ run test_capacity.cpp test_capacity_main.cpp ]
[ run test_comparison.cpp test_comparison_main.cpp ]
diff --git a/test/test_all_main.cpp b/test/test_all_main.cpp
index 3eb694c..d453618 100644
--- a/test/test_all_main.cpp
+++ b/test/test_all_main.cpp
@@ -1,6 +1,6 @@
/* Boost.MultiIndex test suite.
*
- * Copyright 2003-2018 Joaquin M Lopez Munoz.
+ * 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)
@@ -9,6 +9,7 @@
*/
#include
+#include "test_alloc_awareness.hpp"
#include "test_basic.hpp"
#include "test_capacity.hpp"
#include "test_comparison.hpp"
@@ -35,6 +36,7 @@
int main()
{
+ test_allocator_awareness();
test_basic();
test_capacity();
test_comparison();
diff --git a/test/test_alloc_awareness.cpp b/test/test_alloc_awareness.cpp
new file mode 100644
index 0000000..1e851fb
--- /dev/null
+++ b/test/test_alloc_awareness.cpp
@@ -0,0 +1,192 @@
+/* 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
+}
diff --git a/test/test_alloc_awareness.hpp b/test/test_alloc_awareness.hpp
new file mode 100644
index 0000000..d659ef5
--- /dev/null
+++ b/test/test_alloc_awareness.hpp
@@ -0,0 +1,11 @@
+/* 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.
+ */
+
+void test_allocator_awareness();
diff --git a/test/test_alloc_awareness_main.cpp b/test/test_alloc_awareness_main.cpp
new file mode 100644
index 0000000..8fed7f9
--- /dev/null
+++ b/test/test_alloc_awareness_main.cpp
@@ -0,0 +1,18 @@
+/* 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
+#include "test_alloc_awareness.hpp"
+
+int main()
+{
+ test_allocator_awareness();
+ return boost::report_errors();
+}