[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

NOKEYCHECK=True
GitOrigin-RevId: 1dc62f2653f837745251bd905940c11962469b45
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 1947aa1..cd5674a 100644
--- a/include/CMakeLists.txt
+++ b/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/include/__bit/byteswap.h b/include/__bit/byteswap.h
new file mode 100644
index 0000000..970074e
--- /dev/null
+++ b/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/include/bit b/include/bit
index 634475b..0aab83e 100644
--- a/include/bit
+++ b/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 @@
     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/include/module.modulemap b/include/module.modulemap
index f34442e..f3de49e 100644
--- a/include/module.modulemap
+++ b/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/include/version b/include/version
index 7c16ac8..4b6f9b3 100644
--- a/include/version
+++ b/include/version
@@ -41,6 +41,7 @@
 __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 @@
 #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