1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___BIT_BYTESWAP_H
11#define _LIBCPP___BIT_BYTESWAP_H
12
13#include <__concepts/arithmetic.h>
14#include <__config>
15#include <__type_traits/is_same.h>
16#include <__type_traits/remove_cv.h>
17#include <climits>
18#include <cstdint>
19#include <limits>
20
21#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22# pragma GCC system_header
23#endif
24
25_LIBCPP_BEGIN_NAMESPACE_STD
26
27#if _LIBCPP_STD_VER >= 23
28
29template <integral _Tp>
30[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp byteswap(_Tp __val) noexcept {
31 // [bit.byteswap]/Mandates: T does not have padding bits.
32 // bool is grandfathered: every shipping implementation admits it and the
33 // size-1 identity path can't shuffle padding bits into value positions.
34 // LWG 4583 proposes relaxing this to allow byte-aligned padding (e.g.
35 // _BitInt(48) where 2 whole bytes are padding); revisit once it resolves.
36 static_assert(is_same_v<remove_cv_t<_Tp>, bool> ||
37 numeric_limits<_Tp>::digits + numeric_limits<_Tp>::is_signed == sizeof(_Tp) * CHAR_BIT,
38 "std::byteswap requires T to have no padding bits");
39
40 if constexpr (sizeof(_Tp) == 1) {
41 return __val;
42# if __has_builtin(__builtin_bswapg)
43 } else {
44 return __builtin_bswapg(__val);
45 }
46# else
47 } else if constexpr (sizeof(_Tp) == 2) {
48 return __builtin_bswap16(__val);
49 } else if constexpr (sizeof(_Tp) == 4) {
50 return __builtin_bswap32(__val);
51 } else if constexpr (sizeof(_Tp) == 8) {
52 return __builtin_bswap64(__val);
53# if _LIBCPP_HAS_INT128
54 } else if constexpr (sizeof(_Tp) == 16) {
55# if __has_builtin(__builtin_bswap128)
56 return __builtin_bswap128(__val);
57# else
58 return (static_cast<_Tp>(byteswap(static_cast<uint64_t>(__val))) << 64) |
59 static_cast<_Tp>(byteswap(static_cast<uint64_t>(__val >> 64)));
60# endif // __has_builtin(__builtin_bswap128)
61# endif // _LIBCPP_HAS_INT128
62 } else {
63 static_assert(sizeof(_Tp) == 0, "byteswap is unimplemented for integral types of this size");
64 }
65# endif // __has_builtin(__builtin_bswapg)
66}
67
68#endif // _LIBCPP_STD_VER >= 23
69
70_LIBCPP_END_NAMESPACE_STD
71
72#endif // _LIBCPP___BIT_BYTESWAP_H
73