// Multiset implementation -*- C++ -*-
-// Copyright (C) 2001-2013 Free Software Foundation, Inc.
+// Copyright (C) 2001-2017 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
{
_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
+ template<typename _Key, typename _Compare, typename _Alloc>
+ class set;
+
/**
* @brief A standard container made up of elements, which can be retrieved
* in logarithmic time.
private:
/// This turns a red-black tree into a [multi]set.
- typedef typename _Alloc::template rebind<_Key>::other _Key_alloc_type;
+ typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
+ rebind<_Key>::other _Key_alloc_type;
typedef _Rb_tree<key_type, value_type, _Identity<value_type>,
key_compare, _Key_alloc_type> _Rep_type;
/// The actual tree structure.
_Rep_type _M_t;
+ typedef __gnu_cxx::__alloc_traits<_Key_alloc_type> _Alloc_traits;
+
public:
- typedef typename _Key_alloc_type::pointer pointer;
- typedef typename _Key_alloc_type::const_pointer const_pointer;
- typedef typename _Key_alloc_type::reference reference;
- typedef typename _Key_alloc_type::const_reference const_reference;
+ typedef typename _Alloc_traits::pointer pointer;
+ typedef typename _Alloc_traits::const_pointer const_pointer;
+ typedef typename _Alloc_traits::reference reference;
+ typedef typename _Alloc_traits::const_reference const_reference;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 103. set::iterator is required to be modifiable,
// but this allows modification of keys.
typedef typename _Rep_type::size_type size_type;
typedef typename _Rep_type::difference_type difference_type;
+#if __cplusplus > 201402L
+ using node_type = typename _Rep_type::node_type;
+#endif
+
// allocation/deallocation
/**
* @brief Default constructor creates no elements.
*/
- multiset()
- : _M_t() { }
+#if __cplusplus < 201103L
+ multiset() : _M_t() { }
+#else
+ multiset() = default;
+#endif
/**
* @brief Creates a %multiset with no elements.
/**
* @brief %Multiset copy constructor.
- * @param __x A %multiset of identical element and allocator types.
*
- * The newly-created %multiset uses a copy of the allocation object used
- * by @a __x.
+ * Whether the allocator is copied depends on the allocator traits.
*/
+#if __cplusplus < 201103L
multiset(const multiset& __x)
: _M_t(__x._M_t) { }
+#else
+ multiset(const multiset&) = default;
-#if __cplusplus >= 201103L
/**
* @brief %Multiset move constructor.
- * @param __x A %multiset of identical element and allocator types.
*
- * The newly-created %multiset contains the exact contents of @a __x.
- * The contents of @a __x are a valid, but unspecified %multiset.
+ * The newly-created %multiset contains the exact contents of the
+ * moved instance. The moved instance is a valid, but unspecified
+ * %multiset.
*/
- multiset(multiset&& __x)
- noexcept(is_nothrow_copy_constructible<_Compare>::value)
- : _M_t(std::move(__x._M_t)) { }
+ multiset(multiset&&) = default;
/**
* @brief Builds a %multiset from an initializer_list.
const allocator_type& __a = allocator_type())
: _M_t(__comp, _Key_alloc_type(__a))
{ _M_t._M_insert_equal(__l.begin(), __l.end()); }
+
+ /// Allocator-extended default constructor.
+ explicit
+ multiset(const allocator_type& __a)
+ : _M_t(_Compare(), _Key_alloc_type(__a)) { }
+
+ /// Allocator-extended copy constructor.
+ multiset(const multiset& __m, const allocator_type& __a)
+ : _M_t(__m._M_t, _Key_alloc_type(__a)) { }
+
+ /// Allocator-extended move constructor.
+ multiset(multiset&& __m, const allocator_type& __a)
+ noexcept(is_nothrow_copy_constructible<_Compare>::value
+ && _Alloc_traits::_S_always_equal())
+ : _M_t(std::move(__m._M_t), _Key_alloc_type(__a)) { }
+
+ /// Allocator-extended initialier-list constructor.
+ multiset(initializer_list<value_type> __l, const allocator_type& __a)
+ : _M_t(_Compare(), _Key_alloc_type(__a))
+ { _M_t._M_insert_equal(__l.begin(), __l.end()); }
+
+ /// Allocator-extended range constructor.
+ template<typename _InputIterator>
+ multiset(_InputIterator __first, _InputIterator __last,
+ const allocator_type& __a)
+ : _M_t(_Compare(), _Key_alloc_type(__a))
+ { _M_t._M_insert_equal(__first, __last); }
+
+ /**
+ * The dtor only erases the elements, and note that if the elements
+ * themselves are pointers, the pointed-to memory is not touched in any
+ * way. Managing the pointer is the user's responsibility.
+ */
+ ~multiset() = default;
#endif
/**
* @brief %Multiset assignment operator.
- * @param __x A %multiset of identical element and allocator types.
*
- * All the elements of @a __x are copied, but unlike the copy
- * constructor, the allocator object is not copied.
+ * Whether the allocator is copied depends on the allocator traits.
*/
+#if __cplusplus < 201103L
multiset&
operator=(const multiset& __x)
{
_M_t = __x._M_t;
return *this;
}
+#else
+ multiset&
+ operator=(const multiset&) = default;
-#if __cplusplus >= 201103L
- /**
- * @brief %Multiset move assignment operator.
- * @param __x A %multiset of identical element and allocator types.
- *
- * The contents of @a __x are moved into this %multiset
- * (without copying). @a __x is a valid, but unspecified
- * %multiset.
- */
+ /// Move assignment operator.
multiset&
- operator=(multiset&& __x)
- {
- // NB: DR 1204.
- // NB: DR 675.
- this->clear();
- this->swap(__x);
- return *this;
- }
+ operator=(multiset&&) = default;
/**
* @brief %Multiset list assignment operator.
*
* Note that the assignment completely changes the %multiset and
* that the resulting %multiset's size is the same as the number
- * of elements assigned. Old data may be lost.
+ * of elements assigned.
*/
multiset&
operator=(initializer_list<value_type> __l)
{
- this->clear();
- this->insert(__l.begin(), __l.end());
+ _M_t._M_assign_equal(__l.begin(), __l.end());
return *this;
}
#endif
* be quite fast.)
* Note that the global std::swap() function is specialized such that
* std::swap(s1,s2) will feed to this function.
+ *
+ * Whether the allocators are swapped depends on the allocator traits.
*/
void
swap(multiset& __x)
+ _GLIBCXX_NOEXCEPT_IF(__is_nothrow_swappable<_Compare>::value)
{ _M_t.swap(__x._M_t); }
// insert/erase
* improve the performance of the insertion process. A bad hint would
* cause no gains in efficiency.
*
- * See http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt07ch17.html
+ * See https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints
* for more on @a hinting.
*
* Insertion requires logarithmic time (if the hint is not taken).
* improve the performance of the insertion process. A bad hint would
* cause no gains in efficiency.
*
- * See http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt07ch17.html
+ * See https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints
* for more on @a hinting.
*
* Insertion requires logarithmic time (if the hint is not taken).
{ this->insert(__l.begin(), __l.end()); }
#endif
+#if __cplusplus > 201402L
+ /// Extract a node.
+ node_type
+ extract(const_iterator __pos)
+ {
+ __glibcxx_assert(__pos != end());
+ return _M_t.extract(__pos);
+ }
+
+ /// Extract a node.
+ node_type
+ extract(const key_type& __x)
+ { return _M_t.extract(__x); }
+
+ /// Re-insert an extracted node.
+ iterator
+ insert(node_type&& __nh)
+ { return _M_t._M_reinsert_node_equal(std::move(__nh)); }
+
+ /// Re-insert an extracted node.
+ iterator
+ insert(const_iterator __hint, node_type&& __nh)
+ { return _M_t._M_reinsert_node_hint_equal(__hint, std::move(__nh)); }
+
+ template<typename, typename>
+ friend class _Rb_tree_merge_helper;
+
+ template<typename _Compare1>
+ void
+ merge(multiset<_Key, _Compare1, _Alloc>& __source)
+ {
+ using _Merge_helper = _Rb_tree_merge_helper<multiset, _Compare1>;
+ _M_t._M_merge_equal(_Merge_helper::_S_get_tree(__source));
+ }
+
+ template<typename _Compare1>
+ void
+ merge(multiset<_Key, _Compare1, _Alloc>&& __source)
+ { merge(__source); }
+
+ template<typename _Compare1>
+ void
+ merge(set<_Key, _Compare1, _Alloc>& __source)
+ {
+ using _Merge_helper = _Rb_tree_merge_helper<multiset, _Compare1>;
+ _M_t._M_merge_equal(_Merge_helper::_S_get_tree(__source));
+ }
+
+ template<typename _Compare1>
+ void
+ merge(set<_Key, _Compare1, _Alloc>&& __source)
+ { merge(__source); }
+#endif // C++17
+
#if __cplusplus >= 201103L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 130. Associative erase should return an iterator.
// multiset operations:
+ //@{
/**
* @brief Finds the number of elements with given key.
* @param __x Key of elements to be located.
count(const key_type& __x) const
{ return _M_t.count(__x); }
+#if __cplusplus > 201103L
+ template<typename _Kt>
+ auto
+ count(const _Kt& __x) const -> decltype(_M_t._M_count_tr(__x))
+ { return _M_t._M_count_tr(__x); }
+#endif
+ //@}
+
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 214. set::find() missing const overload
//@{
const_iterator
find(const key_type& __x) const
{ return _M_t.find(__x); }
+
+#if __cplusplus > 201103L
+ template<typename _Kt>
+ auto
+ find(const _Kt& __x)
+ -> decltype(iterator{_M_t._M_find_tr(__x)})
+ { return iterator{_M_t._M_find_tr(__x)}; }
+
+ template<typename _Kt>
+ auto
+ find(const _Kt& __x) const
+ -> decltype(const_iterator{_M_t._M_find_tr(__x)})
+ { return const_iterator{_M_t._M_find_tr(__x)}; }
+#endif
//@}
//@{
const_iterator
lower_bound(const key_type& __x) const
{ return _M_t.lower_bound(__x); }
+
+#if __cplusplus > 201103L
+ template<typename _Kt>
+ auto
+ lower_bound(const _Kt& __x)
+ -> decltype(_M_t._M_lower_bound_tr(__x))
+ { return _M_t._M_lower_bound_tr(__x); }
+
+ template<typename _Kt>
+ auto
+ lower_bound(const _Kt& __x) const
+ -> decltype(_M_t._M_lower_bound_tr(__x))
+ { return _M_t._M_lower_bound_tr(__x); }
+#endif
//@}
//@{
const_iterator
upper_bound(const key_type& __x) const
{ return _M_t.upper_bound(__x); }
+
+#if __cplusplus > 201103L
+ template<typename _Kt>
+ auto
+ upper_bound(const _Kt& __x)
+ -> decltype(_M_t._M_upper_bound_tr(__x))
+ { return _M_t._M_upper_bound_tr(__x); }
+
+ template<typename _Kt>
+ auto
+ upper_bound(const _Kt& __x) const
+ -> decltype(_M_t._M_upper_bound_tr(__x))
+ { return _M_t._M_upper_bound_tr(__x); }
+#endif
//@}
//@{
std::pair<const_iterator, const_iterator>
equal_range(const key_type& __x) const
{ return _M_t.equal_range(__x); }
+
+#if __cplusplus > 201103L
+ template<typename _Kt>
+ auto
+ equal_range(const _Kt& __x)
+ -> decltype(_M_t._M_equal_range_tr(__x))
+ { return _M_t._M_equal_range_tr(__x); }
+
+ template<typename _Kt>
+ auto
+ equal_range(const _Kt& __x) const
+ -> decltype(_M_t._M_equal_range_tr(__x))
+ { return _M_t._M_equal_range_tr(__x); }
+#endif
//@}
template<typename _K1, typename _C1, typename _A1>
* @return True iff @a __x is lexicographically less than @a __y.
*
* This is a total ordering relation. It is linear in the size of the
- * maps. The elements must be comparable with @c <.
+ * sets. The elements must be comparable with @c <.
*
* See std::lexicographical_compare() for how the determination is made.
*/
inline void
swap(multiset<_Key, _Compare, _Alloc>& __x,
multiset<_Key, _Compare, _Alloc>& __y)
+ _GLIBCXX_NOEXCEPT_IF(noexcept(__x.swap(__y)))
{ __x.swap(__y); }
_GLIBCXX_END_NAMESPACE_CONTAINER
+
+#if __cplusplus > 201402L
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ // Allow std::multiset access to internals of compatible sets.
+ template<typename _Val, typename _Cmp1, typename _Alloc, typename _Cmp2>
+ struct
+ _Rb_tree_merge_helper<_GLIBCXX_STD_C::multiset<_Val, _Cmp1, _Alloc>,
+ _Cmp2>
+ {
+ private:
+ friend class _GLIBCXX_STD_C::multiset<_Val, _Cmp1, _Alloc>;
+
+ static auto&
+ _S_get_tree(_GLIBCXX_STD_C::set<_Val, _Cmp2, _Alloc>& __set)
+ { return __set._M_t; }
+
+ static auto&
+ _S_get_tree(_GLIBCXX_STD_C::multiset<_Val, _Cmp2, _Alloc>& __set)
+ { return __set._M_t; }
+ };
+_GLIBCXX_END_NAMESPACE_VERSION
+#endif // C++17
+
} // namespace std
#endif /* _STL_MULTISET_H */