added partial merge functionality to key-based indices

plus fixed a compile-time error with legacy splice code when applied to different-type indices
This commit is contained in:
joaquintides 2021-08-10 19:24:48 +02:00
parent 4d15bf41fa
commit dc480499a2
6 changed files with 359 additions and 74 deletions

View File

@ -331,9 +331,6 @@ protected:
void final_delete_all_nodes_(){final().delete_all_nodes_();}
void final_clear_(){final().clear_();}
template<typename Index>
void final_transfer_range_(Index& x)
{final_transfer_range_(x,x.begin(),x.end());}
template<typename Index>
void final_transfer_range_(
Index& x,

View File

@ -238,11 +238,9 @@ protected:
typedef typename call_traits<
key_type>::param_type key_param_type;
/* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
* expansion.
*/
/* needed to avoid commas in some macros */
typedef std::pair<iterator,bool> emplace_return_type;
typedef std::pair<iterator,bool> pair_return_type;
public:
@ -305,7 +303,7 @@ public:
/* modifiers */
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
emplace_return_type,emplace,emplace_impl)
pair_return_type,emplace,emplace_impl)
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
iterator,emplace_hint,emplace_hint_impl,iterator,position)
@ -540,17 +538,69 @@ public:
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
merge(Index& x)
{
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
if(x.end().get_node()!=this->header()){ /* different containers */
this->final_transfer_range_(x);
}
merge(x,x.begin(),x.end());
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
merge(BOOST_RV_REF(Index) x){merge(static_cast<Index&>(x));}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
ordered_index_impl,Index,pair_return_type)
merge(Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(i);
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x);
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
if(x.end().get_node()==this->header()){ /* same container */
return std::pair<iterator,bool>(
make_iterator(static_cast<final_node_type*>(i.get_node())),true);
}
else{
std::pair<final_node_type*,bool> p=this->final_transfer_(
x,static_cast<final_node_type*>(i.get_node()));
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
}
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
ordered_index_impl,Index,pair_return_type)
merge(BOOST_RV_REF(Index) x,BOOST_DEDUCED_TYPENAME Index::iterator i)
{
return merge(static_cast<Index&>(x),i);
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
merge(
Index& x,
BOOST_DEDUCED_TYPENAME Index::iterator first,
BOOST_DEDUCED_TYPENAME Index::iterator last)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,x);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x);
BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
if(x.end().get_node()!=this->header()){ /* different containers */
this->final_transfer_range_(x,first,last);
}
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
merge(
BOOST_RV_REF(Index) x,
BOOST_DEDUCED_TYPENAME Index::iterator first,
BOOST_DEDUCED_TYPENAME Index::iterator last)
{
merge(static_cast<Index&>(x),first,last);
}
/* observers */
key_from_value key_extractor()const{return key;}

View File

@ -206,11 +206,9 @@ private:
typedef typename call_traits<
key_type>::param_type key_param_type;
/* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
* expansion.
*/
/* needed to avoid commas in some macros */
typedef std::pair<iterator,bool> emplace_return_type;
typedef std::pair<iterator,bool> pair_return_type;
public:
@ -280,7 +278,7 @@ public:
/* modifiers */
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
emplace_return_type,emplace,emplace_impl)
pair_return_type,emplace,emplace_impl)
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
iterator,emplace_hint,emplace_hint_impl,iterator,position)
@ -519,17 +517,67 @@ public:
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
merge(Index& x)
{
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
if(x.end().get_node()!=this->header()){ /* different containers */
this->final_transfer_range_(x);
}
merge(x,x.begin(),x.end());
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
merge(BOOST_RV_REF(Index) x){merge(static_cast<Index&>(x));}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,pair_return_type)
merge(Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(i);
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x);
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
if(x.end().get_node()==this->header()){ /* same container */
return std::pair<iterator,bool>(
make_iterator(static_cast<final_node_type*>(i.get_node())),true);
}
else{
std::pair<final_node_type*,bool> p=this->final_transfer_(
x,static_cast<final_node_type*>(i.get_node()));
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
}
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,pair_return_type)
merge(BOOST_RV_REF(Index) x,BOOST_DEDUCED_TYPENAME Index::iterator i)
{
return merge(static_cast<Index&>(x),i);
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
merge(
Index& x,
BOOST_DEDUCED_TYPENAME Index::iterator first,
BOOST_DEDUCED_TYPENAME Index::iterator last)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,x);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x);
BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
if(x.end().get_node()!=this->header()){ /* different containers */
this->final_transfer_range_(x,first,last);
}
}
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
merge(
BOOST_RV_REF(Index) x,
BOOST_DEDUCED_TYPENAME Index::iterator first,
BOOST_DEDUCED_TYPENAME Index::iterator last)
{
merge(static_cast<Index&>(x),first,last);
}
/* observers */
key_from_value key_extractor()const{return key;}

