tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Utils.h (7038B)


      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 #ifndef Utils_h
      8 #define Utils_h
      9 
     10 #include <cstring>
     11 #include <type_traits>
     12 
     13 #ifdef XP_WIN
     14 #  include <io.h>  // for _write()
     15 #endif
     16 
     17 #include "mozilla/CheckedInt.h"
     18 
     19 // Helper for log2 of powers of 2 at compile time.
     20 constexpr size_t LOG2(size_t N) { return mozilla::CeilingLog2(N); }
     21 
     22 enum class Order {
     23  eLess = -1,
     24  eEqual = 0,
     25  eGreater = 1,
     26 };
     27 
     28 // Compare two integers. Returns whether the first integer is Less,
     29 // Equal or Greater than the second integer.
     30 template <typename T>
     31 Order CompareInt(T aValue1, T aValue2) {
     32  static_assert(std::is_integral_v<T>, "Type must be integral");
     33  if (aValue1 < aValue2) {
     34    return Order::eLess;
     35  }
     36  if (aValue1 > aValue2) {
     37    return Order::eGreater;
     38  }
     39  return Order::eEqual;
     40 }
     41 
     42 // Compare two addresses. Returns whether the first address is Less,
     43 // Equal or Greater than the second address.
     44 template <typename T>
     45 Order CompareAddr(T* aAddr1, T* aAddr2) {
     46  return CompareInt(uintptr_t(aAddr1), uintptr_t(aAddr2));
     47 }
     48 
     49 // Helper for (fast) comparison of fractions without involving divisions or
     50 // floats.
     51 class Fraction {
     52 public:
     53  explicit constexpr Fraction(size_t aNumerator, size_t aDenominator)
     54      : mNumerator(aNumerator), mDenominator(aDenominator) {}
     55 
     56  MOZ_IMPLICIT constexpr Fraction(long double aValue)
     57      // We use an arbitrary power of two as denominator that provides enough
     58      // precision for our use case.
     59      : mNumerator(aValue * 4096), mDenominator(4096) {}
     60 
     61  inline bool operator<(const Fraction& aOther) const {
     62 #ifndef MOZ_DEBUG
     63    // We are comparing A / B < C / D, with all A, B, C and D being positive
     64    // numbers. Multiplying both sides with B * D, we have:
     65    // (A * B * D) / B < (C * B * D) / D, which can then be simplified as
     66    // A * D < C * B. When can thus compare our fractions without actually
     67    // doing any division.
     68    // This however assumes the multiplied quantities are small enough not
     69    // to overflow the multiplication. We use CheckedInt on debug builds
     70    // to enforce the assumption.
     71    return mNumerator * aOther.mDenominator < aOther.mNumerator * mDenominator;
     72 #else
     73    mozilla::CheckedInt<size_t> numerator(mNumerator);
     74    mozilla::CheckedInt<size_t> denominator(mDenominator);
     75    // value() asserts when the multiplication overflowed.
     76    size_t lhs = (numerator * aOther.mDenominator).value();
     77    size_t rhs = (aOther.mNumerator * denominator).value();
     78    return lhs < rhs;
     79 #endif
     80  }
     81 
     82  inline bool operator>(const Fraction& aOther) const { return aOther < *this; }
     83 
     84  inline bool operator>=(const Fraction& aOther) const {
     85    return !(*this < aOther);
     86  }
     87 
     88  inline bool operator<=(const Fraction& aOther) const {
     89    return !(*this > aOther);
     90  }
     91 
     92  inline bool operator==(const Fraction& aOther) const {
     93 #ifndef MOZ_DEBUG
     94    // Same logic as operator<
     95    return mNumerator * aOther.mDenominator == aOther.mNumerator * mDenominator;
     96 #else
     97    mozilla::CheckedInt<size_t> numerator(mNumerator);
     98    mozilla::CheckedInt<size_t> denominator(mDenominator);
     99    size_t lhs = (numerator * aOther.mDenominator).value();
    100    size_t rhs = (aOther.mNumerator * denominator).value();
    101    return lhs == rhs;
    102 #endif
    103  }
    104 
    105  inline bool operator!=(const Fraction& aOther) const {
    106    return !(*this == aOther);
    107  }
    108 
    109 private:
    110  size_t mNumerator;
    111  size_t mDenominator;
    112 };
    113 
    114 // Fast division
    115 //
    116 // During deallocation we want to divide by the size class.  This class
    117 // provides a routine and sets up a constant as follows.
    118 //
    119 // To divide by a number D that is not a power of two we multiply by (2^17 /
    120 // D) and then right shift by 17 positions.
    121 //
    122 //   X / D
    123 //
    124 // becomes
    125 //
    126 //   (X * m) >> p
    127 //
    128 // Where m is calculated during the FastDivisor constructor similarly to:
    129 //
    130 //   m = 2^p / D
    131 //
    132 template <typename T>
    133 class FastDivisor {
    134 private:
    135  // The shift amount (p) is chosen to minimise the size of m while
    136  // working for divisors up to 65536 in steps of 16.  I arrived at 17
    137  // experimentally.  I wanted a low number to minimise the range of m
    138  // so it can fit in a uint16_t, 16 didn't work but 17 worked perfectly.
    139  //
    140  // We'd need to increase this if we allocated memory on smaller boundaries
    141  // than 16.
    142  static const unsigned p = 17;
    143 
    144  // We can fit the inverted divisor in 16 bits, but we template it here for
    145  // convenience.
    146  T m;
    147 
    148 public:
    149  // Needed so mBins can be constructed.
    150  FastDivisor() : m(0) {}
    151 
    152  FastDivisor(unsigned div, unsigned max) {
    153    MOZ_ASSERT(div <= max);
    154 
    155    // divide_inv_shift is large enough.
    156    MOZ_ASSERT((1U << p) >= div);
    157 
    158    // The calculation here for m is formula 26 from Section
    159    // 10-9 "Unsigned Division by Divisors >= 1" in
    160    // Henry S. Warren, Jr.'s Hacker's Delight, 2nd Ed.
    161    unsigned m_ = ((1U << p) + div - 1 - (((1U << p) - 1) % div)) / div;
    162 
    163    // Make sure that max * m does not overflow.
    164    MOZ_DIAGNOSTIC_ASSERT(max < UINT_MAX / m_);
    165 
    166    MOZ_ASSERT(m_ <= std::numeric_limits<T>::max());
    167    m = static_cast<T>(m_);
    168 
    169    // Initialisation made m non-zero.
    170    MOZ_ASSERT(m);
    171 
    172    // Test that all the divisions in the range we expected would work.
    173 #ifdef MOZ_DEBUG
    174    for (unsigned num = 0; num < max; num += div) {
    175      MOZ_ASSERT(num / div == divide(num));
    176    }
    177 #endif
    178  }
    179 
    180  // Note that this always occurs in uint32_t regardless of m's type.  If m is
    181  // a uint16_t it will be zero-extended before the multiplication.  We also use
    182  // uint32_t rather than something that could possibly be larger because it is
    183  // most-likely the cheapest multiplication.
    184  inline uint32_t divide(uint32_t num) const {
    185    // Check that m was initialised.
    186    MOZ_ASSERT(m);
    187    return (num * m) >> p;
    188  }
    189 };
    190 
    191 template <typename T>
    192 unsigned inline operator/(unsigned num, FastDivisor<T> divisor) {
    193  return divisor.divide(num);
    194 }
    195 
    196 // Return the offset between a and the nearest aligned address at or below a.
    197 #define ALIGNMENT_ADDR2OFFSET(a, alignment) \
    198  ((size_t)((uintptr_t)(a) & ((alignment) - 1)))
    199 
    200 // Return the smallest alignment multiple that is >= s.
    201 #define ALIGNMENT_CEILING(s, alignment) \
    202  (((s) + ((alignment) - 1)) & (~((alignment) - 1)))
    203 
    204 #define ALIGNMENT_FLOOR(s, alignment) ((s) & (~((alignment) - 1)))
    205 
    206 static inline const char* _getprogname(void) { return "<jemalloc>"; }
    207 
    208 #ifdef XP_WIN
    209 #  define STDERR_FILENO 2
    210 #else
    211 #  define _write write
    212 #endif
    213 inline void _malloc_message(const char* p) {
    214  // Pretend to check _write() errors to suppress gcc warnings about
    215  // warn_unused_result annotations in some versions of glibc headers.
    216  if (_write(STDERR_FILENO, p, (unsigned int)strlen(p)) < 0) {
    217    return;
    218  }
    219 }
    220 
    221 template <typename... Args>
    222 static void _malloc_message(const char* p, Args... args) {
    223  _malloc_message(p);
    224  _malloc_message(args...);
    225 }
    226 
    227 #endif