Add improved range insertion to flat associative containers and improve merge operation for vector.

This commit is contained in:
Ion Gaztañaga
2017-12-26 22:04:15 +01:00
parent 3c6f4ea2ed
commit 6ce2b2d0f8
8 changed files with 309 additions and 274 deletions

View File

@@ -1237,6 +1237,8 @@ use [*Boost.Container]? There are several reasons for that:
* ['vector] can now have options, using [classref boost::container::vector_options vector_options].
The growth factor and the stored size type can be specified.
* Improved range insertion in ['flat_[multi]map/set] containers overall complexity is reduced to O(NlogN).
* Fixed bugs:
* [@https://github.com/boostorg/container/pull/64 GitHub #64: ['"Fix splice for slist"]].

View File

@@ -116,6 +116,56 @@ namespace dtl {
BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type)
///////////////////////////////////////
//
// flat_tree_container_inplace_merge
//
///////////////////////////////////////
template<class SequenceContainer, class Compare>
void flat_tree_container_inplace_merge //is_contiguous_container == true
(SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::true_)
{
typedef typename SequenceContainer::value_type value_type;
value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin());
value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
boost::movelib::adaptive_merge(braw, iraw, eraw, comp, eraw, dest.capacity()- dest.size());
}
template<class SequenceContainer, class Compare>
void flat_tree_container_inplace_merge //is_contiguous_container == false
(SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::false_)
{
boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp);
}
///////////////////////////////////////
//
// flat_tree_container_inplace_sort_ending
//
///////////////////////////////////////
template<class SequenceContainer, class Compare>
void flat_tree_container_inplace_sort_ending //is_contiguous_container == true
(SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::true_)
{
typedef typename SequenceContainer::value_type value_type;
value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
boost::movelib::adaptive_sort(iraw, eraw, comp, eraw, dest.capacity()- dest.size());
}
template<class SequenceContainer, class Compare>
void flat_tree_container_inplace_sort_ending //is_contiguous_container == false
(SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::false_)
{
boost::movelib::adaptive_sort(it, dest.end(), comp);
}
///////////////////////////////////////
//
// flat_tree_merge
//
///////////////////////////////////////
template<class SequenceContainer, class Iterator, class Compare>
BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal
(SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_)
@@ -123,43 +173,21 @@ BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal
dest.merge(first, last, comp);
}
template<class SequenceContainer, class Iterator, class Compare>
void aux_flat_tree_merge_equal_non_merge_member //is_contiguous_container == true
(SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_)
{
typedef typename SequenceContainer::iterator iterator;
typedef typename SequenceContainer::value_type value_type;
typedef typename SequenceContainer::size_type size_type;
iterator const it = dest.insert( dest.end(), first, last );
value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin());
value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
value_type *const sraw = boost::movelib::iterator_to_raw_pointer(dest.begin())+dest.size();
size_type const sraw_size = dest.capacity()- dest.size();
boost::movelib::adaptive_sort(iraw, eraw, comp, sraw, sraw_size);
boost::movelib::adaptive_merge(braw, iraw, eraw, comp, sraw, sraw_size);
}
template<class SequenceContainer, class Iterator, class Compare>
void aux_flat_tree_merge_equal_non_merge_member //is_contiguous_container == false
(SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_)
{
typedef typename SequenceContainer::iterator iterator;
iterator const it = dest.insert( dest.end(), first, last );
boost::movelib::adaptive_sort(it, dest.end(), comp);
boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp);
}
template<class SequenceContainer, class Iterator, class Compare>
BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal //has_merge_unique == false
(SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_)
{
(aux_flat_tree_merge_equal_non_merge_member)
( dest, first, last, comp, dtl::bool_<is_contiguous_container<SequenceContainer>::value>());
typedef typename SequenceContainer::iterator iterator;
iterator const it = dest.insert( dest.end(), first, last );
dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag;
(flat_tree_container_inplace_merge)(dest, it, comp, contiguous_tag);
}
///////////////////////////////////////
//
// flat_tree_merge_unique
//
///////////////////////////////////////
template<class SequenceContainer, class Iterator, class Compare>
BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == true
(SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_)
@@ -171,11 +199,22 @@ template<class SequenceContainer, class Iterator, class Compare>
BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == false
(SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_)
{
(flat_tree_merge_equal)(dest, first, last, comp, dtl::false_());
dest.erase(boost::movelib::unique
(dest.begin(), dest.end(), boost::movelib::negate<Compare>(comp)), dest.cend());
typedef typename SequenceContainer::iterator iterator;
typedef typename SequenceContainer::size_type size_type;
size_type const old_sz = dest.size();
iterator const first_new = dest.insert(dest.cend(), first, last );
iterator e = boost::movelib::inplace_set_difference(first_new, dest.end(), dest.begin(), first_new, comp);
dest.erase(e, dest.end());
dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag;
(flat_tree_container_inplace_merge)(dest, dest.begin()+old_sz, comp, contiguous_tag);
}
///////////////////////////////////////
//
// flat_tree_index_of
//
///////////////////////////////////////
template<class SequenceContainer, class Iterator>
BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
flat_tree_index_of // has_index_of == true
@@ -193,6 +232,11 @@ BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
return static_cast<size_type>(p - cont.begin());
}
///////////////////////////////////////
//
// flat_tree_nth
//
///////////////////////////////////////
template<class Iterator, class SequenceContainer>
BOOST_CONTAINER_FORCEINLINE Iterator
flat_tree_nth // has_nth == true
@@ -209,6 +253,11 @@ BOOST_CONTAINER_FORCEINLINE Iterator
return cont.begin()+ n;
}
///////////////////////////////////////
//
// flat_tree_get_stored_allocator
//
///////////////////////////////////////
template<class SequenceContainer>
BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::stored_allocator_type &
flat_tree_get_stored_allocator // has_get_stored_allocator == true
@@ -233,17 +282,39 @@ BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::allocator_type
return cont.get_allocator();
}
///////////////////////////////////////
//
// flat_tree_adopt_sequence_equal
//
///////////////////////////////////////
template<class SequenceContainer, class Compare>
void flat_tree_sort_contiguous_to_adopt // is_contiguous_container == true
(SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp)
{
if(tseq.capacity() >= (seq.capacity() - seq.size())) {
tseq.clear();
boost::movelib::adaptive_sort
(boost::movelib::iterator_to_raw_pointer(seq.begin())
, boost::movelib::iterator_to_raw_pointer(seq.end())
, comp
, boost::movelib::iterator_to_raw_pointer(tseq.begin())
, tseq.capacity());
}
else{
boost::movelib::adaptive_sort
(boost::movelib::iterator_to_raw_pointer(seq.begin())
, boost::movelib::iterator_to_raw_pointer(seq.end())
, comp
, boost::movelib::iterator_to_raw_pointer(seq.end())
, seq.capacity() - seq.size());
}
}
template<class SequenceContainer, class Compare>
void flat_tree_adopt_sequence_equal // is_contiguous_container == true
(SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_)
{
tseq.clear();
boost::movelib::adaptive_sort
(boost::movelib::iterator_to_raw_pointer(seq.begin())
, boost::movelib::iterator_to_raw_pointer(seq.end())
, comp
, boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size())
, tseq.capacity() - tseq.size());
flat_tree_sort_contiguous_to_adopt(tseq, boost::move(seq), comp);
tseq = boost::move(seq);
}
@@ -255,10 +326,16 @@ void flat_tree_adopt_sequence_equal // is_contiguous_container == false
tseq = boost::move(seq);
}
///////////////////////////////////////
//
// flat_tree_adopt_sequence_unique
//
///////////////////////////////////////
template<class SequenceContainer, class Compare>
void flat_tree_adopt_sequence_unique// is_contiguous_container == true
(SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_)
{
tseq.clear();
boost::movelib::adaptive_sort
( boost::movelib::iterator_to_raw_pointer(seq.begin())
, boost::movelib::iterator_to_raw_pointer(seq.end())
@@ -281,6 +358,11 @@ void flat_tree_adopt_sequence_unique// is_contiguous_container == false
tseq = boost::move(seq);
}
///////////////////////////////////////
//
// flat_tree_reserve
//
///////////////////////////////////////
template<class SequenceContainer>
BOOST_CONTAINER_FORCEINLINE void // has_reserve == true
flat_tree_reserve(SequenceContainer &tseq, typename SequenceContainer::size_type cap, dtl::true_)
@@ -294,6 +376,11 @@ BOOST_CONTAINER_FORCEINLINE void // has_reserve == false
{
}
///////////////////////////////////////
//
// flat_tree_capacity
//
///////////////////////////////////////
template<class SequenceContainer> // has_capacity == true
BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type
flat_tree_capacity(const SequenceContainer &tseq, dtl::true_)
@@ -784,108 +871,50 @@ class flat_tree
template <class InIt>
void insert_unique(InIt first, InIt last)
{
for ( ; first != last; ++first){
this->insert_unique(*first);
}
dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
container_type &seq = this->m_data.m_seq;
value_compare &val_cmp = this->priv_value_comp();
//Step 1: put new elements in the back
typename container_type::iterator const it = seq.insert(seq.cend(), first, last);
//Step 2: sort them
(flat_tree_container_inplace_sort_ending)(seq, it, val_cmp, contiguous_tag);
//Step 3: only left unique values from the back not already present in the original range
typename container_type::iterator const e = boost::movelib::inplace_set_unique_difference
(it, seq.end(), seq.begin(), it, val_cmp);
seq.erase(e, seq.cend());
//Step 4: merge both ranges
(flat_tree_container_inplace_merge)(seq, it, this->priv_value_comp(), contiguous_tag);
}
template <class InIt>
void insert_equal(InIt first, InIt last
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
, typename dtl::enable_if_c
< dtl::is_input_iterator<InIt>::value
>::type * = 0
#endif
)
{ this->priv_insert_equal_loop(first, last); }
template <class InIt>
void insert_equal(InIt first, InIt last
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
, typename dtl::enable_if_c
< !dtl::is_input_iterator<InIt>::value
>::type * = 0
#endif
)
void insert_equal(InIt first, InIt last)
{
const size_type len = static_cast<size_type>(boost::container::iterator_distance(first, last));
this->reserve(this->size()+len);
this->priv_insert_equal_loop(first, last);
dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
container_type &seq = this->m_data.m_seq;
typename container_type::iterator const it = seq.insert(seq.cend(), first, last);
(flat_tree_container_inplace_sort_ending)(seq, it, this->priv_value_comp(), contiguous_tag);
(flat_tree_container_inplace_merge) (seq, it, this->priv_value_comp(), contiguous_tag);
}
//Ordered
template <class InIt>
void insert_equal(ordered_range_t, InIt first, InIt last
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
, typename dtl::enable_if_c
< dtl::is_input_iterator<InIt>::value
>::type * = 0
#endif
)
{ this->priv_insert_equal_loop_ordered(first, last); }
template <class FwdIt>
void insert_equal(ordered_range_t, FwdIt first, FwdIt last
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
, typename dtl::enable_if_c
< !dtl::is_input_iterator<FwdIt>::value &&
dtl::is_forward_iterator<FwdIt>::value
>::type * = 0
#endif
)
{
const size_type len = static_cast<size_type>(boost::container::iterator_distance(first, last));
this->reserve(this->size()+len);
this->priv_insert_equal_loop_ordered(first, last);
}
template <class BidirIt>
void insert_equal(ordered_range_t, BidirIt first, BidirIt last
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
, typename dtl::disable_if_or
< void
, dtl::is_input_iterator<BidirIt>
, dtl::is_forward_iterator<BidirIt>
>::type * = 0
#endif
)
void insert_equal(ordered_range_t, InIt first, InIt last)
{
const bool value = boost::container::dtl::
has_member_function_callable_with_merge_unique<container_type, iterator, iterator, value_compare>::value;
has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
(flat_tree_merge_equal)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>());
}
template <class InIt>
void insert_unique(ordered_unique_range_t, InIt first, InIt last
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
, typename dtl::enable_if_or
< void
, dtl::is_input_iterator<InIt>
, dtl::is_forward_iterator<InIt>
>::type * = 0
#endif
)
{
const_iterator pos(this->cend());
for ( ; first != last; ++first){
pos = this->insert_unique(pos, *first);
++pos;
}
}
template <class BidirIt>
void insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
, typename dtl::enable_if_c
< !(dtl::is_input_iterator<BidirIt>::value ||
dtl::is_forward_iterator<BidirIt>::value)
>::type * = 0
#endif
)
void insert_unique(ordered_unique_range_t, InIt first, InIt last)
{
const bool value = boost::container::dtl::
has_member_function_callable_with_merge_unique<container_type, iterator, iterator, value_compare>::value;
has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
(flat_tree_merge_unique)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>());
}
@@ -1287,14 +1316,10 @@ class flat_tree
//for the constructor
//Call end() every iteration as reallocation might have invalidated iterators
if(unique_insertion){
for ( ; first != last; ++first){
this->insert_unique(this->cend(), *first);
}
this->insert_unique(first, last);
}
else{
for ( ; first != last; ++first){
this->insert_equal(this->cend(), *first);
}
this->insert_equal (first, last);
}
}
@@ -1491,27 +1516,6 @@ class flat_tree
}
return std::pair<RanIt, RanIt>(lb, ub);
}
template<class InIt>
void priv_insert_equal_loop(InIt first, InIt last)
{
for ( ; first != last; ++first){
this->insert_equal(*first);
}
}
template<class InIt>
void priv_insert_equal_loop_ordered(InIt first, InIt last)
{
const_iterator pos(this->cend());
for ( ; first != last; ++first){
//If ordered, then try hint version
//to achieve constant-time complexity per insertion
//in some cases
pos = this->insert_equal(pos, *first);
++pos;
}
}
};
} //namespace dtl {