View File

@ -184,7 +184,7 @@ private:
/* needed to avoid commas in some macros */
typedef std::pair<iterator,bool> insertion_return_type;
typedef std::pair<iterator,bool> pair_return_type;
public:
@ -330,7 +330,7 @@ public:
/* modifiers */
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
insertion_return_type,emplace_front,emplace_front_impl)
pair_return_type,emplace_front,emplace_front_impl)
std::pair<iterator,bool> push_front(const value_type& x)
{return insert(begin(),x);}
@ -339,7 +339,7 @@ public:
void pop_front(){erase(begin());}
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
insertion_return_type,emplace_back,emplace_back_impl)
pair_return_type,emplace_back,emplace_back_impl)
std::pair<iterator,bool> push_back(const value_type& x)
{return insert(end(),x);}
@ -348,7 +348,7 @@ public:
void pop_back(){erase(--end());}
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
insertion_return_type,emplace,emplace_impl,iterator,position)
pair_return_type,emplace,emplace_impl,iterator,position)
std::pair<iterator,bool> insert(iterator position,const value_type& x)
{
@ -557,7 +557,7 @@ public:
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
random_access_index,Index,insertion_return_type)
random_access_index,Index,pair_return_type)
splice(
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
{
@ -583,7 +583,7 @@ public:
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
random_access_index,Index,insertion_return_type)
random_access_index,Index,pair_return_type)
splice(
iterator position,BOOST_RV_REF(Index) x,
BOOST_DEDUCED_TYPENAME Index::iterator i)
@ -1121,20 +1121,7 @@ private:
/* backwards compatibility with old, non-transfer-based splice */
std::pair<iterator,bool> p=insert(position,*i);
if(p.second){
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
/* MSVC++ 6.0 optimizer has a hard time with safe mode, and the
* following workaround is needed. Left it for all compilers as it
* does no harm.
*/
i.detach();
x.erase(x.make_iterator(i.get_node()));
#else
x.erase(i);
#endif
}
if(p.second)x.erase(i);
return std::pair<final_node_type*,bool>(
static_cast<final_node_type*>(p.first.get_node()),p.second);
}

View File

@ -170,7 +170,7 @@ private:
/* needed to avoid commas in some macros */
typedef std::pair<iterator,bool> insertion_return_type;
typedef std::pair<iterator,bool> pair_return_type;
public:
@ -292,7 +292,7 @@ public:
/* modifiers */
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
insertion_return_type,emplace_front,emplace_front_impl)
pair_return_type,emplace_front,emplace_front_impl)
std::pair<iterator,bool> push_front(const value_type& x)
{return insert(begin(),x);}
@ -301,7 +301,7 @@ public:
void pop_front(){erase(begin());}
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
insertion_return_type,emplace_back,emplace_back_impl)
pair_return_type,emplace_back,emplace_back_impl)
std::pair<iterator,bool> push_back(const value_type& x)
{return insert(end(),x);}
@ -310,7 +310,7 @@ public:
void pop_back(){erase(--end());}
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
insertion_return_type,emplace,emplace_impl,iterator,position)
pair_return_type,emplace,emplace_impl,iterator,position)
std::pair<iterator,bool> insert(iterator position,const value_type& x)
{
@ -508,7 +508,7 @@ public:
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
sequenced_index,Index,insertion_return_type)
sequenced_index,Index,pair_return_type)
splice(
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
{
@ -534,7 +534,7 @@ public:
template<typename Index>
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
sequenced_index,Index,insertion_return_type)
sequenced_index,Index,pair_return_type)
splice(
iterator position,BOOST_RV_REF(Index) x,
BOOST_DEDUCED_TYPENAME Index::iterator i)
@ -1034,20 +1034,7 @@ private:
/* backwards compatibility with old, non-transfer-based splice */
std::pair<iterator,bool> p=insert(position,*i);
if(p.second){
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
/* MSVC++ 6.0 optimizer has a hard time with safe mode, and the
* following workaround is needed. Left it for all compilers as it
* does no harm.
*/
i.detach();
x.erase(x.make_iterator(i.get_node()));
#else
x.erase(i);
#endif
}
if(p.second)x.erase(i);
return std::pair<final_node_type*,bool>(
static_cast<final_node_type*>(p.first.get_node()),p.second);
}

