Bug 1036561 - Reduce log spam from SharedBufferManagerChild. r=nical, a=bajaj
[gecko.git] / mfbt / MathAlgorithms.h
blob7a77b00042dd04ca035b92f8b0bb14c8e5e6098b
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/. */
7 /* mfbt maths algorithms. */
9 #ifndef mozilla_MathAlgorithms_h
10 #define mozilla_MathAlgorithms_h
12 #include "mozilla/Assertions.h"
13 #include "mozilla/TypeTraits.h"
15 #include <cmath>
16 #include <limits.h>
17 #include <stdint.h>
19 namespace mozilla {
21 // Greatest Common Divisor
22 template<typename IntegerType>
23 MOZ_ALWAYS_INLINE IntegerType
24 EuclidGCD(IntegerType a, IntegerType b)
26 // Euclid's algorithm; O(N) in the worst case. (There are better
27 // ways, but we don't need them for the current use of this algo.)
28 MOZ_ASSERT(a > IntegerType(0));
29 MOZ_ASSERT(b > IntegerType(0));
31 while (a != b) {
32 if (a > b) {
33 a = a - b;
34 } else {
35 b = b - a;
39 return a;
42 // Least Common Multiple
43 template<typename IntegerType>
44 MOZ_ALWAYS_INLINE IntegerType
45 EuclidLCM(IntegerType a, IntegerType b)
47 // Divide first to reduce overflow risk.
48 return (a / EuclidGCD(a, b)) * b;
51 namespace detail {
53 template<typename T>
54 struct AllowDeprecatedAbsFixed : FalseType {};
56 template<> struct AllowDeprecatedAbsFixed<int32_t> : TrueType {};
57 template<> struct AllowDeprecatedAbsFixed<int64_t> : TrueType {};
59 template<typename T>
60 struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed<T> {};
62 template<> struct AllowDeprecatedAbs<int> : TrueType {};
63 template<> struct AllowDeprecatedAbs<long> : TrueType {};
65 } // namespace detail
67 // DO NOT USE DeprecatedAbs. It exists only until its callers can be converted
68 // to Abs below, and it will be removed when all callers have been changed.
69 template<typename T>
70 inline typename mozilla::EnableIf<detail::AllowDeprecatedAbs<T>::value, T>::Type
71 DeprecatedAbs(const T t)
73 // The absolute value of the smallest possible value of a signed-integer type
74 // won't fit in that type (on twos-complement systems -- and we're blithely
75 // assuming we're on such systems, for the non-<stdint.h> types listed above),
76 // so assert that the input isn't that value.
78 // This is the case if: the value is non-negative; or if adding one (giving a
79 // value in the range [-maxvalue, 0]), then negating (giving a value in the
80 // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement,
81 // (minvalue + 1) == -maxvalue).
82 MOZ_ASSERT(t >= 0 ||
83 -(t + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1),
84 "You can't negate the smallest possible negative integer!");
85 return t >= 0 ? t : -t;
88 namespace detail {
90 // For now mozilla::Abs only takes intN_T, the signed natural types, and
91 // float/double/long double. Feel free to add overloads for other standard,
92 // signed types if you need them.
94 template<typename T>
95 struct AbsReturnTypeFixed;
97 template<> struct AbsReturnTypeFixed<int8_t> { typedef uint8_t Type; };
98 template<> struct AbsReturnTypeFixed<int16_t> { typedef uint16_t Type; };
99 template<> struct AbsReturnTypeFixed<int32_t> { typedef uint32_t Type; };
100 template<> struct AbsReturnTypeFixed<int64_t> { typedef uint64_t Type; };
102 template<typename T>
103 struct AbsReturnType : AbsReturnTypeFixed<T> {};
105 template<> struct AbsReturnType<char> : EnableIf<char(-1) < char(0), unsigned char> {};
106 template<> struct AbsReturnType<signed char> { typedef unsigned char Type; };
107 template<> struct AbsReturnType<short> { typedef unsigned short Type; };
108 template<> struct AbsReturnType<int> { typedef unsigned int Type; };
109 template<> struct AbsReturnType<long> { typedef unsigned long Type; };
110 template<> struct AbsReturnType<long long> { typedef unsigned long long Type; };
111 template<> struct AbsReturnType<float> { typedef float Type; };
112 template<> struct AbsReturnType<double> { typedef double Type; };
113 template<> struct AbsReturnType<long double> { typedef long double Type; };
115 } // namespace detail
117 template<typename T>
118 inline typename detail::AbsReturnType<T>::Type
119 Abs(const T t)
121 typedef typename detail::AbsReturnType<T>::Type ReturnType;
122 return t >= 0 ? ReturnType(t) : ~ReturnType(t) + 1;
125 template<>
126 inline float
127 Abs<float>(const float f)
129 return std::fabs(f);
132 template<>
133 inline double
134 Abs<double>(const double d)
136 return std::fabs(d);
139 template<>
140 inline long double
141 Abs<long double>(const long double d)
143 return std::fabs(d);
146 } // namespace mozilla
148 #if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
149 # define MOZ_BITSCAN_WINDOWS
151 extern "C" {
152 unsigned char _BitScanForward(unsigned long* Index, unsigned long mask);
153 unsigned char _BitScanReverse(unsigned long* Index, unsigned long mask);
154 # pragma intrinsic(_BitScanForward, _BitScanReverse)
156 # if defined(_M_AMD64) || defined(_M_X64)
157 # define MOZ_BITSCAN_WINDOWS64
158 unsigned char _BitScanForward64(unsigned long* index, unsigned __int64 mask);
159 unsigned char _BitScanReverse64(unsigned long* index, unsigned __int64 mask);
160 # pragma intrinsic(_BitScanForward64, _BitScanReverse64)
161 # endif
162 } // extern "C"
164 #endif
166 namespace mozilla {
168 namespace detail {
170 #if defined(MOZ_BITSCAN_WINDOWS)
172 inline uint_fast8_t
173 CountLeadingZeroes32(uint32_t u)
175 unsigned long index;
176 _BitScanReverse(&index, static_cast<unsigned long>(u));
177 return uint_fast8_t(31 - index);
181 inline uint_fast8_t
182 CountTrailingZeroes32(uint32_t u)
184 unsigned long index;
185 _BitScanForward(&index, static_cast<unsigned long>(u));
186 return uint_fast8_t(index);
189 inline uint_fast8_t
190 CountPopulation32(uint32_t u)
192 uint32_t x = u - ((u >> 1) & 0x55555555);
193 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
194 return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
197 inline uint_fast8_t
198 CountLeadingZeroes64(uint64_t u)
200 # if defined(MOZ_BITSCAN_WINDOWS64)
201 unsigned long index;
202 _BitScanReverse64(&index, static_cast<unsigned __int64>(u));
203 return uint_fast8_t(63 - index);
204 # else
205 uint32_t hi = uint32_t(u >> 32);
206 if (hi != 0)
207 return CountLeadingZeroes32(hi);
208 return 32u + CountLeadingZeroes32(uint32_t(u));
209 # endif
212 inline uint_fast8_t
213 CountTrailingZeroes64(uint64_t u)
215 # if defined(MOZ_BITSCAN_WINDOWS64)
216 unsigned long index;
217 _BitScanForward64(&index, static_cast<unsigned __int64>(u));
218 return uint_fast8_t(index);
219 # else
220 uint32_t lo = uint32_t(u);
221 if (lo != 0)
222 return CountTrailingZeroes32(lo);
223 return 32u + CountTrailingZeroes32(uint32_t(u >> 32));
224 # endif
227 # ifdef MOZ_HAVE_BITSCAN64
228 # undef MOZ_HAVE_BITSCAN64
229 # endif
231 #elif defined(__clang__) || defined(__GNUC__)
233 # if defined(__clang__)
234 # if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz)
235 # error "A clang providing __builtin_c[lt]z is required to build"
236 # endif
237 # else
238 // gcc has had __builtin_clz and friends since 3.4: no need to check.
239 # endif
241 inline uint_fast8_t
242 CountLeadingZeroes32(uint32_t u)
244 return __builtin_clz(u);
247 inline uint_fast8_t
248 CountTrailingZeroes32(uint32_t u)
250 return __builtin_ctz(u);
253 inline uint_fast8_t
254 CountPopulation32(uint32_t u)
256 return __builtin_popcount(u);
259 inline uint_fast8_t
260 CountLeadingZeroes64(uint64_t u)
262 return __builtin_clzll(u);
265 inline uint_fast8_t
266 CountTrailingZeroes64(uint64_t u)
268 return __builtin_ctzll(u);
271 #else
272 # error "Implement these!"
273 inline uint_fast8_t CountLeadingZeroes32(uint32_t u) MOZ_DELETE;
274 inline uint_fast8_t CountTrailingZeroes32(uint32_t u) MOZ_DELETE;
275 inline uint_fast8_t CountPopulation32(uint32_t u) MOZ_DELETE;
276 inline uint_fast8_t CountLeadingZeroes64(uint64_t u) MOZ_DELETE;
277 inline uint_fast8_t CountTrailingZeroes64(uint64_t u) MOZ_DELETE;
278 #endif
280 } // namespace detail
283 * Compute the number of high-order zero bits in the NON-ZERO number |u|. That
284 * is, looking at the bitwise representation of the number, with the highest-
285 * valued bits at the start, return the number of zeroes before the first one
286 * is observed.
288 * CountLeadingZeroes32(0xF0FF1000) is 0;
289 * CountLeadingZeroes32(0x7F8F0001) is 1;
290 * CountLeadingZeroes32(0x3FFF0100) is 2;
291 * CountLeadingZeroes32(0x1FF50010) is 3; and so on.
293 inline uint_fast8_t
294 CountLeadingZeroes32(uint32_t u)
296 MOZ_ASSERT(u != 0);
297 return detail::CountLeadingZeroes32(u);
301 * Compute the number of low-order zero bits in the NON-ZERO number |u|. That
302 * is, looking at the bitwise representation of the number, with the lowest-
303 * valued bits at the start, return the number of zeroes before the first one
304 * is observed.
306 * CountTrailingZeroes32(0x0100FFFF) is 0;
307 * CountTrailingZeroes32(0x7000FFFE) is 1;
308 * CountTrailingZeroes32(0x0080FFFC) is 2;
309 * CountTrailingZeroes32(0x0080FFF8) is 3; and so on.
311 inline uint_fast8_t
312 CountTrailingZeroes32(uint32_t u)
314 MOZ_ASSERT(u != 0);
315 return detail::CountTrailingZeroes32(u);
319 * Compute the number of one bits in the number |u|,
321 inline uint_fast8_t
322 CountPopulation32(uint32_t u)
324 return detail::CountPopulation32(u);
327 /** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
328 inline uint_fast8_t
329 CountLeadingZeroes64(uint64_t u)
331 MOZ_ASSERT(u != 0);
332 return detail::CountLeadingZeroes64(u);
335 /** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */
336 inline uint_fast8_t
337 CountTrailingZeroes64(uint64_t u)
339 MOZ_ASSERT(u != 0);
340 return detail::CountTrailingZeroes64(u);
343 namespace detail {
345 template<typename T, size_t Size = sizeof(T)>
346 class CeilingLog2;
348 template<typename T>
349 class CeilingLog2<T, 4>
351 public:
352 static uint_fast8_t compute(const T t) {
353 // Check for <= 1 to avoid the == 0 undefined case.
354 return t <= 1 ? 0u : 32u - CountLeadingZeroes32(t - 1);
358 template<typename T>
359 class CeilingLog2<T, 8>
361 public:
362 static uint_fast8_t compute(const T t) {
363 // Check for <= 1 to avoid the == 0 undefined case.
364 return t <= 1 ? 0 : 64 - CountLeadingZeroes64(t - 1);
368 } // namespace detail
371 * Compute the log of the least power of 2 greater than or equal to |t|.
373 * CeilingLog2(0..1) is 0;
374 * CeilingLog2(2) is 1;
375 * CeilingLog2(3..4) is 2;
376 * CeilingLog2(5..8) is 3;
377 * CeilingLog2(9..16) is 4; and so on.
379 template<typename T>
380 inline uint_fast8_t
381 CeilingLog2(const T t)
383 return detail::CeilingLog2<T>::compute(t);
386 /** A CeilingLog2 variant that accepts only size_t. */
387 inline uint_fast8_t
388 CeilingLog2Size(size_t n)
390 return CeilingLog2(n);
393 namespace detail {
395 template<typename T, size_t Size = sizeof(T)>
396 class FloorLog2;
398 template<typename T>
399 class FloorLog2<T, 4>
401 public:
402 static uint_fast8_t compute(const T t) {
403 return 31u - CountLeadingZeroes32(t | 1);
407 template<typename T>
408 class FloorLog2<T, 8>
410 public:
411 static uint_fast8_t compute(const T t) {
412 return 63u - CountLeadingZeroes64(t | 1);
416 } // namespace detail
419 * Compute the log of the greatest power of 2 less than or equal to |t|.
421 * FloorLog2(0..1) is 0;
422 * FloorLog2(2..3) is 1;
423 * FloorLog2(4..7) is 2;
424 * FloorLog2(8..15) is 3; and so on.
426 template<typename T>
427 inline uint_fast8_t
428 FloorLog2(const T t)
430 return detail::FloorLog2<T>::compute(t);
433 /** A FloorLog2 variant that accepts only size_t. */
434 inline uint_fast8_t
435 FloorLog2Size(size_t n)
437 return FloorLog2(n);
441 * Compute the smallest power of 2 greater than or equal to |x|. |x| must not
442 * be so great that the computed value would overflow |size_t|.
444 inline size_t
445 RoundUpPow2(size_t x)
447 MOZ_ASSERT(x <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)),
448 "can't round up -- will overflow!");
449 return size_t(1) << CeilingLog2(x);
453 * Rotates the bits of the given value left by the amount of the shift width.
455 template<typename T>
456 inline T
457 RotateLeft(const T t, uint_fast8_t shift)
459 MOZ_ASSERT(shift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
460 static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
461 return (t << shift) | (t >> (sizeof(T) * CHAR_BIT - shift));
465 * Rotates the bits of the given value right by the amount of the shift width.
467 template<typename T>
468 inline T
469 RotateRight(const T t, uint_fast8_t shift)
471 MOZ_ASSERT(shift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
472 static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
473 return (t >> shift) | (t << (sizeof(T) * CHAR_BIT - shift));
476 } /* namespace mozilla */
478 #endif /* mozilla_MathAlgorithms_h */