[libc++] Fix std::copy and std::move for ranges with potentially overlapping tail padding

This fixes thr bug reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846.

Reviewed By: ldionne, #libc

Spies: mstorsjo, libcxx-commits

Differential Revision: https://reviews.llvm.org/D151953
This commit is contained in:
Nikolas Klauser
2023-06-30 13:47:39 -07:00
committed by Nikolas Klauser
parent e8e0f32958
commit c4e98722ca
22 changed files with 440 additions and 375 deletions

View File

@@ -707,6 +707,7 @@ set(files
__type_traits/conjunction.h
__type_traits/copy_cv.h
__type_traits/copy_cvref.h
__type_traits/datasizeof.h
__type_traits/decay.h
__type_traits/dependent_type.h
__type_traits/disjunction.h

View File

@@ -15,6 +15,7 @@
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__memory/pointer_traits.h>
#include <__string/constexpr_c_functions.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_always_bitcastable.h>
#include <__type_traits/is_constant_evaluated.h>
@@ -61,7 +62,8 @@ template <class _In, class _Out>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
__copy_trivial_impl(_In* __first, _In* __last, _Out* __result) {
const size_t __n = static_cast<size_t>(__last - __first);
::__builtin_memmove(__result, __first, __n * sizeof(_Out));
std::__constexpr_memmove(__result, __first, __element_count(__n));
return std::make_pair(__last, __result + __n);
}
@@ -72,7 +74,7 @@ __copy_backward_trivial_impl(_In* __first, _In* __last, _Out* __result) {
const size_t __n = static_cast<size_t>(__last - __first);
__result -= __n;
::__builtin_memmove(__result, __first, __n * sizeof(_Out));
std::__constexpr_memmove(__result, __first, __element_count(__n));
return std::make_pair(__last, __result);
}
@@ -119,16 +121,6 @@ __unwrap_and_dispatch(_InIter __first, _Sent __last, _OutIter __out_first) {
return _Algorithm()(std::move(__first), std::move(__last), std::move(__out_first));
}
template <class _IterOps, class _InValue, class _OutIter, class = void>
struct __can_copy_without_conversion : false_type {};
template <class _IterOps, class _InValue, class _OutIter>
struct __can_copy_without_conversion<
_IterOps,
_InValue,
_OutIter,
__enable_if_t<is_same<_InValue, typename _IterOps::template __value_type<_OutIter> >::value> > : true_type {};
template <class _AlgPolicy,
class _NaiveAlgorithm,
class _OptimizedAlgorithm,
@@ -137,23 +129,6 @@ template <class _AlgPolicy,
class _OutIter>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter>
__dispatch_copy_or_move(_InIter __first, _Sent __last, _OutIter __out_first) {
#ifdef _LIBCPP_COMPILER_GCC
// GCC doesn't support `__builtin_memmove` during constant evaluation.
if (__libcpp_is_constant_evaluated()) {
return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first));
}
#else
// In Clang, `__builtin_memmove` only supports fully trivially copyable types (just having trivial copy assignment is
// insufficient). Also, conversions are not supported.
if (__libcpp_is_constant_evaluated()) {
using _InValue = typename _IterOps<_AlgPolicy>::template __value_type<_InIter>;
if (!is_trivially_copyable<_InValue>::value ||
!__can_copy_without_conversion<_IterOps<_AlgPolicy>, _InValue, _OutIter>::value) {
return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first));
}
}
#endif // _LIBCPP_COMPILER_GCC
using _Algorithm = __overload<_NaiveAlgorithm, _OptimizedAlgorithm>;
return std::__unwrap_and_dispatch<_Algorithm>(std::move(__first), std::move(__last), std::move(__out_first));
}

View File

@@ -170,25 +170,6 @@ struct _LIBCPP_DEPRECATED_("char_traits<T> for T not equal to char, wchar_t, cha
{return int_type(EOF);}
};
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
_CharT* __char_traits_move(_CharT* __dest, const _CharT* __source, size_t __n) _NOEXCEPT
{
#ifdef _LIBCPP_COMPILER_GCC
if (__libcpp_is_constant_evaluated()) {
if (__n == 0)
return __dest;
_CharT* __allocation = new _CharT[__n];
std::copy_n(__source, __n, __allocation);
std::copy_n(static_cast<const _CharT*>(__allocation), __n, __dest);
delete[] __allocation;
return __dest;
}
#endif
::__builtin_memmove(__dest, __source, __n * sizeof(_CharT));
return __dest;
}
// char_traits<char>
template <>
@@ -249,7 +230,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char>
static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
return std::__char_traits_move(__s1, __s2, __n);
return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
}
static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -320,7 +301,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t>
static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
return std::__char_traits_move(__s1, __s2, __n);
return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
}
static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -384,7 +365,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
return std::__char_traits_move(__s1, __s2, __n);
return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
}
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -468,7 +449,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
return std::__char_traits_move(__s1, __s2, __n);
return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -562,7 +543,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
return std::__char_traits_move(__s1, __s2, __n);
return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20