View File

@ -26,6 +26,7 @@
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
#include "count_allocator.hpp"
@ -454,6 +455,44 @@ void merge(
dst.splice(dst.end(),final_forward<Src>(src));
}
template<typename Dst,typename Src>
std::pair<typename Dst::iterator,bool> merge(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator i,
typename enable_if_key_based<Dst>::type=0)
{
return dst.merge(final_forward<Src>(src),i);
}
template<typename Dst,typename Src>
std::pair<typename Dst::iterator,bool> merge(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator i,
typename enable_if_not_key_based<Dst>::type=0)
{
return dst.splice(dst.end(),final_forward<Src>(src),i);
}
template<typename Dst,typename Src>
void merge(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator first,
typename boost::remove_reference<Src>::type::iterator last,
typename enable_if_key_based<Dst>::type=0)
{
dst.merge(final_forward<Src>(src),first,last);
}
template<typename Dst,typename Src>
void merge(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator first,
typename boost::remove_reference<Src>::type::iterator last,
typename enable_if_not_key_based<Dst>::type=0)
{
dst.splice(dst.end(),final_forward<Src>(src),first,last);
}
template<typename Dst,typename Src>
void test_merge_same(Dst& dst,BOOST_FWD_REF(Src) src)
{
@ -480,27 +519,160 @@ void test_merge_different(Dst& dst,BOOST_FWD_REF(Src) src)
}
merge(dst,boost::forward<Src>(src));
BOOST_TEST(dst.size()+src.size()==n+m);
BOOST_TEST(dst.size()>=n && m>=src.size() && dst.size()-n==m-src.size());
for(std::size_t i=0;i<v.size();++i){
BOOST_TEST(&*(v[i].first)==v[i].second);
}
}
template<typename Dst,typename Src>
void test_merge_same(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator i,
bool key_based=is_key_based<Dst>::value)
{
typedef typename Dst::iterator dst_iterator;
std::size_t n=dst.size();
std::pair<dst_iterator,bool> p=merge(dst,boost::forward<Src>(src),i);
BOOST_TEST(dst.size()==n);
BOOST_TEST(src.size()==n);
BOOST_TEST(&*(p.first)==&*i && p.second);
if(!key_based)BOOST_TEST(boost::next(p.first)==dst.end());
}
template<typename Dst,typename Src>
void test_merge_different(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator i,
bool key_based=is_key_based<Dst>::value)
{
typedef typename Dst::iterator dst_iterator;
std::size_t n=dst.size(),m=src.size();
const typename Dst::value_type* pi=&*i;
std::pair<dst_iterator,bool> p=merge(dst,boost::forward<Src>(src),i);
BOOST_TEST(dst.size()+src.size()==n+m);
BOOST_TEST(p.second?
&*(p.first)==pi:
&*(p.first)!=pi && *(p.first)==*i);
if(!key_based)BOOST_TEST(!p.second || boost::next(p.first)==dst.end());
}
template<typename Dst,typename Src>
void test_merge_same(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator first,
typename boost::remove_reference<Src>::type::iterator last,
bool key_based=is_key_based<Dst>::value)
{
typedef typename Dst::iterator dst_iterator;
typedef typename boost::remove_reference<Src>::
type::iterator src_iterator;
typedef typename boost::remove_reference<Src>::
type::value_type src_value_type;
std::size_t n=dst.size(),d=std::distance(first,last);
std::vector<const src_value_type*> v;
for(src_iterator it=first;it!=last;++it)v.push_back(&*it);
merge(dst,boost::forward<Src>(src),first,last);
BOOST_TEST(dst.size()==n);
BOOST_TEST(src.size()==n);
if(!key_based){
dst_iterator it=boost::next(dst.begin(),dst.size()-d);
for(std::size_t i=0;i<d;++i){
BOOST_TEST(&*it++==v[i]);
}
}
else{
src_iterator it=first;
for(std::size_t i=0;i<d;++i){
BOOST_TEST(&*it++==v[i]);
}
}
}
template<typename Iterator,typename Value>
bool find_address(Iterator first,Iterator last,const Value* x)
{
while(first!=last)if(&*first++==x)return true;
return false;
}
template<typename Dst,typename Src>
void test_merge_different(
Dst& dst,BOOST_FWD_REF(Src) src,
typename boost::remove_reference<Src>::type::iterator first,
typename boost::remove_reference<Src>::type::iterator last,
bool key_based=is_key_based<Dst>::value)
{
typedef typename Dst::iterator dst_iterator;
typedef typename boost::remove_reference<Src>::
type::iterator src_iterator;
typedef typename boost::remove_reference<Src>::
type::value_type src_value_type;
std::size_t n=dst.size(),
m=src.size(),
d=std::distance(first,last);
std::vector<const src_value_type*> v;
for(src_iterator it=first;it!=last;++it)v.push_back(&*it);
merge(dst,boost::forward<Src>(src),first,last);
BOOST_TEST(dst.size()>=n && m>=src.size() && dst.size()-n==m-src.size());
if(!key_based){
for(dst_iterator it=boost::next(dst.begin(),n);it!=dst.end();++it){
BOOST_TEST(std::find(v.begin(),v.end(),&*it)!=v.end());
}
}
for(std::size_t i=0;i<v.size();++i){
BOOST_TEST(
find_address(src.begin(),src.end(),v[i])||
find_address(dst.begin(),dst.end(),v[i]));
}
}
template<int N,int M,typename Dst>
void test_merge_same(Dst& dst)
{
Dst dst1=dst;
test_merge_same(
dst1.template get<N>(),dst1.template get<M>());
test_merge_same(
dst1.template get<N>(),boost::move(dst1.template get<M>()));
const Dst dst1=dst;
{
Dst dst2=dst1;
test_merge_same(
dst2.template get<N>(),dst2.template get<M>());
test_merge_same(
dst2.template get<N>(),boost::move(dst2.template get<M>()));
}
{
Dst dst2=dst1;
test_merge_same(
dst2.template get<N>(),dst2.template get<M>(),
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
test_merge_same(
dst2.template get<N>(),boost::move(dst2.template get<M>()),
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
}
{
Dst dst2=dst1;
test_merge_same(
dst2.template get<N>(),dst2.template get<M>(),
dst2.template get<M>().begin(),
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
test_merge_same(
dst2.template get<N>(),boost::move(dst2.template get<M>()),
dst2.template get<M>().begin(),
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
}
}
template<int N,int M,typename Dst,typename Src>
void test_merge_different(Dst& dst,Src& src)
{
Dst dst1=dst;
Src src1=src;
const Dst dst1=dst;
const Src src1=src;
{
Dst dst2=dst1;
Src src2=src1;
@ -513,6 +685,36 @@ void test_merge_different(Dst& dst,Src& src)
test_merge_different(
dst2.template get<N>(),boost::move(src2.template get<M>()));
}
{
Dst dst2=dst1;
Src src2=src1;
test_merge_different(
dst2.template get<N>(),src2.template get<M>(),
boost::next(src2.template get<M>().begin(),src2.size()/2));
}
{
Dst dst2=dst1;
Src src2=src1;
test_merge_different(
dst2.template get<N>(),boost::move(src2.template get<M>()),
boost::next(src2.template get<M>().begin(),src2.size()/2));
}
{
Dst dst2=dst1;
Src src2=src1;
test_merge_different(
dst2.template get<N>(),src2.template get<M>(),
src2.template get<M>().begin(),
boost::next(src2.template get<M>().begin(),src2.size()/2));
}
{
Dst dst2=dst1;
Src src2=src1;
test_merge_different(
dst2.template get<N>(),boost::move(src2.template get<M>()),
src2.template get<M>().begin(),
boost::next(src2.template get<M>().begin(),src2.size()/2));
}
}
template<int N,int M,typename Dst,typename Src>
@ -528,6 +730,14 @@ void test_merge(Dst& dst,Dst& src)
else test_merge_different<N,M>(dst,src);
}
struct another_int_hash
{
std::size_t operator()(int x)const
{
return boost::hash<int>()(x)*2;
}
};
void test_merge()
{
typedef multi_index_container<
@ -544,8 +754,14 @@ void test_merge()
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >,
hashed_unique<identity<int> >,
ordered_unique<
identity<int>,
std::greater<int>
>,
hashed_unique<
identity<int>,
another_int_hash
>,
random_access<>,
sequenced<>,
ranked_unique<
@ -557,7 +773,7 @@ void test_merge()
container1 c1;
container2 c2;
for(int i=0;i<5;++i){
for(int i=0;i<10;++i){
c1.insert(i);
c2.insert(2*i);
}