This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Improve relocation


Hello,

here are some tweaks so that I can usefully mark deque as trivially relocatable. It includes more noexcept(auto) madness. For __relocate_a_1, I should also test if copying, ++ and != are noexcept, but I wanted to ask first because there might be restrictions on what iterators are allowed to do, even if I didn't see them. Also, the current code already ignores those, so it may as well be fixed in another patch.

Allocators are complicated. I specialized only for the default allocator, because that's by far the one that is used the most, and I have much less risk of getting it wrong. Some allocator expert is welcome to make a better test. I do not know in details how deque is implemented. A quick look seemed to show that trivial relocation should be fine, but I would appreciate a confirmation.

The extra parameter for __is_trivially_relocatable is not used, but I expect it will be as soon as the specializations of __is_trivially_relocatable become more advanced.

If I use or specialize __is_trivially_relocatable in many places, this forces to #include bits/stl_uninitialized.h in many places. I wonder if I should move some of that stuff. Since I may use it in std::swap, bits/move.h looks like a sensible place for the core pieces (__is_trivially_relocatable, and __relocate_object if I ever create that). That or type_traits.

Regtested on gcc112. I manually checked that there was a speed-up for operations on vector<deque<int>>, although doing any kind of benchmarking on gcc112 is hard, I'll test locally next time.

2018-10-26  Marc Glisse  <marc.glisse@inria.fr>

	PR libstdc++/87106
	* include/bits/stl_algobase.h: Include <type_traits>.
	(__niter_base): Add noexcept specification.
	* include/bits/stl_deque.h: Include <bits/stl_uninitialized.h>.
	(__is_trivially_relocatable): Specialize for deque.
	* include/bits/stl_iterator.h: Include <type_traits>.
	(__niter_base): Add noexcept specification.
	* include/bits/stl_uninitialized.h (__is_trivially_relocatable):
	Add parameter for meta-programming.
	(__relocate_a_1, __relocate_a): Add noexcept specification.
	* include/bits/stl_vector.h (__use_relocate): Test __relocate_a.

--
Marc Glisse
Index: libstdc++-v3/include/bits/stl_algobase.h
===================================================================
--- libstdc++-v3/include/bits/stl_algobase.h	(revision 265522)
+++ libstdc++-v3/include/bits/stl_algobase.h	(working copy)
@@ -62,20 +62,23 @@
 #include <ext/type_traits.h>
 #include <ext/numeric_traits.h>
 #include <bits/stl_pair.h>
 #include <bits/stl_iterator_base_types.h>
 #include <bits/stl_iterator_base_funcs.h>
 #include <bits/stl_iterator.h>
 #include <bits/concept_check.h>
 #include <debug/debug.h>
 #include <bits/move.h> // For std::swap
 #include <bits/predefined_ops.h>
+#if __cplusplus >= 201103L
+# include <type_traits>
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus < 201103L
   // See http://gcc.gnu.org/ml/libstdc++/2004-08/msg00167.html: in a
   // nutshell, we are partially implementing the resolution of DR 187,
   // when it's safe, i.e., the value_types are equal.
   template<bool _BoolType>
@@ -268,20 +271,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (__comp(__a, __b))
 	return __b;
       return __a;
     }
 
   // Fallback implementation of the function in bits/stl_iterator.h used to
   // remove the __normal_iterator wrapper. See copy, fill, ...
   template<typename _Iterator>
     inline _Iterator
     __niter_base(_Iterator __it)
+    _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
     { return __it; }
 
   // Reverse the __niter_base transformation to get a
   // __normal_iterator back again (this assumes that __normal_iterator
   // is only used to wrap random access iterators, like pointers).
   template<typename _From, typename _To>
     inline _From
     __niter_wrap(_From __from, _To __res)
     { return __from + (__res - std::__niter_base(__from)); }
 
Index: libstdc++-v3/include/bits/stl_deque.h
===================================================================
--- libstdc++-v3/include/bits/stl_deque.h	(revision 265522)
+++ libstdc++-v3/include/bits/stl_deque.h	(working copy)
@@ -54,20 +54,21 @@
  */
 
 #ifndef _STL_DEQUE_H
 #define _STL_DEQUE_H 1
 
 #include <bits/concept_check.h>
 #include <bits/stl_iterator_base_types.h>
 #include <bits/stl_iterator_base_funcs.h>
 #if __cplusplus >= 201103L
 #include <initializer_list>
+#include <bits/stl_uninitialized.h> // for __is_trivially_relocatable
 #endif
 
 #include <debug/assertions.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
   /**
@@ -2359,14 +2360,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   /// See std::deque::swap().
   template<typename _Tp, typename _Alloc>
     inline void
     swap(deque<_Tp,_Alloc>& __x, deque<_Tp,_Alloc>& __y)
     _GLIBCXX_NOEXCEPT_IF(noexcept(__x.swap(__y)))
     { __x.swap(__y); }
 
 #undef _GLIBCXX_DEQUE_BUF_SIZE
 
 _GLIBCXX_END_NAMESPACE_CONTAINER
+
+#if __cplusplus >= 201103L
+  // std::allocator is safe, but it is not the only allocator
+  // for which this is valid.
+  template<class _Tp>
+    struct __is_trivially_relocatable<_GLIBCXX_STD_C::deque<_Tp>>
+    : true_type { };
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #endif /* _STL_DEQUE_H */
Index: libstdc++-v3/include/bits/stl_iterator.h
===================================================================
--- libstdc++-v3/include/bits/stl_iterator.h	(revision 265522)
+++ libstdc++-v3/include/bits/stl_iterator.h	(working copy)
@@ -59,20 +59,24 @@
 
 #ifndef _STL_ITERATOR_H
 #define _STL_ITERATOR_H 1
 
 #include <bits/cpp_type_traits.h>
 #include <ext/type_traits.h>
 #include <bits/move.h>
 #include <bits/ptr_traits.h>
 
 #if __cplusplus > 201402L