View File

@@ -22,6 +22,7 @@
#endif
#include <boost/intrusive/detail/iterator.hpp>
#include <boost/move/utility_core.hpp>
namespace boost {
namespace container {
@@ -34,6 +35,35 @@ using ::boost::intrusive::iterator_enable_if_tag;
using ::boost::intrusive::iterator_disable_if_tag;
using ::boost::intrusive::iterator_arrow_result;
template <class Container>
class back_emplacer
{
private:
Container& container;
public:
typedef std::output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
back_emplacer(Container& x)
: container(x)
{}
template<class U>
back_emplacer& operator=(BOOST_FWD_REF(U) value)
{
container.emplace_back(boost::forward<U>(value));
return *this;
}
back_emplacer& operator*() { return *this; }
back_emplacer& operator++() { return *this; }
back_emplacer& operator++(int){ return *this; }
};
} //namespace container {
} //namespace boost {

View File

@@ -1113,8 +1113,7 @@ class flat_map
//! <b>Effects</b>: inserts each element from the range [first,last) if and only
//! if there is no element with key equivalent to the key of that element.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(size()+N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
@@ -1130,8 +1129,7 @@ class flat_map
//! if there is no element with key equivalent to the key of that element. This
//! function is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
//!
@@ -1144,8 +1142,7 @@ class flat_map
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) if and only
//! if there is no element with key equivalent to the key of that element.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from il.first() to il.end())
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list<value_type> il)
@@ -1161,8 +1158,7 @@ class flat_map
//! if there is no element with key equivalent to the key of that element. This
//! function is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
//!
@@ -2262,8 +2258,7 @@ class flat_multimap
//!
//! <b>Effects</b>: inserts each element from the range [first,last) .
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
@@ -2278,8 +2273,7 @@ class flat_multimap
//! if there is no element with key equivalent to the key of that element. This
//! function is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
//!
@@ -2291,8 +2285,7 @@ class flat_multimap
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) .
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list<value_type> il)
@@ -2307,8 +2300,7 @@ class flat_multimap
//! if there is no element with key equivalent to the key of that element. This
//! function is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
//!