View File

@@ -10,11 +10,15 @@
#define _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H
#include <__config>
#include <__type_traits/datasizeof.h>
#include <__type_traits/is_always_bitcastable.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_equality_comparable.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_trivially_copyable.h>
#include <__type_traits/is_trivially_lexicographically_comparable.h>
#include <__type_traits/remove_cv.h>
#include <__utility/is_pointer_in_range.h>
#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -129,6 +133,30 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __constexpr_memchr(_Tp*
}
}
template <class _Tp, class _Up, __enable_if_t<__is_always_bitcastable<_Up, _Tp>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp*
__constexpr_memmove(_Tp* __dest, _Up* __src, __element_count __n) {
size_t __count = static_cast<size_t>(__n);
if (__libcpp_is_constant_evaluated()) {
#ifdef _LIBCPP_COMPILER_CLANG_BASED
if (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value) {
::__builtin_memmove(__dest, __src, __count * sizeof(_Tp));
return __dest;
}
#endif
if (std::__is_pointer_in_range(__src, __src + __count, __dest)) {
for (; __count > 0; --__count)
__dest[__count - 1] = __src[__count - 1];
} else {
for (size_t __i = 0; __i != __count; ++__i)
__dest[__i] = __src[__i];
}
} else if (__count > 0) {
::__builtin_memmove(__dest, __src, (__count - 1) * sizeof(_Tp) + __libcpp_datasizeof<_Tp>::value);
}
return __dest;
}
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H

View File

@@ -0,0 +1,55 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___TYPE_TRAITS_DATASIZEOF_H
#define _LIBCPP___TYPE_TRAITS_DATASIZEOF_H
#include <__config>
#include <__type_traits/is_class.h>
#include <__type_traits/is_final.h>
#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
// This trait provides the size of a type excluding any tail padding.
//
// It is useful in contexts where performing an operation using the full size of the class (including padding) may
// have unintended side effects, such as overwriting a derived class' member when writing the tail padding of a class
// through a pointer-to-base.
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp>
struct __libcpp_datasizeof {
#if __has_cpp_attribute(__no_unique_address__)
template <class = char>
struct _FirstPaddingByte {
[[__no_unique_address__]] _Tp __v_;
char __first_padding_byte_;
};
#else
template <bool = __libcpp_is_final<_Tp>::value || !is_class<_Tp>::value>
struct _FirstPaddingByte : _Tp {
char __first_padding_byte_;
};
template <>
struct _FirstPaddingByte<true> {
_Tp __v_;
char __first_padding_byte_;
};
#endif
static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_);
};
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___TYPE_TRAITS_DATASIZEOF_H

View File

@@ -15,8 +15,6 @@
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_function.h>
#include <__type_traits/is_member_pointer.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
@@ -26,14 +24,16 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Up, class = void>
struct __is_less_than_comparable : false_type {};
template <class _Tp, class _Up>
struct __is_less_than_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() < std::declval<_Up>())> > : true_type {
};
template <class _Tp, class _Up, __enable_if_t<__is_less_than_comparable<const _Tp*, const _Up*>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range(
const _Tp* __begin, const _Tp* __end, const _Up* __ptr) {
static_assert(!is_function<_Tp>::value && !is_function<_Up>::value,
"__is_pointer_in_range should not be called with function pointers");
static_assert(!is_member_pointer<_Tp>::value && !is_member_pointer<_Up>::value,
"__is_pointer_in_range should not be called with member pointers");
if (__libcpp_is_constant_evaluated()) {
_LIBCPP_ASSERT_UNCATEGORIZED(__builtin_constant_p(__begin <= __end), "__begin and __end do not form a range");
@@ -47,6 +47,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address
return !__less<>()(__ptr, __begin) && __less<>()(__ptr, __end);
}
template <class _Tp, class _Up, __enable_if_t<!__is_less_than_comparable<const _Tp*, const _Up*>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range(
const _Tp* __begin, const _Tp* __end, const _Up* __ptr) {
if (__libcpp_is_constant_evaluated())
return false;
return reinterpret_cast<const char*>(__begin) <= reinterpret_cast<const char*>(__ptr) &&
reinterpret_cast<const char*>(__ptr) < reinterpret_cast<const char*>(__end);
}
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___UTILITY_IS_POINTER_IN_RANGE_H

View File

@@ -1576,6 +1576,7 @@ module std [system] {
module conjunction { private header "__type_traits/conjunction.h" }
module copy_cv { private header "__type_traits/copy_cv.h" }
module copy_cvref { private header "__type_traits/copy_cvref.h" }
module datasizeof { private header "__type_traits/datasizeof.h" }
module decay { private header "__type_traits/decay.h" }
module dependent_type { private header "__type_traits/dependent_type.h" }
module disjunction { private header "__type_traits/disjunction.h" }

View File

@@ -663,13 +663,6 @@ struct __can_be_converted_to_string_view : public _BoolConstant<
struct __uninitialized_size_tag {};
template <class _Tp, class _Up, class = void>
struct __is_less_than_comparable : false_type {};
template <class _Tp, class _Up>
struct __is_less_than_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() < std::declval<_Up>())> > : true_type {
};
template<class _CharT, class _Traits, class _Allocator>
class basic_string
{
@@ -1910,25 +1903,11 @@ private:
return *this;
}
template <
class _Tp,
__enable_if_t<__is_less_than_comparable<const __remove_cvref_t<_Tp>*, const value_type*>::value, int> = 0>
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __addr_in_range(const _Tp& __v) const {
return std::__is_pointer_in_range(data(), data() + size() + 1, std::addressof(__v));
}
template <
class _Tp,
__enable_if_t<!__is_less_than_comparable<const __remove_cvref_t<_Tp>*, const value_type*>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __addr_in_range(const _Tp& __v) const {
if (__libcpp_is_constant_evaluated())
return false;
auto __t_ptr = reinterpret_cast<const char*>(std::addressof(__v));
return reinterpret_cast<const char*>(data()) <= __t_ptr &&
__t_ptr < reinterpret_cast<const char*>(data() + size() + 1);
}
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI
void __throw_length_error() const {
std::__throw_length_error("basic_string");

View File

@@ -156,26 +156,6 @@ void test_one(Func func) {
}
}));
}
// Empty input sequence.
{
const std::size_t N = 0;
From input[1] = {make<From>(1)};
To output[1] = {make<To>(2)};
auto in = InIter(input);
auto in_end = InIter(input + N);
auto sent = SentWrapper<decltype(in_end)>(in_end);
auto out = OutIter(output);
assert(!memmove_called);
func(in, sent, out, N);
assert(memmove_called);
memmove_called = false;
assert(output[0] == make<To>(2));
}
}
template <class InIter, template <class> class SentWrapper, class OutIter>

