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