#define _STL_UNINITIALIZED_H 1
#if __cplusplus >= 201103L
-#include <type_traits>
+# 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/stl_algobase.h> // copy
+#include <bits/cpp_type_traits.h> // __is_pointer
+#include <bits/stl_iterator_base_funcs.h> // distance, advance
+#include <bits/stl_iterator.h> // __niter_base
#include <ext/alloc_traits.h> // __alloc_traits
-#if __cplusplus >= 201703L
-#include <bits/stl_pair.h>
-#endif
-
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/// @cond undocumented
-#if __cplusplus >= 201103L
- template<typename _ValueType, typename _Tp>
- constexpr bool
- __check_constructible()
- {
- // Trivial types can have deleted constructors, but std::copy etc.
- // only use assignment (or memmove) not construction, so we need an
- // explicit check that construction from _Tp is actually valid,
- // otherwise some ill-formed uses of std::uninitialized_xxx would
- // compile without errors. This gives a nice clear error message.
- static_assert(is_constructible<_ValueType, _Tp>::value,
- "result type must be constructible from input type");
-
- return true;
- }
-
-// If the type is trivial we don't need to construct it, just assign to it.
-// But trivial types can still have deleted or inaccessible assignment,
-// so don't try to use std::copy or std::fill etc. if we can't assign.
-# define _GLIBCXX_USE_ASSIGN_FOR_INIT(T, U) \
- __is_trivial(T) && __is_assignable(T&, U) \
- && std::__check_constructible<T, U>()
-#else
-// No need to check if is_constructible<T, U> for C++98. Trivial types have
-// no user-declared constructors, so if the assignment is valid, construction
-// should be too.
-# define _GLIBCXX_USE_ASSIGN_FOR_INIT(T, U) \
- __is_trivial(T) && __is_assignable(T&, U)
-#endif
-
template<typename _ForwardIterator, typename _Alloc = void>
struct _UninitDestroyGuard
{
_UninitDestroyGuard(const _UninitDestroyGuard&);
};
+ // This is the default implementation of std::uninitialized_copy.
template<typename _InputIterator, typename _ForwardIterator>
_GLIBCXX20_CONSTEXPR
_ForwardIterator
return __result;
}
- template<bool _TrivialValueTypes>
+#if __cplusplus < 201103L
+
+ // True if we can unwrap _Iter to get a pointer by using std::__niter_base.
+ template<typename _Iter,
+ typename _Base = __decltype(std::__niter_base(*(_Iter*)0))>
+ struct __unwrappable_niter
+ { enum { __value = false }; };
+
+ template<typename _Iter, typename _Tp>
+ struct __unwrappable_niter<_Iter, _Tp*>
+ { enum { __value = true }; };
+
+ // Use template specialization for C++98 when 'if constexpr' can't be used.
+ template<bool _CanMemcpy>
struct __uninitialized_copy
{
template<typename _InputIterator, typename _ForwardIterator>
template<>
struct __uninitialized_copy<true>
{
+ // Overload for generic iterators.
template<typename _InputIterator, typename _ForwardIterator>
static _ForwardIterator
__uninit_copy(_InputIterator __first, _InputIterator __last,
_ForwardIterator __result)
- { return std::copy(__first, __last, __result); }
- };
+ {
+ if (__unwrappable_niter<_InputIterator>::__value
+ && __unwrappable_niter<_ForwardIterator>::__value)
+ {
+ __uninit_copy(std::__niter_base(__first),
+ std::__niter_base(__last),
+ std::__niter_base(__result));
+ std::advance(__result, std::distance(__first, __last));
+ return __result;
+ }
+ else
+ return std::__do_uninit_copy(__first, __last, __result);
+ }
+ // Overload for pointers.
+ template<typename _Tp, typename _Up>
+ static _Up*
+ __uninit_copy(_Tp* __first, _Tp* __last, _Up* __result)
+ {
+ // Ensure that we don't successfully memcpy in cases that should be
+ // ill-formed because is_constructible<_Up, _Tp&> is false.
+ typedef __typeof__(static_cast<_Up>(*__first)) __check
+ __attribute__((__unused__));
+
+ const ptrdiff_t __n = __last - __first;
+ if (__builtin_expect(__n > 0, true))
+ {
+ __builtin_memcpy(__result, __first, __n * sizeof(_Tp));
+ __result += __n;
+ }
+ return __result;
+ }
+ };
+#endif
/// @endcond
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
/**
* @brief Copies the range [first,last) into result.
* @param __first An input iterator.
* @param __last An input iterator.
- * @param __result An output iterator.
- * @return __result + (__first - __last)
+ * @param __result A forward iterator.
+ * @return __result + (__last - __first)
*
- * Like copy(), but does not require an initialized output range.
+ * Like std::copy, but does not require an initialized output range.
*/
template<typename _InputIterator, typename _ForwardIterator>
inline _ForwardIterator
uninitialized_copy(_InputIterator __first, _InputIterator __last,
_ForwardIterator __result)
{
+ // We can use memcpy to copy the ranges under these conditions:
+ //
+ // _ForwardIterator and _InputIterator are both contiguous iterators,
+ // so that we can turn them into pointers to pass to memcpy.
+ // Before C++20 we can't detect all contiguous iterators, so we only
+ // handle built-in pointers and __normal_iterator<T*, C> types.
+ //
+ // The value types of both iterators are trivially-copyable types,
+ // so that memcpy is not undefined and can begin the lifetime of
+ // new objects in the output range.
+ //
+ // Finally, memcpy from the source type, S, to the destination type, D,
+ // must give the same value as initialization of D from S would give.
+ // We require is_trivially_constructible<D, S> to be true, but that is
+ // not sufficient. Some cases of trivial initialization are not just a
+ // bitwise copy, even when sizeof(D) == sizeof(S),
+ // e.g. bit_cast<unsigned>(1.0f) != 1u because the corresponding bits
+ // of the value representations do not have the same meaning.
+ // We cannot tell when this condition is true in general,
+ // so we rely on the __memcpyable trait.
+
+#if __cplusplus >= 201103L
+ using _Dest = decltype(std::__niter_base(__result));
+ using _Src = decltype(std::__niter_base(__first));
+ using _ValT = typename iterator_traits<_ForwardIterator>::value_type;
+
+ if constexpr (!__is_trivially_constructible(_ValT, decltype(*__first)))
+ return std::__do_uninit_copy(__first, __last, __result);
+ else if constexpr (__memcpyable<_Dest, _Src>::__value)
+ {
+ ptrdiff_t __n = __last - __first;
+ if (__n > 0) [[__likely__]]
+ {
+ using _ValT = typename remove_pointer<_Src>::type;
+ __builtin_memcpy(std::__niter_base(__result),
+ std::__niter_base(__first),
+ __n * sizeof(_ValT));
+ __result += __n;
+ }
+ return __result;
+ }
+#if __cpp_lib_concepts
+ else if constexpr (contiguous_iterator<_ForwardIterator>
+ && contiguous_iterator<_InputIterator>)
+ {
+ using _DestPtr = decltype(std::to_address(__result));
+ using _SrcPtr = decltype(std::to_address(__first));
+ if constexpr (__memcpyable<_DestPtr, _SrcPtr>::__value)
+ {
+ if (auto __n = __last - __first; __n > 0) [[likely]]
+ {
+ void* __dest = std::to_address(__result);
+ const void* __src = std::to_address(__first);
+ size_t __nbytes = __n * sizeof(remove_pointer_t<_DestPtr>);
+ __builtin_memcpy(__dest, __src, __nbytes);
+ __result += __n;
+ }
+ return __result;
+ }
+ else
+ return std::__do_uninit_copy(__first, __last, __result);
+ }
+#endif
+ else
+ return std::__do_uninit_copy(__first, __last, __result);
+#else // C++98
typedef typename iterator_traits<_InputIterator>::value_type
_ValueType1;
typedef typename iterator_traits<_ForwardIterator>::value_type
_ValueType2;
- // _ValueType1 must be trivially-copyable to use memmove, so don't
- // bother optimizing to std::copy if it isn't.
- // XXX Unnecessary because std::copy would check it anyway?
- const bool __can_memmove = __is_trivial(_ValueType1);
+ const bool __can_memcpy
+ = __memcpyable<_ValueType1*, _ValueType2*>::__value
+ && __is_trivially_constructible(_ValueType2, __decltype(*__first));
-#if __cplusplus < 201103L
- typedef typename iterator_traits<_InputIterator>::reference _From;
-#else
- using _From = decltype(*__first);
+ return __uninitialized_copy<__can_memcpy>::
+ __uninit_copy(__first, __last, __result);
#endif
- const bool __assignable
- = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From);
-
- return std::__uninitialized_copy<__can_memmove && __assignable>::
- __uninit_copy(__first, __last, __result);
}
+#pragma GCC diagnostic pop
/// @cond undocumented
+ // This is the default implementation of std::uninitialized_fill.
template<typename _ForwardIterator, typename _Tp>
_GLIBCXX20_CONSTEXPR void
__do_uninit_fill(_ForwardIterator __first, _ForwardIterator __last,
__guard.release();
}
- template<bool _TrivialValueType>
+#if __cplusplus < 201103L
+ // Use template specialization for C++98 when 'if constexpr' can't be used.
+ template<bool _CanMemset>
struct __uninitialized_fill
{
template<typename _ForwardIterator, typename _Tp>
- static void
- __uninit_fill(_ForwardIterator __first, _ForwardIterator __last,
+ static void
+ __uninit_fill(_ForwardIterator __first, _ForwardIterator __last,
const _Tp& __x)
{ std::__do_uninit_fill(__first, __last, __x); }
};
template<>
struct __uninitialized_fill<true>
{
+ // Overload for generic iterators.
template<typename _ForwardIterator, typename _Tp>
- static void
- __uninit_fill(_ForwardIterator __first, _ForwardIterator __last,
+ static void
+ __uninit_fill(_ForwardIterator __first, _ForwardIterator __last,
const _Tp& __x)
- { std::fill(__first, __last, __x); }
- };
+ {
+ if (__unwrappable_niter<_ForwardIterator>::__value)
+ __uninit_fill(std::__niter_base(__first),
+ std::__niter_base(__last),
+ __x);
+ else
+ std::__do_uninit_copy(__first, __last, __x);
+ }
+ // Overload for pointers.
+ template<typename _Up, typename _Tp>
+ static void
+ __uninit_fill(_Up* __first, _Up* __last, const _Tp& __x)
+ {
+ // Ensure that we don't successfully memset in cases that should be
+ // ill-formed because is_constructible<_Up, const _Tp&> is false.
+ typedef __typeof__(static_cast<_Up>(__x)) __check
+ __attribute__((__unused__));
+
+ if (__first != __last)
+ __builtin_memset(__first, (unsigned char)__x, __last - __first);
+ }
+ };
+#endif
/// @endcond
/**
* @brief Copies the value x into the range [first,last).
- * @param __first An input iterator.
- * @param __last An input iterator.
+ * @param __first A forward iterator.
+ * @param __last A forward iterator.
* @param __x The source value.
* @return Nothing.
*
- * Like fill(), but does not require an initialized output range.
+ * Like std::fill, but does not require an initialized output range.
*/
template<typename _ForwardIterator, typename _Tp>
inline void
uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last,
const _Tp& __x)
{
+ // We would like to use memset to optimize this loop when possible.
+ // As for std::uninitialized_copy, the optimization requires
+ // contiguous iterators and trivially copyable value types,
+ // with the additional requirement that sizeof(_Tp) == 1 because
+ // memset only writes single bytes.
+
+ // FIXME: We could additionally enable this for 1-byte enums.
+ // Maybe any 1-byte Val if is_trivially_constructible<Val, const T&>?
+
typedef typename iterator_traits<_ForwardIterator>::value_type
_ValueType;
- // Trivial types do not need a constructor to begin their lifetime,
- // so try to use std::fill to benefit from its memset optimization.
- const bool __can_fill
- = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType, const _Tp&);
-
- std::__uninitialized_fill<__can_fill>::
- __uninit_fill(__first, __last, __x);
+#if __cplusplus >= 201103L
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ if constexpr (__is_byte<_ValueType>::__value)
+ if constexpr (is_same<_ValueType, _Tp>::value
+ || is_integral<_Tp>::value)
+ {
+ using _BasePtr = decltype(std::__niter_base(__first));
+ if constexpr (is_pointer<_BasePtr>::value)
+ {
+ void* __dest = std::__niter_base(__first);
+ ptrdiff_t __n = __last - __first;
+ if (__n > 0) [[__likely__]]
+ __builtin_memset(__dest, (unsigned char)__x, __n);
+ return;
+ }
+#if __cpp_lib_concepts
+ else if constexpr (contiguous_iterator<_ForwardIterator>)
+ {
+ auto __dest = std::to_address(__first);
+ auto __n = __last - __first;
+ if (__n > 0) [[__likely__]]
+ __builtin_memset(__dest, (unsigned char)__x, __n);
+ return;
+ }
+#endif
+ }
+ std::__do_uninit_fill(__first, __last, __x);
+#pragma GCC diagnostic pop
+#else // C++98
+ const bool __can_memset = __is_byte<_ValueType>::__value
+ && __is_integer<_Tp>::__value;
+
+ __uninitialized_fill<__can_memset>::__uninit_fill(__first, __last, __x);
+#endif
}
/// @cond undocumented
+ // This is the default implementation of std::uninitialized_fill_n.
template<typename _ForwardIterator, typename _Size, typename _Tp>
_GLIBCXX20_CONSTEXPR
_ForwardIterator
__do_uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
{
_UninitDestroyGuard<_ForwardIterator> __guard(__first);
- for (; __n > 0; --__n, (void) ++__first)
+#if __cplusplus >= 201103L
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ if constexpr (is_integral<_Size>::value)
+ // Loop will never terminate if __n is negative.
+ __glibcxx_assert(__n >= 0);
+ else if constexpr (is_floating_point<_Size>::value)
+ // Loop will never terminate if __n is not an integer.
+ __glibcxx_assert(__n >= 0 && static_cast<size_t>(__n) == __n);
+#pragma GCC diagnostic pop
+#endif
+ for (; __n--; ++__first)
std::_Construct(std::__addressof(*__first), __x);
__guard.release();
return __first;
}
- template<bool _TrivialValueType>
+#if __cplusplus < 201103L
+ // Use template specialization for C++98 when 'if constexpr' can't be used.
+ template<bool _CanMemset>
struct __uninitialized_fill_n
{
template<typename _ForwardIterator, typename _Size, typename _Tp>
template<>
struct __uninitialized_fill_n<true>
{
+ // Overload for generic iterators.
template<typename _ForwardIterator, typename _Size, typename _Tp>
static _ForwardIterator
__uninit_fill_n(_ForwardIterator __first, _Size __n,
const _Tp& __x)
- { return std::fill_n(__first, __n, __x); }
+ {
+ if (__unwrappable_niter<_ForwardIterator>::__value)
+ {
+ _ForwardIterator __last = __first;
+ std::advance(__last, __n);
+ __uninitialized_fill<true>::__uninit_fill(__first, __last, __x);
+ return __last;
+ }
+ else
+ return std::__do_uninit_fill_n(__first, __n, __x);
+ }
};
-
+#endif
/// @endcond
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 1339. uninitialized_fill_n should return the end of its range
/**
* @brief Copies the value x into the range [first,first+n).
- * @param __first An input iterator.
+ * @param __first A forward iterator.
* @param __n The number of copies to make.
* @param __x The source value.
- * @return Nothing.
+ * @return __first + __n.
*
- * Like fill_n(), but does not require an initialized output range.
+ * Like std::fill_n, but does not require an initialized output range.
*/
template<typename _ForwardIterator, typename _Size, typename _Tp>
inline _ForwardIterator
uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
{
+ // See uninitialized_fill conditions. We also require _Size to be
+ // an integer. The standard only requires _Size to be decrementable
+ // and contextually convertible to bool, so don't assume first+n works.
+
+ // FIXME: We could additionally enable this for 1-byte enums.
+
typedef typename iterator_traits<_ForwardIterator>::value_type
_ValueType;
- // Trivial types do not need a constructor to begin their lifetime,
- // so try to use std::fill_n to benefit from its optimizations.
- const bool __can_fill
- = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType, const _Tp&)
- // For arbitrary class types and floating point types we can't assume
- // that __n > 0 and std::__size_to_integer(__n) > 0 are equivalent,
- // so only use std::fill_n when _Size is already an integral type.
- && __is_integer<_Size>::__value;
+#if __cplusplus >= 201103L
+ if constexpr (__is_byte<_ValueType>::__value)
+ if constexpr (is_integral<_Tp>::value)
+ if constexpr (is_integral<_Size>::value)
+ {
+ using _BasePtr = decltype(std::__niter_base(__first));
+ if constexpr (is_pointer<_BasePtr>::value)
+ {
+ void* __dest = std::__niter_base(__first);
+ if (__n > 0) [[__likely__]]
+ {
+ __builtin_memset(__dest, (unsigned char)__x, __n);
+ __first += __n;
+ }
+ return __first;
+ }
+#if __cpp_lib_concepts
+ else if constexpr (contiguous_iterator<_ForwardIterator>)
+ {
+ auto __dest = std::to_address(__first);
+ if (__n > 0) [[__likely__]]
+ {
+ __builtin_memset(__dest, (unsigned char)__x, __n);
+ __first += __n;
+ }
+ return __first;
+ }
+#endif
+ }
+ return std::__do_uninit_fill_n(__first, __n, __x);
+#else // C++98
+ const bool __can_memset = __is_byte<_ValueType>::__value
+ && __is_integer<_Tp>::__value
+ && __is_integer<_Size>::__value;
- return __uninitialized_fill_n<__can_fill>::
+ return __uninitialized_fill_n<__can_memset>::
__uninit_fill_n(__first, __n, __x);
+#endif
}
-
-#undef _GLIBCXX_USE_ASSIGN_FOR_INIT
+#pragma GCC diagnostic pop
/// @cond undocumented