View File

@@ -42,6 +42,7 @@ array algorithm
array compare
array concepts
array cstddef
array cstdint
array cstdlib
array initializer_list
array iterator
@@ -506,6 +507,7 @@ locale version
map compare
map concepts
map cstddef
map cstdint
map cstdlib
map functional
map initializer_list
@@ -731,6 +733,7 @@ semaphore version
set compare
set concepts
set cstddef
set cstdint
set cstdlib
set functional
set initializer_list
1 algorithm atomic
42 array compare
43 array concepts
44 array cstddef
45 array cstdint
46 array cstdlib
47 array initializer_list
48 array iterator
507 map compare
508 map concepts
509 map cstddef
510 map cstdint
511 map cstdlib
512 map functional
513 map initializer_list
733 set compare
734 set concepts
735 set cstddef
736 set cstdint
737 set cstdlib
738 set functional
739 set initializer_list

View File

@@ -42,6 +42,7 @@ array algorithm
array compare
array concepts
array cstddef
array cstdint
array cstdlib
array initializer_list
array iterator
@@ -506,6 +507,7 @@ locale version
map compare
map concepts
map cstddef
map cstdint
map cstdlib
map functional
map initializer_list
@@ -732,6 +734,7 @@ semaphore version
set compare
set concepts
set cstddef
set cstdint
set cstdlib
set functional
set initializer_list
1 algorithm atomic
42 array compare
43 array concepts
44 array cstddef
45 array cstdint
46 array cstdlib
47 array initializer_list
48 array iterator
507 map compare
508 map concepts
509 map cstddef
510 map cstdint
511 map cstdlib
512 map functional
513 map initializer_list
734 set compare
735 set concepts
736 set cstddef
737 set cstdint
738 set cstdlib
739 set functional
740 set initializer_list

View File

@@ -42,6 +42,7 @@ array algorithm
array compare
array concepts
array cstddef
array cstdint
array cstdlib
array initializer_list
array iterator
@@ -508,6 +509,7 @@ locale version
map compare
map concepts
map cstddef
map cstdint
map cstdlib
map functional
map initializer_list
@@ -734,6 +736,7 @@ semaphore version
set compare
set concepts
set cstddef
set cstdint
set cstdlib
set functional
set initializer_list
1 algorithm atomic
42 array compare
43 array concepts
44 array cstddef
45 array cstdint
46 array cstdlib
47 array initializer_list
48 array iterator
509 map compare
510 map concepts
511 map cstddef
512 map cstdint
513 map cstdlib
514 map functional
515 map initializer_list
736 set compare
737 set concepts
738 set cstddef
739 set cstdint
740 set cstdlib
741 set functional
742 set initializer_list

View File

