1/** 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#ifndef LIBPANDABASE_UTILS_BIT_UTILS_H 17#define LIBPANDABASE_UTILS_BIT_UTILS_H 18 19#include <cmath> 20#include <cstdint> 21#include <cstring> 22#include <limits> 23#include <type_traits> 24#include <bitset> 25 26#include <securec.h> 27 28#include "globals.h" 29#include "macros.h" 30 31#define panda_bit_utils_ctz __builtin_ctz // NOLINT(cppcoreguidelines-macro-usage) 32#define panda_bit_utils_ctzll __builtin_ctzll // NOLINT(cppcoreguidelines-macro-usage) 33 34#define panda_bit_utils_clz __builtin_clz // NOLINT(cppcoreguidelines-macro-usage) 35#define panda_bit_utils_clzll __builtin_clzll // NOLINT(cppcoreguidelines-macro-usage) 36 37#define panda_bit_utils_ffs __builtin_ffs // NOLINT(cppcoreguidelines-macro-usage) 38#define panda_bit_utils_ffsll __builtin_ffsll // NOLINT(cppcoreguidelines-macro-usage) 39 40#define panda_bit_utils_popcount __builtin_popcount // NOLINT(cppcoreguidelines-macro-usage) 41#define panda_bit_utils_popcountll __builtin_popcountll // NOLINT(cppcoreguidelines-macro-usage) 42 43namespace panda { 44 45template <typename T> 46constexpr int Clz(T x) 47{ 48 constexpr size_t RADIX = 2; 49 static_assert(std::is_integral<T>::value, "T must be integral"); 50 static_assert(std::is_unsigned<T>::value, "T must be unsigned"); 51 static_assert(std::numeric_limits<T>::radix == RADIX, "Unexpected radix!"); 52 static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t), "Unsupported sizeof(T)"); 53 ASSERT(x != 0U); 54 55 if (sizeof(T) == sizeof(uint64_t)) { 56 return panda_bit_utils_clzll(x); 57 } 58 return panda_bit_utils_clz(x) - (std::numeric_limits<uint32_t>::digits - std::numeric_limits<T>::digits); 59} 60 61template <typename T> 62constexpr int Ctz(T x) 63{ 64 constexpr size_t RADIX = 2; 65 static_assert(std::is_integral<T>::value, "T must be integral"); 66 static_assert(std::is_unsigned<T>::value, "T must be unsigned"); 67 static_assert(std::numeric_limits<T>::radix == RADIX, "Unexpected radix!"); 68 static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t), "Unsupported sizeof(T)"); 69 ASSERT(x != 0U); 70 71 if (sizeof(T) == sizeof(uint64_t)) { 72 return panda_bit_utils_ctzll(x); 73 } 74 return panda_bit_utils_ctz(x); 75} 76 77template <typename T> 78constexpr int Popcount(T x) 79{ 80 constexpr size_t RADIX = 2; 81 static_assert(std::is_integral<T>::value, "T must be integral"); 82 static_assert(std::is_unsigned<T>::value, "T must be unsigned"); 83 static_assert(std::numeric_limits<T>::radix == RADIX, "Unexpected radix!"); 84 static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t), "Unsupported sizeof(T)"); 85 86 if (sizeof(T) == sizeof(uint64_t)) { 87 return panda_bit_utils_popcountll(x); 88 } 89 return panda_bit_utils_popcount(x); 90} 91 92// How many bits (minimally) does it take to store the constant 'value'? i.e. 1 for 1, 2 for 2 and 3, 3 for 4 and 5 etc. 93template <typename T> 94constexpr size_t MinimumBitsToStore(T value) 95{ 96 static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t), "Unsupported sizeof(T)"); 97 if constexpr (std::is_enum_v<T>) { // NOLINT 98 using UnderlyingType = std::make_unsigned_t<std::underlying_type_t<T>>; 99 auto uvalue = static_cast<UnderlyingType>(value); 100 if (uvalue == 0) { 101 uvalue = 1; 102 } 103 return std::numeric_limits<UnderlyingType>::digits - Clz(static_cast<UnderlyingType>(uvalue)); 104 } else { // NOLINT 105 constexpr size_t RADIX = 2; 106 static_assert(std::is_integral_v<T>, "T must be integral"); 107 static_assert(std::is_unsigned_v<T>, "T must be unsigned"); 108 static_assert(std::numeric_limits<T>::radix == RADIX, "Unexpected radix!"); 109 if (value == 0) { 110 return 0; 111 } 112 return std::numeric_limits<T>::digits - Clz(value); 113 } 114} 115 116template <typename T> 117constexpr int Ffs(T x) 118{ 119 constexpr size_t RADIX = 2; 120 static_assert(std::is_integral<T>::value, "T must be integral"); 121 static_assert(std::is_unsigned<T>::value, "T must be unsigned"); 122 static_assert(std::numeric_limits<T>::radix == RADIX, "Unexpected radix!"); 123 static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t), "Unsupported sizeof(T)"); 124 125 if (sizeof(T) == sizeof(uint64_t)) { 126 return panda_bit_utils_ffsll(x); 127 } 128 return panda_bit_utils_ffs(x); 129} 130 131template <size_t n, typename T> 132constexpr bool IsAligned(T value) 133{ 134 static_assert(std::is_integral<T>::value, "T must be integral"); 135 return value % n == 0; 136} 137 138template <typename T> 139constexpr bool IsAligned(T value, size_t n) 140{ 141 static_assert(std::is_integral<T>::value, "T must be integral"); 142 return value % n == 0; 143} 144 145template <typename T> 146constexpr T RoundUp(T x, size_t n) 147{ 148 static_assert(std::is_integral<T>::value, "T must be integral"); 149 return (static_cast<size_t>(x) + n - 1U) & (-n); 150} 151 152constexpr size_t BitsToBytesRoundUp(size_t num_bits) 153{ 154 return RoundUp(num_bits, BITS_PER_BYTE) / BITS_PER_BYTE; 155} 156 157template <typename T> 158constexpr T RoundDown(T x, size_t n) 159{ 160 static_assert(std::is_integral<T>::value, "T must be integral"); 161 return x & static_cast<size_t>(-n); 162} 163 164template <typename T> 165constexpr T SwapBits(T value, T mask, uint32_t offset) 166{ 167 return ((value >> offset) & mask) | ((value & mask) << offset); 168} 169 170template <typename T> 171inline uint8_t GetByteFrom(T value, uint64_t index) 172{ 173 static_assert(std::is_unsigned<T>::value, "T must be unsigned"); 174 constexpr uint8_t OFFSET_BYTE = 3; 175 constexpr uint8_t MASK = 0xffU; 176 uint64_t shift = index << OFFSET_BYTE; 177 return static_cast<uint8_t>((value >> shift) & MASK); 178} 179 180inline uint16_t ReverseBytes(uint16_t value) 181{ 182 constexpr uint32_t OFFSET_0 = 8; 183 return static_cast<uint16_t>(value << OFFSET_0) | static_cast<uint16_t>(value >> OFFSET_0); 184} 185 186inline uint32_t ReverseBytes(uint32_t value) 187{ 188 constexpr uint32_t BYTES_MASK = 0xff00ffU; 189 constexpr uint32_t OFFSET_0 = 8; 190 constexpr uint32_t OFFSET_1 = 16; 191 value = SwapBits(value, BYTES_MASK, OFFSET_0); 192 return (value >> OFFSET_1) | (value << OFFSET_1); 193} 194 195inline uint64_t ReverseBytes(uint64_t value) 196{ 197 constexpr uint64_t BYTES_MASK = 0xff00ff00ff00ffLU; 198 constexpr uint64_t WORDS_MASK = 0xffff0000ffffLU; 199 constexpr uint32_t OFFSET_0 = 8; 200 constexpr uint32_t OFFSET_1 = 16; 201 constexpr uint32_t OFFSET_2 = 32; 202 value = SwapBits(value, BYTES_MASK, OFFSET_0); 203 value = SwapBits(value, WORDS_MASK, OFFSET_1); 204 return (value >> OFFSET_2) | (value << OFFSET_2); 205} 206 207template <typename T> 208constexpr T BSWAP(T x) 209{ 210 if (sizeof(T) == sizeof(uint16_t)) { 211 return ReverseBytes(static_cast<uint16_t>(x)); 212 } 213 if (sizeof(T) == sizeof(uint32_t)) { 214 return ReverseBytes(static_cast<uint32_t>(x)); 215 } 216 return ReverseBytes(static_cast<uint64_t>(x)); 217} 218 219inline uint32_t ReverseBits(uint32_t value) 220{ 221 constexpr uint32_t BITS_MASK = 0x55555555U; 222 constexpr uint32_t TWO_BITS_MASK = 0x33333333U; 223 constexpr uint32_t HALF_BYTES_MASK = 0x0f0f0f0fU; 224 constexpr uint32_t OFFSET_0 = 1; 225 constexpr uint32_t OFFSET_1 = 2; 226 constexpr uint32_t OFFSET_2 = 4; 227 value = SwapBits(value, BITS_MASK, OFFSET_0); 228 value = SwapBits(value, TWO_BITS_MASK, OFFSET_1); 229 value = SwapBits(value, HALF_BYTES_MASK, OFFSET_2); 230 return ReverseBytes(value); 231} 232 233inline uint64_t ReverseBits(uint64_t value) 234{ 235 constexpr uint64_t BITS_MASK = 0x5555555555555555LU; 236 constexpr uint64_t TWO_BITS_MASK = 0x3333333333333333LU; 237 constexpr uint64_t HALF_BYTES_MASK = 0x0f0f0f0f0f0f0f0fLU; 238 constexpr uint32_t OFFSET_0 = 1; 239 constexpr uint32_t OFFSET_1 = 2; 240 constexpr uint32_t OFFSET_2 = 4; 241 value = SwapBits(value, BITS_MASK, OFFSET_0); 242 value = SwapBits(value, TWO_BITS_MASK, OFFSET_1); 243 value = SwapBits(value, HALF_BYTES_MASK, OFFSET_2); 244 return ReverseBytes(value); 245} 246 247inline uint32_t BitCount(int32_t value) 248{ 249 constexpr size_t BIT_SIZE = sizeof(int32_t) * 8; 250 return std::bitset<BIT_SIZE>(value).count(); 251} 252 253inline uint32_t BitCount(uint32_t value) 254{ 255 constexpr size_t BIT_SIZE = sizeof(uint32_t) * 8; 256 return std::bitset<BIT_SIZE>(value).count(); 257} 258 259inline uint32_t BitCount(int64_t value) 260{ 261 constexpr size_t BIT_SIZE = sizeof(int64_t) * 8; 262 return std::bitset<BIT_SIZE>(value).count(); 263} 264 265template <typename T> 266inline constexpr uint32_t BitNumbers() 267{ 268 constexpr int BIT_NUMBER_OF_CHAR = 8; 269 return sizeof(T) * BIT_NUMBER_OF_CHAR; 270} 271 272template <typename T> 273inline constexpr T ExtractBits(T value, size_t offset, size_t count) 274{ 275 static_assert(std::is_integral<T>::value, "T must be integral"); 276 static_assert(std::is_unsigned<T>::value, "T must be unsigned"); 277 ASSERT(sizeof(value) * panda::BITS_PER_BYTE >= offset + count); 278 return (value >> offset) & ((1ULL << count) - 1); 279} 280 281template <typename T> 282inline constexpr uint32_t Low32Bits(T value) 283{ 284 return static_cast<uint32_t>(reinterpret_cast<uint64_t>(value)); 285} 286 287template <typename T> 288inline constexpr uint32_t High32Bits(T value) 289{ 290 if constexpr (sizeof(T) < sizeof(uint64_t)) { // NOLINT 291 return 0; 292 } 293 return static_cast<uint32_t>(reinterpret_cast<uint64_t>(value) >> BITS_PER_UINT32); 294} 295 296template <class To, class From> 297inline To bit_cast(const From &src) noexcept // NOLINT(readability-identifier-naming) 298{ 299 static_assert(sizeof(To) == sizeof(From), "size of the types must be equal"); 300 static_assert(std::is_trivially_copyable_v<To> && std::is_trivially_copyable_v<From>, 301 "source and destination types must be trivially copyable"); 302 static_assert(std::is_trivially_constructible_v<To>, "destination type must be default constructible"); 303 304 To dst; 305 errno_t res = memcpy_s(&dst, sizeof(To), &src, sizeof(To)); 306 if (res != EOK) { 307 UNREACHABLE(); 308 } 309 return dst; 310} 311 312template <class To, class From> 313inline To down_cast(const From &src) noexcept // NOLINT(readability-identifier-naming) 314{ 315 static_assert(sizeof(To) <= sizeof(From), "size of the types must be lesser"); 316 To dst; 317 errno_t res = memcpy_s(&dst, sizeof(To), &src, sizeof(To)); 318 if (res != EOK) { 319 UNREACHABLE(); 320 } 321 return dst; 322} 323 324template <typename T> 325inline constexpr uint32_t BitsNumInValue(const T v) 326{ 327 return sizeof(v) * panda::BITS_PER_BYTE; 328} 329 330template <typename T> 331inline constexpr uint32_t BitsNumInType() 332{ 333 return sizeof(T) * panda::BITS_PER_BYTE; 334} 335 336template <typename From, typename To> 337inline constexpr To CastFloatToInt(From value) 338{ 339 static_assert(std::is_floating_point_v<From>); 340 static_assert(std::is_integral_v<To>); 341 To res; 342 constexpr To MIN_INT = std::numeric_limits<To>::min(); 343 constexpr To MAX_INT = std::numeric_limits<To>::max(); 344 constexpr auto FLOAT_MIN_INT = static_cast<From>(MIN_INT); 345 constexpr auto FLOAT_MAX_INT = static_cast<From>(MAX_INT); 346 347 if (value > FLOAT_MIN_INT) { 348 if (value < FLOAT_MAX_INT) { 349 res = static_cast<To>(value); 350 } else { 351 res = MAX_INT; 352 } 353 } else if (std::isnan(value)) { 354 res = 0; 355 } else { 356 res = MIN_INT; 357 } 358 return res; 359} 360 361} // namespace panda 362 363#endif // LIBPANDABASE_UTILS_BIT_UTILS_H 364