View File

@@ -687,8 +687,7 @@ class flat_set
//! <b>Effects</b>: inserts each element from the range [first,last) if and only
//! if there is no element with key equivalent to the key of that element.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
@@ -702,8 +701,7 @@ class flat_set
//! <b>Effects</b>: inserts each element from the range [first,last) .This function
//! is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
template <class InputIterator>
@@ -714,8 +712,7 @@ class flat_set
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) if and only
//! if there is no element with key equivalent to the key of that element.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from il.begin() to il.end())
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list<value_type> il)
@@ -727,8 +724,7 @@ class flat_set
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) .This function
//! is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from il.begin() to il.end())
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
BOOST_CONTAINER_FORCEINLINE void insert(ordered_unique_range_t, std::initializer_list<value_type> il)
@@ -1456,8 +1452,7 @@ class flat_multiset
//!
//! <b>Effects</b>: inserts each element from the range [first,last) .
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
@@ -1470,8 +1465,7 @@ class flat_multiset
//! <b>Effects</b>: inserts each element from the range [first,last) .This function
//! is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
template <class InputIterator>
@@ -1481,8 +1475,7 @@ class flat_multiset
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()).
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from first to last)
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: N log(N).
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list<value_type> il)
@@ -1493,8 +1486,7 @@ class flat_multiset
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()). This function
//! is more efficient than the normal range creation for ordered ranges.
//!
//! <b>Complexity</b>: At most N log(size()+N) (N is the distance from il.begin() to il.end())
//! search time plus N*size() insertion time.
//! <b>Complexity</b>: Linear.
//!
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
BOOST_CONTAINER_FORCEINLINE void insert(ordered_range_t, std::initializer_list<value_type> il)