@@ -42,6 +42,7 @@ array algorithm
array compare
array concepts
array cstddef
array cstdint
array cstdlib
array initializer_list
array iterator
@@ -508,6 +509,7 @@ locale version
map compare
map concepts
map cstddef
map cstdint
map cstdlib
map functional
map initializer_list
@@ -734,6 +736,7 @@ semaphore version
set compare
set concepts
set cstddef
set cstdint
set cstdlib
set functional
set initializer_list
1 algorithm atomic
42 array compare
43 array concepts
44 array cstddef
45 array cstdint
46 array cstdlib
47 array initializer_list
48 array iterator
509 map compare
510 map concepts
511 map cstddef
512 map cstdint
513 map cstdlib
514 map functional
515 map initializer_list
736 set compare
737 set concepts
738 set cstddef
739 set cstdint
740 set cstdlib
741 set functional
742 set initializer_list

View File

@@ -41,6 +41,7 @@ array algorithm
array compare
array concepts
array cstddef
array cstdint
array cstdlib
array initializer_list
array iterator
@@ -514,6 +515,7 @@ locale version
map compare
map concepts
map cstddef
map cstdint
map cstdlib
map functional
map initializer_list
@@ -740,6 +742,7 @@ semaphore version
set compare
set concepts
set cstddef
set cstdint
set cstdlib
set functional
set initializer_list
1 algorithm atomic
41 array compare
42 array concepts
43 array cstddef
44 array cstdint
45 array cstdlib
46 array initializer_list
47 array iterator
515 map compare
516 map concepts
517 map cstddef
518 map cstdint
519 map cstdlib
520 map functional
521 map initializer_list
742 set compare
743 set concepts
744 set cstddef
745 set cstdint
746 set cstdlib
747 set functional
748 set initializer_list

View File

@@ -21,6 +21,7 @@ any typeinfo
any version
array compare
array cstddef
array cstdint
array initializer_list
array limits
array stdexcept
@@ -348,6 +349,7 @@ locale string
locale version
map compare
map cstddef
map cstdint
map initializer_list
map limits
map new
@@ -501,6 +503,7 @@ semaphore ratio
semaphore version
set compare
set cstddef
set cstdint
set initializer_list
set limits
set new
1 algorithm climits
21 any version
22 array compare
23 array cstddef
24 array cstdint
25 array initializer_list
26 array limits
27 array stdexcept
349 locale version
350 map compare
351 map cstddef
352 map cstdint
353 map initializer_list
354 map limits
355 map new
503 semaphore version
504 set compare
505 set cstddef
506 set cstdint
507 set initializer_list
508 set limits
509 set new

View File

@@ -21,6 +21,7 @@ any typeinfo
any version
array compare
array cstddef
array cstdint
array initializer_list
array limits
array stdexcept
@@ -348,6 +349,7 @@ locale string
locale version
map compare
map cstddef
map cstdint
map initializer_list
map limits
map new
@@ -501,6 +503,7 @@ semaphore ratio
semaphore version
set compare
set cstddef
set cstdint
set initializer_list
set limits
set new
1 algorithm climits
21 any version
22 array compare
23 array cstddef
24 array cstdint
25 array initializer_list
26 array limits
27 array stdexcept
349 locale version
350 map compare
351 map cstddef
352 map cstdint
353 map initializer_list
354 map limits
355 map new
503 semaphore version
504 set compare
505 set cstddef
506 set cstdint
507 set initializer_list
508 set limits
509 set new

View File

@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header
#include <__type_traits/datasizeof.h>
#include <cstdint>
static_assert(std::__libcpp_datasizeof<std::int8_t>::value == 1, "");
static_assert(std::__libcpp_datasizeof<std::int16_t>::value == 2, "");
static_assert(std::__libcpp_datasizeof<std::int32_t>::value == 4, "");
static_assert(std::__libcpp_datasizeof<std::int64_t>::value == 8, "");
struct OneBytePadding {
OneBytePadding() {}
std::int16_t a;
std::int8_t b;
};
#if defined(_WIN32) && !defined(__MINGW32__)
static_assert(std::__libcpp_datasizeof<OneBytePadding>::value == 4, "");
#else
static_assert(std::__libcpp_datasizeof<OneBytePadding>::value == 3, "");
#endif
struct InBetweenPadding {
InBetweenPadding() {}
std::int32_t a;
std::int8_t b;
std::int16_t c;
};
static_assert(std::__libcpp_datasizeof<InBetweenPadding>::value == 8, "");

View File

