diff --git a/stl/inc/bit b/stl/inc/bit index 85040110d3..b412a53b96 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -233,6 +233,34 @@ _NODISCARD int _Checked_arm_arm64_countl_zero(const _Ty _Val) noexcept { } #endif // defined(_M_ARM) || defined(_M_ARM64) +#if _HAS_CXX23 +_NODISCARD constexpr unsigned short _Byteswap_ushort(const unsigned short _Val) noexcept { + if (_STD is_constant_evaluated()) { + return static_cast((_Val << 8) | (_Val >> 8)); + } else { + return _byteswap_ushort(_Val); + } +} + +_NODISCARD constexpr unsigned long _Byteswap_ulong(const unsigned long _Val) noexcept { + if (_STD is_constant_evaluated()) { + return (_Val << 24) | ((_Val << 8) & 0x00FF'0000) | ((_Val >> 8) & 0x0000'FF00) | (_Val >> 24); + } else { + return _byteswap_ulong(_Val); + } +} + +_NODISCARD constexpr unsigned long long _Byteswap_uint64(const unsigned long long _Val) noexcept { + if (_STD is_constant_evaluated()) { + return (_Val << 56) | ((_Val << 40) & 0x00FF'0000'0000'0000) | ((_Val << 24) & 0x0000'FF00'0000'0000) + | ((_Val << 8) & 0x0000'00FF'0000'0000) | ((_Val >> 8) & 0x0000'0000'FF00'0000) + | ((_Val >> 24) & 0x0000'0000'00FF'0000) | ((_Val >> 40) & 0x0000'0000'0000'FF00) | (_Val >> 56); + } else { + return _byteswap_uint64(_Val); + } +} +#endif // _HAS_CXX23 + template , int> _Enabled> _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { #if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) @@ -268,6 +296,23 @@ _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { return _Popcount(_Val); } +#if _HAS_CXX23 +template , int> = 0> +_NODISCARD constexpr _Ty byteswap(const _Ty _Val) noexcept { + if constexpr (sizeof(_Ty) == 1) { + return _Val; + } else if constexpr (sizeof(_Ty) == 2) { + return static_cast<_Ty>(_Byteswap_ushort(static_cast(_Val))); + } else if constexpr (sizeof(_Ty) == 4) { + return static_cast<_Ty>(_Byteswap_ulong(static_cast(_Val))); + } else if constexpr (sizeof(_Ty) == 8) { + return static_cast<_Ty>(_Byteswap_uint64(static_cast(_Val))); + } else { + static_assert(_Always_false<_Ty>, "Unexpected integer size"); + } +} +#endif // _HAS_CXX23 + enum class endian { little = 0, big = 1, native = little }; _STD_END diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index a50241bf19..6779025d33 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -275,6 +275,7 @@ // P0943R6 Supporting C Atomics In C++ // P1048R1 is_scoped_enum // P1132R7 out_ptr(), inout_ptr() +// P1272R4 byteswap() // P1425R4 Iterator Pair Constructors For stack And queue // P1679R3 contains() For basic_string/basic_string_view // P1682R3 to_underlying() For Enumerations @@ -1376,6 +1377,7 @@ #define __cpp_lib_allocate_at_least 202106L #endif // __cpp_lib_concepts +#define __cpp_lib_byteswap 202110L #define __cpp_lib_invoke_r 202106L #define __cpp_lib_is_scoped_enum 202011L diff --git a/tests/std/test.lst b/tests/std/test.lst index f3f611f9b5..21ac8e4527 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -434,6 +434,7 @@ tests\P1135R6_latch tests\P1135R6_semaphore tests\P1165R1_consistently_propagating_stateful_allocators tests\P1208R6_source_location +tests\P1272R4_byteswap tests\P1423R3_char8_t_remediation tests\P1425R4_queue_stack_constructors tests\P1502R1_standard_library_header_units diff --git a/tests/std/tests/P1272R4_byteswap/env.lst b/tests/std/tests/P1272R4_byteswap/env.lst new file mode 100644 index 0000000000..642f530ffa --- /dev/null +++ b/tests/std/tests/P1272R4_byteswap/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1272R4_byteswap/test.cpp b/tests/std/tests/P1272R4_byteswap/test.cpp new file mode 100644 index 0000000000..9522ade0da --- /dev/null +++ b/tests/std/tests/P1272R4_byteswap/test.cpp @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +using namespace std; + +template +constexpr bool test_byteswap(const auto src, const auto result) { + static_assert(noexcept(byteswap(T{}))); + return byteswap(static_cast(src)) == static_cast(result); +} + +constexpr bool test_byteswap_all_types() { + assert(test_byteswap(true, true)); + + assert(test_byteswap(0x13, 0x13)); + assert(test_byteswap(0x13, 0x13)); + assert(test_byteswap(0x13, 0x13)); +#ifdef __cpp_char8_t + assert(test_byteswap(0x13, 0x13)); +#endif + + assert(test_byteswap(0xAC34, 0x34AC)); + assert(test_byteswap(0xAC34, 0x34AC)); + assert(test_byteswap(0xAC34, 0x34AC)); + assert(test_byteswap(0xAC34, 0x34AC)); + + assert(test_byteswap(0x1234ABCD, 0xCDAB3412)); + assert(test_byteswap(0x1234ABCD, 0xCDAB3412)); + assert(test_byteswap(0x1234ABCD, 0xCDAB3412)); + assert(test_byteswap(0x1234ABCD, 0xCDAB3412)); + assert(test_byteswap(0x1234ABCD, 0xCDAB3412)); + + assert(test_byteswap(0x1234567890ABCDEF, 0xEFCDAB9078563412)); + assert(test_byteswap(0x1234567890ABCDEF, 0xEFCDAB9078563412)); + + return true; +} + +static_assert(test_byteswap_all_types()); + +int main() { + test_byteswap_all_types(); +} diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 86aaf50b68..179830a641 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -336,6 +336,20 @@ STATIC_ASSERT(__cpp_lib_byte == 201603L); #endif #endif +#if _HAS_CXX23 +#ifndef __cpp_lib_byteswap +#error __cpp_lib_byteswap is not defined +#elif __cpp_lib_byteswap != 202110L +#error __cpp_lib_byteswap is not 202110L +#else +STATIC_ASSERT(__cpp_lib_byteswap == 202110L); +#endif +#else +#ifdef __cpp_lib_byteswap +#error __cpp_lib_byteswap is defined +#endif +#endif + #if _HAS_CXX20 && defined(__cpp_char8_t) #ifndef __cpp_lib_char8_t #error __cpp_lib_char8_t is not defined