зеркало из https://github.com/microsoft/STL.git
Scalarize `swap` and `ranges::swap` for arrays (#2700)
This commit is contained in:
Родитель
8999b68330
Коммит
9ccb781ce7
|
@ -151,22 +151,6 @@ namespace ranges {
|
|||
constexpr void operator()(_Ty1 (&__t)[_Size], _Ty2 (&__u)[_Size]) const
|
||||
noexcept(noexcept((*this)(__t[0], __u[0])))
|
||||
requires requires { (*this)(__t[0], __u[0]); } {
|
||||
#if _USE_STD_VECTOR_ALGORITHMS
|
||||
if constexpr (is_same_v<_Ty1, _Ty2> && _Is_trivially_swappable_v<_Ty1>) {
|
||||
const auto _First1 = __t;
|
||||
const auto _First2 = __u;
|
||||
|
||||
if (_First1 == _First2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_STD is_constant_evaluated()) {
|
||||
__std_swap_ranges_trivially_swappable_noalias(_First1, _First1 + _Size, _First2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
|
||||
for (size_t __i = 0; __i < _Size; ++__i) {
|
||||
(*this)(__t[__i], __u[__i]);
|
||||
}
|
||||
|
|
|
@ -18,39 +18,6 @@ _STL_DISABLE_CLANG_WARNINGS
|
|||
#pragma push_macro("new")
|
||||
#undef new
|
||||
|
||||
// Note: Defining _USE_STD_VECTOR_ALGORITHMS to 0 may be necessary to use "core" headers
|
||||
// without linking to the STL's separately compiled code.
|
||||
|
||||
#if defined(_CRTBLD) && defined(CRTDLL2)
|
||||
// TRANSITION, ABI: The vector algorithms are compiled into the import lib, so we disable their usage when building
|
||||
// the DLL. (We could additionally link them into the DLL - not as exports, just for internal usage - but we
|
||||
// haven't chosen to do that yet.) When we can break ABI and export the vector algorithms from the DLL,
|
||||
// this preprocessor case should be removed.
|
||||
#ifndef _USE_STD_VECTOR_ALGORITHMS
|
||||
#define _USE_STD_VECTOR_ALGORITHMS 0
|
||||
#elif _USE_STD_VECTOR_ALGORITHMS
|
||||
#error Vector algorithms are not supported when building msvcp140.dll, but _USE_STD_VECTOR_ALGORITHMS is set.
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
#elif (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) && !defined(_M_ARM64EC)
|
||||
#ifndef _USE_STD_VECTOR_ALGORITHMS
|
||||
#define _USE_STD_VECTOR_ALGORITHMS 1
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
#else // ^^^ arch supports vector algorithms / no support for vector algorithms vvv
|
||||
#ifndef _USE_STD_VECTOR_ALGORITHMS
|
||||
#define _USE_STD_VECTOR_ALGORITHMS 0
|
||||
#elif _USE_STD_VECTOR_ALGORITHMS
|
||||
#error Vector algorithms are not supported on this architecture, but _USE_STD_VECTOR_ALGORITHMS is set.
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
#endif // ^^^ no support for vector algorithms ^^^
|
||||
|
||||
#if _USE_STD_VECTOR_ALGORITHMS
|
||||
_EXTERN_C
|
||||
// See the important comment about the "noalias" attribute in <xutility>.
|
||||
__declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias(
|
||||
void* _First1, void* _Last1, void* _First2) noexcept;
|
||||
_END_EXTERN_C
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
|
||||
_STD_BEGIN
|
||||
template <class _Ty, _Ty... _Vals>
|
||||
struct integer_sequence { // sequence of integer parameters
|
||||
|
|
|
@ -80,29 +80,14 @@ _CONSTEXPR20 void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right) { // swap *_Left and
|
|||
|
||||
template <class _Ty, size_t _Size, enable_if_t<_Is_swappable<_Ty>::value, int> _Enabled>
|
||||
_CONSTEXPR20 void swap(_Ty (&_Left)[_Size], _Ty (&_Right)[_Size]) noexcept(_Is_nothrow_swappable<_Ty>::value) {
|
||||
_Ty* _First1 = _Left;
|
||||
_Ty* _Last1 = _First1 + _Size;
|
||||
_Ty* _First2 = _Right;
|
||||
|
||||
if (_First1 == _First2) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if _USE_STD_VECTOR_ALGORITHMS
|
||||
if constexpr (_Is_trivially_swappable_v<_Ty>) {
|
||||
#if _HAS_CXX20
|
||||
if (!_STD is_constant_evaluated())
|
||||
#endif // _HAS_CXX20
|
||||
{
|
||||
__std_swap_ranges_trivially_swappable_noalias(_First1, _Last1, _First2);
|
||||
return;
|
||||
if (&_Left != &_Right) {
|
||||
_Ty* _First1 = _Left;
|
||||
_Ty* _Last1 = _First1 + _Size;
|
||||
_Ty* _First2 = _Right;
|
||||
for (; _First1 != _Last1; ++_First1, ++_First2) {
|
||||
_STD iter_swap(_First1, _First2);
|
||||
}
|
||||
}
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
|
||||
for (; _First1 != _Last1; ++_First1, ++_First2) {
|
||||
_STD iter_swap(_First1, _First2);
|
||||
}
|
||||
}
|
||||
|
||||
#if _HAS_CXX17
|
||||
|
|
|
@ -21,6 +21,28 @@ _STL_DISABLE_CLANG_WARNINGS
|
|||
#pragma push_macro("new")
|
||||
#undef new
|
||||
|
||||
#if defined(_CRTBLD) && defined(CRTDLL2)
|
||||
// TRANSITION, ABI: The vector algorithms are compiled into the import lib, so we disable their usage when building
|
||||
// the DLL. (We could additionally link them into the DLL - not as exports, just for internal usage - but we
|
||||
// haven't chosen to do that yet.) When we can break ABI and export the vector algorithms from the DLL,
|
||||
// this preprocessor case should be removed.
|
||||
#ifndef _USE_STD_VECTOR_ALGORITHMS
|
||||
#define _USE_STD_VECTOR_ALGORITHMS 0
|
||||
#elif _USE_STD_VECTOR_ALGORITHMS
|
||||
#error Vector algorithms are not supported when building msvcp140.dll, but _USE_STD_VECTOR_ALGORITHMS is set.
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
#elif (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) && !defined(_M_ARM64EC)
|
||||
#ifndef _USE_STD_VECTOR_ALGORITHMS
|
||||
#define _USE_STD_VECTOR_ALGORITHMS 1
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
#else // ^^^ arch supports vector algorithms / no support for vector algorithms vvv
|
||||
#ifndef _USE_STD_VECTOR_ALGORITHMS
|
||||
#define _USE_STD_VECTOR_ALGORITHMS 0
|
||||
#elif _USE_STD_VECTOR_ALGORITHMS
|
||||
#error Vector algorithms are not supported on this architecture, but _USE_STD_VECTOR_ALGORITHMS is set.
|
||||
#endif // _USE_STD_VECTOR_ALGORITHMS
|
||||
#endif // ^^^ no support for vector algorithms ^^^
|
||||
|
||||
#ifdef __CUDACC__
|
||||
#define _CONSTEXPR_BIT_CAST inline
|
||||
#else // ^^^ workaround ^^^ / vvv no workaround vvv
|
||||
|
@ -40,6 +62,8 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_1(void* _Firs
|
|||
__declspec(noalias) void __cdecl __std_reverse_trivially_swappable_2(void* _First, void* _Last) noexcept;
|
||||
__declspec(noalias) void __cdecl __std_reverse_trivially_swappable_4(void* _First, void* _Last) noexcept;
|
||||
__declspec(noalias) void __cdecl __std_reverse_trivially_swappable_8(void* _First, void* _Last) noexcept;
|
||||
__declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias(
|
||||
void* _First1, void* _Last1, void* _First2) noexcept;
|
||||
|
||||
__declspec(noalias) size_t
|
||||
__stdcall __std_count_trivial_1(const void* _First, const void* _Last, uint8_t _Val) noexcept;
|
||||
|
|
|
@ -826,6 +826,7 @@ void test_buffer_resizing() {
|
|||
}
|
||||
|
||||
void test_gh_2618() {
|
||||
// GH-2618 <xloctime>: get_time does not return correct year in tm.tm_year if year is 1
|
||||
auto TestTimeGetYear = [](const char* input, const int expected_y, const int expected_Y,
|
||||
const int expected_get_year) {
|
||||
{
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#define _CORE_HEADERS_ONLY
|
||||
|
||||
#include <__msvc_all_public_headers.hpp>
|
||||
|
||||
#ifdef _YVALS
|
||||
#error Core headers should not include <yvals.h>.
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#ifndef _YVALS
|
||||
#error Non-core headers like <chrono> should include <yvals.h>.
|
||||
#endif
|
||||
|
||||
int main() {} // COMPILE-ONLY
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#define _CORE_HEADERS_ONLY
|
||||
|
||||
#include <__msvc_all_public_headers.hpp>
|
||||
|
||||
#ifdef _YVALS
|
||||
#error Core headers should not include <yvals.h>.
|
||||
#endif
|
||||
|
||||
void test_gh_2699() {
|
||||
// GH-2699 Vectorized swap emits error LNK2019:
|
||||
// unresolved external symbol ___std_swap_ranges_trivially_swappable_noalias
|
||||
int cats[]{10, 20, 30};
|
||||
int dogs[]{40, 50, 60};
|
||||
|
||||
std::swap(cats, dogs);
|
||||
assert(cats[1] == 50);
|
||||
assert(dogs[1] == 20);
|
||||
|
||||
#ifdef __cpp_lib_ranges
|
||||
std::ranges::swap(cats, dogs);
|
||||
assert(cats[1] == 20);
|
||||
assert(dogs[1] == 50);
|
||||
#endif // __cpp_lib_ranges
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_gh_2699();
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <isa_availability.h>
|
||||
#include <list>
|
||||
|
@ -12,10 +11,6 @@
|
|||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
#include <concepts>
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE)
|
||||
|
@ -172,31 +167,6 @@ void test_swap_ranges(mt19937_64& gen) {
|
|||
}
|
||||
}
|
||||
|
||||
// GH-2683 "std::swap of arrays, why is there no specialization for trivial types"
|
||||
template <class T, size_t N>
|
||||
void test_swap_arrays(mt19937_64& gen) {
|
||||
const auto fn = [&]() { return static_cast<T>(gen()); };
|
||||
T left[N];
|
||||
T right[N];
|
||||
generate(begin(left), end(left), fn);
|
||||
generate(begin(right), end(right), fn);
|
||||
|
||||
const vector<T> origLeft(begin(left), end(left));
|
||||
const vector<T> origRight(begin(right), end(right));
|
||||
|
||||
swap(left, right);
|
||||
|
||||
assert(equal(begin(left), end(left), origRight.begin(), origRight.end()));
|
||||
assert(equal(begin(right), end(right), origLeft.begin(), origLeft.end()));
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
ranges::swap(left, right);
|
||||
|
||||
assert(equal(begin(left), end(left), origLeft.begin(), origLeft.end()));
|
||||
assert(equal(begin(right), end(right), origRight.begin(), origRight.end()));
|
||||
#endif // __cpp_lib_concepts
|
||||
}
|
||||
|
||||
void test_vector_algorithms() {
|
||||
mt19937_64 gen(1729);
|
||||
|
||||
|
@ -251,21 +221,6 @@ void test_vector_algorithms() {
|
|||
test_swap_ranges<int>(gen);
|
||||
test_swap_ranges<unsigned int>(gen);
|
||||
test_swap_ranges<unsigned long long>(gen);
|
||||
|
||||
test_swap_arrays<uint8_t, 1>(gen);
|
||||
test_swap_arrays<uint16_t, 1>(gen);
|
||||
test_swap_arrays<uint32_t, 1>(gen);
|
||||
test_swap_arrays<uint64_t, 1>(gen);
|
||||
|
||||
test_swap_arrays<uint8_t, 47>(gen);
|
||||
test_swap_arrays<uint16_t, 47>(gen);
|
||||
test_swap_arrays<uint32_t, 47>(gen);
|
||||
test_swap_arrays<uint64_t, 47>(gen);
|
||||
|
||||
test_swap_arrays<uint8_t, 512>(gen);
|
||||
test_swap_arrays<uint16_t, 512>(gen);
|
||||
test_swap_arrays<uint32_t, 512>(gen);
|
||||
test_swap_arrays<uint64_t, 512>(gen);
|
||||
}
|
||||
|
||||
template <typename Container1, typename Container2>
|
||||
|
|
Загрузка…
Ссылка в новой задаче