@@ -18,78 +18,74 @@
#include "test_macros.h"
#include "test_iterators.h"
template <class InIter, class OutIter>
TEST_CONSTEXPR_CXX20 void
test_copy()
{
class PaddedBase {
public:
TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
std::int16_t a_;
std::int8_t b_;
};
class Derived : public PaddedBase {
public:
TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
std::int8_t c_;
};
template <class InIter>
struct Test {
template <class OutIter>
TEST_CONSTEXPR_CXX20 void operator()() {
const unsigned N = 1000;
int ia[N] = {};
int ia[N] = {};
for (unsigned i = 0; i < N; ++i)
ia[i] = i;
ia[i] = i;
int ib[N] = {0};
OutIter r = std::copy(InIter(ia), InIter(ia+N), OutIter(ib));
assert(base(r) == ib+N);
OutIter r = std::copy(InIter(ia), InIter(ia + N), OutIter(ib));
assert(base(r) == ib + N);
for (unsigned i = 0; i < N; ++i)
assert(ia[i] == ib[i]);
}
assert(ia[i] == ib[i]);
}
};
TEST_CONSTEXPR_CXX20 bool
test()
{
test_copy<cpp17_input_iterator<const int*>, cpp17_output_iterator<int*> >();
test_copy<cpp17_input_iterator<const int*>, forward_iterator<int*> >();
test_copy<cpp17_input_iterator<const int*>, bidirectional_iterator<int*> >();
test_copy<cpp17_input_iterator<const int*>, random_access_iterator<int*> >();
test_copy<cpp17_input_iterator<const int*>, int*>();
struct TestInIters {
template <class InIter>
TEST_CONSTEXPR_CXX20 void operator()() {
types::for_each(
types::concatenate_t<types::cpp17_input_iterator_list<int*>, types::type_list<cpp17_output_iterator<int*> > >(),
Test<InIter>());
}
};
test_copy<forward_iterator<const int*>, cpp17_output_iterator<int*> >();
test_copy<forward_iterator<const int*>, forward_iterator<int*> >();
test_copy<forward_iterator<const int*>, bidirectional_iterator<int*> >();
test_copy<forward_iterator<const int*>, random_access_iterator<int*> >();
test_copy<forward_iterator<const int*>, int*>();
TEST_CONSTEXPR_CXX20 bool test() {
types::for_each(types::cpp17_input_iterator_list<int*>(), TestInIters());
test_copy<bidirectional_iterator<const int*>, cpp17_output_iterator<int*> >();
test_copy<bidirectional_iterator<const int*>, forward_iterator<int*> >();
test_copy<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >();
test_copy<bidirectional_iterator<const int*>, random_access_iterator<int*> >();
test_copy<bidirectional_iterator<const int*>, int*>();
{ // Make sure that padding bits aren't copied
Derived src(1, 2, 3);
Derived dst(4, 5, 6);
std::copy(static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst));
assert(dst.a_ == 1);
assert(dst.b_ == 2);
assert(dst.c_ == 6);
}
test_copy<random_access_iterator<const int*>, cpp17_output_iterator<int*> >();
test_copy<random_access_iterator<const int*>, forward_iterator<int*> >();
test_copy<random_access_iterator<const int*>, bidirectional_iterator<int*> >();
test_copy<random_access_iterator<const int*>, random_access_iterator<int*> >();
test_copy<random_access_iterator<const int*>, int*>();
test_copy<const int*, cpp17_output_iterator<int*> >();
test_copy<const int*, forward_iterator<int*> >();
test_copy<const int*, bidirectional_iterator<int*> >();
test_copy<const int*, random_access_iterator<int*> >();
test_copy<const int*, int*>();
#if TEST_STD_VER > 17
test_copy<cpp17_input_iterator<const int*>, contiguous_iterator<int*>>();
test_copy<forward_iterator<const int*>, contiguous_iterator<int*>>();
test_copy<bidirectional_iterator<const int*>, contiguous_iterator<int*>>();
test_copy<random_access_iterator<const int*>, contiguous_iterator<int*>>();
test_copy<const int*, contiguous_iterator<int*>>();
test_copy<contiguous_iterator<const int*>, cpp17_output_iterator<int*>>();
test_copy<contiguous_iterator<const int*>, forward_iterator<int*>>();
test_copy<contiguous_iterator<const int*>, bidirectional_iterator<int*>>();
test_copy<contiguous_iterator<const int*>, random_access_iterator<int*>>();
test_copy<contiguous_iterator<const int*>, int*>();
#endif
{ // Make sure that overlapping ranges can be copied
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::copy(a + 3, a + 10, a);
int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10};
assert(std::equal(a, a + 10, expected));
}
return true;
}
int main(int, char**)
{
test();
int main(int, char**) {
test();
#if TEST_STD_VER > 17
static_assert(test());
static_assert(test());
#endif
return 0;

View File

@@ -20,10 +20,26 @@
#include "test_iterators.h"
#include "user_defined_integral.h"
class PaddedBase {
public:
TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
std::int16_t a_;
std::int8_t b_;
};
class Derived : public PaddedBase {
public:
TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
std::int8_t c_;
};
template <class InIter, class OutIter>
TEST_CONSTEXPR_CXX20 void
test_copy_backward()
{
{
const unsigned N = 1000;
int ia[N] = {};
for (unsigned i = 0; i < N; ++i)
@@ -34,6 +50,7 @@ test_copy_backward()
assert(base(r) == ib);
for (unsigned i = 0; i < N; ++i)
assert(ia[i] == ib[i]);
}
}
TEST_CONSTEXPR_CXX20 bool
@@ -62,6 +79,23 @@ test()
test_copy_backward<const int*, contiguous_iterator<int*>>();
#endif
{ // Make sure that padding bits aren't copied
Derived src(1, 2, 3);
Derived dst(4, 5, 6);
std::copy_backward(
static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst) + 1);
assert(dst.a_ == 1);
assert(dst.b_ == 2);
assert(dst.c_ == 6);
}
{ // Make sure that overlapping ranges can be copied
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::copy_backward(a, a + 7, a + 10);
int expected[] = {1, 2, 3, 1, 2, 3, 4, 5, 6, 7};
assert(std::equal(a, a + 10, expected));
}
return true;
}

