mfbt/MathAlgorithms.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/MathAlgorithms.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,478 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* mfbt maths algorithms. */
    1.11 +
    1.12 +#ifndef mozilla_MathAlgorithms_h
    1.13 +#define mozilla_MathAlgorithms_h
    1.14 +
    1.15 +#include "mozilla/Assertions.h"
    1.16 +#include "mozilla/TypeTraits.h"
    1.17 +
    1.18 +#include <cmath>
    1.19 +#include <limits.h>
    1.20 +#include <stdint.h>
    1.21 +
    1.22 +namespace mozilla {
    1.23 +
    1.24 +// Greatest Common Divisor
    1.25 +template<typename IntegerType>
    1.26 +MOZ_ALWAYS_INLINE IntegerType
    1.27 +EuclidGCD(IntegerType a, IntegerType b)
    1.28 +{
    1.29 +  // Euclid's algorithm; O(N) in the worst case.  (There are better
    1.30 +  // ways, but we don't need them for the current use of this algo.)
    1.31 +  MOZ_ASSERT(a > 0);
    1.32 +  MOZ_ASSERT(b > 0);
    1.33 +
    1.34 +  while (a != b) {
    1.35 +    if (a > b) {
    1.36 +      a = a - b;
    1.37 +    } else {
    1.38 +      b = b - a;
    1.39 +    }
    1.40 +  }
    1.41 +
    1.42 +  return a;
    1.43 +}
    1.44 +
    1.45 +// Least Common Multiple
    1.46 +template<typename IntegerType>
    1.47 +MOZ_ALWAYS_INLINE IntegerType
    1.48 +EuclidLCM(IntegerType a, IntegerType b)
    1.49 +{
    1.50 +  // Divide first to reduce overflow risk.
    1.51 +  return (a / EuclidGCD(a, b)) * b;
    1.52 +}
    1.53 +
    1.54 +namespace detail {
    1.55 +
    1.56 +template<typename T>
    1.57 +struct AllowDeprecatedAbsFixed : FalseType {};
    1.58 +
    1.59 +template<> struct AllowDeprecatedAbsFixed<int32_t> : TrueType {};
    1.60 +template<> struct AllowDeprecatedAbsFixed<int64_t> : TrueType {};
    1.61 +
    1.62 +template<typename T>
    1.63 +struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed<T> {};
    1.64 +
    1.65 +template<> struct AllowDeprecatedAbs<int> : TrueType {};
    1.66 +template<> struct AllowDeprecatedAbs<long> : TrueType {};
    1.67 +
    1.68 +} // namespace detail
    1.69 +
    1.70 +// DO NOT USE DeprecatedAbs.  It exists only until its callers can be converted
    1.71 +// to Abs below, and it will be removed when all callers have been changed.
    1.72 +template<typename T>
    1.73 +inline typename mozilla::EnableIf<detail::AllowDeprecatedAbs<T>::value, T>::Type
    1.74 +DeprecatedAbs(const T t)
    1.75 +{
    1.76 +  // The absolute value of the smallest possible value of a signed-integer type
    1.77 +  // won't fit in that type (on twos-complement systems -- and we're blithely
    1.78 +  // assuming we're on such systems, for the non-<stdint.h> types listed above),
    1.79 +  // so assert that the input isn't that value.
    1.80 +  //
    1.81 +  // This is the case if: the value is non-negative; or if adding one (giving a
    1.82 +  // value in the range [-maxvalue, 0]), then negating (giving a value in the
    1.83 +  // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement,
    1.84 +  // (minvalue + 1) == -maxvalue).
    1.85 +  MOZ_ASSERT(t >= 0 ||
    1.86 +             -(t + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1),
    1.87 +             "You can't negate the smallest possible negative integer!");
    1.88 +  return t >= 0 ? t : -t;
    1.89 +}
    1.90 +
    1.91 +namespace detail {
    1.92 +
    1.93 +// For now mozilla::Abs only takes intN_T, the signed natural types, and
    1.94 +// float/double/long double.  Feel free to add overloads for other standard,
    1.95 +// signed types if you need them.
    1.96 +
    1.97 +template<typename T>
    1.98 +struct AbsReturnTypeFixed;
    1.99 +
   1.100 +template<> struct AbsReturnTypeFixed<int8_t> { typedef uint8_t Type; };
   1.101 +template<> struct AbsReturnTypeFixed<int16_t> { typedef uint16_t Type; };
   1.102 +template<> struct AbsReturnTypeFixed<int32_t> { typedef uint32_t Type; };
   1.103 +template<> struct AbsReturnTypeFixed<int64_t> { typedef uint64_t Type; };
   1.104 +
   1.105 +template<typename T>
   1.106 +struct AbsReturnType : AbsReturnTypeFixed<T> {};
   1.107 +
   1.108 +template<> struct AbsReturnType<char> : EnableIf<char(-1) < char(0), unsigned char> {};
   1.109 +template<> struct AbsReturnType<signed char> { typedef unsigned char Type; };
   1.110 +template<> struct AbsReturnType<short> { typedef unsigned short Type; };
   1.111 +template<> struct AbsReturnType<int> { typedef unsigned int Type; };
   1.112 +template<> struct AbsReturnType<long> { typedef unsigned long Type; };
   1.113 +template<> struct AbsReturnType<long long> { typedef unsigned long long Type; };
   1.114 +template<> struct AbsReturnType<float> { typedef float Type; };
   1.115 +template<> struct AbsReturnType<double> { typedef double Type; };
   1.116 +template<> struct AbsReturnType<long double> { typedef long double Type; };
   1.117 +
   1.118 +} // namespace detail
   1.119 +
   1.120 +template<typename T>
   1.121 +inline typename detail::AbsReturnType<T>::Type
   1.122 +Abs(const T t)
   1.123 +{
   1.124 +  typedef typename detail::AbsReturnType<T>::Type ReturnType;
   1.125 +  return t >= 0 ? ReturnType(t) : ~ReturnType(t) + 1;
   1.126 +}
   1.127 +
   1.128 +template<>
   1.129 +inline float
   1.130 +Abs<float>(const float f)
   1.131 +{
   1.132 +  return std::fabs(f);
   1.133 +}
   1.134 +
   1.135 +template<>
   1.136 +inline double
   1.137 +Abs<double>(const double d)
   1.138 +{
   1.139 +  return std::fabs(d);
   1.140 +}
   1.141 +
   1.142 +template<>
   1.143 +inline long double
   1.144 +Abs<long double>(const long double d)
   1.145 +{
   1.146 +  return std::fabs(d);
   1.147 +}
   1.148 +
   1.149 +} // namespace mozilla
   1.150 +
   1.151 +#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
   1.152 +#  define MOZ_BITSCAN_WINDOWS
   1.153 +
   1.154 +  extern "C" {
   1.155 +    unsigned char _BitScanForward(unsigned long* Index, unsigned long mask);
   1.156 +    unsigned char _BitScanReverse(unsigned long* Index, unsigned long mask);
   1.157 +#  pragma intrinsic(_BitScanForward, _BitScanReverse)
   1.158 +
   1.159 +#  if defined(_M_AMD64) || defined(_M_X64)
   1.160 +#    define MOZ_BITSCAN_WINDOWS64
   1.161 +    unsigned char _BitScanForward64(unsigned long* index, unsigned __int64 mask);
   1.162 +    unsigned char _BitScanReverse64(unsigned long* index, unsigned __int64 mask);
   1.163 +#   pragma intrinsic(_BitScanForward64, _BitScanReverse64)
   1.164 +#  endif
   1.165 +  } // extern "C"
   1.166 +
   1.167 +#endif
   1.168 +
   1.169 +namespace mozilla {
   1.170 +
   1.171 +namespace detail {
   1.172 +
   1.173 +#if defined(MOZ_BITSCAN_WINDOWS)
   1.174 +
   1.175 +  inline uint_fast8_t
   1.176 +  CountLeadingZeroes32(uint32_t u)
   1.177 +  {
   1.178 +    unsigned long index;
   1.179 +    _BitScanReverse(&index, static_cast<unsigned long>(u));
   1.180 +    return uint_fast8_t(31 - index);
   1.181 +  }
   1.182 +
   1.183 +
   1.184 +  inline uint_fast8_t
   1.185 +  CountTrailingZeroes32(uint32_t u)
   1.186 +  {
   1.187 +    unsigned long index;
   1.188 +    _BitScanForward(&index, static_cast<unsigned long>(u));
   1.189 +    return uint_fast8_t(index);
   1.190 +  }
   1.191 +
   1.192 +  inline uint_fast8_t
   1.193 +  CountPopulation32(uint32_t u)
   1.194 +  {
   1.195 +    uint32_t x = u - ((u >> 1) & 0x55555555);
   1.196 +    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
   1.197 +    return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
   1.198 +  }
   1.199 +
   1.200 +  inline uint_fast8_t
   1.201 +  CountLeadingZeroes64(uint64_t u)
   1.202 +  {
   1.203 +#  if defined(MOZ_BITSCAN_WINDOWS64)
   1.204 +    unsigned long index;
   1.205 +    _BitScanReverse64(&index, static_cast<unsigned __int64>(u));
   1.206 +    return uint_fast8_t(63 - index);
   1.207 +#  else
   1.208 +    uint32_t hi = uint32_t(u >> 32);
   1.209 +    if (hi != 0)
   1.210 +      return CountLeadingZeroes32(hi);
   1.211 +    return 32 + CountLeadingZeroes32(uint32_t(u));
   1.212 +#  endif
   1.213 +  }
   1.214 +
   1.215 +  inline uint_fast8_t
   1.216 +  CountTrailingZeroes64(uint64_t u)
   1.217 +  {
   1.218 +#  if defined(MOZ_BITSCAN_WINDOWS64)
   1.219 +    unsigned long index;
   1.220 +    _BitScanForward64(&index, static_cast<unsigned __int64>(u));
   1.221 +    return uint_fast8_t(index);
   1.222 +#  else
   1.223 +    uint32_t lo = uint32_t(u);
   1.224 +    if (lo != 0)
   1.225 +      return CountTrailingZeroes32(lo);
   1.226 +    return 32 + CountTrailingZeroes32(uint32_t(u >> 32));
   1.227 +#  endif
   1.228 +  }
   1.229 +
   1.230 +#  ifdef MOZ_HAVE_BITSCAN64
   1.231 +#    undef MOZ_HAVE_BITSCAN64
   1.232 +#  endif
   1.233 +
   1.234 +#elif defined(__clang__) || defined(__GNUC__)
   1.235 +
   1.236 +#  if defined(__clang__)
   1.237 +#    if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz)
   1.238 +#      error "A clang providing __builtin_c[lt]z is required to build"
   1.239 +#    endif
   1.240 +#  else
   1.241 +     // gcc has had __builtin_clz and friends since 3.4: no need to check.
   1.242 +#  endif
   1.243 +
   1.244 +  inline uint_fast8_t
   1.245 +  CountLeadingZeroes32(uint32_t u)
   1.246 +  {
   1.247 +    return __builtin_clz(u);
   1.248 +  }
   1.249 +
   1.250 +  inline uint_fast8_t
   1.251 +  CountTrailingZeroes32(uint32_t u)
   1.252 +  {
   1.253 +    return __builtin_ctz(u);
   1.254 +  }
   1.255 +
   1.256 +  inline uint_fast8_t
   1.257 +  CountPopulation32(uint32_t u)
   1.258 +  {
   1.259 +    return __builtin_popcount(u);
   1.260 +  }
   1.261 +
   1.262 +  inline uint_fast8_t
   1.263 +  CountLeadingZeroes64(uint64_t u)
   1.264 +  {
   1.265 +    return __builtin_clzll(u);
   1.266 +  }
   1.267 +
   1.268 +  inline uint_fast8_t
   1.269 +  CountTrailingZeroes64(uint64_t u)
   1.270 +  {
   1.271 +    return __builtin_ctzll(u);
   1.272 +  }
   1.273 +
   1.274 +#else
   1.275 +#  error "Implement these!"
   1.276 +  inline uint_fast8_t CountLeadingZeroes32(uint32_t u) MOZ_DELETE;
   1.277 +  inline uint_fast8_t CountTrailingZeroes32(uint32_t u) MOZ_DELETE;
   1.278 +  inline uint_fast8_t CountPopulation32(uint32_t u) MOZ_DELETE;
   1.279 +  inline uint_fast8_t CountLeadingZeroes64(uint64_t u) MOZ_DELETE;
   1.280 +  inline uint_fast8_t CountTrailingZeroes64(uint64_t u) MOZ_DELETE;
   1.281 +#endif
   1.282 +
   1.283 +} // namespace detail
   1.284 +
   1.285 +/**
   1.286 + * Compute the number of high-order zero bits in the NON-ZERO number |u|.  That
   1.287 + * is, looking at the bitwise representation of the number, with the highest-
   1.288 + * valued bits at the start, return the number of zeroes before the first one
   1.289 + * is observed.
   1.290 + *
   1.291 + * CountLeadingZeroes32(0xF0FF1000) is 0;
   1.292 + * CountLeadingZeroes32(0x7F8F0001) is 1;
   1.293 + * CountLeadingZeroes32(0x3FFF0100) is 2;
   1.294 + * CountLeadingZeroes32(0x1FF50010) is 3; and so on.
   1.295 + */
   1.296 +inline uint_fast8_t
   1.297 +CountLeadingZeroes32(uint32_t u)
   1.298 +{
   1.299 +  MOZ_ASSERT(u != 0);
   1.300 +  return detail::CountLeadingZeroes32(u);
   1.301 +}
   1.302 +
   1.303 +/**
   1.304 + * Compute the number of low-order zero bits in the NON-ZERO number |u|.  That
   1.305 + * is, looking at the bitwise representation of the number, with the lowest-
   1.306 + * valued bits at the start, return the number of zeroes before the first one
   1.307 + * is observed.
   1.308 + *
   1.309 + * CountTrailingZeroes32(0x0100FFFF) is 0;
   1.310 + * CountTrailingZeroes32(0x7000FFFE) is 1;
   1.311 + * CountTrailingZeroes32(0x0080FFFC) is 2;
   1.312 + * CountTrailingZeroes32(0x0080FFF8) is 3; and so on.
   1.313 + */
   1.314 +inline uint_fast8_t
   1.315 +CountTrailingZeroes32(uint32_t u)
   1.316 +{
   1.317 +  MOZ_ASSERT(u != 0);
   1.318 +  return detail::CountTrailingZeroes32(u);
   1.319 +}
   1.320 +
   1.321 +/**
   1.322 + * Compute the number of one bits in the number |u|,
   1.323 + */
   1.324 +inline uint_fast8_t
   1.325 +CountPopulation32(uint32_t u)
   1.326 +{
   1.327 +  return detail::CountPopulation32(u);
   1.328 +}
   1.329 +
   1.330 +/** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
   1.331 +inline uint_fast8_t
   1.332 +CountLeadingZeroes64(uint64_t u)
   1.333 +{
   1.334 +  MOZ_ASSERT(u != 0);
   1.335 +  return detail::CountLeadingZeroes64(u);
   1.336 +}
   1.337 +
   1.338 +/** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */
   1.339 +inline uint_fast8_t
   1.340 +CountTrailingZeroes64(uint64_t u)
   1.341 +{
   1.342 +  MOZ_ASSERT(u != 0);
   1.343 +  return detail::CountTrailingZeroes64(u);
   1.344 +}
   1.345 +
   1.346 +namespace detail {
   1.347 +
   1.348 +template<typename T, size_t Size = sizeof(T)>
   1.349 +class CeilingLog2;
   1.350 +
   1.351 +template<typename T>
   1.352 +class CeilingLog2<T, 4>
   1.353 +{
   1.354 +  public:
   1.355 +    static uint_fast8_t compute(const T t) {
   1.356 +      // Check for <= 1 to avoid the == 0 undefined case.
   1.357 +      return t <= 1 ? 0 : 32 - CountLeadingZeroes32(t - 1);
   1.358 +    }
   1.359 +};
   1.360 +
   1.361 +template<typename T>
   1.362 +class CeilingLog2<T, 8>
   1.363 +{
   1.364 +  public:
   1.365 +    static uint_fast8_t compute(const T t) {
   1.366 +      // Check for <= 1 to avoid the == 0 undefined case.
   1.367 +      return t <= 1 ? 0 : 64 - CountLeadingZeroes64(t - 1);
   1.368 +    }
   1.369 +};
   1.370 +
   1.371 +} // namespace detail
   1.372 +
   1.373 +/**
   1.374 + * Compute the log of the least power of 2 greater than or equal to |t|.
   1.375 + *
   1.376 + * CeilingLog2(0..1) is 0;
   1.377 + * CeilingLog2(2) is 1;
   1.378 + * CeilingLog2(3..4) is 2;
   1.379 + * CeilingLog2(5..8) is 3;
   1.380 + * CeilingLog2(9..16) is 4; and so on.
   1.381 + */
   1.382 +template<typename T>
   1.383 +inline uint_fast8_t
   1.384 +CeilingLog2(const T t)
   1.385 +{
   1.386 +  return detail::CeilingLog2<T>::compute(t);
   1.387 +}
   1.388 +
   1.389 +/** A CeilingLog2 variant that accepts only size_t. */
   1.390 +inline uint_fast8_t
   1.391 +CeilingLog2Size(size_t n)
   1.392 +{
   1.393 +  return CeilingLog2(n);
   1.394 +}
   1.395 +
   1.396 +namespace detail {
   1.397 +
   1.398 +template<typename T, size_t Size = sizeof(T)>
   1.399 +class FloorLog2;
   1.400 +
   1.401 +template<typename T>
   1.402 +class FloorLog2<T, 4>
   1.403 +{
   1.404 +  public:
   1.405 +    static uint_fast8_t compute(const T t) {
   1.406 +      return 31 - CountLeadingZeroes32(t | 1);
   1.407 +    }
   1.408 +};
   1.409 +
   1.410 +template<typename T>
   1.411 +class FloorLog2<T, 8>
   1.412 +{
   1.413 +  public:
   1.414 +    static uint_fast8_t compute(const T t) {
   1.415 +      return 63 - CountLeadingZeroes64(t | 1);
   1.416 +    }
   1.417 +};
   1.418 +
   1.419 +} // namespace detail
   1.420 +
   1.421 +/**
   1.422 + * Compute the log of the greatest power of 2 less than or equal to |t|.
   1.423 + *
   1.424 + * FloorLog2(0..1) is 0;
   1.425 + * FloorLog2(2..3) is 1;
   1.426 + * FloorLog2(4..7) is 2;
   1.427 + * FloorLog2(8..15) is 3; and so on.
   1.428 + */
   1.429 +template<typename T>
   1.430 +inline uint_fast8_t
   1.431 +FloorLog2(const T t)
   1.432 +{
   1.433 +  return detail::FloorLog2<T>::compute(t);
   1.434 +}
   1.435 +
   1.436 +/** A FloorLog2 variant that accepts only size_t. */
   1.437 +inline uint_fast8_t
   1.438 +FloorLog2Size(size_t n)
   1.439 +{
   1.440 +  return FloorLog2(n);
   1.441 +}
   1.442 +
   1.443 +/*
   1.444 + * Compute the smallest power of 2 greater than or equal to |x|.  |x| must not
   1.445 + * be so great that the computed value would overflow |size_t|.
   1.446 + */
   1.447 +inline size_t
   1.448 +RoundUpPow2(size_t x)
   1.449 +{
   1.450 +  MOZ_ASSERT(x <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)),
   1.451 +             "can't round up -- will overflow!");
   1.452 +  return size_t(1) << CeilingLog2(x);
   1.453 +}
   1.454 +
   1.455 +/**
   1.456 + * Rotates the bits of the given value left by the amount of the shift width.
   1.457 + */
   1.458 +template<typename T>
   1.459 +inline T
   1.460 +RotateLeft(const T t, uint_fast8_t shift)
   1.461 +{
   1.462 +  MOZ_ASSERT(shift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
   1.463 +  static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
   1.464 +  return (t << shift) | (t >> (sizeof(T) * CHAR_BIT - shift));
   1.465 +}
   1.466 +
   1.467 +/**
   1.468 + * Rotates the bits of the given value right by the amount of the shift width.
   1.469 + */
   1.470 +template<typename T>
   1.471 +inline T
   1.472 +RotateRight(const T t, uint_fast8_t shift)
   1.473 +{
   1.474 +  MOZ_ASSERT(shift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
   1.475 +  static_assert(IsUnsigned<T>::value, "Rotates require unsigned values");
   1.476 +  return (t >> shift) | (t << (sizeof(T) * CHAR_BIT - shift));
   1.477 +}
   1.478 +
   1.479 +} /* namespace mozilla */
   1.480 +
   1.481 +#endif /* mozilla_MathAlgorithms_h */

mercurial