With improved memset optimizations in std::uninitialized_fill and
std::uninitialized_fill_n (see r15-4473-g3abe751ea86e34), we can make
the non-standard internal helpers __uninitialized_default and
__uninitialized_default_n use those directly instead of using std::fill
and std::fill_n respectively. And if we do that, we no longer need to
check whether the type is assignable, because avoiding std::fill means
no assignment happens.

If the type being constructed is trivially default constructible and
trivially copy constructible, then it's unobservable if we construct one
object and copy it N-1 times, rather than constructing N objects. For
byte-sized integer types this allows the loop to be replaced with
memset.

Because these functions are not defined for C++98 at all, we can use
if-constexpr to simplify them and remove the dispatching to members of
class template specializations.

By removing the uses of std::fill and std::fill_n we no longer need to
include stl_algobase.h in stl_uninitialized.h which might improve
compilation time for some other parts of the library.

libstdc++-v3/ChangeLog:

        * include/bits/stl_uninitialized.h: Do not include
        bits/stl_algobase.h.
        (__uninitialized_default_1, __uninitialized_default_n_1):
        Remove.
        (__uninitialized_default, __uninitialized_default_n): Use
        'if constexpr' and only consider triviality constructibility
        not assignability when deciding on the algorithm to use.
---

Tested x86_64-linux.

 libstdc++-v3/include/bits/stl_uninitialized.h | 136 ++++++------------
 1 file changed, 42 insertions(+), 94 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h 
b/libstdc++-v3/include/bits/stl_uninitialized.h
index bde787c2beaa..d5a399e16c90 100644
--- a/libstdc++-v3/include/bits/stl_uninitialized.h
+++ b/libstdc++-v3/include/bits/stl_uninitialized.h
@@ -60,7 +60,6 @@
 # include <type_traits>
 # include <bits/ptr_traits.h>      // to_address
 # include <bits/stl_pair.h>        // pair
-# include <bits/stl_algobase.h>    // fill, fill_n
 #endif
 
 #include <bits/cpp_type_traits.h> // __is_pointer
@@ -829,92 +828,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Extensions: __uninitialized_default, __uninitialized_default_n,
   // __uninitialized_default_a, __uninitialized_default_n_a.
 
-  template<bool _TrivialValueType>
-    struct __uninitialized_default_1
-    {
-      template<typename _ForwardIterator>
-        _GLIBCXX26_CONSTEXPR
-        static void
-        __uninit_default(_ForwardIterator __first, _ForwardIterator __last)
-        {
-         _UninitDestroyGuard<_ForwardIterator> __guard(__first);
-         for (; __first != __last; ++__first)
-           std::_Construct(std::addressof(*__first));
-         __guard.release();
-       }
-    };
-
-  template<>
-    struct __uninitialized_default_1<true>
-    {
-      template<typename _ForwardIterator>
-        _GLIBCXX26_CONSTEXPR
-        static void
-        __uninit_default(_ForwardIterator __first, _ForwardIterator __last)
-        {
-         if (__first == __last)
-           return;
-
-         typename iterator_traits<_ForwardIterator>::value_type* __val
-           = std::addressof(*__first);
-         std::_Construct(__val);
-         if (++__first != __last)
-           std::fill(__first, __last, *__val);
-       }
-    };
-
-  template<bool _TrivialValueType>
-    struct __uninitialized_default_n_1
-    {
-      template<typename _ForwardIterator, typename _Size>
-       _GLIBCXX20_CONSTEXPR
-        static _ForwardIterator
-        __uninit_default_n(_ForwardIterator __first, _Size __n)
-        {
-         _UninitDestroyGuard<_ForwardIterator> __guard(__first);
-         for (; __n > 0; --__n, (void) ++__first)
-           std::_Construct(std::addressof(*__first));
-         __guard.release();
-         return __first;
-       }
-    };
-
-  template<>
-    struct __uninitialized_default_n_1<true>
-    {
-      template<typename _ForwardIterator, typename _Size>
-       _GLIBCXX20_CONSTEXPR
-        static _ForwardIterator
-        __uninit_default_n(_ForwardIterator __first, _Size __n)
-        {
-         if (__n > 0)
-           {
-             typename iterator_traits<_ForwardIterator>::value_type* __val
-               = std::addressof(*__first);
-             std::_Construct(__val);
-             ++__first;
-             __first = std::fill_n(__first, __n - 1, *__val);
-           }
-         return __first;
-       }
-    };
-
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
   // __uninitialized_default
   // Fills [first, last) with value-initialized value_types.
   template<typename _ForwardIterator>
     _GLIBCXX26_CONSTEXPR
     inline void
-    __uninitialized_default(_ForwardIterator __first,
-                           _ForwardIterator __last)
+    __uninitialized_default(_ForwardIterator __first, _ForwardIterator __last)
     {
-      typedef typename iterator_traits<_ForwardIterator>::value_type
-       _ValueType;
-      // trivial types can have deleted assignment
-      const bool __assignable = is_copy_assignable<_ValueType>::value;
+      using _ValueType = typename 
iterator_traits<_ForwardIterator>::value_type;
 
-      std::__uninitialized_default_1<__is_trivial(_ValueType)
-                                    && __assignable>::
-       __uninit_default(__first, __last);
+      if constexpr (__and_<is_trivially_default_constructible<_ValueType>,
+                          is_trivially_copy_constructible<_ValueType>>::value)
+       {
+         if (__first == __last)
+           return;
+         if (!std::__is_constant_evaluated())
+           {
+             auto* __addr = std::addressof(*__first);
+             std::_Construct(__addr);
+             const auto& __val = *__addr;
+             if (++__first != __last)
+               std::uninitialized_fill(__first, __last, __val);
+           }
+       }
+
+      _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+      for (; __first != __last; ++__first)
+       std::_Construct(std::addressof(*__first));
+      __guard.release();
     }
 
   // __uninitialized_default_n
@@ -924,23 +867,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline _ForwardIterator
     __uninitialized_default_n(_ForwardIterator __first, _Size __n)
     {
-#ifdef __cpp_lib_is_constant_evaluated
-      if (std::is_constant_evaluated())
-       return __uninitialized_default_n_1<false>::
-                __uninit_default_n(__first, __n);
-#endif
+      using _ValueType = typename 
iterator_traits<_ForwardIterator>::value_type;
 
-      typedef typename iterator_traits<_ForwardIterator>::value_type
-       _ValueType;
-      // See uninitialized_fill_n for the conditions for using std::fill_n.
-      constexpr bool __can_fill
-       = __and_<is_integral<_Size>, is_copy_assignable<_ValueType>>::value;
+      if constexpr (__and_<is_trivially_default_constructible<_ValueType>,
+                          is_trivially_copy_constructible<_ValueType>,
+                          is_integral<_Size>>::value)
+       {
+         if (!std::__is_constant_evaluated() && __n > 0)
+           {
+             auto* __addr = std::addressof(*__first);
+             std::_Construct(__addr);
+             const auto& __val = *__addr;
+             return std::uninitialized_fill_n(++__first, --__n, __val);
+           }
+       }
 
-      return __uninitialized_default_n_1<__is_trivial(_ValueType)
-                                        && __can_fill>::
-       __uninit_default_n(__first, __n);
+      _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+      for (; __n > 0; --__n, (void) ++__first)
+       std::_Construct(std::addressof(*__first));
+      __guard.release();
+      return __first;
     }
-
+#pragma GCC diagnostic pop
 
   // __uninitialized_default_a
   // Fills [first, last) with value_types constructed by the allocator
-- 
2.49.0

Reply via email to