mfbt/MathAlgorithms.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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)
    25 {
    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 > 0);
    29   MOZ_ASSERT(b > 0);
    31   while (a != b) {
    32     if (a > b) {
    33       a = a - b;
    34     } else {
    35       b = b - a;
    36     }
    37   }
    39   return a;
    40 }
    42 // Least Common Multiple
    43 template<typename IntegerType>
    44 MOZ_ALWAYS_INLINE IntegerType
    45 EuclidLCM(IntegerType a, IntegerType b)
    46 {
    47   // Divide first to reduce overflow risk.
    48   return (a / EuclidGCD(a, b)) * b;
    49 }
    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)
    72 {
    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.
    77   //
    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;
    86 }
    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)
   120 {
   121   typedef typename detail::AbsReturnType<T>::Type ReturnType;
   122   return t >= 0 ? ReturnType(t) : ~ReturnType(t) + 1;
   123 }
   125 template<>
   126 inline float
   127 Abs<float>(const float f)
   128 {
   129   return std::fabs(f);
   130 }
   132 template<>
   133 inline double
   134 Abs<double>(const double d)
   135 {
   136   return std::fabs(d);
   137 }
   139 template<>
   140 inline long double
   141 Abs<long double>(const long double d)
   142 {
   143   return std::fabs(d);
   144 }
   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)
   174   {
   175     unsigned long index;
   176     _BitScanReverse(&index, static_cast<unsigned long>(u));
   177     return uint_fast8_t(31 - index);
   178   }
   181   inline uint_fast8_t
   182   CountTrailingZeroes32(uint32_t u)
   183   {
   184     unsigned long index;
   185     _BitScanForward(&index, static_cast<unsigned long>(u));
   186     return uint_fast8_t(index);
   187   }
   189   inline uint_fast8_t
   190   CountPopulation32(uint32_t u)
   191   {
   192     uint32_t x = u - ((u >> 1) & 0x55555555);
   193     x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
   194     return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
   195   }
   197   inline uint_fast8_t
   198   CountLeadingZeroes64(uint64_t u)
   199   {
   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 32 + CountLeadingZeroes32(uint32_t(u));
   209 #  endif
   210   }
   212   inline uint_fast8_t
   213   CountTrailingZeroes64(uint64_t u)
   214   {
   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 32 + CountTrailingZeroes32(uint32_t(u >> 32));
   224 #  endif
   225   }
   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)
   243   {
   244     return __builtin_clz(u);
   245   }
   247   inline uint_fast8_t
   248   CountTrailingZeroes32(uint32_t u)
   249   {
   250     return __builtin_ctz(u);
   251   }
   253   inline uint_fast8_t
   254   CountPopulation32(uint32_t u)
   255   {
   256     return __builtin_popcount(u);
   257   }
   259   inline uint_fast8_t
   260   CountLeadingZeroes64(uint64_t u)
   261   {
   262     return __builtin_clzll(u);
   263   }
   265   inline uint_fast8_t
   266   CountTrailingZeroes64(uint64_t u)
   267   {
   268     return __builtin_ctzll(u);
   269   }
   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
   282 /**
   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.
   287  *
   288  * CountLeadingZeroes32(0xF0FF1000) is 0;
   289  * CountLeadingZeroes32(0x7F8F0001) is 1;
   290  * CountLeadingZeroes32(0x3FFF0100) is 2;
   291  * CountLeadingZeroes32(0x1FF50010) is 3; and so on.
   292  */
   293 inline uint_fast8_t
   294 CountLeadingZeroes32(uint32_t u)
   295 {
   296   MOZ_ASSERT(u != 0);
   297   return detail::CountLeadingZeroes32(u);
   298 }
   300 /**
   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.
   305  *
   306  * CountTrailingZeroes32(0x0100FFFF) is 0;
   307  * CountTrailingZeroes32(0x7000FFFE) is 1;
   308  * CountTrailingZeroes32(0x0080FFFC) is 2;
   309  * CountTrailingZeroes32(0x0080FFF8) is 3; and so on.
   310  */
   311 inline uint_fast8_t
   312 CountTrailingZeroes32(uint32_t u)
   313 {
   314   MOZ_ASSERT(u != 0);
   315   return detail::CountTrailingZeroes32(u);
   316 }
   318 /**
   319  * Compute the number of one bits in the number |u|,
   320  */
   321 inline uint_fast8_t
   322 CountPopulation32(uint32_t u)
   323 {
   324   return detail::CountPopulation32(u);
   325 }
   327 /** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
   328 inline uint_fast8_t
   329 CountLeadingZeroes64(uint64_t u)
   330 {
   331   MOZ_ASSERT(u != 0);
   332   return detail::CountLeadingZeroes64(u);
   333 }
   335 /** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */
   336 inline uint_fast8_t
   337 CountTrailingZeroes64(uint64_t u)
   338 {
   339   MOZ_ASSERT(u != 0);
   340   return detail::CountTrailingZeroes64(u);
   341 }
   343 namespace detail {
   345 template<typename T, size_t Size = sizeof(T)>
   346 class CeilingLog2;
   348 template<typename T>
   349 class CeilingLog2<T, 4>
   350 {
   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 ? 0 : 32 - CountLeadingZeroes32(t - 1);
   355     }
   356 };
   358 template<typename T>
   359 class CeilingLog2<T, 8>
   360 {
   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);
   365     }
   366 };
   368 } // namespace detail
   370 /**
   371  * Compute the log of the least power of 2 greater than or equal to |t|.
   372  *
   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.
   378  */
   379 template<typename T>
   380 inline uint_fast8_t
   381 CeilingLog2(const T t)
   382 {
   383   return detail::CeilingLog2<T>::compute(t);
   384 }
   386 /** A CeilingLog2 variant that accepts only size_t. */
   387 inline uint_fast8_t
   388 CeilingLog2Size(size_t n)
   389 {
   390   return CeilingLog2(n);
   391 }
   393 namespace detail {
   395 template<typename T, size_t Size = sizeof(T)>
   396 class FloorLog2;
   398 template<typename T>
   399 class FloorLog2<T, 4>
   400 {
   401   public:
   402     static uint_fast8_t compute(const T t) {
   403       return 31 - CountLeadingZeroes32(t | 1);
   404     }
   405 };
   407 template<typename T>
   408 class FloorLog2<T, 8>
   409 {
   410   public:
   411     static uint_fast8_t compute(const T t) {
   412       return 63 - CountLeadingZeroes64(t | 1);
   413     }
   414 };
   416 } // namespace detail
   418 /**
   419  * Compute the log of the greatest power of 2 less than or equal to |t|.
   420  *
   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.
   425  */
   426 template<typename T>
   427 inline uint_fast8_t
   428 FloorLog2(const T t)
   429 {
   430   return detail::FloorLog2<T>::compute(t);
   431 }
   433 /** A FloorLog2 variant that accepts only size_t. */
   434 inline uint_fast8_t
   435 FloorLog2Size(size_t n)
   436 {
   437   return FloorLog2(n);
   438 }
   440 /*
   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|.
   443  */
   444 inline size_t
   445 RoundUpPow2(size_t x)
   446 {
   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);
   450 }
   452 /**
   453  * Rotates the bits of the given value left by the amount of the shift width.
   454  */
   455 template<typename T>
   456 inline T
   457 RotateLeft(const T t, uint_fast8_t shift)
   458 {
   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));
   462 }
   464 /**
   465  * Rotates the bits of the given value right by the amount of the shift width.
   466  */
   467 template<typename T>
   468 inline T
   469 RotateRight(const T t, uint_fast8_t shift)
   470 {
   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));
   474 }
   476 } /* namespace mozilla */
   478 #endif /* mozilla_MathAlgorithms_h */

mercurial