Implement C++26 heterogeneous "insert" for set and flat_set. Range insertion functions in flat_tree are renamed to support some older compilers that have problems with SFINAE against the heterogeneous insert overload

This commit is contained in:
Ion Gaztañaga
2025-11-09 21:16:24 +01:00
parent 77699d11e6
commit 5353cfc736
8 changed files with 382 additions and 285 deletions

View File

@@ -885,6 +885,18 @@ class flat_tree
return ret;
}
template<class Convertible>
std::pair<iterator,bool> insert_unique(BOOST_FWD_REF(Convertible) val)
{
std::pair<iterator,bool> ret;
insert_commit_data data;
ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data);
ret.first = ret.second ? this->priv_insert_commit(data, boost::move(val))
: this->begin() + (data.position - this->cbegin());
//: iterator(vector_iterator_get_ptr(data.position));
return ret;
}
iterator insert_equal(const value_type& val)
{
iterator i = this->upper_bound(KeyOfValue()(val));
@@ -919,6 +931,21 @@ class flat_tree
//: iterator(vector_iterator_get_ptr(data.position));
}
template<class K>
inline typename dtl::enable_if_c<
!dtl::is_convertible<K, iterator>::value && //not convertible to iterator
!dtl::is_convertible<K, const_iterator>::value //not convertible to const_iterator
, iterator>::type
insert_unique(const_iterator hint, BOOST_FWD_REF(K) val)
{
BOOST_ASSERT(this->priv_in_range_or_end(hint));
insert_commit_data data;
return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data)
? this->priv_insert_commit(data, boost::move(val))
: this->begin() + (data.position - this->cbegin());
//: iterator(vector_iterator_get_ptr(data.position));
}
iterator insert_equal(const_iterator hint, const value_type& val)
{
BOOST_ASSERT(this->priv_in_range_or_end(hint));
@@ -936,7 +963,7 @@ class flat_tree
}
template <class InIt>
void insert_unique(InIt first, InIt last)
void insert_unique_range(InIt first, InIt last)
{
dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
container_type &seq = this->m_data.m_seq;
@@ -963,7 +990,7 @@ class flat_tree
}
template <class InIt>
void insert_equal(InIt first, InIt last)
void insert_equal_range(InIt first, InIt last)
{
if (first != last) {
dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag;
@@ -977,7 +1004,7 @@ class flat_tree
//Ordered
template <class InIt>
void insert_equal(ordered_range_t, InIt first, InIt last)
void insert_equal_range(ordered_range_t, InIt first, InIt last)
{
const bool value = boost::container::dtl::
has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
@@ -985,7 +1012,7 @@ class flat_tree
}
template <class InIt>
void insert_unique(ordered_unique_range_t, InIt first, InIt last)
void insert_unique_range(ordered_unique_range_t, InIt first, InIt last)
{
const bool value = boost::container::dtl::
has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value;
@@ -1331,15 +1358,15 @@ class flat_tree
template<class C2>
inline void merge_unique(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source)
{
this->insert_unique( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end()));
this->insert_unique_range( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end()));
}
template<class C2>
inline void merge_equal(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source)
{
this->insert_equal( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end()));
this->insert_equal_range( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end()));
}
inline void merge_unique(flat_tree& source)
@@ -1541,10 +1568,10 @@ class flat_tree
//for the constructor
//Call end() every iteration as reallocation might have invalidated iterators
if(unique_insertion){
this->insert_unique(first, last);
this->insert_unique_range(first, last);
}
else{
this->insert_equal (first, last);
this->insert_equal_range(first, last);
}
}
@@ -1645,7 +1672,7 @@ class flat_tree
inline iterator priv_insert_commit
(insert_commit_data &commit_data, BOOST_FWD_REF(Convertible) convertible)
{
return this->m_data.m_seq.insert
return this->m_data.m_seq.emplace
( commit_data.position
, boost::forward<Convertible>(convertible));
}

View File