View File

@@ -21,10 +21,26 @@
typedef UserDefinedIntegral<unsigned> UDI;
class PaddedBase {
public:
TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
std::int16_t a_;
std::int8_t b_;
};
class Derived : public PaddedBase {
public:
TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
std::int8_t c_;
};
template <class InIter, class OutIter>
TEST_CONSTEXPR_CXX20 void
test_copy_n()
{
{
const unsigned N = 1000;
int ia[N] = {};
for (unsigned i = 0; i < N; ++i)
@@ -35,6 +51,23 @@ test_copy_n()
assert(base(r) == ib+N/2);
for (unsigned i = 0; i < N/2; ++i)
assert(ia[i] == ib[i]);
}
{ // Make sure that padding bits aren't copied
Derived src(1, 2, 3);
Derived dst(4, 5, 6);
std::copy_n(static_cast<PaddedBase*>(&src), 1, static_cast<PaddedBase*>(&dst));
assert(dst.a_ == 1);
assert(dst.b_ == 2);
assert(dst.c_ == 6);
}
{ // Make sure that overlapping ranges can be copied
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::copy_n(a + 3, 7, a);
int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10};
assert(std::equal(a, a + 10, expected));
}
}
TEST_CONSTEXPR_CXX20 bool

View File

@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03 && !stdlib=libc++
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
// <algorithm>
// template<InputIterator InIter, typename OutIter>
@@ -20,10 +23,25 @@
#include "test_macros.h"
#include "test_iterators.h"
template <class InIter, class OutIter>
TEST_CONSTEXPR_CXX17 bool
test()
{
class PaddedBase {
public:
TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
std::int16_t a_;
std::int8_t b_;
};
class Derived : public PaddedBase {
public:
TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
std::int8_t c_;
};
template <class InIter>
struct Test {
template <class OutIter>
TEST_CONSTEXPR_CXX20 void operator()() {
const unsigned N = 1000;
int ia[N] = {};
for (unsigned i = 0; i < N; ++i)
@@ -34,15 +52,22 @@ test()
assert(base(r) == ib+N);
for (unsigned i = 0; i < N; ++i)
assert(ia[i] == ib[i]);
}
};
return true;
}
struct TestOutIters {
template <class InIter>
TEST_CONSTEXPR_CXX20 void operator()() {
types::for_each(
types::concatenate_t<types::cpp17_input_iterator_list<int*>, types::type_list<cpp17_output_iterator<int*> > >(),
Test<InIter>());
}
};
#if TEST_STD_VER >= 11
template <class InIter, class OutIter>
void
test1()
{
template <class InIter>
struct Test1 {
template <class OutIter>
TEST_CONSTEXPR_CXX23 void operator()() {
const unsigned N = 100;
std::unique_ptr<int> ia[N];
for (unsigned i = 0; i < N; ++i)
@@ -53,140 +78,48 @@ test1()
assert(base(r) == ib+N);
for (unsigned i = 0; i < N; ++i)
assert(*ib[i] == static_cast<int>(i));
}
};
struct Test1OutIters {
template <class InIter>
TEST_CONSTEXPR_CXX23 void operator()() {
types::for_each(types::concatenate_t<types::cpp17_input_iterator_list<std::unique_ptr<int>*>,
types::type_list<cpp17_output_iterator<std::unique_ptr<int>*> > >(),
Test1<InIter>());
}
};
TEST_CONSTEXPR_CXX20 bool test() {
types::for_each(types::cpp17_input_iterator_list<int*>(), TestOutIters());
if (TEST_STD_VER >= 23 || !TEST_IS_CONSTANT_EVALUATED)
types::for_each(types::cpp17_input_iterator_list<std::unique_ptr<int>*>(), Test1OutIters());
{ // Make sure that padding bits aren't copied
Derived src(1, 2, 3);
Derived dst(4, 5, 6);
std::move(static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst));
assert(dst.a_ == 1);
assert(dst.b_ == 2);
assert(dst.c_ == 6);
}
{ // Make sure that overlapping ranges can be copied
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::move(a + 3, a + 10, a);
int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10};
assert(std::equal(a, a + 10, expected));
}
return true;
}
#endif
int main(int, char**)
{
test<cpp17_input_iterator<const int*>, cpp17_output_iterator<int*> >();
test<cpp17_input_iterator<const int*>, forward_iterator<int*> >();
test<cpp17_input_iterator<const int*>, bidirectional_iterator<int*> >();
test<cpp17_input_iterator<const int*>, random_access_iterator<int*> >();
test<cpp17_input_iterator<const int*>, int*>();
test<forward_iterator<const int*>, cpp17_output_iterator<int*> >();
test<forward_iterator<const int*>, forward_iterator<int*> >();
test<forward_iterator<const int*>, bidirectional_iterator<int*> >();
test<forward_iterator<const int*>, random_access_iterator<int*> >();
test<forward_iterator<const int*>, int*>();
test<bidirectional_iterator<const int*>, cpp17_output_iterator<int*> >();
test<bidirectional_iterator<const int*>, forward_iterator<int*> >();
test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >();
test<bidirectional_iterator<const int*>, random_access_iterator<int*> >();
test<bidirectional_iterator<const int*>, int*>();
test<random_access_iterator<const int*>, cpp17_output_iterator<int*> >();
test<random_access_iterator<const int*>, forward_iterator<int*> >();
test<random_access_iterator<const int*>, bidirectional_iterator<int*> >();
test<random_access_iterator<const int*>, random_access_iterator<int*> >();
test<random_access_iterator<const int*>, int*>();
test<const int*, cpp17_output_iterator<int*> >();
test<const int*, forward_iterator<int*> >();
test<const int*, bidirectional_iterator<int*> >();
test<const int*, random_access_iterator<int*> >();
test<const int*, int*>();
#if TEST_STD_VER >= 11
test1<cpp17_input_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
test1<cpp17_input_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
test1<cpp17_input_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<cpp17_input_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
test1<cpp17_input_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<forward_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
test1<forward_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
test1<forward_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<forward_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
test1<forward_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<bidirectional_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
test1<bidirectional_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
test1<bidirectional_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<bidirectional_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
test1<bidirectional_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<random_access_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
test1<random_access_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
test1<random_access_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<random_access_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
test1<random_access_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<std::unique_ptr<int>*, cpp17_output_iterator<std::unique_ptr<int>*> >();
test1<std::unique_ptr<int>*, forward_iterator<std::unique_ptr<int>*> >();
test1<std::unique_ptr<int>*, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<std::unique_ptr<int>*, random_access_iterator<std::unique_ptr<int>*> >();
test1<std::unique_ptr<int>*, std::unique_ptr<int>*>();
#endif // TEST_STD_VER >= 11
#if TEST_STD_VER > 17
test<cpp17_input_iterator<const int*>, contiguous_iterator<int*>>();
test<forward_iterator<const int*>, contiguous_iterator<int*>>();
test<bidirectional_iterator<const int*>, contiguous_iterator<int*>>();
test<random_access_iterator<const int*>, contiguous_iterator<int*>>();
test<const int*, contiguous_iterator<int*>>();
test<contiguous_iterator<const int*>, cpp17_output_iterator<int*>>();
test<contiguous_iterator<const int*>, forward_iterator<int*>>();
test<contiguous_iterator<const int*>, bidirectional_iterator<int*>>();
test<contiguous_iterator<const int*>, random_access_iterator<int*>>();
test<contiguous_iterator<const int*>, int*>();
test<contiguous_iterator<const int*>, contiguous_iterator<int*>>();
test1<cpp17_input_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
test1<forward_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
test1<bidirectional_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
test1<random_access_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
test1<std::unique_ptr<int>*, contiguous_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<contiguous_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
static_assert(test<cpp17_input_iterator<const int*>, cpp17_input_iterator<int*> >());
static_assert(test<cpp17_input_iterator<const int*>, forward_iterator<int*> >());
static_assert(test<cpp17_input_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<cpp17_input_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<cpp17_input_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<cpp17_input_iterator<const int*>, int*>());
static_assert(test<forward_iterator<const int*>, cpp17_input_iterator<int*> >());
static_assert(test<forward_iterator<const int*>, forward_iterator<int*> >());
static_assert(test<forward_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<forward_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<forward_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<forward_iterator<const int*>, int*>());
static_assert(test<bidirectional_iterator<const int*>, cpp17_input_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, forward_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, int*>());
static_assert(test<random_access_iterator<const int*>, cpp17_input_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, forward_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, int*>());
static_assert(test<contiguous_iterator<const int*>, cpp17_input_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, forward_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, int*>());
static_assert(test<const int*, cpp17_input_iterator<int*> >());
static_assert(test<const int*, forward_iterator<int*> >());
static_assert(test<const int*, bidirectional_iterator<int*> >());
static_assert(test<const int*, random_access_iterator<int*> >());
static_assert(test<const int*, contiguous_iterator<int*> >());
static_assert(test<const int*, int*>());
#endif // TEST_STD_VER > 17
test();
#if TEST_STD_VER >= 20
static_assert(test());
#endif
return 0;
}

