[libcxx-commits] [libcxx] 1dc62f2 - [libc++] Implement P1272R4 (std::byteswap)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sun Nov 21 16:28:57 PST 2021


Author: Nikolas Klauser
Date: 2021-11-22T01:28:18+01:00
New Revision: 1dc62f2653f837745251bd905940c11962469b45

URL: https://github.com/llvm/llvm-project/commit/1dc62f2653f837745251bd905940c11962469b45
DIFF: https://github.com/llvm/llvm-project/commit/1dc62f2653f837745251bd905940c11962469b45.diff

LOG: [libc++] Implement P1272R4 (std::byteswap)

Implement P1274R4

Reviewed By: Quuxplusone, Mordante, #libc

Spies: jloser, lebedev.ri, mgorny, libcxx-commits, arichardson

Differential Revision: https://reviews.llvm.org/D114074

Added: 
    libcxx/include/__bit/byteswap.h
    libcxx/test/libcxx/diagnostics/detail.headers/bit/byteswap.module.verify.cpp
    libcxx/test/std/numerics/bit/byteswap.pass.cpp

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/Status/Cxx2bPapers.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/bit
    libcxx/include/module.modulemap
    libcxx/include/version
    libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 8300b86f565bc..763e6513028b4 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -294,6 +294,8 @@ Status
     ------------------------------------------------- -----------------
     **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
index 1a1ca7272db98..ae756c392beeb 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -28,7 +28,7 @@
 "`P0849R8 <https://wg21.link/P0849R8>`__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","",""
 "`P1072R10 <https://wg21.link/P1072R10>`__","LWG","``basic_string::resize_and_overwrite``","October 2021","",""
 "`P1147R1 <https://wg21.link/P1147R1>`__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0"
-"`P1272R4 <https://wg21.link/P1272R4>`__","LWG","Byteswapping for fun&&nuf","October 2021","",""
+"`P1272R4 <https://wg21.link/P1272R4>`__","LWG","Byteswapping for fun&&nuf","October 2021","|Complete|","14.0"
 "`P1675R2 <https://wg21.link/P1675R2>`__","LWG","``rethrow_exception`` must be allowed to copy","October 2021","",""
 "`P2077R3 <https://wg21.link/P2077R3>`__","LWG","Heterogeneous erasure overloads for associative containers","October 2021","",""
 "`P2251R1 <https://wg21.link/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
index 1947aa1a8506f..cd5674a018e80 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -95,6 +95,7 @@ set(files
   __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
index 0000000000000..970074ed98cea
--- /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 <cstdint>
+#include <cstdlib>
+
+#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 <integral _Tp>
+_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<uint64_t>(__val))) << 64 |
+           static_cast<_Tp>(byteswap(static_cast<uint64_t>(__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
index 634475b99879b..0aab83e7a6ebe 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -14,9 +14,13 @@
     bit synopsis
 
 namespace std {
-    // [bit.cast], bit_cast
-    template<class To, class From>
-      constexpr To bit_cast(const From& from) noexcept; // C++20
+  // [bit.cast], bit_cast
+  template<class To, class From>
+    constexpr To bit_cast(const From& from) noexcept; // C++20
+
+  // [bit.byteswap], byteswap
+  template<class T>
+    constexpr T byteswap(T value) noexcept;      // C++23
 
   // [bit.pow.two], integral powers of 2
   template <class T>
@@ -51,13 +55,14 @@ namespace std {
     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
index f34442ed5c9a9..f3de49eaf41d7 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -338,6 +338,7 @@ module std [system] {
 
     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
index 7c16ac85e4302..4b6f9b3ed7107 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -41,6 +41,7 @@ __cpp_lib_bool_constant                                 201505L <type_traits>
 __cpp_lib_bounded_array_traits                          201902L <type_traits>
 __cpp_lib_boyer_moore_searcher                          201603L <functional>
 __cpp_lib_byte                                          201603L <cstddef>
+__cpp_lib_byteswap                                      202110L <bit>
 __cpp_lib_char8_t                                       201811L <atomic> <filesystem> <istream>
                                                                 <limits> <locale> <ostream>
                                                                 <string> <string_view>
@@ -344,6 +345,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 #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
index 0000000000000..08dc7f36c21f6
--- /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
index 3c0f7002025d2..d5dcc86e5c069 100644
--- 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
index 782c09c147a66..7c1ac22a74768 100644
--- 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
index 0000000000000..076dc4343a395
--- /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 <bit>
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+#include "test_macros.h"
+
+template <class T>
+concept has_byteswap = requires(T t) {
+  std::byteswap(t);
+};
+
+static_assert(!has_byteswap<void*>);
+static_assert(!has_byteswap<float>);
+static_assert(!has_byteswap<char[2]>);
+static_assert(!has_byteswap<std::byte>);
+
+template <class T>
+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 <class T>
+constexpr std::pair<T, T> get_test_data() {
+  switch (sizeof(T)) {
+  case 2:
+    return {static_cast<T>(0x1234), static_cast<T>(0x3412)};
+  case 4:
+    return {static_cast<T>(0x60AF8503), static_cast<T>(0x0385AF60)};
+  case 8:
+    return {static_cast<T>(0xABCDFE9477936406), static_cast<T>(0x0664937794FECDAB)};
+  }
+  assert(false);
+}
+
+template <class T>
+constexpr void test_implementation_defined_size() {
+  const auto [in, expected] = get_test_data<T>();
+  test_num<T>(in, expected);
+}
+
+constexpr bool test() {
+  test_num<uint8_t>(0xAB, 0xAB);
+  test_num<uint16_t>(0xCDEF, 0xEFCD);
+  test_num<uint32_t>(0x01234567, 0x67452301);
+  test_num<uint64_t>(0x0123456789ABCDEF, 0xEFCDAB8967452301);
+
+  test_num<int8_t>(0xAB, 0xAB);
+  test_num<int16_t>(0xCDEF, 0xEFCD);
+  test_num<int32_t>(0x01234567, 0x67452301);
+  test_num<int64_t>(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<bool>(true, true);
+  test_num<bool>(false, false);
+  test_num<char>(0xCD, 0xCD);
+  test_num<unsigned char>(0xEF, 0xEF);
+  test_num<signed char>(0x45, 0x45);
+  test_num<char8_t>(0xAB, 0xAB);
+  test_num<char16_t>(0xABCD, 0xCDAB);
+  test_num<char32_t>(0xABCDEF01, 0x01EFCDAB);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_implementation_defined_size<wchar_t>();
+#endif
+
+  test_implementation_defined_size<short>();
+  test_implementation_defined_size<unsigned short>();
+  test_implementation_defined_size<int>();
+  test_implementation_defined_size<unsigned int>();
+  test_implementation_defined_size<long>();
+  test_implementation_defined_size<unsigned long>();
+  test_implementation_defined_size<long long>();
+  test_implementation_defined_size<unsigned long long>();
+  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
index 1a78acee6292c..fa0a3eadbea47 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -164,6 +164,10 @@ def add_version_header(tc):
     "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 },


        


More information about the libcxx-commits mailing list