Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: f0937d2768d2390922a064bd6bdb75b02ab5b42b [file] [log] [blame]
danakj590d15232024-02-08 17:17:441// Copyright 2024 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tom Sepez8726d30e2025-01-29 02:11:085#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
7#pragma allow_unsafe_libc_calls
8#endif
9
danakj590d15232024-02-08 17:17:4410#ifndef BASE_NUMERICS_BASIC_OPS_IMPL_H_
11#define BASE_NUMERICS_BASIC_OPS_IMPL_H_
12
Jean-Philippe Gravelf81c63b2024-04-23 20:33:1713#include <array>
danakj590d15232024-02-08 17:17:4414#include <cstdint>
Hans Wennborge21518d2024-02-16 18:20:1215#include <cstdlib>
danakj590d15232024-02-08 17:17:4416#include <cstring>
17#include <span>
18#include <type_traits>
19
Daniel Chengb8069cb12025-11-12 18:19:2220namespace base::numerics_internal {
danakj590d15232024-02-08 17:17:4421
22// The correct type to perform math operations on given values of type `T`. This
23// may be a larger type than `T` to avoid promotion to `int` which involves sign
24// conversion!
25template <class T>
26 requires(std::is_integral_v<T>)
27using MathType = std::conditional_t<
28 sizeof(T) >= sizeof(int),
29 T,
30 std::conditional_t<std::is_signed_v<T>, int, unsigned int>>;
31
32// Reverses the byte order of the integer.
33template <class T>
34 requires(std::is_unsigned_v<T> && std::is_integral_v<T>)
35inline constexpr T SwapBytes(T value) {
36 // MSVC intrinsics are not constexpr, so we provide our own constexpr
37 // implementation. We provide it unconditionally so we can test it on all
38 // platforms for correctness.
39 if (std::is_constant_evaluated()) {
40 if constexpr (sizeof(T) == 1u) {
41 return value;
42 } else if constexpr (sizeof(T) == 2u) {
43 MathType<T> a = (MathType<T>(value) >> 0) & MathType<T>{0xff};
44 MathType<T> b = (MathType<T>(value) >> 8) & MathType<T>{0xff};
45 return static_cast<T>((a << 8) | (b << 0));
46 } else if constexpr (sizeof(T) == 4u) {
47 T a = (value >> 0) & T{0xff};
48 T b = (value >> 8) & T{0xff};
49 T c = (value >> 16) & T{0xff};
50 T d = (value >> 24) & T{0xff};
51 return (a << 24) | (b << 16) | (c << 8) | (d << 0);
52 } else {
53 static_assert(sizeof(T) == 8u);
54 T a = (value >> 0) & T{0xff};
55 T b = (value >> 8) & T{0xff};
56 T c = (value >> 16) & T{0xff};
57 T d = (value >> 24) & T{0xff};
58 T e = (value >> 32) & T{0xff};
59 T f = (value >> 40) & T{0xff};
60 T g = (value >> 48) & T{0xff};
61 T h = (value >> 56) & T{0xff};
62 return (a << 56) | (b << 48) | (c << 40) | (d << 32) | //
63 (e << 24) | (f << 16) | (g << 8) | (h << 0);
64 }
65 }
66
67#if _MSC_VER
68 if constexpr (sizeof(T) == 1u) {
69 return value;
70 } else if constexpr (sizeof(T) == sizeof(unsigned short)) {
71 using U = unsigned short;
72 return _byteswap_ushort(U{value});
73 } else if constexpr (sizeof(T) == sizeof(unsigned long)) {
74 using U = unsigned long;
75 return _byteswap_ulong(U{value});
76 } else {
77 static_assert(sizeof(T) == 8u);
78 return _byteswap_uint64(value);
79 }
80#else
81 if constexpr (sizeof(T) == 1u) {
82 return value;
83 } else if constexpr (sizeof(T) == 2u) {
84 return __builtin_bswap16(uint16_t{value});
85 } else if constexpr (sizeof(T) == 4u) {
86 return __builtin_bswap32(value);
87 } else {
88 static_assert(sizeof(T) == 8u);
89 return __builtin_bswap64(value);
90 }
91#endif
92}
93
danakjc0d032ef2024-03-21 18:36:3494// Signed values are byte-swapped as unsigned values.
95template <class T>
96 requires(std::is_signed_v<T> && std::is_integral_v<T>)
97inline constexpr T SwapBytes(T value) {
98 return static_cast<T>(SwapBytes(static_cast<std::make_unsigned_t<T>>(value)));
99}
100
danakj590d15232024-02-08 17:17:44101// Converts from a byte array to an integer.
102template <class T>
103 requires(std::is_unsigned_v<T> && std::is_integral_v<T>)
104inline constexpr T FromLittleEndian(std::span<const uint8_t, sizeof(T)> bytes) {
105 T val;
106 if (std::is_constant_evaluated()) {
107 val = T{0};
108 for (size_t i = 0u; i < sizeof(T); i += 1u) {
109 // SAFETY: `i < sizeof(T)` (the number of bytes in T), so `(8 * i)` is
110 // less than the number of bits in T.
111 val |= MathType<T>(bytes[i]) << (8u * i);
112 }
113 } else {
114 // SAFETY: `bytes` has sizeof(T) bytes, and `val` is of type `T` so has
115 // sizeof(T) bytes, and the two can not alias as `val` is a stack variable.
116 memcpy(&val, bytes.data(), sizeof(T));
117 }
118 return val;
119}
120
Phillis Tangea3b92a2024-03-28 22:21:33121template <class T>
122 requires(std::is_signed_v<T> && std::is_integral_v<T>)
123inline constexpr T FromLittleEndian(std::span<const uint8_t, sizeof(T)> bytes) {
124 return static_cast<T>(FromLittleEndian<std::make_unsigned_t<T>>(bytes));
125}
126
danakj04a8eb22024-02-16 18:24:56127// Converts to a byte array from an integer.
128template <class T>
129 requires(std::is_unsigned_v<T> && std::is_integral_v<T>)
130inline constexpr std::array<uint8_t, sizeof(T)> ToLittleEndian(T val) {
131 auto bytes = std::array<uint8_t, sizeof(T)>();
132 if (std::is_constant_evaluated()) {
133 for (size_t i = 0u; i < sizeof(T); i += 1u) {
134 const auto last_byte = static_cast<uint8_t>(val & 0xff);
135 // The low bytes go to the front of the array in little endian.
136 bytes[i] = last_byte;
137 // If `val` is one byte, this shift would be UB. But it's also not needed
138 // since the loop will not run again.
139 if constexpr (sizeof(T) > 1u) {
140 val >>= 8u;
141 }
142 }
143 } else {
144 // SAFETY: `bytes` has sizeof(T) bytes, and `val` is of type `T` so has
145 // sizeof(T) bytes, and the two can not alias as `val` is a stack variable.
146 memcpy(bytes.data(), &val, sizeof(T));
147 }
148 return bytes;
149}
150
Phillis Tangea3b92a2024-03-28 22:21:33151template <class T>
152 requires(std::is_signed_v<T> && std::is_integral_v<T>)
153inline constexpr std::array<uint8_t, sizeof(T)> ToLittleEndian(T val) {
154 return ToLittleEndian(static_cast<std::make_unsigned_t<T>>(val));
155}
Daniel Chengb8069cb12025-11-12 18:19:22156} // namespace base::numerics_internal
danakj590d15232024-02-08 17:17:44157
Daniel Chengb8069cb12025-11-12 18:19:22158#endif // BASE_NUMERICS_BASIC_OPS_IMPL_H_