* Implemented merge operations for associative containers.

* Update tree-based containers to changes done in Intrusive internal utilities in order to fix Trac 12432.
This commit is contained in:
Ion Gaztañaga
2016-09-03 00:03:42 +02:00
parent 0617d0e538
commit f540b83ccd
13 changed files with 722 additions and 172 deletions

View File

@@ -1231,10 +1231,11 @@ use [*Boost.Container]? There are several reasons for that:
* [@https://svn.boost.org/trac/boost/ticket/12319 Trac #12319: ['"flat_set` should be nothrow move constructible"]].
* Revised noexcept expressions of default and move constructors in all containers.
* Implemented C++17 `insert_or_assign`/`try_emplace` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map].
* Implemented C++17 `extract`/`insert(node)` for [classref boost::container::map map], [classref boost::container::multimap multimap],
* Implemented C++17's `insert_or_assign`/`try_emplace` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map].
* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0083r3.pdf ['Splicing Maps and Sets (Revision 5)]]
Splicing Maps and Sets (Revision 5) for [classref boost::container::map map], [classref boost::container::multimap multimap],
[classref boost::container::set set], [classref boost::container::multiset multiset].
* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf P0084R2 Emplace Return Type]
* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf ['P0084R2 Emplace Return Type]]
in `deque`, `vector`, `stable_vector`, `small_vector`, `static_vector`, `list` and `slist`.
[endsect]

View File

@@ -46,6 +46,7 @@
#endif
#include <boost/intrusive/detail/minimal_pair_header.hpp> //pair
#include <boost/move/iterator.hpp>
namespace boost {
namespace container {
@@ -100,7 +101,7 @@ struct get_flat_tree_iterators
typedef boost::container::reverse_iterator<const_iterator> const_reverse_iterator;
};
template <class Key, class Value, class KeyOfValue,
template <class Value, class KeyOfValue,
class Compare, class Allocator>
class flat_tree
{
@@ -185,7 +186,7 @@ class flat_tree
typedef typename vector_t::const_pointer const_pointer;
typedef typename vector_t::reference reference;
typedef typename vector_t::const_reference const_reference;
typedef Key key_type;
typedef typename KeyOfValue::type key_type;
typedef Compare key_compare;
typedef typename vector_t::allocator_type allocator_type;
typedef typename vector_t::size_type size_type;
@@ -778,6 +779,36 @@ class flat_tree
return n;
}
template<class C2>
void merge_unique(flat_tree<Value, KeyOfValue, C2, Allocator>& source)
{
this->insert( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end()));
}
template<class C2>
void merge_equal(flat_tree<Value, KeyOfValue, C2, Allocator>& source)
{
this->insert( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end()));
}
void merge_unique(flat_tree& source)
{
this->m_data.m_vect.merge_unique
( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end())
, static_cast<const value_compare &>(this->m_data));
}
void merge_equal(flat_tree& source)
{
this->m_data.m_vect.merge
( boost::make_move_iterator(source.begin())
, boost::make_move_iterator(source.end())
, static_cast<const value_compare &>(this->m_data));
}
BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k)
{ return this->priv_lower_bound(this->begin(), this->end(), k); }
@@ -1062,9 +1093,9 @@ class flat_tree
//!has_trivial_destructor_after_move<> == true_type
//!specialization for optimizations
template <class Key, class T, class KeyOfValue,
template <class T, class KeyOfValue,
class Compare, class Allocator>
struct has_trivial_destructor_after_move<boost::container::container_detail::flat_tree<Key, T, KeyOfValue, Compare, Allocator> >
struct has_trivial_destructor_after_move<boost::container::container_detail::flat_tree<T, KeyOfValue, Compare, Allocator> >
{
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value &&

View File

@@ -394,12 +394,6 @@ struct node_alloc_holder
ICont &non_const_icont() const
{ return const_cast<ICont&>(this->members_.m_icont); }
ICont &icont()
{ return this->members_.m_icont; }
const ICont &icont() const
{ return this->members_.m_icont; }
NodeAlloc &node_alloc()
{ return static_cast<NodeAlloc &>(this->members_); }
@@ -407,6 +401,13 @@ struct node_alloc_holder
{ return static_cast<const NodeAlloc &>(this->members_); }
members_holder members_;
public:
ICont &icont()
{ return this->members_.m_icont; }
const ICont &icont() const
{ return this->members_.m_icont; }
};
} //namespace container_detail {

View File

