wez@chromium.org | 9eb7b11 | 2012-03-28 20:19:31 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
wez@chromium.org | eda78e6 | 2012-04-06 04:32:28 | [diff] [blame] | 5 | // This header defines cross-platform ByteSwap() implementations for 16, 32 and |
| 6 | // 64-bit values, and NetToHostXX() / HostToNextXX() functions equivalent to |
| 7 | // the traditional ntohX() and htonX() functions. |
| 8 | // Use the functions defined here rather than using the platform-specific |
| 9 | // functions directly. |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 10 | |
| 11 | #ifndef BASE_SYS_BYTEORDER_H_ |
| 12 | #define BASE_SYS_BYTEORDER_H_ |
| 13 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 14 | #include <stdint.h> |
| 15 | |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 16 | #include "build/build_config.h" |
| 17 | |
robert.bradford | 1a09b177 | 2016-06-17 23:26:11 | [diff] [blame] | 18 | #if defined(COMPILER_MSVC) |
| 19 | #include <stdlib.h> |
| 20 | #endif |
| 21 | |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 22 | #if defined(COMPILER_MSVC) && !defined(__clang__) |
| 23 | // TODO(pkasting): See |
| 24 | // https://developercommunity.visualstudio.com/t/Mark-some-built-in-functions-as-constexp/362558 |
| 25 | // https://developercommunity.visualstudio.com/t/constexpr-byte-swapping-optimization/983963 |
| 26 | #define BASE_BYTESWAPS_CONSTEXPR |
| 27 | #else |
| 28 | #define BASE_BYTESWAPS_CONSTEXPR constexpr |
| 29 | #endif |
| 30 | |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 31 | namespace base { |
| 32 | |
| 33 | // Returns a value with all bytes in |x| swapped, i.e. reverses the endianness. |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 34 | // TODO(pkasting): Once C++23 is available, replace with std::byteswap. |
| 35 | inline BASE_BYTESWAPS_CONSTEXPR uint16_t ByteSwap(uint16_t x) { |
Benoit Lize | 63ce115 | 2021-02-04 17:44:53 | [diff] [blame] | 36 | #if defined(COMPILER_MSVC) && !defined(__clang__) |
robert.bradford | 1a09b177 | 2016-06-17 23:26:11 | [diff] [blame] | 37 | return _byteswap_ushort(x); |
| 38 | #else |
| 39 | return __builtin_bswap16(x); |
| 40 | #endif |
wez@chromium.org | 9eb7b11 | 2012-03-28 20:19:31 | [diff] [blame] | 41 | } |
sergeyu@chromium.org | 2090c52 | 2013-12-23 04:02:49 | [diff] [blame] | 42 | |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 43 | inline BASE_BYTESWAPS_CONSTEXPR uint32_t ByteSwap(uint32_t x) { |
Benoit Lize | 63ce115 | 2021-02-04 17:44:53 | [diff] [blame] | 44 | #if defined(COMPILER_MSVC) && !defined(__clang__) |
robert.bradford | 1a09b177 | 2016-06-17 23:26:11 | [diff] [blame] | 45 | return _byteswap_ulong(x); |
| 46 | #else |
| 47 | return __builtin_bswap32(x); |
| 48 | #endif |
wez@chromium.org | 9eb7b11 | 2012-03-28 20:19:31 | [diff] [blame] | 49 | } |
sergeyu@chromium.org | 2090c52 | 2013-12-23 04:02:49 | [diff] [blame] | 50 | |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 51 | inline BASE_BYTESWAPS_CONSTEXPR uint64_t ByteSwap(uint64_t x) { |
Benoit Lize | 63ce115 | 2021-02-04 17:44:53 | [diff] [blame] | 52 | // Per build/build_config.h, clang masquerades as MSVC on Windows. If we are |
| 53 | // actually using clang, we can rely on the builtin. |
| 54 | // |
| 55 | // This matters in practice, because on x86(_64), this is a single "bswap" |
| 56 | // instruction. MSVC correctly replaces the call with an inlined bswap at /O2 |
| 57 | // as of 2021, but clang as we use it in Chromium doesn't, keeping a function |
| 58 | // call for a single instruction. |
| 59 | #if defined(COMPILER_MSVC) && !defined(__clang__) |
robert.bradford | 1a09b177 | 2016-06-17 23:26:11 | [diff] [blame] | 60 | return _byteswap_uint64(x); |
| 61 | #else |
| 62 | return __builtin_bswap64(x); |
| 63 | #endif |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 64 | } |
| 65 | |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 66 | inline BASE_BYTESWAPS_CONSTEXPR uintptr_t ByteSwapUintPtrT(uintptr_t x) { |
palmer | a988c50 | 2016-12-14 09:40:38 | [diff] [blame] | 67 | // We do it this way because some build configurations are ILP32 even when |
| 68 | // defined(ARCH_CPU_64_BITS). Unfortunately, we can't use sizeof in #ifs. But, |
| 69 | // because these conditionals are constexprs, the irrelevant branches will |
| 70 | // likely be optimized away, so this construction should not result in code |
| 71 | // bloat. |
Lei Zhang | 5bf451c | 2020-01-06 20:49:42 | [diff] [blame] | 72 | static_assert(sizeof(uintptr_t) == 4 || sizeof(uintptr_t) == 8, |
| 73 | "Unsupported uintptr_t size"); |
| 74 | if (sizeof(uintptr_t) == 4) |
palmer | a988c50 | 2016-12-14 09:40:38 | [diff] [blame] | 75 | return ByteSwap(static_cast<uint32_t>(x)); |
Lei Zhang | 5bf451c | 2020-01-06 20:49:42 | [diff] [blame] | 76 | return ByteSwap(static_cast<uint64_t>(x)); |
palmer | a988c50 | 2016-12-14 09:40:38 | [diff] [blame] | 77 | } |
| 78 | |
jwd@chromium.org | 7f8ce3d9 | 2012-04-16 15:29:27 | [diff] [blame] | 79 | // Converts the bytes in |x| from host order (endianness) to little endian, and |
| 80 | // returns the result. |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 81 | inline BASE_BYTESWAPS_CONSTEXPR uint16_t ByteSwapToLE16(uint16_t x) { |
jwd@chromium.org | 7f8ce3d9 | 2012-04-16 15:29:27 | [diff] [blame] | 82 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 83 | return x; |
| 84 | #else |
| 85 | return ByteSwap(x); |
| 86 | #endif |
| 87 | } |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 88 | inline BASE_BYTESWAPS_CONSTEXPR uint32_t ByteSwapToLE32(uint32_t x) { |
jwd@chromium.org | 7f8ce3d9 | 2012-04-16 15:29:27 | [diff] [blame] | 89 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 90 | return x; |
| 91 | #else |
| 92 | return ByteSwap(x); |
| 93 | #endif |
| 94 | } |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 95 | inline BASE_BYTESWAPS_CONSTEXPR uint64_t ByteSwapToLE64(uint64_t x) { |
jwd@chromium.org | 7f8ce3d9 | 2012-04-16 15:29:27 | [diff] [blame] | 96 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 97 | return x; |
| 98 | #else |
| 99 | return ByteSwap(x); |
| 100 | #endif |
| 101 | } |
| 102 | |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 103 | // Converts the bytes in |x| from network to host order (endianness), and |
| 104 | // returns the result. |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 105 | inline BASE_BYTESWAPS_CONSTEXPR uint16_t NetToHost16(uint16_t x) { |
wez@chromium.org | 9eb7b11 | 2012-03-28 20:19:31 | [diff] [blame] | 106 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 107 | return ByteSwap(x); |
| 108 | #else |
| 109 | return x; |
| 110 | #endif |
| 111 | } |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 112 | inline BASE_BYTESWAPS_CONSTEXPR uint32_t NetToHost32(uint32_t x) { |
wez@chromium.org | 9eb7b11 | 2012-03-28 20:19:31 | [diff] [blame] | 113 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 114 | return ByteSwap(x); |
| 115 | #else |
| 116 | return x; |
| 117 | #endif |
| 118 | } |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 119 | inline BASE_BYTESWAPS_CONSTEXPR uint64_t NetToHost64(uint64_t x) { |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 120 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 121 | return ByteSwap(x); |
| 122 | #else |
| 123 | return x; |
| 124 | #endif |
| 125 | } |
| 126 | |
| 127 | // Converts the bytes in |x| from host to network order (endianness), and |
| 128 | // returns the result. |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 129 | inline BASE_BYTESWAPS_CONSTEXPR uint16_t HostToNet16(uint16_t x) { |
wez@chromium.org | 9eb7b11 | 2012-03-28 20:19:31 | [diff] [blame] | 130 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 131 | return ByteSwap(x); |
| 132 | #else |
| 133 | return x; |
| 134 | #endif |
| 135 | } |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 136 | inline BASE_BYTESWAPS_CONSTEXPR uint32_t HostToNet32(uint32_t x) { |
wez@chromium.org | 9eb7b11 | 2012-03-28 20:19:31 | [diff] [blame] | 137 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 138 | return ByteSwap(x); |
| 139 | #else |
| 140 | return x; |
| 141 | #endif |
| 142 | } |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 143 | inline BASE_BYTESWAPS_CONSTEXPR uint64_t HostToNet64(uint64_t x) { |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 144 | #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 145 | return ByteSwap(x); |
| 146 | #else |
| 147 | return x; |
| 148 | #endif |
| 149 | } |
| 150 | |
| 151 | } // namespace base |
| 152 | |
Peter Kasting | 64c67dd | 2022-05-12 18:11:51 | [diff] [blame] | 153 | #undef BASE_BYTESWAPS_CONSTEXPR |
| 154 | |
isherman@chromium.org | 0e6f619 | 2011-12-28 23:18:21 | [diff] [blame] | 155 | #endif // BASE_SYS_BYTEORDER_H_ |