I've become quite disatsified with the lack of noexcept specifications on container move construction, move assignment operator and swap. Without proper decoration on at least move construction, vectors of containers will have unacceptable performance. Here's the fix for deque.

llvm-svn: 132480
This commit is contained in:
Howard Hinnant 2011-06-02 20:00:14 +00:00
parent aa318ae495
commit 9eebe11dd5
2 changed files with 90 additions and 27 deletions

View File

@ -47,10 +47,10 @@ public:
typedef typename add_lvalue_reference<allocator_type>::type __alloc_ref; typedef typename add_lvalue_reference<allocator_type>::type __alloc_ref;
typedef typename add_lvalue_reference<allocator_type>::type __alloc_const_ref; typedef typename add_lvalue_reference<allocator_type>::type __alloc_const_ref;
_LIBCPP_INLINE_VISIBILITY __alloc_rr& __alloc() {return __end_cap_.second();} _LIBCPP_INLINE_VISIBILITY __alloc_rr& __alloc() _NOEXCEPT {return __end_cap_.second();}
_LIBCPP_INLINE_VISIBILITY const __alloc_rr& __alloc() const {return __end_cap_.second();} _LIBCPP_INLINE_VISIBILITY const __alloc_rr& __alloc() const _NOEXCEPT {return __end_cap_.second();}
_LIBCPP_INLINE_VISIBILITY pointer& __end_cap() {return __end_cap_.first();} _LIBCPP_INLINE_VISIBILITY pointer& __end_cap() _NOEXCEPT {return __end_cap_.first();}
_LIBCPP_INLINE_VISIBILITY const pointer& __end_cap() const {return __end_cap_.first();} _LIBCPP_INLINE_VISIBILITY const pointer& __end_cap() const _NOEXCEPT {return __end_cap_.first();}
__split_buffer(); __split_buffer();
explicit __split_buffer(__alloc_rr& __a); explicit __split_buffer(__alloc_rr& __a);
@ -59,17 +59,23 @@ public:
~__split_buffer(); ~__split_buffer();
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
__split_buffer(__split_buffer&& __c); __split_buffer(__split_buffer&& __c)
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
__split_buffer(__split_buffer&& __c, const __alloc_rr& __a); __split_buffer(__split_buffer&& __c, const __alloc_rr& __a);
__split_buffer& operator=(__split_buffer&& __c); __split_buffer& operator=(__split_buffer&& __c)
_NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value) ||
!__alloc_traits::propagate_on_container_move_assignment::value);
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY iterator begin() {return __begin_;} _LIBCPP_INLINE_VISIBILITY iterator begin() _NOEXCEPT {return __begin_;}
_LIBCPP_INLINE_VISIBILITY const_iterator begin() const {return __begin_;} _LIBCPP_INLINE_VISIBILITY const_iterator begin() const _NOEXCEPT {return __begin_;}
_LIBCPP_INLINE_VISIBILITY iterator end() {return __end_;} _LIBCPP_INLINE_VISIBILITY iterator end() _NOEXCEPT {return __end_;}
_LIBCPP_INLINE_VISIBILITY const_iterator end() const {return __end_;} _LIBCPP_INLINE_VISIBILITY const_iterator end() const _NOEXCEPT {return __end_;}
_LIBCPP_INLINE_VISIBILITY void clear() {__destruct_at_end(__begin_);} _LIBCPP_INLINE_VISIBILITY
void clear() _NOEXCEPT
{__destruct_at_end(__begin_);}
_LIBCPP_INLINE_VISIBILITY size_type size() const {return static_cast<size_type>(__end_ - __begin_);} _LIBCPP_INLINE_VISIBILITY size_type size() const {return static_cast<size_type>(__end_ - __begin_);}
_LIBCPP_INLINE_VISIBILITY bool empty() const {return __end_ == __begin_;} _LIBCPP_INLINE_VISIBILITY bool empty() const {return __end_ == __begin_;}
_LIBCPP_INLINE_VISIBILITY size_type capacity() const {return static_cast<size_type>(__end_cap() - __first_);} _LIBCPP_INLINE_VISIBILITY size_type capacity() const {return static_cast<size_type>(__end_cap() - __first_);}
@ -82,7 +88,7 @@ public:
_LIBCPP_INLINE_VISIBILITY const_reference back() const {return *(__end_ - 1);} _LIBCPP_INLINE_VISIBILITY const_reference back() const {return *(__end_ - 1);}
void reserve(size_type __n); void reserve(size_type __n);
void shrink_to_fit(); void shrink_to_fit() _NOEXCEPT;
void push_front(const_reference __x); void push_front(const_reference __x);
void push_back(const_reference __x); void push_back(const_reference __x);
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
@ -120,40 +126,47 @@ public:
void __destruct_at_begin(pointer __new_begin, false_type); void __destruct_at_begin(pointer __new_begin, false_type);
void __destruct_at_begin(pointer __new_begin, true_type); void __destruct_at_begin(pointer __new_begin, true_type);
_LIBCPP_INLINE_VISIBILITY void __destruct_at_end(pointer __new_last) _LIBCPP_INLINE_VISIBILITY
void __destruct_at_end(pointer __new_last) _NOEXCEPT
{__destruct_at_end(__new_last, is_trivially_destructible<value_type>());} {__destruct_at_end(__new_last, is_trivially_destructible<value_type>());}
void __destruct_at_end(pointer __new_last, false_type); void __destruct_at_end(pointer __new_last, false_type) _NOEXCEPT;
void __destruct_at_end(pointer __new_last, true_type); void __destruct_at_end(pointer __new_last, true_type) _NOEXCEPT;
void swap(__split_buffer& __x); void swap(__split_buffer& __x)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
__is_nothrow_swappable<__alloc_rr>::value);
bool __invariants() const; bool __invariants() const;
private: private:
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(const __split_buffer& __c, true_type) void __move_assign_alloc(const __split_buffer& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
{ {
__alloc() = _STD::move(__c.__alloc()); __alloc() = _STD::move(__c.__alloc());
} }
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(const __split_buffer& __c, false_type) void __move_assign_alloc(const __split_buffer& __c, false_type) _NOEXCEPT
{} {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y) static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
__is_nothrow_swappable<__alloc_rr>::value)
{__swap_alloc(__x, __y, integral_constant<bool, {__swap_alloc(__x, __y, integral_constant<bool,
__alloc_traits::propagate_on_container_swap::value>());} __alloc_traits::propagate_on_container_swap::value>());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y, true_type) static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y, true_type)
_NOEXCEPT_(__is_nothrow_swappable<__alloc_rr>::value)
{ {
using _STD::swap; using _STD::swap;
swap(__x, __y); swap(__x, __y);
} }
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y, false_type) static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y, false_type) _NOEXCEPT
{} {}
}; };
@ -284,7 +297,7 @@ __split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, true_t
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY inline
void void
__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT
{ {
while (__new_last < __end_) while (__new_last < __end_)
__alloc_traits::destroy(__alloc(), --__end_); __alloc_traits::destroy(__alloc(), --__end_);
@ -293,7 +306,7 @@ __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_typ
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY inline
void void
__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) _NOEXCEPT
{ {
__end_ = __new_last; __end_ = __new_last;
} }
@ -340,6 +353,7 @@ __split_buffer<_Tp, _Allocator>::~__split_buffer()
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c) __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c)
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
: __first_(_STD::move(__c.__first_)), : __first_(_STD::move(__c.__first_)),
__begin_(_STD::move(__c.__begin_)), __begin_(_STD::move(__c.__begin_)),
__end_(_STD::move(__c.__end_)), __end_(_STD::move(__c.__end_)),
@ -380,6 +394,9 @@ __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __al
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
__split_buffer<_Tp, _Allocator>& __split_buffer<_Tp, _Allocator>&
__split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c) __split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c)
_NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value) ||
!__alloc_traits::propagate_on_container_move_assignment::value)
{ {
clear(); clear();
shrink_to_fit(); shrink_to_fit();
@ -399,6 +416,8 @@ __split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c)
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
void void
__split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x) __split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
__is_nothrow_swappable<__alloc_rr>::value)
{ {
_STD::swap(__first_, __x.__first_); _STD::swap(__first_, __x.__first_);
_STD::swap(__begin_, __x.__begin_); _STD::swap(__begin_, __x.__begin_);
@ -425,7 +444,7 @@ __split_buffer<_Tp, _Allocator>::reserve(size_type __n)
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
void void
__split_buffer<_Tp, _Allocator>::shrink_to_fit() __split_buffer<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT
{ {
if (capacity() > size()) if (capacity() > size())
{ {
@ -612,6 +631,16 @@ __split_buffer<_Tp, _Allocator>::emplace_back(_Args&&... __args)
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
void
swap(__split_buffer<_Tp, _Allocator>& __x, __split_buffer<_Tp, _Allocator>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
{
__x.swap(__y);
}
_LIBCPP_END_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_SPLIT_BUFFER #endif // _LIBCPP_SPLIT_BUFFER

View File

@ -930,21 +930,29 @@ protected:
__deque_base(); __deque_base();
explicit __deque_base(const allocator_type& __a); explicit __deque_base(const allocator_type& __a);
public:
~__deque_base(); ~__deque_base();
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
__deque_base(__deque_base&& __c); __deque_base(__deque_base&& __c)
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
__deque_base(__deque_base&& __c, const allocator_type& __a); __deque_base(__deque_base&& __c, const allocator_type& __a);
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
void swap(__deque_base& __c); void swap(__deque_base& __c)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
__is_nothrow_swappable<allocator_type>::value);
protected:
void clear() _NOEXCEPT; void clear() _NOEXCEPT;
bool __invariants() const; bool __invariants() const;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void __move_assign(__deque_base& __c) void __move_assign(__deque_base& __c)
_NOEXCEPT_(is_nothrow_move_assignable<__map>::value &&
(!__alloc_traits::propagate_on_container_move_assignment::value ||
is_nothrow_move_assignable<allocator_type>::value))
{ {
__map_ = _STD::move(__c.__map_); __map_ = _STD::move(__c.__map_);
__start_ = __c.__start_; __start_ = __c.__start_;
@ -955,27 +963,33 @@ protected:
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(__deque_base& __c) void __move_assign_alloc(__deque_base& __c)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_move_assignment::value ||
is_nothrow_move_assignable<allocator_type>::value)
{__move_assign_alloc(__c, integral_constant<bool, {__move_assign_alloc(__c, integral_constant<bool,
__alloc_traits::propagate_on_container_move_assignment::value>());} __alloc_traits::propagate_on_container_move_assignment::value>());}
private: private:
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(const __deque_base& __c, true_type) void __move_assign_alloc(const __deque_base& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
{ {
__alloc() = _STD::move(__c.__alloc()); __alloc() = _STD::move(__c.__alloc());
} }
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(const __deque_base& __c, false_type) void __move_assign_alloc(const __deque_base& __c, false_type) _NOEXCEPT
{} {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
static void __swap_alloc(allocator_type& __x, allocator_type& __y) static void __swap_alloc(allocator_type& __x, allocator_type& __y)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value)
{__swap_alloc(__x, __y, integral_constant<bool, {__swap_alloc(__x, __y, integral_constant<bool,
__alloc_traits::propagate_on_container_swap::value>());} __alloc_traits::propagate_on_container_swap::value>());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type) static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type)
_NOEXCEPT_(__is_nothrow_swappable<allocator_type>::value)
{ {
using _STD::swap; using _STD::swap;
swap(__x, __y); swap(__x, __y);
@ -983,6 +997,7 @@ private:
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
static void __swap_alloc(allocator_type& __x, allocator_type& __y, false_type) static void __swap_alloc(allocator_type& __x, allocator_type& __y, false_type)
_NOEXCEPT
{} {}
}; };
@ -1073,6 +1088,7 @@ __deque_base<_Tp, _Allocator>::~__deque_base()
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
__deque_base<_Tp, _Allocator>::__deque_base(__deque_base&& __c) __deque_base<_Tp, _Allocator>::__deque_base(__deque_base&& __c)
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
: __map_(_STD::move(__c.__map_)), : __map_(_STD::move(__c.__map_)),
__start_(_STD::move(__c.__start_)), __start_(_STD::move(__c.__start_)),
__size_(_STD::move(__c.__size_)) __size_(_STD::move(__c.__size_))
@ -1105,6 +1121,8 @@ __deque_base<_Tp, _Allocator>::__deque_base(__deque_base&& __c, const allocator_
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
void void
__deque_base<_Tp, _Allocator>::swap(__deque_base& __c) __deque_base<_Tp, _Allocator>::swap(__deque_base& __c)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
__is_nothrow_swappable<allocator_type>::value)
{ {
__map_.swap(__c.__map_); __map_.swap(__c.__map_);
_STD::swap(__start_, __c.__start_); _STD::swap(__start_, __c.__start_);
@ -1183,9 +1201,14 @@ public:
deque& operator=(initializer_list<value_type> __il) {assign(__il); return *this;} deque& operator=(initializer_list<value_type> __il) {assign(__il); return *this;}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
deque(deque&& __c); deque(deque&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__base>::value);
deque(deque&& __c, const allocator_type& __a); deque(deque&& __c, const allocator_type& __a);
deque& operator=(deque&& __c); deque& operator=(deque&& __c)
_NOEXCEPT_(
(__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value) ||
(!__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<value_type>::value));
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _InputIter> template <class _InputIter>
@ -1290,7 +1313,9 @@ public:
iterator erase(const_iterator __p); iterator erase(const_iterator __p);
iterator erase(const_iterator __f, const_iterator __l); iterator erase(const_iterator __f, const_iterator __l);
void swap(deque& __c); void swap(deque& __c)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
void clear() _NOEXCEPT; void clear() _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
@ -1448,6 +1473,7 @@ deque<_Tp, _Allocator>::operator=(const deque& __c)
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
deque<_Tp, _Allocator>::deque(deque&& __c) deque<_Tp, _Allocator>::deque(deque&& __c)
_NOEXCEPT_(is_nothrow_move_constructible<__base>::value)
: __base(_STD::move(__c)) : __base(_STD::move(__c))
{ {
} }
@ -1468,6 +1494,11 @@ template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
deque<_Tp, _Allocator>& deque<_Tp, _Allocator>&
deque<_Tp, _Allocator>::operator=(deque&& __c) deque<_Tp, _Allocator>::operator=(deque&& __c)
_NOEXCEPT_(
(__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value) ||
(!__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<value_type>::value))
{ {
__move_assign(__c, integral_constant<bool, __move_assign(__c, integral_constant<bool,
__alloc_traits::propagate_on_container_move_assignment::value>()); __alloc_traits::propagate_on_container_move_assignment::value>());
@ -2713,6 +2744,8 @@ template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
void void
deque<_Tp, _Allocator>::swap(deque& __c) deque<_Tp, _Allocator>::swap(deque& __c)
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value)
{ {
__base::swap(__c); __base::swap(__c);
} }
@ -2778,6 +2811,7 @@ template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY inline
void void
swap(deque<_Tp, _Allocator>& __x, deque<_Tp, _Allocator>& __y) swap(deque<_Tp, _Allocator>& __x, deque<_Tp, _Allocator>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
{ {
__x.swap(__y); __x.swap(__y);
} }