MathAlgorithms.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* mfbt maths algorithms. */
  6. #ifndef mozilla_MathAlgorithms_h
  7. #define mozilla_MathAlgorithms_h
  8. #include "mozilla/Assertions.h"
  9. #include "mozilla/TypeTraits.h"
  10. #include <cmath>
  11. #include <limits.h>
  12. #include <stdint.h>
  13. namespace mozilla {
  14. // Greatest Common Divisor
  15. template<typename IntegerType>
  16. MOZ_ALWAYS_INLINE IntegerType
  17. EuclidGCD(IntegerType aA, IntegerType aB)
  18. {
  19. // Euclid's algorithm; O(N) in the worst case. (There are better
  20. // ways, but we don't need them for the current use of this algo.)
  21. MOZ_ASSERT(aA > IntegerType(0));
  22. MOZ_ASSERT(aB > IntegerType(0));
  23. while (aA != aB) {
  24. if (aA > aB) {
  25. aA = aA - aB;
  26. } else {
  27. aB = aB - aA;
  28. }
  29. }
  30. return aA;
  31. }
  32. // Least Common Multiple
  33. template<typename IntegerType>
  34. MOZ_ALWAYS_INLINE IntegerType
  35. EuclidLCM(IntegerType aA, IntegerType aB)
  36. {
  37. // Divide first to reduce overflow risk.
  38. return (aA / EuclidGCD(aA, aB)) * aB;
  39. }
  40. namespace detail {
  41. template<typename T>
  42. struct AllowDeprecatedAbsFixed : FalseType {};
  43. template<> struct AllowDeprecatedAbsFixed<int32_t> : TrueType {};
  44. template<> struct AllowDeprecatedAbsFixed<int64_t> : TrueType {};
  45. template<typename T>
  46. struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed<T> {};
  47. template<> struct AllowDeprecatedAbs<int> : TrueType {};
  48. template<> struct AllowDeprecatedAbs<long> : TrueType {};
  49. } // namespace detail
  50. // DO NOT USE DeprecatedAbs. It exists only until its callers can be converted
  51. // to Abs below, and it will be removed when all callers have been changed.
  52. template<typename T>
  53. inline typename mozilla::EnableIf<detail::AllowDeprecatedAbs<T>::value, T>::Type
  54. DeprecatedAbs(const T aValue)
  55. {
  56. // The absolute value of the smallest possible value of a signed-integer type
  57. // won't fit in that type (on twos-complement systems -- and we're blithely
  58. // assuming we're on such systems, for the non-<stdint.h> types listed above),
  59. // so assert that the input isn't that value.
  60. //
  61. // This is the case if: the value is non-negative; or if adding one (giving a
  62. // value in the range [-maxvalue, 0]), then negating (giving a value in the
  63. // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement,
  64. // (minvalue + 1) == -maxvalue).
  65. MOZ_ASSERT(aValue >= 0 ||
  66. -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1),
  67. "You can't negate the smallest possible negative integer!");
  68. return aValue >= 0 ? aValue : -aValue;
  69. }
  70. namespace detail {
  71. // For now mozilla::Abs only takes intN_T, the signed natural types, and
  72. // float/double/long double. Feel free to add overloads for other standard,
  73. // signed types if you need them.
  74. template<typename T>
  75. struct AbsReturnTypeFixed;
  76. template<> struct AbsReturnTypeFixed<int8_t> { typedef uint8_t Type; };
  77. template<> struct AbsReturnTypeFixed<int16_t> { typedef uint16_t Type; };
  78. template<> struct AbsReturnTypeFixed<int32_t> { typedef uint32_t Type; };
  79. template<> struct AbsReturnTypeFixed<int64_t> { typedef uint64_t Type; };
  80. template<typename T>
  81. struct AbsReturnType : AbsReturnTypeFixed<T> {};
  82. template<> struct AbsReturnType<char> :
  83. EnableIf<char(-1) < char(0), unsigned char> {};
  84. template<> struct AbsReturnType<signed char> { typedef unsigned char Type; };
  85. template<> struct AbsReturnType<short> { typedef unsigned short Type; };
  86. template<> struct AbsReturnType<int> { typedef unsigned int Type; };
  87. template<> struct AbsReturnType<long> { typedef unsigned long Type; };
  88. template<> struct AbsReturnType<long long> { typedef unsigned long long Type; };
  89. template<> struct AbsReturnType<float> { typedef float Type; };
  90. template<> struct AbsReturnType<double> { typedef double Type; };
  91. template<> struct AbsReturnType<long double> { typedef long double Type; };
  92. } // namespace detail
  93. template<typename T>
  94. inline typename detail::AbsReturnType<T>::Type
  95. Abs(const T aValue)
  96. {
  97. typedef typename detail::AbsReturnType<T>::Type ReturnType;
  98. return aValue >= 0 ? ReturnType(aValue) : ~ReturnType(aValue) + 1;
  99. }
  100. template<>
  101. inline float
  102. Abs<float>(const float aFloat)
  103. {
  104. return std::fabs(aFloat);
  105. }
  106. template<>
  107. inline double
  108. Abs<double>(const double aDouble)
  109. {
  110. return std::fabs(aDouble);
  111. }
  112. template<>
  113. inline long double
  114. Abs<long double>(const long double aLongDouble)
  115. {
  116. return std::fabs(aLongDouble);
  117. }
  118. } // namespace mozilla
  119. #if defined(_MSC_VER) && \
  120. (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
  121. # define MOZ_BITSCAN_WINDOWS
  122. # include <intrin.h>
  123. # pragma intrinsic(_BitScanForward, _BitScanReverse)
  124. # if defined(_M_AMD64) || defined(_M_X64)
  125. # define MOZ_BITSCAN_WINDOWS64
  126. # pragma intrinsic(_BitScanForward64, _BitScanReverse64)
  127. # endif
  128. #endif
  129. namespace mozilla {
  130. namespace detail {
  131. #if defined(MOZ_BITSCAN_WINDOWS)
  132. inline uint_fast8_t
  133. CountLeadingZeroes32(uint32_t aValue)
  134. {
  135. unsigned long index;
  136. if (!_BitScanReverse(&index, static_cast<unsigned long>(aValue)))
  137. return 32;
  138. return uint_fast8_t(31 - index);
  139. }
  140. inline uint_fast8_t
  141. CountTrailingZeroes32(uint32_t aValue)
  142. {
  143. unsigned long index;
  144. if (!_BitScanForward(&index, static_cast<unsigned long>(aValue)))
  145. return 32;
  146. return uint_fast8_t(index);
  147. }
  148. inline uint_fast8_t
  149. CountPopulation32(uint32_t aValue)
  150. {
  151. uint32_t x = aValue - ((aValue >> 1) & 0x55555555);
  152. x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  153. return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
  154. }
  155. inline uint_fast8_t
  156. CountPopulation64(uint64_t aValue)
  157. {
  158. return uint_fast8_t(CountPopulation32(aValue & 0xffffffff) +
  159. CountPopulation32(aValue >> 32));
  160. }
  161. inline uint_fast8_t
  162. CountLeadingZeroes64(uint64_t aValue)
  163. {
  164. #if defined(MOZ_BITSCAN_WINDOWS64)
  165. unsigned long index;
  166. if (!_BitScanReverse64(&index, static_cast<unsigned __int64>(aValue)))
  167. return 64;
  168. return uint_fast8_t(63 - index);
  169. #else
  170. uint32_t hi = uint32_t(aValue >> 32);
  171. if (hi != 0) {
  172. return CountLeadingZeroes32(hi);
  173. }
  174. return 32u + CountLeadingZeroes32(uint32_t(aValue));
  175. #endif
  176. }
  177. inline uint_fast8_t
  178. CountTrailingZeroes64(uint64_t aValue)
  179. {
  180. #if defined(MOZ_BITSCAN_WINDOWS64)
  181. unsigned long index;
  182. if (!_BitScanForward64(&index, static_cast<unsigned __int64>(aValue)))
  183. return 64;
  184. return uint_fast8_t(index);
  185. #else
  186. uint32_t lo = uint32_t(aValue);
  187. if (lo != 0) {
  188. return CountTrailingZeroes32(lo);
  189. }
  190. return 32u + CountTrailingZeroes32(uint32_t(aValue >> 32));
  191. #endif
  192. }
  193. # ifdef MOZ_HAVE_BITSCAN64
  194. # undef MOZ_HAVE_BITSCAN64
  195. # endif
  196. #elif defined(__clang__) || defined(__GNUC__)
  197. # if defined(__clang__)
  198. # if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz)
  199. # error "A clang providing __builtin_c[lt]z is required to build"
  200. # endif
  201. # else
  202. // gcc has had __builtin_clz and friends since 3.4: no need to check.
  203. # endif
  204. inline uint_fast8_t
  205. CountLeadingZeroes32(uint32_t aValue)
  206. {
  207. return __builtin_clz(aValue);
  208. }
  209. inline uint_fast8_t
  210. CountTrailingZeroes32(uint32_t aValue)
  211. {
  212. return __builtin_ctz(aValue);
  213. }
  214. inline uint_fast8_t
  215. CountPopulation32(uint32_t aValue)
  216. {
  217. return __builtin_popcount(aValue);
  218. }
  219. inline uint_fast8_t
  220. CountPopulation64(uint64_t aValue)
  221. {
  222. return __builtin_popcountll(aValue);
  223. }
  224. inline uint_fast8_t
  225. CountLeadingZeroes64(uint64_t aValue)
  226. {
  227. return __builtin_clzll(aValue);
  228. }
  229. inline uint_fast8_t
  230. CountTrailingZeroes64(uint64_t aValue)
  231. {
  232. return __builtin_ctzll(aValue);
  233. }
  234. #else
  235. # error "Implement these!"
  236. inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) = delete;
  237. inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) = delete;
  238. inline uint_fast8_t CountPopulation32(uint32_t aValue) = delete;
  239. inline uint_fast8_t CountPopulation64(uint64_t aValue) = delete;
  240. inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) = delete;
  241. inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) = delete;
  242. #endif
  243. } // namespace detail
  244. /**
  245. * Compute the number of high-order zero bits in the NON-ZERO number |aValue|.
  246. * That is, looking at the bitwise representation of the number, with the
  247. * highest- valued bits at the start, return the number of zeroes before the
  248. * first one is observed.
  249. *
  250. * CountLeadingZeroes32(0xF0FF1000) is 0;
  251. * CountLeadingZeroes32(0x7F8F0001) is 1;
  252. * CountLeadingZeroes32(0x3FFF0100) is 2;
  253. * CountLeadingZeroes32(0x1FF50010) is 3; and so on.
  254. */
  255. inline uint_fast8_t
  256. CountLeadingZeroes32(uint32_t aValue)
  257. {
  258. MOZ_ASSERT(aValue != 0);
  259. return detail::CountLeadingZeroes32(aValue);
  260. }
  261. /**
  262. * Compute the number of low-order zero bits in the NON-ZERO number |aValue|.
  263. * That is, looking at the bitwise representation of the number, with the
  264. * lowest- valued bits at the start, return the number of zeroes before the
  265. * first one is observed.
  266. *
  267. * CountTrailingZeroes32(0x0100FFFF) is 0;
  268. * CountTrailingZeroes32(0x7000FFFE) is 1;
  269. * CountTrailingZeroes32(0x0080FFFC) is 2;
  270. * CountTrailingZeroes32(0x0080FFF8) is 3; and so on.
  271. */
  272. inline uint_fast8_t
  273. CountTrailingZeroes32(uint32_t aValue)
  274. {
  275. MOZ_ASSERT(aValue != 0);
  276. return detail::CountTrailingZeroes32(aValue);
  277. }
  278. /**
  279. * Compute the number of one bits in the number |aValue|,
  280. */
  281. inline uint_fast8_t
  282. CountPopulation32(uint32_t aValue)
  283. {
  284. return detail::CountPopulation32(aValue);
  285. }
  286. /** Analogous to CountPopulation32, but for 64-bit numbers */
  287. inline uint_fast8_t
  288. CountPopulation64(uint64_t aValue)
  289. {
  290. return detail::CountPopulation64(aValue);
  291. }
  292. /** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
  293. inline uint_fast8_t
  294. CountLeadingZeroes64(uint64_t aValue)
  295. {
  296. MOZ_ASSERT(aValue != 0);
  297. return detail::CountLeadingZeroes64(aValue);
  298. }
  299. /** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */
  300. inline uint_fast8_t
  301. CountTrailingZeroes64(uint64_t aValue)
  302. {
  303. MOZ_ASSERT(aValue != 0);
  304. return detail::CountTrailingZeroes64(aValue);
  305. }
  306. namespace detail {
  307. template<typename T, size_t Size = sizeof(T)>
  308. class CeilingLog2;
  309. template<typename T>
  310. class CeilingLog2<T, 4>
  311. {
  312. public:
  313. static uint_fast8_t compute(const T aValue)
  314. {
  315. // Check for <= 1 to avoid the == 0 undefined case.
  316. return aValue <= 1 ? 0u : 32u - CountLeadingZeroes32(aValue - 1);
  317. }
  318. };
  319. template<typename T>
  320. class CeilingLog2<T, 8>
  321. {
  322. public:
  323. static uint_fast8_t compute(const T aValue)
  324. {
  325. // Check for <= 1 to avoid the == 0 undefined case.
  326. return aValue <= 1 ? 0u : 64u - CountLeadingZeroes64(aValue - 1);
  327. }
  328. };
  329. } // namespace detail
  330. /**
  331. * Compute the log of the least power of 2 greater than or equal to |aValue|.
  332. *
  333. * CeilingLog2(0..1) is 0;
  334. * CeilingLog2(2) is 1;
  335. * CeilingLog2(3..4) is 2;
  336. * CeilingLog2(5..8) is 3;
  337. * CeilingLog2(9..16) is 4; and so on.
  338. */
  339. template<typename T>
  340. inline uint_fast8_t
  341. CeilingLog2(const T aValue)
  342. {
  343. return detail::CeilingLog2<T>::compute(aValue);
  344. }
  345. /** A CeilingLog2 variant that accepts only size_t. */
  346. inline uint_fast8_t
  347. CeilingLog2Size(size_t aValue)
  348. {
  349. return CeilingLog2(aValue);
  350. }
  351. namespace detail {
  352. template<typename T, size_t Size = sizeof(T)>
  353. class FloorLog2;
  354. template<typename T>
  355. class FloorLog2<T, 4>
  356. {
  357. public:
  358. static uint_fast8_t compute(const T aValue)
  359. {
  360. return 31u - CountLeadingZeroes32(aValue | 1);
  361. }
  362. };
  363. template<typename T>
  364. class FloorLog2<T, 8>
  365. {
  366. public:
  367. static uint_fast8_t compute(const T aValue)
  368. {
  369. return 63u - CountLeadingZeroes64(aValue | 1);
  370. }
  371. };
  372. } // namespace detail
  373. /**
  374. * Compute the log of the greatest power of 2 less than or equal to |aValue|.
  375. *
  376. * FloorLog2(0..1) is 0;
  377. * FloorLog2(2..3) is 1;
  378. * FloorLog2(4..7) is 2;
  379. * FloorLog2(8..15) is 3; and so on.
  380. */
  381. template<typename T>
  382. inline uint_fast8_t
  383. FloorLog2(const T aValue)
  384. {
  385. return detail::FloorLog2<T>::compute(aValue);
  386. }
  387. /** A FloorLog2 variant that accepts only size_t. */
  388. inline uint_fast8_t
  389. FloorLog2Size(size_t aValue)
  390. {
  391. return FloorLog2(aValue);
  392. }
  393. /*
  394. * Compute the smallest power of 2 greater than or equal to |x|. |x| must not
  395. * be so great that the computed value would overflow |size_t|.
  396. */
  397. inline size_t
  398. RoundUpPow2(size_t aValue)
  399. {
  400. MOZ_ASSERT(aValue <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)),
  401. "can't round up -- will overflow!");
  402. return size_t(1) << CeilingLog2(aValue);
  403. }
  404. /**
  405. * Rotates the bits of the given value left by the amount of the shift width.
  406. */
  407. template<typename T>
  408. inline T
  409. RotateLeft(const T aValue, uint_fast8_t aShift)
  410. {
  411. MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
  412. MOZ_ASSERT(aShift > 0,
  413. "Rotation by value length is undefined behavior, but compilers "
  414. "do not currently fold a test into the rotate instruction. "
  415. "Please remove this restriction when compilers optimize the "
  416. "zero case (http://blog.regehr.org/archives/1063).");
  417. static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
  418. return (aValue << aShift) | (aValue >> (sizeof(T) * CHAR_BIT - aShift));
  419. }
  420. /**
  421. * Rotates the bits of the given value right by the amount of the shift width.
  422. */
  423. template<typename T>
  424. inline T
  425. RotateRight(const T aValue, uint_fast8_t aShift)
  426. {
  427. MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
  428. MOZ_ASSERT(aShift > 0,
  429. "Rotation by value length is undefined behavior, but compilers "
  430. "do not currently fold a test into the rotate instruction. "
  431. "Please remove this restriction when compilers optimize the "
  432. "zero case (http://blog.regehr.org/archives/1063).");
  433. static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
  434. return (aValue >> aShift) | (aValue << (sizeof(T) * CHAR_BIT - aShift));
  435. }
  436. /**
  437. * Returns true if |x| is a power of two.
  438. * Zero is not an integer power of two. (-Inf is not an integer)
  439. */
  440. template<typename T>
  441. constexpr bool
  442. IsPowerOfTwo(T x)
  443. {
  444. static_assert(IsUnsigned<T>::value,
  445. "IsPowerOfTwo requires unsigned values");
  446. return x && (x & (x - 1)) == 0;
  447. }
  448. template<typename T>
  449. inline T
  450. Clamp(const T aValue, const T aMin, const T aMax)
  451. {
  452. static_assert(IsIntegral<T>::value,
  453. "Clamp accepts only integral types, so that it doesn't have"
  454. " to distinguish differently-signed zeroes (which users may"
  455. " or may not care to distinguish, likely at a perf cost) or"
  456. " to decide how to clamp NaN or a range with a NaN"
  457. " endpoint.");
  458. MOZ_ASSERT(aMin <= aMax);
  459. if (aValue <= aMin)
  460. return aMin;
  461. if (aValue >= aMax)
  462. return aMax;
  463. return aValue;
  464. }
  465. } /* namespace mozilla */
  466. #endif /* mozilla_MathAlgorithms_h */