@@ -813,25 +813,27 @@ class tree
&& boost::container::dtl::is_nothrow_swappable<Compare>::value )
{ AllocHolder::swap(x); }
public:
protected:
typedef typename Icont::insert_commit_data insert_commit_data;
// insert/erase
template <class Comparable>
std::pair<iterator,bool> insert_unique_check
(const key_type& key, insert_commit_data &data)
(const Comparable& key, insert_commit_data &data)
{
std::pair<iiterator, bool> ret =
this->icont().insert_unique_check(key, data);
this->icont().insert_unique_check(key, KeyNodeCompare(key_comp()), data);
return std::pair<iterator, bool>(iterator(ret.first), ret.second);
}
template <class Comparable>
std::pair<iterator,bool> insert_unique_check
(const_iterator hint, const key_type& key, insert_commit_data &data)
(const_iterator hint, const Comparable& key, insert_commit_data &data)
{
BOOST_ASSERT((priv_is_linked)(hint));
std::pair<iiterator, bool> ret =
this->icont().insert_unique_check(hint.get(), key, data);
this->icont().insert_unique_check(hint.get(), key, KeyNodeCompare(key_comp()), data);
return std::pair<iterator, bool>(iterator(ret.first), ret.second);
}
@@ -850,8 +852,9 @@ class tree
std::pair<iterator,bool> insert_unique_convertible(BOOST_FWD_REF(MovableConvertible) v)
{
insert_commit_data data;
const typename remove_cvref<MovableConvertible>::type & k = v; //Support emulated rvalue references
std::pair<iterator,bool> ret =
this->insert_unique_check(key_of_value_t()(v), data);
this->insert_unique_check(key_of_value_t()(k), data);
if(ret.second){
ret.first = this->insert_unique_commit(boost::forward<MovableConvertible>(v), data);
}

View File

@@ -1396,7 +1396,7 @@ class flat_map
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
inline void insert(InputIterator first, InputIterator last)
{ m_flat_tree.insert_unique(first, last); }
{ m_flat_tree.insert_unique_range(first, last); }
//! <b>Requires</b>: first, last are not iterators into *this.
//!
@@ -1414,7 +1414,7 @@ class flat_map
//! <b>Note</b>: Non-standard extension.
template <class InputIterator>
inline void insert(ordered_unique_range_t, InputIterator first, InputIterator last)
{ m_flat_tree.insert_unique(ordered_unique_range, first, last); }
{ m_flat_tree.insert_unique_range(ordered_unique_range, first, last); }
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) if and only
@@ -1425,8 +1425,8 @@ class flat_map
//! <b>Note</b>: If an element is inserted it might invalidate elements.
inline void insert(std::initializer_list<value_type> il)
{
m_flat_tree.insert_unique( dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
m_flat_tree.insert_unique_range( dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
}
//! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate and must be
@@ -1443,9 +1443,9 @@ class flat_map
//! <b>Note</b>: Non-standard extension.
inline void insert(ordered_unique_range_t, std::initializer_list<value_type> il)
{
m_flat_tree.insert_unique(ordered_unique_range
, dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
m_flat_tree.insert_unique_range(ordered_unique_range
, dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
}
#endif
@@ -2794,7 +2794,7 @@ class flat_multimap
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
inline void insert(InputIterator first, InputIterator last)
{ m_flat_tree.insert_equal(first, last); }
{ m_flat_tree.insert_equal_range(first, last); }
//! <b>Requires</b>: first, last are not iterators into *this.
//!
@@ -2811,7 +2811,7 @@ class flat_multimap
//! <b>Note</b>: Non-standard extension.
template <class InputIterator>
inline void insert(ordered_range_t, InputIterator first, InputIterator last)
{ m_flat_tree.insert_equal(ordered_range, first, last); }
{ m_flat_tree.insert_equal_range(ordered_range, first, last); }
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) .
@@ -2821,8 +2821,8 @@ class flat_multimap
//! <b>Note</b>: If an element is inserted it might invalidate elements.
inline void insert(std::initializer_list<value_type> il)
{
m_flat_tree.insert_equal( dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
m_flat_tree.insert_equal_range( dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
}
//! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate.
@@ -2838,9 +2838,9 @@ class flat_multimap
//! <b>Note</b>: Non-standard extension.
inline void insert(ordered_range_t, std::initializer_list<value_type> il)
{
m_flat_tree.insert_equal( ordered_range
, dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
m_flat_tree.insert_equal_range( ordered_range
, dtl::force<impl_initializer_list>(il).begin()
, dtl::force<impl_initializer_list>(il).end());
}
#endif

View File

@@ -638,7 +638,7 @@ class flat_set
#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Inserts x if and only if there is no element in the container
//! with key equivalent to the key of x.
//!
@@ -650,7 +650,8 @@ class flat_set
//! to the elements with bigger keys than x.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
std::pair<iterator, bool> insert(const value_type &x);
std::pair<iterator, bool> insert(const value_type &x)
{ return this->tree_t::insert_unique(x); }
//! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and
//! only if there is no element in the container with key equivalent to the key of x.
@@ -663,15 +664,35 @@ class flat_set
//! to the elements with bigger keys than x.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
std::pair<iterator, bool> insert(value_type &&x);
#else
private:
typedef std::pair<iterator, bool> insert_return_pair;
public:
BOOST_MOVE_CONVERSION_AWARE_CATCH(insert, value_type, insert_return_pair, this->tree_t::insert_unique)
#endif
std::pair<iterator, bool> insert(value_type &&x)
{ return this->tree_t::insert_unique(boost::move(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and
//! only if there is no element in the container with key equivalent to the key of x.
//!
//! <b>Returns</b>: The bool component of the returned pair is true if and only
//! if the insertion takes place, and the iterator component of the pair
//! points to the element with key equivalent to the key of x.
//!
//! <b>Complexity</b>: Logarithmic search time plus linear insertion
//! to the elements with bigger keys than x.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class K>
inline BOOST_CONTAINER_DOC1ST
(std::pair<iterator BOOST_MOVE_I bool>
, typename dtl::enable_if_c<
dtl::is_transparent<key_compare>::value && //transparent
!dtl::is_convertible<K BOOST_MOVE_I iterator>::value && //not convertible to iterator
!dtl::is_convertible<K BOOST_MOVE_I const_iterator>::value //not convertible to const_iterator
BOOST_MOVE_I std::pair<iterator BOOST_MOVE_I bool>
>::type)
insert(K &&x)
{ return this->tree_t::insert_unique(boost::forward<K>(x)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Inserts a copy of x in the container if and only if there is
//! no element in the container with key equivalent to the key of x.
//! p is a hint pointing to where the insert should start to search.
@@ -683,9 +704,11 @@ class flat_set
//! right before p) plus insertion linear to the elements with bigger keys than x.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
iterator insert(const_iterator p, const value_type &x);
iterator insert(const_iterator p, const value_type &x)
{ return this->tree_t::insert_unique(p, x); }
//! <b>Effects</b>: Inserts an element move constructed from x in the container.
//! <b>Effects</b>: Move-inserts x in the container if and only if there is
//! no element in the container with key equivalent to the key of x.
//! p is a hint pointing to where the insert should start to search.
//!
//! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
@@ -694,8 +717,38 @@ class flat_set
//! right before p) plus insertion linear to the elements with bigger keys than x.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
iterator insert(const_iterator p, value_type &&x);
iterator insert(const_iterator p, value_type &&x)
{ return this->tree_t::insert_unique(p, boost::move(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Forward-inserts x in the container if and only if there is
//! no element in the container with key equivalent to the key of x.
//! p is a hint pointing to where the insert should start to search.
//!
//! <b>Returns</b>: An iterator pointing to the element with key equivalent
//! to the key of x.
//!
//! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
//! right before p) plus insertion linear to the elements with bigger keys than x.
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class K>
inline BOOST_CONTAINER_DOC1ST
( iterator
, typename dtl::enable_if_transparent< key_compare
BOOST_MOVE_I K
BOOST_MOVE_I iterator
>::type) //transparent
insert(const_iterator p, K &&x)
{ return this->tree_t::insert_unique(p, boost::forward<K>(x)); }
#else
private:
typedef std::pair<iterator, bool> insert_return_pair;
public:
BOOST_MOVE_CONVERSION_AWARE_CATCH(insert, value_type, insert_return_pair, this->tree_t::insert_unique)
BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, value_type, iterator, this->tree_t::insert_unique, const_iterator, const_iterator)
#endif
@@ -709,7 +762,7 @@ class flat_set
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
inline void insert(InputIterator first, InputIterator last)
{ this->tree_t::insert_unique(first, last); }
{ this->tree_t::insert_unique_range(first, last); }
//! <b>Requires</b>: first, last are not iterators into *this and
//! must be ordered according to the predicate and must be
@@ -723,7 +776,7 @@ class flat_set
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
template <class InputIterator>
inline void insert(ordered_unique_range_t, InputIterator first, InputIterator last)
{ this->tree_t::insert_unique(ordered_unique_range, first, last); }
{ this->tree_t::insert_unique_range(ordered_unique_range, first, last); }
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) if and only
@@ -733,7 +786,7 @@ class flat_set
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
inline void insert(std::initializer_list<value_type> il)
{ this->tree_t::insert_unique(il.begin(), il.end()); }
{ this->tree_t::insert_unique_range(il.begin(), il.end()); }
//! <b>Requires</b>: Range [il.begin(), il.end()) must be ordered according to the predicate
//! and must be unique values.
@@ -745,7 +798,7 @@ class flat_set
//!
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
inline void insert(ordered_unique_range_t, std::initializer_list<value_type> il)
{ this->tree_t::insert_unique(ordered_unique_range, il.begin(), il.end()); }
{ this->tree_t::insert_unique_range(ordered_unique_range, il.begin(), il.end()); }
#endif
//! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, AllocatorOrContainer>&)
@@ -1678,7 +1731,7 @@ class flat_multiset
//! <b>Note</b>: If an element is inserted it might invalidate elements.
template <class InputIterator>
inline void insert(InputIterator first, InputIterator last)
{ this->tree_t::insert_equal(first, last); }
{ this->tree_t::insert_equal_range(first, last); }
//! <b>Requires</b>: first, last are not iterators into *this and
//! must be ordered according to the predicate.
@@ -1691,7 +1744,7 @@ class flat_multiset
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
template <class InputIterator>
inline void insert(ordered_range_t, InputIterator first, InputIterator last)
{ this->tree_t::insert_equal(ordered_range, first, last); }
{ this->tree_t::insert_equal_range(ordered_range, first, last); }
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
//! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()).
@@ -1700,7 +1753,7 @@ class flat_multiset
//!
//! <b>Note</b>: If an element is inserted it might invalidate elements.
inline void insert(std::initializer_list<value_type> il)
{ this->tree_t::insert_equal(il.begin(), il.end()); }
{ this->tree_t::insert_equal_range(il.begin(), il.end()); }
//! <b>Requires</b>: Range [il.begin(), il.end()) must be ordered according to the predicate.
//!
@@ -1711,7 +1764,7 @@ class flat_multiset
//!
//! <b>Note</b>: Non-standard extension. If an element is inserted it might invalidate elements.
inline void insert(ordered_range_t, std::initializer_list<value_type> il)
{ this->tree_t::insert_equal(ordered_range, il.begin(), il.end()); }
{ this->tree_t::insert_equal_range(ordered_range, il.begin(), il.end()); }
#endif
//! @copydoc ::boost::container::flat_multimap::merge(flat_multimap<Key, T, C2, AllocatorOrContainer>&)

View File

@@ -574,7 +574,7 @@ class set
#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Inserts x if and only if there is no element in the container
//! with key equivalent to the key of x.
//!
@@ -583,7 +583,8 @@ class set
//! points to the element with key equivalent to the key of x.
//!
//! <b>Complexity</b>: Logarithmic.
std::pair<iterator, bool> insert(const value_type &x);
std::pair<iterator, bool> insert(const value_type &x)
{ return this->base_t::insert_unique_convertible(x); }
//! <b>Effects</b>: Move constructs a new value from x if and only if there is
//! no element in the container with key equivalent to the key of x.
@@ -593,16 +594,32 @@ class set
//! points to the element with key equivalent to the key of x.
//!
//! <b>Complexity</b>: Logarithmic.
std::pair<iterator, bool> insert(value_type &&x);
#else
private:
typedef std::pair<iterator, bool> insert_return_pair;
public:
BOOST_MOVE_CONVERSION_AWARE_CATCH
(insert, value_type, insert_return_pair, this->base_t::insert_unique_convertible)
#endif
std::pair<iterator, bool> insert(value_type &&x)
{ return this->base_t::insert_unique_convertible(boost::move(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Forward constructs a new value from x if and only if there is
//! no element in the container with key equivalent to the key of x.
//!
//! <b>Returns</b>: The bool component of the returned pair is true if and only
//! if the insertion takes place, and the iterator component of the pair
//! points to the element with key equivalent to the key of x.
//!
//! <b>Complexity</b>: Logarithmic.
template <class K>
inline BOOST_CONTAINER_DOC1ST
(std::pair<iterator BOOST_MOVE_I bool>
, typename dtl::enable_if_c<
dtl::is_transparent<key_compare>::value && //transparent
!dtl::is_convertible<K BOOST_MOVE_I iterator>::value && //not convertible to iterator
!dtl::is_convertible<K BOOST_MOVE_I const_iterator>::value //not convertible to const_iterator
BOOST_MOVE_I std::pair<iterator BOOST_MOVE_I bool>
>::type)
insert(K &&x)
{ return this->base_t::insert_unique_convertible(boost::forward<K>(x)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Inserts a copy of x in the container if and only if there is
//! no element in the container with key equivalent to the key of x.
//! p is a hint pointing to where the insert should start to search.
@@ -612,7 +629,8 @@ class set
//!
//! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
//! is inserted right before p.
iterator insert(const_iterator p, const value_type &x);
iterator insert(const_iterator p, const value_type &x)
{ return this->base_t::insert_unique_hint_convertible(p, x); }
//! <b>Effects</b>: Inserts an element move constructed from x in the container.
//! p is a hint pointing to where the insert should start to search.
@@ -620,8 +638,38 @@ class set
//! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
//!
//! <b>Complexity</b>: Logarithmic.
iterator insert(const_iterator p, value_type &&x);
iterator insert(const_iterator p, value_type &&x)
{ return this->base_t::insert_unique_hint_convertible(p, boost::move(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Inserts an element forward constructed from x in the container.
//! p is a hint pointing to where the insert should start to search.
//!
//! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
//!
//! <b>Complexity</b>: Logarithmic.
template <class K>
inline BOOST_CONTAINER_DOC1ST
( iterator
, typename dtl::enable_if_transparent< key_compare
BOOST_MOVE_I K
BOOST_MOVE_I iterator
>::type) //transparent
insert(const_iterator p, K &&x)
{ return this->base_t::insert_unique_hint_convertible(p, boost::forward<K>(x)); }
#else
private:
typedef std::pair<iterator, bool> insert_return_pair;
public:
BOOST_MOVE_CONVERSION_AWARE_CATCH
(insert, value_type, insert_return_pair, this->base_t::insert_unique_convertible)
BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG
(insert, value_type, iterator, this->base_t::insert_unique_hint_convertible, const_iterator, const_iterator)
#endif

View File

@@ -495,104 +495,6 @@ bool flat_tree_extract_adopt_test()
return true;
}
bool test_heterogeneous_lookups()
{
typedef flat_set<int, test::less_transparent> set_t;
typedef flat_multiset<int, test::less_transparent> mset_t;
set_t set1;
mset_t mset1;
const set_t &cset1 = set1;
const mset_t &cmset1 = mset1;
set1.insert(1);
set1.insert(1);
set1.insert(2);
set1.insert(2);
set1.insert(3);
mset1.insert(1);
mset1.insert(1);
mset1.insert(2);
mset1.insert(2);
mset1.insert(3);
const test::non_copymovable_int find_me(2);
//find
if(*set1.find(find_me) != 2)
return false;
if(*cset1.find(find_me) != 2)
return false;
if(*mset1.find(find_me) != 2)
return false;
if(*cmset1.find(find_me) != 2)
return false;
//count
if(set1.count(find_me) != 1)
return false;
if(cset1.count(find_me) != 1)
return false;
if(mset1.count(find_me) != 2)
return false;
if(cmset1.count(find_me) != 2)
return false;
//contains
if(!set1.contains(find_me))
return false;
if(!cset1.contains(find_me))
return false;
if(!mset1.contains(find_me))
return false;
if(!cmset1.contains(find_me))
return false;
//lower_bound
if(*set1.lower_bound(find_me) != 2)
return false;
if(*cset1.lower_bound(find_me) != 2)
return false;
if(*mset1.lower_bound(find_me) != 2)
return false;
if(*cmset1.lower_bound(find_me) != 2)
return false;
//upper_bound
if(*set1.upper_bound(find_me) != 3)
return false;
if(*cset1.upper_bound(find_me) != 3)
return false;
if(*mset1.upper_bound(find_me) != 3)
return false;
if(*cmset1.upper_bound(find_me) != 3)
return false;
//equal_range
if(*set1.equal_range(find_me).first != 2)
return false;
if(*cset1.equal_range(find_me).second != 3)
return false;
if(*mset1.equal_range(find_me).first != 2)
return false;
if(*cmset1.equal_range(find_me).second != 3)
return false;
//erase
if (set1.erase(find_me) != 1)
return false;
if (set1.erase(find_me) != 0)
return false;
if (mset1.erase(find_me) != 2)
return false;
if (mset1.erase(find_me) != 0)
return false;
return true;
}
// An ordered sequence of std:pair is also ordered by std::pair::first.
struct with_lookup_by_first
{
@@ -765,9 +667,16 @@ int main()
if (!boost::container::test::instantiate_constructors<flat_set<int>, flat_multiset<int> >())
return 1;
if(!test_heterogeneous_lookups()){
if (!test::test_heterogeneous_lookup
< flat_set<int, less_transparent>
, flat_multiset<int, less_transparent>
>())
return 1;
if (!test::test_heterogeneous_insert
< flat_set<test::movable_int, less_transparent>
>())
return 1;
}
if(!test_heterogeneous_lookup_by_partial_key()){
return 1;

View File

@@ -189,6 +189,33 @@ bool node_type_test()
if(dst.size() != 5)
return false;
}
{
typedef set<test::movable_int, test::less_transparent> set_t;
typedef multiset<test::movable_int, test::less_transparent> mset_t;
set_t set1;
mset_t mset1;
//extract
const test::non_copymovable_int extract_me(1);
set1.insert(1);
mset1.emplace(1);
mset1.emplace(1);
//extract
if (!set1.extract(1))
return false;
if (set1.extract(1))
return false;
if (!mset1.extract(1))
return false;
if (!mset1.extract(1))
return false;
if (mset1.extract(1))
return false;
}
return true;
}
@@ -352,127 +379,9 @@ void test_merge_from_different_comparison()
set1.merge(set2);
}
bool test_heterogeneous_lookups()
{
typedef set<int, test::less_transparent> set_t;
typedef multiset<int, test::less_transparent> mset_t;
set_t set1;
mset_t mset1;
const set_t &cset1 = set1;
const mset_t &cmset1 = mset1;
set1.insert(1);
set1.insert(1);
set1.insert(2);
set1.insert(2);
set1.insert(3);
mset1.insert(1);
mset1.insert(1);
mset1.insert(2);
mset1.insert(2);
mset1.insert(3);
const test::non_copymovable_int find_me(2);
//find
if(*set1.find(find_me) != 2)
return false;
if(*cset1.find(find_me) != 2)
return false;
if(*mset1.find(find_me) != 2)
return false;
if(*cmset1.find(find_me) != 2)
return false;
//count
if(set1.count(find_me) != 1)
return false;
if(cset1.count(find_me) != 1)
return false;
if(mset1.count(find_me) != 2)
return false;
if(cmset1.count(find_me) != 2)
return false;
//contains
if(!set1.contains(find_me))
return false;
if(!cset1.contains(find_me))
return false;
if(!mset1.contains(find_me))
return false;
if(!cmset1.contains(find_me))
return false;
//lower_bound
if(*set1.lower_bound(find_me) != 2)
return false;
if(*cset1.lower_bound(find_me) != 2)
return false;
if(*mset1.lower_bound(find_me) != 2)
return false;
if(*cmset1.lower_bound(find_me) != 2)
return false;
//upper_bound
if(*set1.upper_bound(find_me) != 3)
return false;
if(*cset1.upper_bound(find_me) != 3)
return false;
if(*mset1.upper_bound(find_me) != 3)
return false;
if(*cmset1.upper_bound(find_me) != 3)
return false;
//equal_range
if(*set1.equal_range(find_me).first != 2)
return false;
if(*cset1.equal_range(find_me).second != 3)
return false;
if(*mset1.equal_range(find_me).first != 2)
return false;
if(*cmset1.equal_range(find_me).second != 3)
return false;
//erase
if (set1.erase(find_me) != 1)
return false;
if (set1.erase(find_me) != 0)
return false;
if (mset1.erase(find_me) != 2)
return false;
if (mset1.erase(find_me) != 0)
return false;
//extract
set1.clear();
set1.insert(1);
mset1.clear();
mset1.insert(1);
mset1.insert(1);
const test::non_copymovable_int extract_me(1);
if (!set1.extract(extract_me))
return false;
if (set1.extract(extract_me))
return false;
if (!mset1.extract(extract_me))
return false;
if (!mset1.extract(extract_me))
return false;
if (mset1.extract(extract_me))
return false;
return true;
}
int main ()
{
using namespace boost::container::test;
//Recursive container instantiation
{
set<recursive_set> set_;
@@ -509,7 +418,15 @@ int main ()
return 1;
}
if(!test_heterogeneous_lookups())
if (!test::test_heterogeneous_lookup
< set<int, less_transparent>
, multiset<int, less_transparent>
>())
return 1;
if (!test::test_heterogeneous_insert
< set<test::movable_int, less_transparent>
>())
return 1;
////////////////////////////////////

View File

@@ -1002,6 +1002,146 @@ bool instantiate_constructors()
return true;
}
template<typename IntSetType, typename IntMultisetType>
bool test_heterogeneous_lookup()
{
typedef IntSetType set_t;
typedef IntMultisetType mset_t;
set_t set1;
mset_t mset1;
const set_t &cset1 = set1;
const mset_t &cmset1 = mset1;
set1.insert(1);
set1.insert(1);
set1.insert(2);
set1.insert(2);
set1.insert(3);
mset1.insert(1);
mset1.insert(1);
mset1.insert(2);
mset1.insert(2);
mset1.insert(3);
const test::non_copymovable_int find_me(2);
//find
if(*set1.find(find_me) != 2)
return false;
if(*cset1.find(find_me) != 2)
return false;
if(*mset1.find(find_me) != 2)
return false;
if(*cmset1.find(find_me) != 2)
return false;
//count
if(set1.count(find_me) != 1)
return false;
if(cset1.count(find_me) != 1)
return false;
if(mset1.count(find_me) != 2)
return false;
if(cmset1.count(find_me) != 2)
return false;
//contains
if(!set1.contains(find_me))
return false;
if(!cset1.contains(find_me))
return false;
if(!mset1.contains(find_me))
return false;
if(!cmset1.contains(find_me))
return false;
//lower_bound
if(*set1.lower_bound(find_me) != 2)
return false;
if(*cset1.lower_bound(find_me) != 2)
return false;
if(*mset1.lower_bound(find_me) != 2)
return false;
if(*cmset1.lower_bound(find_me) != 2)
return false;
//upper_bound
if(*set1.upper_bound(find_me) != 3)
return false;
if(*cset1.upper_bound(find_me) != 3)
return false;
if(*mset1.upper_bound(find_me) != 3)
return false;
if(*cmset1.upper_bound(find_me) != 3)
return false;
//equal_range
if(*set1.equal_range(find_me).first != 2)
return false;
if(*cset1.equal_range(find_me).second != 3)
return false;
if(*mset1.equal_range(find_me).first != 2)
return false;
if(*cmset1.equal_range(find_me).second != 3)
return false;
//erase
if (set1.erase(find_me) != 1)
return false;
if (set1.erase(find_me) != 0)
return false;
if (mset1.erase(find_me) != 2)
return false;
if (mset1.erase(find_me) != 0)
return false;
return true;
}
template<typename MovableIntSetType>
bool test_heterogeneous_insert()
{
typedef MovableIntSetType set_t;
set_t set1;
const set_t &cset1 = set1;
//insert
if(!set1.insert(1).second)
return false;
if (cset1.find(1) == cset1.end())
return false;
if(set1.insert(1).second)
return false;
if (cset1.find(1) == cset1.end())
return false;
//insert with hint
if(set1.find(2) != set1.end())
return false;
typename set_t::iterator i = set1.insert(set1.begin(), 2);
if(i != set1.insert(set1.end(), 2))
return false;
if (cset1.find(2) == cset1.end())
return false;
return true;
}
} //namespace test{
} //namespace container {
} //namespace boost{