MathAlgorithms.h (12321B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* mfbt maths algorithms. */ 8 9 #ifndef mozilla_MathAlgorithms_h 10 #define mozilla_MathAlgorithms_h 11 12 #include "mozilla/Assertions.h" 13 14 #include <algorithm> 15 #include <cmath> 16 #include <climits> 17 #include <cstdint> 18 #include <type_traits> 19 20 namespace mozilla { 21 22 namespace detail { 23 24 template <typename T> 25 struct AllowDeprecatedAbsFixed : std::false_type {}; 26 27 template <> 28 struct AllowDeprecatedAbsFixed<int32_t> : std::true_type {}; 29 template <> 30 struct AllowDeprecatedAbsFixed<int64_t> : std::true_type {}; 31 32 template <typename T> 33 struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed<T> {}; 34 35 template <> 36 struct AllowDeprecatedAbs<int> : std::true_type {}; 37 template <> 38 struct AllowDeprecatedAbs<long> : std::true_type {}; 39 40 } // namespace detail 41 42 // DO NOT USE DeprecatedAbs. It exists only until its callers can be converted 43 // to Abs below, and it will be removed when all callers have been changed. 44 template <typename T> 45 inline std::enable_if_t<detail::AllowDeprecatedAbs<T>::value, T> DeprecatedAbs( 46 const T aValue) { 47 // The absolute value of the smallest possible value of a signed-integer type 48 // won't fit in that type (on twos-complement systems -- and we're blithely 49 // assuming we're on such systems, for the non-<stdint.h> types listed above), 50 // so assert that the input isn't that value. 51 // 52 // This is the case if: the value is non-negative; or if adding one (giving a 53 // value in the range [-maxvalue, 0]), then negating (giving a value in the 54 // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement, 55 // (minvalue + 1) == -maxvalue). 56 MOZ_ASSERT(aValue >= 0 || 57 -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), 58 "You can't negate the smallest possible negative integer!"); 59 return aValue >= 0 ? aValue : -aValue; 60 } 61 62 namespace detail { 63 64 template <typename T, typename = void> 65 struct AbsReturnType; 66 67 template <typename T> 68 struct AbsReturnType< 69 T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>>> { 70 using Type = std::make_unsigned_t<T>; 71 }; 72 73 template <typename T> 74 struct AbsReturnType<T, std::enable_if_t<std::is_floating_point_v<T>>> { 75 using Type = T; 76 }; 77 78 } // namespace detail 79 80 template <typename T> 81 inline constexpr typename detail::AbsReturnType<T>::Type Abs(const T aValue) { 82 using ReturnType = typename detail::AbsReturnType<T>::Type; 83 return aValue >= 0 ? ReturnType(aValue) : ~ReturnType(aValue) + 1; 84 } 85 86 template <> 87 inline float Abs<float>(const float aFloat) { 88 return std::fabs(aFloat); 89 } 90 91 template <> 92 inline double Abs<double>(const double aDouble) { 93 return std::fabs(aDouble); 94 } 95 96 template <> 97 inline long double Abs<long double>(const long double aLongDouble) { 98 return std::fabs(aLongDouble); 99 } 100 101 } // namespace mozilla 102 103 namespace mozilla { 104 105 namespace detail { 106 107 // FIXME: use std::count[lr]_zero once we move to C++20 108 109 #if defined(__clang__) || defined(__GNUC__) 110 111 # if defined(__clang__) 112 # if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz) 113 # error "A clang providing __builtin_c[lt]z is required to build" 114 # endif 115 # else 116 // gcc has had __builtin_clz and friends since 3.4: no need to check. 117 # endif 118 119 constexpr uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { 120 return static_cast<uint_fast8_t>(__builtin_clz(aValue)); 121 } 122 123 constexpr uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { 124 return static_cast<uint_fast8_t>(__builtin_ctz(aValue)); 125 } 126 127 constexpr uint_fast8_t CountPopulation32(uint32_t aValue) { 128 return static_cast<uint_fast8_t>(__builtin_popcount(aValue)); 129 } 130 131 constexpr uint_fast8_t CountPopulation64(uint64_t aValue) { 132 return static_cast<uint_fast8_t>(__builtin_popcountll(aValue)); 133 } 134 135 constexpr uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { 136 return static_cast<uint_fast8_t>(__builtin_clzll(aValue)); 137 } 138 139 constexpr uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { 140 return static_cast<uint_fast8_t>(__builtin_ctzll(aValue)); 141 } 142 143 #else 144 # error "Implement these!" 145 constexpr uint_fast8_t CountLeadingZeroes32(uint32_t aValue) = delete; 146 constexpr uint_fast8_t CountTrailingZeroes32(uint32_t aValue) = delete; 147 constexpr uint_fast8_t CountPopulation32(uint32_t aValue) = delete; 148 constexpr uint_fast8_t CountPopulation64(uint64_t aValue) = delete; 149 constexpr uint_fast8_t CountLeadingZeroes64(uint64_t aValue) = delete; 150 constexpr uint_fast8_t CountTrailingZeroes64(uint64_t aValue) = delete; 151 #endif 152 153 } // namespace detail 154 155 /** 156 * Compute the number of high-order zero bits in the NON-ZERO number |aValue|. 157 * That is, looking at the bitwise representation of the number, with the 158 * highest- valued bits at the start, return the number of zeroes before the 159 * first one is observed. 160 * 161 * CountLeadingZeroes32(0xF0FF1000) is 0; 162 * CountLeadingZeroes32(0x7F8F0001) is 1; 163 * CountLeadingZeroes32(0x3FFF0100) is 2; 164 * CountLeadingZeroes32(0x1FF50010) is 3; and so on. 165 */ 166 constexpr uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { 167 MOZ_ASSERT(aValue != 0); 168 return detail::CountLeadingZeroes32(aValue); 169 } 170 171 /** 172 * Compute the number of low-order zero bits in the NON-ZERO number |aValue|. 173 * That is, looking at the bitwise representation of the number, with the 174 * lowest- valued bits at the start, return the number of zeroes before the 175 * first one is observed. 176 * 177 * CountTrailingZeroes32(0x0100FFFF) is 0; 178 * CountTrailingZeroes32(0x7000FFFE) is 1; 179 * CountTrailingZeroes32(0x0080FFFC) is 2; 180 * CountTrailingZeroes32(0x0080FFF8) is 3; and so on. 181 */ 182 constexpr uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { 183 MOZ_ASSERT(aValue != 0); 184 return detail::CountTrailingZeroes32(aValue); 185 } 186 187 /** 188 * Compute the number of one bits in the number |aValue|, 189 */ 190 constexpr uint_fast8_t CountPopulation32(uint32_t aValue) { 191 return detail::CountPopulation32(aValue); 192 } 193 194 /** Analogous to CountPopulation32, but for 64-bit numbers */ 195 constexpr uint_fast8_t CountPopulation64(uint64_t aValue) { 196 return detail::CountPopulation64(aValue); 197 } 198 199 /** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */ 200 constexpr uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { 201 MOZ_ASSERT(aValue != 0); 202 return detail::CountLeadingZeroes64(aValue); 203 } 204 205 /** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */ 206 constexpr uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { 207 MOZ_ASSERT(aValue != 0); 208 return detail::CountTrailingZeroes64(aValue); 209 } 210 211 namespace detail { 212 213 template <typename T, size_t Size = sizeof(T)> 214 class CeilingLog2; 215 216 template <typename T> 217 class CeilingLog2<T, 4> { 218 public: 219 static constexpr uint_fast8_t compute(const T aValue) { 220 // Check for <= 1 to avoid the == 0 undefined case. 221 return aValue <= 1 ? 0u : 32u - CountLeadingZeroes32(aValue - 1); 222 } 223 }; 224 225 template <typename T> 226 class CeilingLog2<T, 8> { 227 public: 228 static constexpr uint_fast8_t compute(const T aValue) { 229 // Check for <= 1 to avoid the == 0 undefined case. 230 return aValue <= 1 ? 0u : 64u - CountLeadingZeroes64(aValue - 1); 231 } 232 }; 233 234 } // namespace detail 235 236 /** 237 * Compute the log of the least power of 2 greater than or equal to |aValue|. 238 * 239 * CeilingLog2(0..1) is 0; 240 * CeilingLog2(2) is 1; 241 * CeilingLog2(3..4) is 2; 242 * CeilingLog2(5..8) is 3; 243 * CeilingLog2(9..16) is 4; and so on. 244 */ 245 template <typename T> 246 constexpr uint_fast8_t CeilingLog2(const T aValue) { 247 return detail::CeilingLog2<T>::compute(aValue); 248 } 249 250 /** A CeilingLog2 variant that accepts only size_t. */ 251 constexpr uint_fast8_t CeilingLog2Size(size_t aValue) { 252 return CeilingLog2(aValue); 253 } 254 255 /** 256 * Compute the bit position of the most significant bit set in 257 * |aValue|. Requires that |aValue| is non-zero. 258 */ 259 template <typename T> 260 constexpr uint_fast8_t FindMostSignificantBit(T aValue) { 261 static_assert(sizeof(T) <= 8); 262 static_assert(std::is_integral_v<T>); 263 MOZ_ASSERT(aValue != 0); 264 // This casts to 32-bits 265 if constexpr (sizeof(T) <= 4) { 266 return 31u - CountLeadingZeroes32(aValue); 267 } 268 // This doesn't 269 if constexpr (sizeof(T) == 8) { 270 return 63u - CountLeadingZeroes64(aValue); 271 } 272 } 273 274 /** 275 * Compute the log of the greatest power of 2 less than or equal to |aValue|. 276 * 277 * FloorLog2(0..1) is 0; 278 * FloorLog2(2..3) is 1; 279 * FloorLog2(4..7) is 2; 280 * FloorLog2(8..15) is 3; and so on. 281 */ 282 template <typename T> 283 constexpr uint_fast8_t FloorLog2(const T aValue) { 284 return FindMostSignificantBit(aValue | 1); 285 } 286 287 /** A FloorLog2 variant that accepts only size_t. */ 288 constexpr uint_fast8_t FloorLog2Size(size_t aValue) { 289 return FloorLog2(aValue); 290 } 291 292 /* 293 * Compute the smallest power of 2 greater than or equal to |x|. |x| must not 294 * be so great that the computed value would overflow |size_t|. 295 */ 296 constexpr size_t RoundUpPow2(size_t aValue) { 297 MOZ_ASSERT(aValue <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)), 298 "can't round up -- will overflow!"); 299 return size_t(1) << CeilingLog2(aValue); 300 } 301 302 /** 303 * Rotates the bits of the given value left by the amount of the shift width. 304 */ 305 template <typename T> 306 MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW constexpr T RotateLeft(const T aValue, 307 uint_fast8_t aShift) { 308 static_assert(std::is_unsigned_v<T>, "Rotates require unsigned values"); 309 310 MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); 311 MOZ_ASSERT(aShift > 0, 312 "Rotation by value length is undefined behavior, but compilers " 313 "do not currently fold a test into the rotate instruction. " 314 "Please remove this restriction when compilers optimize the " 315 "zero case (http://blog.regehr.org/archives/1063)."); 316 317 return (aValue << aShift) | (aValue >> (sizeof(T) * CHAR_BIT - aShift)); 318 } 319 320 /** 321 * Rotates the bits of the given value right by the amount of the shift width. 322 */ 323 template <typename T> 324 MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW constexpr T RotateRight(const T aValue, 325 uint_fast8_t aShift) { 326 static_assert(std::is_unsigned_v<T>, "Rotates require unsigned values"); 327 328 MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); 329 MOZ_ASSERT(aShift > 0, 330 "Rotation by value length is undefined behavior, but compilers " 331 "do not currently fold a test into the rotate instruction. " 332 "Please remove this restriction when compilers optimize the " 333 "zero case (http://blog.regehr.org/archives/1063)."); 334 335 return (aValue >> aShift) | (aValue << (sizeof(T) * CHAR_BIT - aShift)); 336 } 337 338 /** 339 * Returns true if |x| is a power of two. 340 * Zero is not an integer power of two. (-Inf is not an integer) 341 */ 342 template <typename T> 343 constexpr bool IsPowerOfTwo(T x) { 344 static_assert(std::is_unsigned_v<T>, "IsPowerOfTwo requires unsigned values"); 345 return x && (x & (x - 1)) == 0; 346 } 347 348 template <typename T> 349 constexpr uint_fast8_t CountTrailingZeroes(T aValue) { 350 static_assert(sizeof(T) <= 8); 351 static_assert(std::is_integral_v<T>); 352 // This casts to 32-bits 353 if constexpr (sizeof(T) <= 4) { 354 return CountTrailingZeroes32(aValue); 355 } 356 // This doesn't 357 if constexpr (sizeof(T) == 8) { 358 return CountTrailingZeroes64(aValue); 359 } 360 } 361 362 // Greatest Common Divisor, from 363 // https://en.wikipedia.org/wiki/Binary_GCD_algorithm#Implementation 364 template <typename T> 365 MOZ_ALWAYS_INLINE T GCD(T aA, T aB) { 366 static_assert(std::is_integral_v<T>); 367 368 MOZ_ASSERT(aA >= 0); 369 MOZ_ASSERT(aB >= 0); 370 371 if (aA == 0) { 372 return aB; 373 } 374 if (aB == 0) { 375 return aA; 376 } 377 378 T az = CountTrailingZeroes(aA); 379 T bz = CountTrailingZeroes(aB); 380 T shift = std::min<T>(az, bz); 381 aA >>= az; 382 aB >>= bz; 383 384 while (aA != 0) { 385 if constexpr (!std::is_signed_v<T>) { 386 if (aA < aB) { 387 std::swap(aA, aB); 388 } 389 } 390 T diff = aA - aB; 391 if constexpr (std::is_signed_v<T>) { 392 aB = std::min<T>(aA, aB); 393 } 394 if constexpr (std::is_signed_v<T>) { 395 aA = std::abs(diff); 396 } else { 397 aA = diff; 398 } 399 if (aA) { 400 aA >>= CountTrailingZeroes(aA); 401 } 402 } 403 404 return aB << shift; 405 } 406 407 } /* namespace mozilla */ 408 409 #endif /* mozilla_MathAlgorithms_h */