View File

@@ -60,6 +60,7 @@
#include <boost/move/algo/adaptive_merge.hpp>
#include <boost/move/algo/unique.hpp>
#include <boost/move/algo/predicate.hpp>
#include <boost/move/algo/detail/set_difference.hpp>
// other
#include <boost/core/no_exceptions_support.hpp>
#include <boost/assert.hpp>
@@ -75,6 +76,7 @@ namespace container {
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
template <class Pointer, bool IsConst>
class vec_iterator
{
@@ -210,40 +212,6 @@ struct vector_insert_ordered_cursor
BiDirValueIt last_value_it;
};
template<class T, class SizeType, class BiDirValueIt, class Comp>
struct vector_merge_cursor
{
typedef SizeType size_type;
typedef typename iterator_traits<BiDirValueIt>::reference reference;
BOOST_CONTAINER_FORCEINLINE vector_merge_cursor(T *pbeg, T *plast, BiDirValueIt valueit, Comp &cmp)
: m_pbeg(pbeg), m_pcur(--plast), m_valueit(valueit), m_cmp(cmp)
{}
void operator --()
{
--m_valueit;
const T &t = *m_valueit;
while((m_pcur + 1) != m_pbeg){
if(!m_cmp(t, *m_pcur)){
break;
}
--m_pcur;
}
}
BOOST_CONTAINER_FORCEINLINE size_type get_pos() const
{ return static_cast<size_type>((m_pcur + 1) - m_pbeg); }
BOOST_CONTAINER_FORCEINLINE reference get_val()
{ return *m_valueit; }
T *const m_pbeg;
T *m_pcur;
BiDirValueIt m_valueit;
Comp &m_cmp;
};
struct initial_capacity_t{};
template<class Pointer, bool IsConst>
@@ -508,10 +476,14 @@ struct vector_alloc_holder
BOOST_CONTAINER_FORCEINLINE const Allocator &alloc() const BOOST_NOEXCEPT_OR_NOTHROW
{ return *this; }
const pointer &start() const BOOST_NOEXCEPT_OR_NOTHROW { return m_start; }
size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return m_capacity; }
void start(const pointer &p) BOOST_NOEXCEPT_OR_NOTHROW { m_start = p; }
void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT( c <= stored_size_type(-1)); m_capacity = c; }
BOOST_CONTAINER_FORCEINLINE const pointer &start() const BOOST_NOEXCEPT_OR_NOTHROW
{ return m_start; }
BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW
{ return m_capacity; }
BOOST_CONTAINER_FORCEINLINE void start(const pointer &p) BOOST_NOEXCEPT_OR_NOTHROW
{ m_start = p; }
BOOST_CONTAINER_FORCEINLINE void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW
{ BOOST_ASSERT( c <= stored_size_type(-1)); m_capacity = c; }
private:
void priv_first_allocation(size_type cap)
@@ -2191,21 +2163,45 @@ class vector
return this->priv_insert_ordered_at(element_count, inserter_t(last_position_it, last_value_it));
}
template<class BidirIt>
BOOST_CONTAINER_FORCEINLINE void merge(BidirIt first, BidirIt last)
template<class InputIt>
BOOST_CONTAINER_FORCEINLINE void merge(InputIt first, InputIt last)
{ this->merge(first, last, value_less_t()); }
template<class BidirIt, class Compare>
BOOST_CONTAINER_FORCEINLINE void merge(BidirIt first, BidirIt last, Compare comp)
{ this->priv_merge(dtl::false_type(), first, last, comp); }
template<class InputIt, class Compare>
BOOST_CONTAINER_FORCEINLINE void merge(InputIt first, InputIt last, Compare comp)
{
size_type const s = this->size();
size_type const c = this->capacity();
size_type n = 0;
size_type const free_cap = c - s;
//If not input iterator and new elements don't fit in the remaining capacity, merge in new buffer
if(!dtl::is_input_iterator<InputIt>::value &&
free_cap < (n = static_cast<size_type>(boost::container::iterator_distance(first, last)))){
this->priv_merge_in_new_buffer(first, n, comp, alloc_version());
}
else{
iterator pos(this->insert(this->cend(), first, last));
T *const raw_beg = this->priv_raw_begin();
T *const raw_end = this->priv_raw_end();
T *const raw_pos = raw_beg + s;
boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, free_cap - n);
}
}
template<class BidirIt>
BOOST_CONTAINER_FORCEINLINE void merge_unique(BidirIt first, BidirIt last)
{ this->priv_merge(dtl::true_type(), first, last, value_less_t()); }
template<class InputIt>
BOOST_CONTAINER_FORCEINLINE void merge_unique(InputIt first, InputIt last)
{ this->merge_unique(first, last, value_less_t()); }
template<class BidirIt, class Compare>
BOOST_CONTAINER_FORCEINLINE void merge_unique(BidirIt first, BidirIt last, Compare comp)
{ this->priv_merge(dtl::true_type(), first, last, comp); }
template<class InputIt, class Compare>
BOOST_CONTAINER_FORCEINLINE void merge_unique(InputIt first, InputIt last, Compare comp)
{
size_type const s = this->size();
this->priv_set_difference_back(first, last, comp);
T *const raw_beg = this->priv_raw_begin();
T *const raw_end = this->priv_raw_end();
T *raw_pos = raw_beg + s;
boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, this->capacity() - this->size());
}
private:
template<class PositionValue>
@@ -2265,43 +2261,48 @@ class vector
}
}
template<class UniqueBool, class BidirIt, class Compare>
void priv_merge(UniqueBool, BidirIt first, BidirIt last, Compare comp)
template<class InputIt, class Compare>
void priv_set_difference_back(InputIt first1, InputIt last1, Compare comp)
{
size_type const n = static_cast<size_type>(boost::container::iterator_distance(first, last));
size_type const s = this->size();
if(BOOST_LIKELY(s)){
size_type const c = this->capacity();
size_type const free_c = (c - s);
//Use a new buffer if current one is too small for new elements
if(free_c < n){
this->priv_merge_in_new_buffer(UniqueBool(), first, n, comp, alloc_version());
T * old_first2 = this->priv_raw_begin();
T * first2 = old_first2;
T * last2 = this->priv_raw_end();
while (first1 != last1) {
if (first2 == last2){
this->insert(this->cend(), first1, last1);
return;
}
else{
T *raw_pos = boost::movelib::iterator_to_raw_pointer(this->insert(this->cend(), first, last));
T *raw_beg = this->priv_raw_begin();
T *raw_end = this->priv_raw_end();
boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, free_c - n);
if(UniqueBool::value){
size_type const count =
static_cast<size_type>(raw_end - boost::movelib::unique(raw_beg, raw_end, boost::movelib::negate<Compare>(comp)));
this->priv_destroy_last_n(count);
if (comp(*first1, *first2)) {
this->emplace_back(*first1);
//Reallocation happened, update range
T * const raw_begin = this->priv_raw_begin();
if(old_first2 != raw_begin){
first2 = raw_begin + (first2 - old_first2);
last2 = first2 + (last2 - old_first2);
old_first2 = raw_begin;
}
++first1;
}
else {
if (!comp(*first2, *first1)) {
++first1;
}
++first2;
}
}
else{
this->insert(this->cend(), n, first, last);
}
}
template<class UniqueBool, class FwdIt, class Compare>
BOOST_CONTAINER_FORCEINLINE void priv_merge_in_new_buffer(UniqueBool, FwdIt, size_type, Compare, version_0)
template<class FwdIt, class Compare>
BOOST_CONTAINER_FORCEINLINE void priv_merge_in_new_buffer(FwdIt, size_type, Compare, version_0)
{
throw_bad_alloc();
}
template<class UniqueBool, class FwdIt, class Compare, class Version>
void priv_merge_in_new_buffer(UniqueBool, FwdIt first, size_type n, Compare comp, Version)
template<class FwdIt, class Compare, class Version>
void priv_merge_in_new_buffer(FwdIt first, size_type n, Compare comp, Version)
{
size_type const new_size = this->size() + n;
size_type new_cap = new_size;
@@ -2335,11 +2336,6 @@ class vector
--n;
++d_first;
}
else if(UniqueBool::value && !comp(*pbeg, *first)){
++first;
--n;
--added;
}
else{
allocator_traits_type::construct( this->m_holder.alloc(), d_first, boost::move(*pbeg) );
new_values_destroyer.increment_size(1u);

View File

@@ -316,6 +316,25 @@ bool flat_tree_ordered_insertion_test()
int_set4.insert(int_even_set.begin(), int_even_set.end());
if(!CheckEqualContainers(int_set4, fset))
return false;
//add even/odd values with not enough capacity
flat_set<int>().swap(fset);
int_set4.clear();
int_set.clear();
fset.reserve(int_even_set.size());
fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end());
int_set4.insert(int_even_set.begin(), int_even_set.end());
for(std::size_t i = 0; i < NumElements*2; i+=2){
int_set.insert(static_cast<int>(i));
int_set.insert(static_cast<int>(i+1));
}
fset.insert(ordered_unique_range, int_set.begin(), int_set.end());
int_set4.insert(int_set.begin(), int_set.end());
if(!CheckEqualContainers(int_set4, fset))
return false;
}
return true;

View File

@@ -388,12 +388,12 @@ int set_test ()
boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50));
stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(aux_vect3 + 50));
stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
if(!CheckEqualContainers(boostset, stdset)){
std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect[0])..." << std::endl;
std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect3[0])..." << std::endl;
return 1;
}
boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(aux_vect3 + 50));
stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
if(!CheckEqualContainers(boostmultiset, stdmultiset)){
std::cout << "Error in boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), ..." << std::endl;
return 1;
@@ -447,14 +447,14 @@ int set_test ()
boostset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + 50));
stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
boostmultiset.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(&aux_vect4[0] + 50));
boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(&aux_vect5[0] + 50));
stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
if(!CheckEqualContainers(boostset, stdset)){
std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect3[0])..." << std::endl;
return 1;
}
boostmultiset.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(&aux_vect4[0] + 50));
boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(&aux_vect5[0] + 50));
stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50);
if(!CheckEqualContainers(boostmultiset, stdmultiset)){
std::cout << "Error in boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0])..." << std::endl;
return 1;
@@ -462,12 +462,12 @@ int set_test ()
boostset.erase(*boostset.begin());
stdset.erase(*stdset.begin());
boostmultiset.erase(*boostmultiset.begin());
stdmultiset.erase(*stdmultiset.begin());
if(!CheckEqualContainers(boostset, stdset)){
std::cout << "Error in boostset.erase(*boostset.begin())" << std::endl;
return 1;
}
boostmultiset.erase(*boostmultiset.begin());
stdmultiset.erase(*stdmultiset.begin());
if(!CheckEqualContainers(boostmultiset, stdmultiset)){
std::cout << "Error in boostmultiset.erase(*boostmultiset.begin())" << std::endl;
return 1;