@@ -429,26 +429,28 @@ struct key_node_compare
{ return this->key_comp()(key_of_value()(nonkey1.get_data()), key_of_value()(nonkey2.get_data())); }
};
template <class Key, class T, class KeyOfValue,
template <class T, class KeyOfValue,
class Compare, class Allocator,
class Options = tree_assoc_defaults>
class tree
: protected container_detail::node_alloc_holder
: public container_detail::node_alloc_holder
< Allocator
, typename container_detail::intrusive_tree_type
< Allocator, tree_value_compare<Compare, KeyOfValue> //ValComp
< Allocator, tree_value_compare
<typename allocator_traits<Allocator>::pointer, Compare, KeyOfValue>
, Options::tree_type, Options::optimize_size>::type
>
{
typedef tree_value_compare
<Compare, KeyOfValue> ValComp;
< typename allocator_traits<Allocator>::pointer
, Compare, KeyOfValue> ValComp;
typedef typename container_detail::intrusive_tree_type
< Allocator, ValComp, Options::tree_type
, Options::optimize_size>::type Icont;
typedef container_detail::node_alloc_holder
<Allocator, Icont> AllocHolder;
typedef typename AllocHolder::NodePtr NodePtr;
typedef tree < Key, T, KeyOfValue
typedef tree < T, KeyOfValue
, Compare, Allocator, Options> ThisType;
typedef typename AllocHolder::NodeAlloc NodeAlloc;
typedef boost::container::
@@ -465,7 +467,7 @@ class tree
public:
typedef Key key_type;
typedef typename KeyOfValue::type key_type;
typedef T value_type;
typedef Allocator allocator_type;
typedef Compare key_compare;
@@ -1176,6 +1178,13 @@ class tree
}
}
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge_unique(tree<T, KeyOfValue, C2, Allocator, Options>& source)
{ return this->icont().merge_unique(source.icont()); }
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge_equal(tree<T, KeyOfValue, C2, Allocator, Options>& source)
{ return this->icont().merge_equal(source.icont()); }
BOOST_CONTAINER_FORCEINLINE void clear()
{ AllocHolder::clear(alloc_version()); }
@@ -1265,11 +1274,11 @@ struct has_trivial_destructor_after_move;
//!has_trivial_destructor_after_move<> == true_type
//!specialization for optimizations
template <class Key, class T, class KeyOfValue, class Compare, class Allocator, class Options>
template <class T, class KeyOfValue, class Compare, class Allocator, class Options>
struct has_trivial_destructor_after_move
<
::boost::container::container_detail::tree
<Key, T, KeyOfValue, Compare, Allocator, Options>
<T, KeyOfValue, Compare, Allocator, Options>
>
{
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;

View File

@@ -53,6 +53,9 @@ namespace container {
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
template <class Key, class T, class Compare, class Allocator>
class flat_multimap;
namespace container_detail{
template<class D, class S>
@@ -110,14 +113,14 @@ class flat_map
private:
BOOST_COPYABLE_AND_MOVABLE(flat_map)
//This is the tree that we should store if pair was movable
typedef container_detail::flat_tree<Key,
typedef container_detail::flat_tree<
std::pair<Key, T>,
container_detail::select1st<Key>,
Compare,
Allocator> tree_t;
//This is the real tree stored here. It's based on a movable pair
typedef container_detail::flat_tree<Key,
typedef container_detail::flat_tree<
container_detail::pair<Key, T>,
container_detail::select1st<Key>,
Compare,
@@ -143,6 +146,13 @@ class flat_map
<typename allocator_traits<Allocator>::pointer>::const_reverse_iterator const_reverse_iterator_impl;
public:
typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type;
impl_tree_t &tree()
{ return m_flat_tree; }
const impl_tree_t &tree() const
{ return m_flat_tree; }
private:
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -1056,6 +1066,39 @@ class flat_map
{ m_flat_tree.insert_unique(ordered_unique_range, il.begin(), il.end()); }
#endif
//! <b>Requires</b>: this->get_allocator() == source.get_allocator().
//!
//! <b>Effects</b>: Attempts to extract each element in source and insert it into a using
//! the comparison object of *this. If there is an element in a with key equivalent to the
//! key of an element from source, then that element is not extracted from source.
//!
//! <b>Postcondition</b>: Pointers and references to the transferred elements of source refer
//! to those same elements but as members of *this. Iterators referring to the transferred
//! elements will continue to refer to their elements, but they now behave as iterators into *this,
//! not into source.
//!
//! <b>Throws</b>: Nothing unless the comparison object throws.
//!
//! <b>Complexity</b>: N log(a.size() + N) (N has the value source.size())
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(flat_map<Key, T, C2, Allocator>& source)
{ m_flat_tree.merge_unique(source.tree()); }
//! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map<Key, T, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_map<Key, T, C2, Allocator>&>(source)); }
//! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap<Key, T, C2, Allocator>& source)
{ m_flat_tree.merge_unique(source.tree()); }
//! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap<Key, T, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_multimap<Key, T, C2, Allocator>&>(source)); }
//! <b>Effects</b>: Erases the element pointed to by p.
//!
//! <b>Returns</b>: Returns an iterator pointing to the element immediately
@@ -1326,13 +1369,13 @@ class flat_multimap
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
BOOST_COPYABLE_AND_MOVABLE(flat_multimap)
typedef container_detail::flat_tree<Key,
typedef container_detail::flat_tree<
std::pair<Key, T>,
container_detail::select1st<Key>,
Compare,
Allocator> tree_t;
//This is the real tree stored here. It's based on a movable pair
typedef container_detail::flat_tree<Key,
typedef container_detail::flat_tree<
container_detail::pair<Key, T>,
container_detail::select1st<Key>,
Compare,
@@ -1358,6 +1401,13 @@ class flat_multimap
<typename allocator_traits<Allocator>::pointer>::const_reverse_iterator const_reverse_iterator_impl;
public:
typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type;
impl_tree_t &tree()
{ return m_flat_tree; }
const impl_tree_t &tree() const
{ return m_flat_tree; }
private:
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -1993,6 +2043,38 @@ class flat_multimap
{ m_flat_tree.insert_equal(ordered_range, il.begin(), il.end()); }
#endif
//! <b>Requires</b>: this->get_allocator() == source.get_allocator().
//!
//! <b>Effects</b>: Extracts each element in source and insert it into a using
//! the comparison object of *this.
//!
//! <b>Postcondition</b>: Pointers and references to the transferred elements of source refer
//! to those same elements but as members of *this. Iterators referring to the transferred
//! elements will continue to refer to their elements, but they now behave as iterators into *this,
//! not into source.
//!
//! <b>Throws</b>: Nothing unless the comparison object throws.
//!
//! <b>Complexity</b>: N log(a.size() + N) (N has the value source.size())
template<class C2>
void merge(flat_multimap<Key, T, C2, Allocator>& source)
{ m_flat_tree.merge_equal(source.tree()); }
//! @copydoc ::boost::container::flat_multimap::merge(flat_multimap<Key, T, C2, Allocator>&)
template<class C2>
void merge(BOOST_RV_REF_BEG flat_multimap<Key, T, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_multimap<Key, T, C2, Allocator>&>(source)); }
//! @copydoc ::boost::container::flat_multimap::merge(flat_multimap<Key, T, C2, Allocator>&)
template<class C2>
void merge(flat_map<Key, T, C2, Allocator>& source)
{ m_flat_tree.merge_equal(source.tree()); }
//! @copydoc ::boost::container::flat_multimap::merge(flat_multimap<Key, T, C2, Allocator>&)
template<class C2>
void merge(BOOST_RV_REF_BEG flat_map<Key, T, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_map<Key, T, C2, Allocator>&>(source)); }
//! <b>Effects</b>: Erases the element pointed to by p.
//!
//! <b>Returns</b>: Returns an iterator pointing to the element immediately

View File

@@ -47,6 +47,11 @@
namespace boost {
namespace container {
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template <class Key, class T, class Compare, class Allocator>
class flat_multimap;
#endif
//! flat_set is a Sorted Associative Container that stores objects of type Key.
//! It is also a Unique Associative Container, meaning that no two elements are the same.
//!
@@ -69,13 +74,21 @@ template <class Key, class Compare, class Allocator>
#endif
class flat_set
///@cond
: public container_detail::flat_tree<Key, Key, container_detail::identity<Key>, Compare, Allocator>
: public container_detail::flat_tree<Key, container_detail::identity<Key>, Compare, Allocator>
///@endcond
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
BOOST_COPYABLE_AND_MOVABLE(flat_set)
typedef container_detail::flat_tree<Key, Key, container_detail::identity<Key>, Compare, Allocator> base_t;
typedef container_detail::flat_tree<Key, container_detail::identity<Key>, Compare, Allocator> base_t;
public:
base_t &tree()
{ return *this; }
const base_t &tree() const
{ return *this; }
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public:
@@ -605,6 +618,26 @@ class flat_set
{ this->base_t::insert_unique(ordered_unique_range, il.begin(), il.end()); }
#endif
//! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(flat_set<Key, C2, Allocator>& source)
{ this->base_t::merge_unique(source.tree()); }
//! @copydoc ::boost::container::flat_map::merge(flat_set<Key, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set<Key, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_set<Key, C2, Allocator>&>(source)); }
//! @copydoc ::boost::container::flat_map::merge(flat_multimap<Key, T, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset<Key, C2, Allocator>& source)
{ this->base_t::merge_unique(source.tree()); }
//! @copydoc ::boost::container::flat_map::merge(flat_multiset<Key, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset<Key, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_multiset<Key, C2, Allocator>&>(source)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Erases the element pointed to by p.
@@ -867,13 +900,20 @@ template <class Key, class Compare, class Allocator>
#endif
class flat_multiset
///@cond
: public container_detail::flat_tree<Key, Key, container_detail::identity<Key>, Compare, Allocator>
: public container_detail::flat_tree<Key, container_detail::identity<Key>, Compare, Allocator>
///@endcond
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
BOOST_COPYABLE_AND_MOVABLE(flat_multiset)
typedef container_detail::flat_tree<Key, Key, container_detail::identity<Key>, Compare, Allocator> base_t;
typedef container_detail::flat_tree<Key, container_detail::identity<Key>, Compare, Allocator> base_t;
public:
base_t &tree()
{ return *this; }
const base_t &tree() const
{ return *this; }
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public:
@@ -1233,6 +1273,26 @@ class flat_multiset
{ this->base_t::insert_equal(ordered_range, il.begin(), il.end()); }
#endif
//! @copydoc ::boost::container::flat_multimap::merge(flat_multimap<Key, T, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset<Key, C2, Allocator>& source)
{ this->base_t::merge_equal(source.tree()); }
//! @copydoc ::boost::container::flat_multiset::merge(flat_multiset<Key, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset<Key, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_multiset<Key, C2, Allocator>&>(source)); }
//! @copydoc ::boost::container::flat_multimap::merge(flat_map<Key, T, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(flat_set<Key, C2, Allocator>& source)
{ this->base_t::merge_equal(source.tree()); }
//! @copydoc ::boost::container::flat_multiset::merge(flat_set<Key, C2, Allocator>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set<Key, C2, Allocator> BOOST_RV_REF_END source)
{ return this->merge(static_cast<flat_set<Key, C2, Allocator>&>(source)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! @copydoc ::boost::container::flat_set::erase(const_iterator)

View File

@@ -96,18 +96,18 @@ struct pair_key_mapped_of_value
//! \tparam Compare is the ordering function for Keys (e.g. <i>std::less<Key></i>).
//! \tparam Allocator is the allocator to allocate the <code>value_type</code>s
//! (e.g. <i>allocator< std::pair<const Key, T> > </i>).
//! \tparam MapOptions is an packed option type generated using using boost::container::tree_assoc_options.
//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options.
template < class Key, class T, class Compare = std::less<Key>
, class Allocator = new_allocator< std::pair< const Key, T> >, class MapOptions = tree_assoc_defaults >
, class Allocator = new_allocator< std::pair< const Key, T> >, class Options = tree_assoc_defaults >
#else
template <class Key, class T, class Compare, class Allocator, class MapOptions>
template <class Key, class T, class Compare, class Allocator, class Options>
#endif
class map
///@cond
: public container_detail::tree
< Key, std::pair<const Key, T>
< std::pair<const Key, T>
, container_detail::select1st<Key>
, Compare, Allocator, MapOptions>
, Compare, Allocator, Options>
///@endcond
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -117,10 +117,9 @@ class map
typedef container_detail::select1st<Key> select_1st_t;
typedef std::pair<const Key, T> value_type_impl;
typedef container_detail::tree
<Key, value_type_impl, select_1st_t, Compare, Allocator, MapOptions> base_t;
<value_type_impl, select_1st_t, Compare, Allocator, Options> base_t;
typedef container_detail::pair <Key, T> movable_value_type_impl;
typedef container_detail::tree_value_compare
<Compare, select_1st_t> value_compare_impl;
typedef typename base_t::value_compare value_compare_impl;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public:
@@ -975,6 +974,47 @@ class map
return BOOST_MOVE_RET(node_type, nh);
}
//! <b>Requires</b>: this->get_allocator() == source.get_allocator().
//!
//! <b>Effects</b>: Attempts to extract each element in source and insert it into a using
//! the comparison object of *this. If there is an element in a with key equivalent to the
//! key of an element from source, then that element is not extracted from source.
//!
//! <b>Postcondition</b>: Pointers and references to the transferred elements of source refer
//! to those same elements but as members of *this. Iterators referring to the transferred
//! elements will continue to refer to their elements, but they now behave as iterators into *this,
//! not into source.
//!
//! <b>Throws</b>: Nothing unless the comparison object throws.
//!
//! <b>Complexity</b>: N log(a.size() + N) (N has the value source.size())
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(map<Key, T, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<value_type_impl, select_1st_t, C2, Allocator, Options> base2_t;
this->merge_unique(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::map::merge(map<Key, T, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG map<Key, T, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<map<Key, T, C2, Allocator, Options>&>(source)); }
//! @copydoc ::boost::container::map::merge(map<Key, T, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(multimap<Key, T, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<value_type_impl, select_1st_t, C2, Allocator, Options> base2_t;
this->base_t::merge_unique(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::map::merge(map<Key, T, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG multimap<Key, T, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<multimap<Key, T, C2, Allocator, Options>&>(source)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Swaps the contents of *this and x.
//!
@@ -1148,18 +1188,18 @@ namespace container {
//! \tparam Compare is the ordering function for Keys (e.g. <i>std::less<Key></i>).
//! \tparam Allocator is the allocator to allocate the <code>value_type</code>s
//! (e.g. <i>allocator< std::pair<const Key, T> > </i>).
//! \tparam MultiMapOptions is an packed option type generated using using boost::container::tree_assoc_options.
//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options.
template < class Key, class T, class Compare = std::less<Key>
, class Allocator = new_allocator< std::pair< const Key, T> >, class MultiMapOptions = tree_assoc_defaults>
, class Allocator = new_allocator< std::pair< const Key, T> >, class Options = tree_assoc_defaults>
#else
template <class Key, class T, class Compare, class Allocator, class MultiMapOptions>
template <class Key, class T, class Compare, class Allocator, class Options>
#endif
class multimap
///@cond
: public container_detail::tree
< Key, std::pair<const Key, T>
< std::pair<const Key, T>
, container_detail::select1st<Key>
, Compare, Allocator, MultiMapOptions>
, Compare, Allocator, Options>
///@endcond
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -1169,10 +1209,9 @@ class multimap
typedef container_detail::select1st<Key> select_1st_t;
typedef std::pair<const Key, T> value_type_impl;
typedef container_detail::tree
<Key, value_type_impl, select_1st_t, Compare, Allocator, MultiMapOptions> base_t;
<value_type_impl, select_1st_t, Compare, Allocator, Options> base_t;
typedef container_detail::pair <Key, T> movable_value_type_impl;
typedef container_detail::tree_value_compare
<Compare, select_1st_t> value_compare_impl;
typedef typename base_t::value_compare value_compare_impl;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
typedef ::boost::container::allocator_traits<Allocator> allocator_traits_type;
@@ -1655,6 +1694,46 @@ class multimap
return node_type (boost::move(base_nh));
}
//! <b>Requires</b>: this->get_allocator() == source.get_allocator().
//!
//! <b>Effects</b>: Extracts each element in source and insert it into a using
//! the comparison object of *this.
//!
//! <b>Postcondition</b>: Pointers and references to the transferred elements of source refer
//! to those same elements but as members of *this. Iterators referring to the transferred
//! elements will continue to refer to their elements, but they now behave as iterators into *this,
//! not into source.
//!
//! <b>Throws</b>: Nothing unless the comparison object throws.
//!
//! <b>Complexity</b>: N log(a.size() + N) (N has the value source.size())
template<class C2>
void merge(multimap<Key, T, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<value_type_impl, select_1st_t, C2, Allocator, Options> base2_t;
this->base_t::merge_equal(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::multimap::merge(multimap<Key, T, C2, Allocator, Options>&)
template<class C2>
void merge(BOOST_RV_REF_BEG multimap<Key, T, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<multimap<Key, T, C2, Allocator, Options>&>(source)); }
//! @copydoc ::boost::container::multimap::merge(multimap<Key, T, C2, Allocator, Options>&)
template<class C2>
void merge(map<Key, T, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<value_type_impl, select_1st_t, C2, Allocator, Options> base2_t;
this->base_t::merge_equal(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::multimap::merge(multimap<Key, T, C2, Allocator, Options>&)
template<class C2>
void merge(BOOST_RV_REF_BEG map<Key, T, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<map<Key, T, C2, Allocator, Options>&>(source)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! @copydoc ::boost::container::set::swap
void swap(multiset& x)

View File

@@ -59,22 +59,22 @@ namespace container {
//! \tparam Key is the type to be inserted in the set, which is also the key_type
//! \tparam Compare is the comparison functor used to order keys
//! \tparam Allocator is the allocator to be used to allocate memory for this container
//! \tparam SetOptions is an packed option type generated using using boost::container::tree_assoc_options.
template <class Key, class Compare = std::less<Key>, class Allocator = new_allocator<Key>, class SetOptions = tree_assoc_defaults >
//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options.
template <class Key, class Compare = std::less<Key>, class Allocator = new_allocator<Key>, class Options = tree_assoc_defaults >
#else
template <class Key, class Compare, class Allocator, class SetOptions>
template <class Key, class Compare, class Allocator, class Options>
#endif
class set
///@cond
: public container_detail::tree
< Key, Key, container_detail::identity<Key>, Compare, Allocator, SetOptions>
< Key, container_detail::identity<Key>, Compare, Allocator, Options>
///@endcond
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
BOOST_COPYABLE_AND_MOVABLE(set)
typedef container_detail::tree
< Key, Key, container_detail::identity<Key>, Compare, Allocator, SetOptions> base_t;
< Key, container_detail::identity<Key>, Compare, Allocator, Options> base_t;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public:
@@ -533,6 +533,34 @@ class set
insert_return_type insert(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh)
{ return this->base_t::insert_unique_node(hint, boost::move(nh)); }
//! @copydoc ::boost::container::map::merge(map<Key, T, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(set<Key, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<Key, container_detail::identity<Key>, C2, Allocator, Options> base2_t;
this->base_t::merge_unique(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::set::merge(set<Key, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG set<Key, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<set<Key, C2, Allocator, Options>&>(source)); }
//! @copydoc ::boost::container::map::merge(multimap<Key, T, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(multiset<Key, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<Key, container_detail::identity<Key>, C2, Allocator, Options> base2_t;
this->base_t::merge_unique(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::set::merge(multiset<Key, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG multiset<Key, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<multiset<Key, C2, Allocator, Options>&>(source)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Erases the element pointed to by p.
@@ -724,8 +752,8 @@ class set
//!has_trivial_destructor_after_move<> == true_type
//!specialization for optimizations
template <class Key, class Compare, class SetOptions, class Allocator>
struct has_trivial_destructor_after_move<boost::container::set<Key, Compare, Allocator, SetOptions> >
template <class Key, class Compare, class Options, class Allocator>
struct has_trivial_destructor_after_move<boost::container::set<Key, Compare, Allocator, Options> >
{
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value &&
@@ -750,22 +778,22 @@ namespace container {
//! \tparam Key is the type to be inserted in the set, which is also the key_type
//! \tparam Compare is the comparison functor used to order keys
//! \tparam Allocator is the allocator to be used to allocate memory for this container
//! \tparam MultiSetOptions is an packed option type generated using using boost::container::tree_assoc_options.
template <class Key, class Compare = std::less<Key>, class Allocator = new_allocator<Key>, class MultiSetOptions = tree_assoc_defaults >
//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options.
template <class Key, class Compare = std::less<Key>, class Allocator = new_allocator<Key>, class Options = tree_assoc_defaults >
#else
template <class Key, class Compare, class Allocator, class MultiSetOptions>
template <class Key, class Compare, class Allocator, class Options>
#endif
class multiset
/// @cond
: public container_detail::tree
<Key, Key,container_detail::identity<Key>, Compare, Allocator, MultiSetOptions>
<Key,container_detail::identity<Key>, Compare, Allocator, Options>
/// @endcond
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
BOOST_COPYABLE_AND_MOVABLE(multiset)
typedef container_detail::tree
<Key, Key,container_detail::identity<Key>, Compare, Allocator, MultiSetOptions> base_t;
<Key,container_detail::identity<Key>, Compare, Allocator, Options> base_t;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public:
@@ -1068,6 +1096,34 @@ class multiset
iterator insert(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh)
{ return this->base_t::insert_equal_node(hint, boost::move(nh)); }
//! @copydoc ::boost::container::multimap::merge(multimap<Key, T, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(multiset<Key, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<Key, container_detail::identity<Key>, C2, Allocator, Options> base2_t;
this->base_t::merge_equal(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::multiset::merge(multiset<Key, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG multiset<Key, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<multiset<Key, C2, Allocator, Options>&>(source)); }
//! @copydoc ::boost::container::multimap::merge(map<Key, T, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(set<Key, C2, Allocator, Options>& source)
{
typedef container_detail::tree
<Key, container_detail::identity<Key>, C2, Allocator, Options> base2_t;
this->base_t::merge_equal(static_cast<base2_t&>(source));
}
//! @copydoc ::boost::container::multiset::merge(set<Key, C2, Allocator, Options>&)
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG set<Key, C2, Allocator, Options> BOOST_RV_REF_END source)
{ return this->merge(static_cast<set<Key, C2, Allocator, Options>&>(source)); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! @copydoc ::boost::container::set::erase(const_iterator)
@@ -1179,8 +1235,8 @@ class multiset
//!has_trivial_destructor_after_move<> == true_type
//!specialization for optimizations
template <class Key, class Compare, class Allocator, class MultiSetOptions>
struct has_trivial_destructor_after_move<boost::container::multiset<Key, Compare, Allocator, MultiSetOptions> >
template <class Key, class Compare, class Allocator, class Options>
struct has_trivial_destructor_after_move<boost::container::multiset<Key, Compare, Allocator, Options> >
{
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value &&

View File

@@ -62,7 +62,6 @@ namespace container_detail {
//Instantiate base class as previous instantiations don't instantiate inherited members
template class flat_tree
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, identity<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, test::simple_allocator<test::movable_and_copyable_int>
@@ -70,7 +69,6 @@ template class flat_tree
template class flat_tree
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, identity<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, allocator<test::movable_and_copyable_int>

View File

@@ -23,6 +23,8 @@
using namespace boost::container;
typedef std::pair<const test::movable_and_copyable_int, test::movable_and_copyable_int> pair_t;
namespace boost {
namespace container {
@@ -33,34 +35,59 @@ template class map
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, std::less<test::movable_and_copyable_int>
, test::simple_allocator
< std::pair<const test::movable_and_copyable_int, test::movable_and_copyable_int> >
, test::simple_allocator< pair_t >
>;
template class map
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, std::less<test::movable_and_copyable_int>
, std::allocator
< std::pair<const test::movable_and_copyable_int, test::movable_and_copyable_int> >
, std::allocator< pair_t >
>;
template class map
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, std::less<test::movable_and_copyable_int>
, adaptive_pool
< std::pair<const test::movable_and_copyable_int, test::movable_and_copyable_int> >
, adaptive_pool< pair_t >
>;
template class multimap
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, std::less<test::movable_and_copyable_int>
, std::allocator
< std::pair<const test::movable_and_copyable_int, test::movable_and_copyable_int> >
, std::allocator< pair_t >
>;
namespace container_detail {
//Instantiate base class as previous instantiations don't instantiate inherited members
template class tree
< pair_t
, select1st<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, test::simple_allocator<pair_t>
, tree_assoc_defaults
>;
template class tree
< pair_t
, select1st<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, std::allocator<pair_t>
, tree_assoc_defaults
>;
template class tree
< pair_t
, select1st<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, adaptive_pool<pair_t>
, tree_assoc_defaults
>;
} //container_detail {
}} //boost::container
class recursive_map
@@ -334,6 +361,13 @@ struct alloc_propagate_base<boost_container_multimap>
};
};
void test_merge_from_different_comparison()
{
map<int, int> map1;
map<int, int, std::greater<int> > map2;
map1.merge(map2);
}
}}} //namespace boost::container::test
int main ()
@@ -357,7 +391,6 @@ int main ()
//Test std::pair value type as tree has workarounds to make old std::pair
//implementations movable that can break things
{
typedef std::pair<int,int> pair_t;
boost::container::map<pair_t, pair_t> s;
std::pair<const pair_t,pair_t> p;
s.insert(p);
@@ -447,6 +480,8 @@ int main ()
if(!node_type_test())
return 1;
test::test_merge_from_different_comparison();
////////////////////////////////////
// Test optimize_size option
////////////////////////////////////

View File

@@ -68,7 +68,7 @@ int map_test_copyable(boost::container::container_detail::true_type)
typedef container_detail::pair<IntType, IntType> IntPairType;
typedef typename MyStdMap::value_type StdPairType;
const int max = 50;
const int MaxElem = 50;
::boost::movelib::unique_ptr<MyBoostMap> const pboostmap = ::boost::movelib::make_unique<MyBoostMap>();
::boost::movelib::unique_ptr<MyStdMap> const pstdmap = ::boost::movelib::make_unique<MyStdMap>();
@@ -86,7 +86,7 @@ int map_test_copyable(boost::container::container_detail::true_type)
boostmultimap.insert(boostmultimap.begin(), boostmultimap.end());
int i;
for(i = 0; i < max; ++i){
for(i = 0; i < MaxElem; ++i){
{
IntType i1(i), i2(i);
IntPairType intpair1(boost::move(i1), boost::move(i2));
@@ -138,7 +138,7 @@ int map_test()
typedef typename MyBoostMap::key_type IntType;
typedef container_detail::pair<IntType, IntType> IntPairType;
typedef typename MyStdMap::value_type StdPairType;
const int max = 50;
const int MaxElem = 50;
typedef typename MyStdMap::value_type StdValueType;
typedef typename MyStdMap::key_type StdKeyType;
typedef typename MyStdMap::mapped_type StdMappedType;
@@ -146,20 +146,20 @@ int map_test()
//Test construction from a range
{
IntPairType aux_vect[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i/2);
IntType i2(i/2);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
StdValueType aux_vect2[50];
for(int i = 0; i < 50; ++i){
StdValueType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2));
}
IntPairType aux_vect3[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i/2);
IntType i2(i/2);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
@@ -167,33 +167,33 @@ int map_test()
::boost::movelib::unique_ptr<MyBoostMap> const pboostmap = ::boost::movelib::make_unique<MyBoostMap>
( boost::make_move_iterator(&aux_vect[0])
, boost::make_move_iterator(&aux_vect[0] + 50), typename MyBoostMap::key_compare());
, boost::make_move_iterator(&aux_vect[0] + MaxElem), typename MyBoostMap::key_compare());
::boost::movelib::unique_ptr<MyStdMap> const pstdmap = ::boost::movelib::make_unique<MyStdMap>
(&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare());
(&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare());
if(!CheckEqualContainers(*pboostmap, *pstdmap)) return 1;
::boost::movelib::unique_ptr<MyBoostMultiMap> const pboostmultimap = ::boost::movelib::make_unique<MyBoostMultiMap>
( boost::make_move_iterator(&aux_vect3[0])
, boost::make_move_iterator(&aux_vect3[0] + 50), typename MyBoostMap::key_compare());
, boost::make_move_iterator(&aux_vect3[0] + MaxElem), typename MyBoostMap::key_compare());
::boost::movelib::unique_ptr<MyStdMultiMap> const pstdmultimap = ::boost::movelib::make_unique<MyStdMultiMap>
(&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare());
(&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare());
if(!CheckEqualContainers(*pboostmultimap, *pstdmultimap)) return 1;
}
{
IntPairType aux_vect[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i/2);
IntType i2(i/2);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
StdValueType aux_vect2[50];
for(int i = 0; i < 50; ++i){
StdValueType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2));
}
IntPairType aux_vect3[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i/2);
IntType i2(i/2);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
@@ -201,16 +201,16 @@ int map_test()
::boost::movelib::unique_ptr<MyBoostMap> const pboostmap = ::boost::movelib::make_unique<MyBoostMap>
( boost::make_move_iterator(&aux_vect[0])
, boost::make_move_iterator(&aux_vect[0] + 50), typename MyBoostMap::allocator_type());
, boost::make_move_iterator(&aux_vect[0] + MaxElem), typename MyBoostMap::allocator_type());
::boost::movelib::unique_ptr<MyStdMap> const pstdmap = ::boost::movelib::make_unique<MyStdMap>
(&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare());
(&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare());
if(!CheckEqualContainers(*pboostmap, *pstdmap)) return 1;
::boost::movelib::unique_ptr<MyBoostMultiMap> const pboostmultimap = ::boost::movelib::make_unique<MyBoostMultiMap>
( boost::make_move_iterator(&aux_vect3[0])
, boost::make_move_iterator(&aux_vect3[0] + 50), typename MyBoostMap::allocator_type());
, boost::make_move_iterator(&aux_vect3[0] + MaxElem), typename MyBoostMap::allocator_type());
::boost::movelib::unique_ptr<MyStdMultiMap> const pstdmultimap = ::boost::movelib::make_unique<MyStdMultiMap>
(&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare());
(&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare());
if(!CheckEqualContainers(*pboostmultimap, *pstdmultimap)) return 1;
}
@@ -225,8 +225,8 @@ int map_test()
{
//This is really nasty, but we have no other simple choice
IntPairType aux_vect[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i/2);
IntType i2(i/2);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
@@ -235,13 +235,13 @@ int map_test()
typedef typename MyStdMap::value_type StdValueType;
typedef typename MyStdMap::key_type StdKeyType;
typedef typename MyStdMap::mapped_type StdMappedType;
StdValueType aux_vect2[50];
for(int i = 0; i < 50; ++i){
StdValueType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2));
}
IntPairType aux_vect3[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i/2);
IntType i2(i/2);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
@@ -249,14 +249,14 @@ int map_test()
::boost::movelib::unique_ptr<MyBoostMap> const pboostmap2 = ::boost::movelib::make_unique<MyBoostMap>
( boost::make_move_iterator(&aux_vect[0])
, boost::make_move_iterator(&aux_vect[0] + 50));
, boost::make_move_iterator(&aux_vect[0] + MaxElem));
::boost::movelib::unique_ptr<MyStdMap> const pstdmap2 = ::boost::movelib::make_unique<MyStdMap>
(&aux_vect2[0], &aux_vect2[0] + 50);
(&aux_vect2[0], &aux_vect2[0] + MaxElem);
::boost::movelib::unique_ptr<MyBoostMultiMap> const pboostmultimap2 = ::boost::movelib::make_unique<MyBoostMultiMap>
( boost::make_move_iterator(&aux_vect3[0])
, boost::make_move_iterator(&aux_vect3[0] + 50));
, boost::make_move_iterator(&aux_vect3[0] + MaxElem));
::boost::movelib::unique_ptr<MyStdMultiMap> const pstdmultimap2 = ::boost::movelib::make_unique<MyStdMultiMap>
(&aux_vect2[0], &aux_vect2[0] + 50);
(&aux_vect2[0], &aux_vect2[0] + MaxElem);
MyBoostMap &boostmap2 = *pboostmap2;
MyStdMap &stdmap2 = *pstdmap2;
MyBoostMultiMap &boostmultimap2 = *pboostmultimap2;
@@ -267,17 +267,17 @@ int map_test()
//ordered range insertion
//This is really nasty, but we have no other simple choice
for(int i = 0; i < 50; ++i){
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
for(int i = 0; i < 50; ++i){
for(int i = 0; i < MaxElem; ++i){
new(&aux_vect2[i])StdValueType(StdKeyType(i), StdMappedType(i));
}
for(int i = 0; i < 50; ++i){
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
@@ -301,14 +301,14 @@ int map_test()
::boost::movelib::unique_ptr<MyBoostMap> const pboostmap3 = ::boost::movelib::make_unique<MyBoostMap>
( boost::make_move_iterator(&aux_vect[0])
, boost::make_move_iterator(&aux_vect[0] + 50));
, boost::make_move_iterator(&aux_vect[0] + MaxElem));
::boost::movelib::unique_ptr<MyStdMap> const pstdmap3 = ::boost::movelib::make_unique<MyStdMap>
(&aux_vect2[0], &aux_vect2[0] + 50);
(&aux_vect2[0], &aux_vect2[0] + MaxElem);
::boost::movelib::unique_ptr<MyBoostMultiMap> const pboostmultimap3 = ::boost::movelib::make_unique<MyBoostMultiMap>
( boost::make_move_iterator(&aux_vect3[0])
, boost::make_move_iterator(&aux_vect3[0] + 50));
, boost::make_move_iterator(&aux_vect3[0] + MaxElem));
::boost::movelib::unique_ptr<MyStdMultiMap> const pstdmultimap3 = ::boost::movelib::make_unique<MyStdMultiMap>
(&aux_vect2[0], &aux_vect2[0] + 50);
(&aux_vect2[0], &aux_vect2[0] + MaxElem);
MyBoostMap &boostmap3 = *pboostmap3;
MyStdMap &stdmap3 = *pstdmap3;
MyBoostMultiMap &boostmultimap3 = *pboostmultimap3;
@@ -344,20 +344,20 @@ int map_test()
}
{
//This is really nasty, but we have no other simple choice
IntPairType aux_vect[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect3[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
}
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
boostmap.insert(boost::move(aux_vect[i]));
stdmap.insert(StdPairType(i, i));
boostmultimap.insert(boost::move(aux_vect3[i]));
@@ -405,22 +405,22 @@ int map_test()
//Initialize values
{
//This is really nasty, but we have no other simple choice
IntPairType aux_vect[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(-1);
IntType i2(-1);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect3[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(-1);
IntType i2(-1);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
}
boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50));
boostmultimap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + 50));
for(std::size_t i = 0; i != 50; ++i){
boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem));
boostmultimap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem));
for(int i = 0; i != MaxElem; ++i){
StdPairType stdpairtype(-1, -1);
stdmap.insert(stdpairtype);
stdmultimap.insert(stdpairtype);
@@ -439,40 +439,40 @@ int map_test()
if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1;
}
{
IntPairType aux_vect[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(-1);
IntType i2(-1);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect3[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(-1);
IntType i2(-1);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect4[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect4[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(-1);
IntType i2(-1);
new(&aux_vect4[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect5[50];
for(int i = 0; i < 50; ++i){
IntPairType aux_vect5[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(-1);
IntType i2(-1);
new(&aux_vect5[i])IntPairType(boost::move(i1), boost::move(i2));
}
boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50));
boostmap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + 50));
boostmultimap.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(aux_vect4 + 50));
boostmultimap.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(aux_vect5 + 50));
boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem));
boostmap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem));
boostmultimap.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(aux_vect4 + MaxElem));
boostmultimap.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(aux_vect5 + MaxElem));
for(std::size_t i = 0; i != 50; ++i){
for(int i = 0; i != MaxElem; ++i){
StdPairType stdpairtype(-1, -1);
stdmap.insert(stdpairtype);
stdmultimap.insert(stdpairtype);
@@ -492,20 +492,20 @@ int map_test()
{
//This is really nasty, but we have no other simple choice
IntPairType aux_vect[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect3[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
}
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
boostmap.insert(boost::move(aux_vect[i]));
stdmap.insert(StdPairType(i, i));
boostmultimap.insert(boost::move(aux_vect3[i]));
@@ -515,7 +515,7 @@ int map_test()
if(!CheckEqualPairContainers(boostmap, stdmap)) return 1;
if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1;
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
IntPairType intpair;
{
IntType i1(i);
@@ -629,7 +629,7 @@ int map_test()
}
//Compare count with std containers
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
IntType k(i);
if(boostmap.count(k) != stdmap.count(i)){
return -1;
@@ -673,14 +673,14 @@ int map_test()
stdmap.clear();
stdmultimap.clear();
IntPairType aux_vect[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
boostmap[boost::move(aux_vect[i].first)] = boost::move(aux_vect[i].second);
stdmap[i] = i;
}
@@ -695,21 +695,21 @@ int map_test()
stdmap.clear();
stdmultimap.clear();
IntPairType aux_vect[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect2[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(max-i);
IntType i2(MaxElem-i);
new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2));
}
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
boostmap.insert_or_assign(boost::move(aux_vect[i].first), boost::move(aux_vect[i].second));
stdmap[i] = i;
}
@@ -717,9 +717,9 @@ int map_test()
if(!CheckEqualPairContainers(boostmap, stdmap)) return 1;
if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1;
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
boostmap.insert_or_assign(boost::move(aux_vect2[i].first), boost::move(aux_vect2[i].second));
stdmap[i] = max-i;
stdmap[i] = MaxElem-i;
}
if(!CheckEqualPairContainers(boostmap, stdmap)) return 1;
@@ -732,22 +732,22 @@ int map_test()
stdmap.clear();
stdmultimap.clear();
IntPairType aux_vect[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect2[max];
for(int i = 0; i < max; ++i){
IntPairType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(max-i);
IntType i2(MaxElem-i);
new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2));
}
typedef typename MyBoostMap::iterator iterator;
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
iterator it;
if(i&1){
std::pair<typename MyBoostMap::iterator, bool> ret =
@@ -769,7 +769,7 @@ int map_test()
if(!CheckEqualPairContainers(boostmap, stdmap)) return 1;
if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1;
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
iterator it;
iterator itex = boostmap.find(aux_vect2[i].first);
if(itex == boostmap.end())
@@ -795,6 +795,108 @@ int map_test()
if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1;
}
{ //merge
::boost::movelib::unique_ptr<MyBoostMap> const pboostmap2 = ::boost::movelib::make_unique<MyBoostMap>();
::boost::movelib::unique_ptr<MyBoostMultiMap> const pboostmultimap2 = ::boost::movelib::make_unique<MyBoostMultiMap>();
MyBoostMap &boostmap2 = *pboostmap2;
MyBoostMultiMap &boostmultimap2 = *pboostmultimap2;
boostmap.clear();
boostmap2.clear();
boostmultimap.clear();
boostmultimap2.clear();
stdmap.clear();
stdmultimap.clear();
{
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(MaxElem/2+i);
IntType i2(MaxElem-i);
new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(MaxElem*2/2+i);
IntType i2(MaxElem*2+i);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
}
boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem));
boostmap2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem));
boostmultimap2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem));
}
for(int i = 0; i < MaxElem; ++i){
stdmap.insert(StdPairType(i, i));
}
for(int i = 0; i < MaxElem; ++i){
stdmap.insert(StdPairType(MaxElem/2+i, MaxElem-i));
}
boostmap.merge(boost::move(boostmap2));
if(!CheckEqualPairContainers(boostmap, stdmap)) return 1;
for(int i = 0; i < MaxElem; ++i){
stdmap.insert(StdPairType(MaxElem*2/2+i, MaxElem*2+i));
}
boostmap.merge(boost::move(boostmultimap2));
if(!CheckEqualPairContainers(boostmap, stdmap)) return 1;
boostmap.clear();
boostmap2.clear();
boostmultimap.clear();
boostmultimap2.clear();
stdmap.clear();
stdmultimap.clear();
{
IntPairType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(i);
IntType i2(i);
new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(MaxElem/2+i);
IntType i2(MaxElem-i);
new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2));
}
IntPairType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
IntType i1(MaxElem*2/2+i);
IntType i2(MaxElem*2+i);
new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2));
}
boostmultimap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem));
boostmultimap2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem));
boostmap2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem));
}
for(int i = 0; i < MaxElem; ++i){
stdmultimap.insert(StdPairType(i, i));
}
for(int i = 0; i < MaxElem; ++i){
stdmultimap.insert(StdPairType(MaxElem/2+i, MaxElem-i));
}
boostmultimap.merge(boost::move(boostmultimap2));
if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1;
for(int i = 0; i < MaxElem; ++i){
stdmultimap.insert(StdPairType(MaxElem*2/2+i, MaxElem*2+i));
}
boostmultimap.merge(boost::move(boostmap2));
if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1;
}
if(map_test_copyable<MyBoostMap, MyStdMap, MyBoostMultiMap, MyStdMultiMap>
(container_detail::bool_<boost::container::test::is_copyable<IntType>::value>())){
return 1;

View File

@@ -58,7 +58,6 @@ namespace container_detail {
//Instantiate base class as previous instantiations don't instantiate inherited members
template class tree
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, identity<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, test::simple_allocator<test::movable_and_copyable_int>
@@ -67,7 +66,6 @@ template class tree
template class tree
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, identity<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, std::allocator<test::movable_and_copyable_int>
@@ -76,7 +74,6 @@ template class tree
template class tree
< test::movable_and_copyable_int
, test::movable_and_copyable_int
, identity<test::movable_and_copyable_int>
, std::less<test::movable_and_copyable_int>
, adaptive_pool<test::movable_and_copyable_int>
@@ -354,6 +351,13 @@ int test_set_variants()
return 0;
}
void test_merge_from_different_comparison()
{
set<int> set1;
set<int, std::greater<int> > set2;
set1.merge(set2);
}
int main ()
{
@@ -381,6 +385,8 @@ int main ()
s.emplace(p);
}
test_merge_from_different_comparison();
////////////////////////////////////
// Testing allocator implementations
////////////////////////////////////

View File

@@ -46,6 +46,8 @@ template<class MyBoostSet
int set_test_copyable(boost::container::container_detail::false_type)
{ return 0; }
const int MaxElem = 50;
template<class MyBoostSet
,class MyStdSet
,class MyBoostMultiSet
@@ -53,7 +55,6 @@ template<class MyBoostSet
int set_test_copyable(boost::container::container_detail::true_type)
{
typedef typename MyBoostSet::value_type IntType;
const int max = 50;
::boost::movelib::unique_ptr<MyBoostSet> const pboostset = ::boost::movelib::make_unique<MyBoostSet>();
::boost::movelib::unique_ptr<MyStdSet> const pstdset = ::boost::movelib::make_unique<MyStdSet>();
@@ -71,7 +72,7 @@ int set_test_copyable(boost::container::container_detail::true_type)
boostset.insert(boostset.begin(), boostset.end());
boostmultiset.insert(boostmultiset.begin(), boostmultiset.end());
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
IntType move_me(i);
boostset.insert(boost::move(move_me));
stdset.insert(i);
@@ -134,7 +135,6 @@ template<class MyBoostSet
int set_test ()
{
typedef typename MyBoostSet::value_type IntType;
const int max = 50;
::boost::movelib::unique_ptr<MyBoostSet> const pboostset = ::boost::movelib::make_unique<MyBoostSet>();
::boost::movelib::unique_ptr<MyStdSet> const pstdset = ::boost::movelib::make_unique<MyStdSet>();
@@ -293,7 +293,7 @@ int set_test ()
}
}
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
IntType move_me(i);
boostset.insert(boost::move(move_me));
stdset.insert(i);
@@ -474,7 +474,7 @@ int set_test ()
}
}
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
IntType move_me(i);
boostset.insert(boost::move(move_me));
stdset.insert(i);
@@ -492,7 +492,7 @@ int set_test ()
return 1;
}
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
{
IntType move_me(i);
boostset.insert(boostset.begin(), boost::move(move_me));
@@ -579,7 +579,7 @@ int set_test ()
}
//Compare count with std containers
for(int i = 0; i < max; ++i){
for(int i = 0; i < MaxElem; ++i){
IntType count_me(i);
if(boostset.count(count_me) != stdset.count(i)){
return -1;
@@ -703,6 +703,96 @@ int set_test ()
}
}
{ //merge
::boost::movelib::unique_ptr<MyBoostSet> const pboostset2 = ::boost::movelib::make_unique<MyBoostSet>();
::boost::movelib::unique_ptr<MyBoostMultiSet> const pboostmultiset2 = ::boost::movelib::make_unique<MyBoostMultiSet>();
MyBoostSet &boostset2 = *pboostset2;
MyBoostMultiSet &boostmultiset2 = *pboostmultiset2;
boostset.clear();
boostset2.clear();
boostmultiset.clear();
boostmultiset2.clear();
stdset.clear();
stdmultiset.clear();
{
IntType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
aux_vect[i] = i;
}
IntType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
aux_vect2[i] = MaxElem/2+i;
}
IntType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
aux_vect3[i] = MaxElem*2/2+i;
}
boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem));
boostset2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem));
boostmultiset2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem));
}
for(int i = 0; i < MaxElem; ++i){
stdset.insert(i);
}
for(int i = 0; i < MaxElem; ++i){
stdset.insert(MaxElem/2+i);
}
boostset.merge(boost::move(boostset2));
if(!CheckEqualContainers(boostset, stdset)) return 1;
for(int i = 0; i < MaxElem; ++i){
stdset.insert(MaxElem*2/2+i);
}
boostset.merge(boost::move(boostmultiset2));
if(!CheckEqualContainers(boostset, stdset)) return 1;
boostset.clear();
boostset2.clear();
boostmultiset.clear();
boostmultiset2.clear();
stdset.clear();
stdmultiset.clear();
{
IntType aux_vect[MaxElem];
for(int i = 0; i < MaxElem; ++i){
aux_vect[i] = i;
}
IntType aux_vect2[MaxElem];
for(int i = 0; i < MaxElem; ++i){
aux_vect2[i] = MaxElem/2+i;
}
IntType aux_vect3[MaxElem];
for(int i = 0; i < MaxElem; ++i){
aux_vect3[i] = MaxElem*2/2+i;
}
boostmultiset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem));
boostmultiset2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem));
boostset2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem));
}
for(int i = 0; i < MaxElem; ++i){
stdmultiset.insert(i);
}
for(int i = 0; i < MaxElem; ++i){
stdmultiset.insert(MaxElem/2+i);
}
boostmultiset.merge(boost::move(boostmultiset2));
if(!CheckEqualContainers(boostmultiset, stdmultiset)) return 1;
for(int i = 0; i < MaxElem; ++i){
stdmultiset.insert(MaxElem*2/2+i);
}
boostmultiset.merge(boost::move(boostset2));
if(!CheckEqualContainers(boostmultiset, stdmultiset)) return 1;
}
if(set_test_copyable<MyBoostSet, MyStdSet, MyBoostMultiSet, MyStdMultiSet>
(container_detail::bool_<boost::container::test::is_copyable<IntType>::value>())){
return 1;