View File

@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03 && !stdlib=libc++
// <algorithm>
// template<BidirectionalIterator InIter, BidirectionalIterator OutIter>
@@ -20,10 +22,25 @@
#include "test_macros.h"
#include "test_iterators.h"
template <class InIter, class OutIter>
TEST_CONSTEXPR_CXX17 bool
test()
{
class PaddedBase {
public:
TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
std::int16_t a_;
std::int8_t b_;
};
class Derived : public PaddedBase {
public:
TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
std::int8_t c_;
};
template <class InIter>
struct Test {
template <class OutIter>
TEST_CONSTEXPR_CXX20 void operator()() {
const unsigned N = 1000;
int ia[N] = {};
for (unsigned i = 0; i < N; ++i)
@@ -34,15 +51,22 @@ test()
assert(base(r) == ib);
for (unsigned i = 0; i < N; ++i)
assert(ia[i] == ib[i]);
}
};
return true;
}
struct TestOutIters {
template <class InIter>
TEST_CONSTEXPR_CXX20 void operator()() {
types::for_each(
types::concatenate_t<types::bidirectional_iterator_list<int*> >(),
Test<InIter>());
}
};
#if TEST_STD_VER >= 11
template <class InIter, class OutIter>
void
test1()
{
template <class InIter>
struct Test1 {
template <class OutIter>
TEST_CONSTEXPR_CXX23 void operator()() {
const unsigned N = 100;
std::unique_ptr<int> ia[N];
for (unsigned i = 0; i < N; ++i)
@@ -53,74 +77,48 @@ test1()
assert(base(r) == ib);
for (unsigned i = 0; i < N; ++i)
assert(*ib[i] == static_cast<int>(i));
}
};
struct Test1OutIters {
template <class InIter>
TEST_CONSTEXPR_CXX23 void operator()() {
types::for_each(types::concatenate_t<types::bidirectional_iterator_list<std::unique_ptr<int>*> >(),
Test1<InIter>());
}
};
TEST_CONSTEXPR_CXX20 bool test() {
types::for_each(types::bidirectional_iterator_list<int*>(), TestOutIters());
if (TEST_STD_VER >= 23 || !TEST_IS_CONSTANT_EVALUATED)
types::for_each(types::bidirectional_iterator_list<std::unique_ptr<int>*>(), Test1OutIters());
{ // Make sure that padding bits aren't copied
Derived src(1, 2, 3);
Derived dst(4, 5, 6);
std::move_backward(
static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst) + 1);
assert(dst.a_ == 1);
assert(dst.b_ == 2);
assert(dst.c_ == 6);
}
{ // Make sure that overlapping ranges can be copied
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::move_backward(a, a + 7, a + 10);
int expected[] = {1, 2, 3, 1, 2, 3, 4, 5, 6, 7};
assert(std::equal(a, a + 10, expected));
}
return true;
}
#endif
int main(int, char**)
{
test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >();
test<bidirectional_iterator<const int*>, random_access_iterator<int*> >();
test<bidirectional_iterator<const int*>, int*>();
test<random_access_iterator<const int*>, bidirectional_iterator<int*> >();
test<random_access_iterator<const int*>, random_access_iterator<int*> >();
test<random_access_iterator<const int*>, int*>();
test<const int*, bidirectional_iterator<int*> >();
test<const int*, random_access_iterator<int*> >();
test<const int*, int*>();
#if TEST_STD_VER >= 11
test1<bidirectional_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<bidirectional_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
test1<bidirectional_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<random_access_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<random_access_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
test1<random_access_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<std::unique_ptr<int>*, bidirectional_iterator<std::unique_ptr<int>*> >();
test1<std::unique_ptr<int>*, random_access_iterator<std::unique_ptr<int>*> >();
test1<std::unique_ptr<int>*, std::unique_ptr<int>*>();
#endif // TEST_STD_VER >= 11
#if TEST_STD_VER > 17
test<bidirectional_iterator<const int*>, contiguous_iterator<int*>>();
test<random_access_iterator<const int*>, contiguous_iterator<int*>>();
test<const int*, contiguous_iterator<int*>>();
test<contiguous_iterator<const int*>, bidirectional_iterator<int*>>();
test<contiguous_iterator<const int*>, random_access_iterator<int*>>();
test<contiguous_iterator<const int*>, int*>();
test<contiguous_iterator<const int*>, contiguous_iterator<int*>>();
test1<bidirectional_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
test1<random_access_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
test1<std::unique_ptr<int>*, contiguous_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*>>();
test1<contiguous_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
test1<contiguous_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
static_assert(test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<bidirectional_iterator<const int*>, int*>());
static_assert(test<random_access_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<random_access_iterator<const int*>, int*>());
static_assert(test<contiguous_iterator<const int*>, bidirectional_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, random_access_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, contiguous_iterator<int*> >());
static_assert(test<contiguous_iterator<const int*>, int*>());
static_assert(test<const int*, bidirectional_iterator<int*> >());
static_assert(test<const int*, random_access_iterator<int*> >());
static_assert(test<const int*, contiguous_iterator<int*> >());
static_assert(test<const int*, int*>());
#endif // TEST_STD_VER > 17
test();
#if TEST_STD_VER >= 20
static_assert(test());
#endif
return 0;
}