+# include <type_traits>
+#endif
+
+#if __cplusplus > 201402L
 # define __cpp_lib_array_constexpr 201603
 #endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /**
    * @addtogroup iterators
    * @{
@@ -997,20 +1001,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _Iterator, typename _Container>
     _Iterator
     __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it)
+    _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
     { return __it.base(); }
 
 #if __cplusplus >= 201103L
 
   /**
    * @addtogroup iterators
    * @{
    */
 
   // 24.4.3  Move iterators
Index: libstdc++-v3/include/bits/stl_uninitialized.h
===================================================================
--- libstdc++-v3/include/bits/stl_uninitialized.h	(revision 265522)
+++ libstdc++-v3/include/bits/stl_uninitialized.h	(working copy)
@@ -887,60 +887,63 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			 __dest, std::move(*__orig)))
 	     && noexcept(std::allocator_traits<_Allocator>::destroy(
 			    __alloc, std::__addressof(*__orig))))
     {
       typedef std::allocator_traits<_Allocator> __traits;
       __traits::construct(__alloc, __dest, std::move(*__orig));
       __traits::destroy(__alloc, std::__addressof(*__orig));
     }
 
   // This class may be specialized for specific types.
-  template<typename _Tp>
+  template<typename _Tp, typename = void>
     struct __is_trivially_relocatable
     : is_trivial<_Tp> { };
 
   template <typename _Tp, typename _Up>
     inline __enable_if_t<std::__is_trivially_relocatable<_Tp>::value, _Tp*>
     __relocate_a_1(_Tp* __first, _Tp* __last,
-		   _Tp* __result, allocator<_Up>& __alloc)
+		   _Tp* __result, allocator<_Up>& __alloc) noexcept
     {
       ptrdiff_t __count = __last - __first;
       __builtin_memmove(__result, __first, __count * sizeof(_Tp));
       return __result + __count;
     }
 
   template <typename _InputIterator, typename _ForwardIterator,
 	    typename _Allocator>
     inline _ForwardIterator
     __relocate_a_1(_InputIterator __first, _InputIterator __last,
 		   _ForwardIterator __result, _Allocator& __alloc)
+    noexcept(noexcept(std::__relocate_object_a(std::addressof(*__result),
+					       std::addressof(*__first),
+					       __alloc)))
     {
       typedef typename iterator_traits<_InputIterator>::value_type
 	_ValueType;
       typedef typename iterator_traits<_ForwardIterator>::value_type
 	_ValueType2;
       static_assert(std::is_same<_ValueType, _ValueType2>::value);
-      static_assert(noexcept(std::__relocate_object_a(std::addressof(*__result),
-						      std::addressof(*__first),
-						      __alloc)));
       _ForwardIterator __cur = __result;
       for (; __first != __last; ++__first, (void)++__cur)
 	std::__relocate_object_a(std::__addressof(*__cur),
 				 std::__addressof(*__first), __alloc);
       return __cur;
     }
 
   template <typename _InputIterator, typename _ForwardIterator,
 	    typename _Allocator>
     inline _ForwardIterator
     __relocate_a(_InputIterator __first, _InputIterator __last,
 		 _ForwardIterator __result, _Allocator& __alloc)
+    noexcept(noexcept(__relocate_a_1(std::__niter_base(__first),
+				     std::__niter_base(__last),
+				     std::__niter_base(__result), __alloc)))
     {
       return __relocate_a_1(std::__niter_base(__first),
 			    std::__niter_base(__last),
 			    std::__niter_base(__result), __alloc);
     }
 #endif
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
Index: libstdc++-v3/include/bits/stl_vector.h
===================================================================
--- libstdc++-v3/include/bits/stl_vector.h	(revision 265522)
+++ libstdc++-v3/include/bits/stl_vector.h	(working copy)
@@ -417,24 +417,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       const_iterator;
       typedef std::reverse_iterator<const_iterator>	const_reverse_iterator;
       typedef std::reverse_iterator<iterator>		reverse_iterator;
       typedef size_t					size_type;
       typedef ptrdiff_t					difference_type;
       typedef _Alloc					allocator_type;
 
     private:
 #if __cplusplus >= 201103L
       static constexpr bool __use_relocate =
-	noexcept(std::__relocate_object_a(
-			std::addressof(*std::declval<pointer>()),
-			std::addressof(*std::declval<pointer>()),
-			std::declval<_Tp_alloc_type&>()));
+	noexcept(std::__relocate_a(std::declval<pointer>(),
+				   std::declval<pointer>(),
+				   std::declval<pointer>(),
+				   std::declval<_Tp_alloc_type&>()));
 #endif
 
     protected:
       using _Base::_M_allocate;
       using _Base::_M_deallocate;
       using _Base::_M_impl;
       using _Base::_M_get_Tp_allocator;
 
     public:
       // [23.2.4.1] construct/copy/destroy

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]