diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -294,6 +294,8 @@ ------------------------------------------------- ----------------- **C++ 2b** ------------------------------------------------------------------- + ``__cpp_lib_byteswap`` ``202110L`` + ------------------------------------------------- ----------------- ``__cpp_lib_is_scoped_enum`` ``202011L`` ------------------------------------------------- ----------------- ``__cpp_lib_stacktrace`` *unimplemented* diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -28,7 +28,7 @@ "`P0849R8 `__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","","" "`P1072R10 `__","LWG","``basic_string::resize_and_overwrite``","October 2021","","" "`P1147R1 `__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0" -"`P1272R4 `__","LWG","Byteswapping for fun&&nuf","October 2021","","" +"`P1272R4 `__","LWG","Byteswapping for fun&&nuf","October 2021","|Complete|","14.0" "`P1675R2 `__","LWG","``rethrow_exception`` must be allowed to copy","October 2021","","" "`P2077R3 `__","LWG","Heterogeneous erasure overloads for associative containers","October 2021","","" "`P2251R1 `__","LWG","Require ``span`` & ``basic_string_view`` to be Trivially Copyable","October 2021","|Complete|","14.0" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -95,6 +95,7 @@ __availability __bit_reference __bit/bit_cast.h + __bit/byteswap.h __bits __bsd_locale_defaults.h __bsd_locale_fallbacks.h diff --git a/libcxx/include/__bit/byteswap.h b/libcxx/include/__bit/byteswap.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__bit/byteswap.h @@ -0,0 +1,55 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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___BIT_BYTESWAP_H +#define _LIBCPP___BIT_BYTESWAP_H + +#include <__concepts/arithmetic.h> +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Tp byteswap(_Tp __val) noexcept { + + if constexpr (sizeof(_Tp) == 1) { + return __val; + } else if constexpr (sizeof(_Tp) == 2) { + return __builtin_bswap16(__val); + } else if constexpr (sizeof(_Tp) == 4) { + return __builtin_bswap32(__val); + } else if constexpr (sizeof(_Tp) == 8) { + return __builtin_bswap64(__val); +#ifndef _LIBCPP_HAS_NO_INT128 + } else if constexpr (sizeof(_Tp) == 16) { +#if __has_builtin(__builtin_bswap128) + return __builtin_bswap128(__val); +#else + return static_cast<_Tp>(byteswap(static_cast(__val))) << 64 | + static_cast<_Tp>(byteswap(static_cast(__val >> 64))); +#endif // __has_builtin(__builtin_bswap128) +#endif // _LIBCPP_HAS_NO_INT128 + } else { + static_assert(sizeof(_Tp) == 0, "byteswap is unimplemented for integral types of this size"); + } +} + +#endif // _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BYTESWAP_H diff --git a/libcxx/include/bit b/libcxx/include/bit --- a/libcxx/include/bit +++ b/libcxx/include/bit @@ -14,9 +14,13 @@ bit synopsis namespace std { - // [bit.cast], bit_cast - template - constexpr To bit_cast(const From& from) noexcept; // C++20 + // [bit.cast], bit_cast + template + constexpr To bit_cast(const From& from) noexcept; // C++20 + + // [bit.byteswap], byteswap + template + constexpr T byteswap(T value) noexcept; // C++23 // [bit.pow.two], integral powers of 2 template @@ -51,13 +55,14 @@ little = see below, // C++20 big = see below, // C++20 native = see below // C++20 -}; + }; } // namespace std */ #include <__bit/bit_cast.h> +#include <__bit/byteswap.h> #include <__bits> // __libcpp_clz #include <__config> #include <__debug> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -338,6 +338,7 @@ module __bit { module bit_cast { private header "__bit/bit_cast.h" } + module byteswap { private header "__bit/byteswap.h" } } } module bitset { diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -41,6 +41,7 @@ __cpp_lib_bounded_array_traits 201902L __cpp_lib_boyer_moore_searcher 201603L __cpp_lib_byte 201603L +__cpp_lib_byteswap 202110L __cpp_lib_char8_t 201811L @@ -344,6 +345,7 @@ #endif #if _LIBCPP_STD_VER > 20 +# define __cpp_lib_byteswap 202110L # define __cpp_lib_is_scoped_enum 202011L // # define __cpp_lib_stacktrace 202011L // # define __cpp_lib_stdatomic_h 202011L diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/bit/byteswap.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/bit/byteswap.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/bit/byteswap.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__bit/byteswap.h'}} +#include <__bit/byteswap.h> diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp @@ -18,6 +18,7 @@ /* Constant Value __cpp_lib_bit_cast 201806L [C++20] __cpp_lib_bitops 201907L [C++20] + __cpp_lib_byteswap 202110L [C++2b] __cpp_lib_endian 201907L [C++20] __cpp_lib_int_pow2 202002L [C++20] */ @@ -35,6 +36,10 @@ # error "__cpp_lib_bitops should not be defined before c++20" # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # ifdef __cpp_lib_endian # error "__cpp_lib_endian should not be defined before c++20" # endif @@ -53,6 +58,10 @@ # error "__cpp_lib_bitops should not be defined before c++20" # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # ifdef __cpp_lib_endian # error "__cpp_lib_endian should not be defined before c++20" # endif @@ -71,6 +80,10 @@ # error "__cpp_lib_bitops should not be defined before c++20" # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # ifdef __cpp_lib_endian # error "__cpp_lib_endian should not be defined before c++20" # endif @@ -101,6 +114,10 @@ # endif # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # ifndef __cpp_lib_endian # error "__cpp_lib_endian should be defined in c++20" # endif @@ -137,6 +154,13 @@ # endif # endif +# ifndef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should be defined in c++2b" +# endif +# if __cpp_lib_byteswap != 202110L +# error "__cpp_lib_byteswap should have the value 202110L in c++2b" +# endif + # ifndef __cpp_lib_endian # error "__cpp_lib_endian should be defined in c++2b" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -40,6 +40,7 @@ __cpp_lib_bounded_array_traits 201902L [C++20] __cpp_lib_boyer_moore_searcher 201603L [C++17] __cpp_lib_byte 201603L [C++17] + __cpp_lib_byteswap 202110L [C++2b] __cpp_lib_char8_t 201811L [C++20] __cpp_lib_chrono 201611L [C++17] __cpp_lib_chrono_udls 201304L [C++14] @@ -251,6 +252,10 @@ # error "__cpp_lib_byte should not be defined before c++17" # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # ifdef __cpp_lib_char8_t # error "__cpp_lib_char8_t should not be defined before c++20" # endif @@ -781,6 +786,10 @@ # error "__cpp_lib_byte should not be defined before c++17" # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # ifdef __cpp_lib_char8_t # error "__cpp_lib_char8_t should not be defined before c++20" # endif @@ -1413,6 +1422,10 @@ # error "__cpp_lib_byte should have the value 201603L in c++17" # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # ifdef __cpp_lib_char8_t # error "__cpp_lib_char8_t should not be defined before c++20" # endif @@ -2288,6 +2301,10 @@ # error "__cpp_lib_byte should have the value 201603L in c++20" # endif +# ifdef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should not be defined before c++2b" +# endif + # if defined(__cpp_char8_t) # ifndef __cpp_lib_char8_t # error "__cpp_lib_char8_t should be defined in c++20" @@ -3409,6 +3426,13 @@ # error "__cpp_lib_byte should have the value 201603L in c++2b" # endif +# ifndef __cpp_lib_byteswap +# error "__cpp_lib_byteswap should be defined in c++2b" +# endif +# if __cpp_lib_byteswap != 202110L +# error "__cpp_lib_byteswap should have the value 202110L in c++2b" +# endif + # if defined(__cpp_char8_t) # ifndef __cpp_lib_char8_t # error "__cpp_lib_char8_t should be defined in c++2b" diff --git a/libcxx/test/std/numerics/bit/byteswap.pass.cpp b/libcxx/test/std/numerics/bit/byteswap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/numerics/bit/byteswap.pass.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include + +#include "test_macros.h" + +template +concept has_byteswap = requires(T t) { + std::byteswap(t); +}; + +static_assert(!has_byteswap); +static_assert(!has_byteswap); +static_assert(!has_byteswap); +static_assert(!has_byteswap); + +template +constexpr void test_num(T in, T expected) { + assert(std::byteswap(in) == expected); + ASSERT_SAME_TYPE(decltype(std::byteswap(in)), decltype(in)); + ASSERT_NOEXCEPT(std::byteswap(in)); +} + +template +constexpr std::pair get_test_data() { + switch (sizeof(T)) { + case 2: + return {static_cast(0x1234), static_cast(0x3412)}; + case 4: + return {static_cast(0x60AF8503), static_cast(0x0385AF60)}; + case 8: + return {static_cast(0xABCDFE9477936406), static_cast(0x0664937794FECDAB)}; + } + assert(false); +} + +template +constexpr void test_implementation_defined_size() { + const auto [in, expected] = get_test_data(); + test_num(in, expected); +} + +constexpr bool test() { + test_num(0xAB, 0xAB); + test_num(0xCDEF, 0xEFCD); + test_num(0x01234567, 0x67452301); + test_num(0x0123456789ABCDEF, 0xEFCDAB8967452301); + + test_num(0xAB, 0xAB); + test_num(0xCDEF, 0xEFCD); + test_num(0x01234567, 0x67452301); + test_num(0x0123456789ABCDEF, 0xEFCDAB8967452301); + +#ifndef _LIBCPP_HAS_NO_INT128 + const auto in = static_cast<__uint128_t>(0x0123456789ABCDEF) << 64 | 0x13579BDF02468ACE; + const auto expected = static_cast<__uint128_t>(0xCE8A4602DF9B5713) << 64 | 0xEFCDAB8967452301; + test_num<__uint128_t>(in, expected); + test_num<__int128_t>(in, expected); +#endif + + test_num(true, true); + test_num(false, false); + test_num(0xCD, 0xCD); + test_num(0xEF, 0xEF); + test_num(0x45, 0x45); + test_num(0xAB, 0xAB); + test_num(0xABCD, 0xCDAB); + test_num(0xABCDEF01, 0x01EFCDAB); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_implementation_defined_size(); +#endif + + test_implementation_defined_size(); + test_implementation_defined_size(); + test_implementation_defined_size(); + test_implementation_defined_size(); + test_implementation_defined_size(); + test_implementation_defined_size(); + test_implementation_defined_size(); + test_implementation_defined_size(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -164,6 +164,10 @@ "name": "__cpp_lib_byte", "values": { "c++17": 201603 }, "headers": ["cstddef"], + }, { + "name": "__cpp_lib_byteswap", + "values": { "c++2b": 202110 }, + "headers": ["bit"], }, { "name": "__cpp_lib_char8_t", "values": { "c++20": 201811 },