tor-browser

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

Tools.h (6053B)


      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 MOZILLA_GFX_TOOLS_H_
      8 #define MOZILLA_GFX_TOOLS_H_
      9 
     10 #include <math.h>
     11 
     12 #include <utility>
     13 
     14 #include "Point.h"
     15 #include "Types.h"
     16 #include "mozilla/CheckedInt.h"
     17 #include "mozilla/MemoryReporting.h"  // for MallocSizeOf
     18 
     19 namespace mozilla {
     20 namespace gfx {
     21 
     22 static inline bool IsOperatorBoundByMask(CompositionOp aOp) {
     23  switch (aOp) {
     24    case CompositionOp::OP_IN:
     25    case CompositionOp::OP_OUT:
     26    case CompositionOp::OP_DEST_IN:
     27    case CompositionOp::OP_DEST_ATOP:
     28    case CompositionOp::OP_SOURCE:
     29      return false;
     30    default:
     31      return true;
     32  }
     33 }
     34 
     35 template <class T>
     36 struct ClassStorage {
     37  char bytes[sizeof(T)];
     38 
     39  const T* addr() const { return (const T*)bytes; }
     40  T* addr() { return (T*)(void*)bytes; }
     41 };
     42 
     43 static inline bool FuzzyEqual(Float aA, Float aB, Float aErr) {
     44  if ((aA + aErr >= aB) && (aA - aErr <= aB)) {
     45    return true;
     46  }
     47  return false;
     48 }
     49 
     50 static inline void NudgeToInteger(float* aVal) {
     51  float r = floorf(*aVal + 0.5f);
     52  // The error threshold should be proportional to the rounded value. This
     53  // bounds the relative error introduced by the nudge operation. However,
     54  // when the rounded value is 0, the error threshold can't be proportional
     55  // to the rounded value (we'd never round), so we just choose the same
     56  // threshold as for a rounded value of 1.
     57  if (FuzzyEqual(r, *aVal, r == 0.0f ? 1e-6f : fabs(r * 1e-6f))) {
     58    *aVal = r;
     59  }
     60 }
     61 
     62 static inline void NudgeToInteger(float* aVal, float aErr) {
     63  float r = floorf(*aVal + 0.5f);
     64  if (FuzzyEqual(r, *aVal, aErr)) {
     65    *aVal = r;
     66  }
     67 }
     68 
     69 static inline void NudgeToInteger(double* aVal) {
     70  float f = float(*aVal);
     71  NudgeToInteger(&f);
     72  *aVal = f;
     73 }
     74 
     75 static inline Float Distance(Point aA, Point aB) {
     76  return hypotf(aB.x - aA.x, aB.y - aA.y);
     77 }
     78 
     79 template <typename T, int alignment = 16>
     80 struct AlignedArray final {
     81  typedef T value_type;
     82 
     83  AlignedArray() : mPtr(nullptr), mStorage(nullptr), mCount(0) {}
     84 
     85  explicit MOZ_ALWAYS_INLINE AlignedArray(size_t aCount, bool aZero = false)
     86      : mPtr(nullptr), mStorage(nullptr), mCount(0) {
     87    Realloc(aCount, aZero);
     88  }
     89 
     90  MOZ_ALWAYS_INLINE ~AlignedArray() { Dealloc(); }
     91 
     92  void Dealloc() {
     93    // If we fail this assert we'll need to uncomment the loop below to make
     94    // sure dtors are properly invoked. If we do that, we should check that the
     95    // comment about compiler dead code elimination is in fact true for all the
     96    // compilers that we care about.
     97    static_assert(std::is_trivially_destructible<T>::value,
     98                  "Destructors must be invoked for this type");
     99 #if 0
    100    for (size_t i = 0; i < mCount; ++i) {
    101      // Since we used the placement |operator new| function to construct the
    102      // elements of this array we need to invoke their destructors manually.
    103      // For types where the destructor does nothing the compiler's dead code
    104      // elimination step should optimize this loop away.
    105      mPtr[i].~T();
    106    }
    107 #endif
    108 
    109    free(mStorage);
    110    mStorage = nullptr;
    111    mPtr = nullptr;
    112  }
    113 
    114  MOZ_ALWAYS_INLINE void Realloc(size_t aCount, bool aZero = false) {
    115    free(mStorage);
    116    CheckedInt32 storageByteCount =
    117        CheckedInt32(sizeof(T)) * aCount + (alignment - 1);
    118    if (!storageByteCount.isValid()) {
    119      mStorage = nullptr;
    120      mPtr = nullptr;
    121      mCount = 0;
    122      return;
    123    }
    124    // We don't create an array of T here, since we don't want ctors to be
    125    // invoked at the wrong places if we realign below.
    126    if (aZero) {
    127      // calloc can be more efficient than new[] for large chunks,
    128      // so we use calloc/malloc/free for everything.
    129      mStorage = static_cast<uint8_t*>(calloc(1u, storageByteCount.value()));
    130    } else {
    131      mStorage = static_cast<uint8_t*>(malloc(storageByteCount.value()));
    132    }
    133    if (!mStorage) {
    134      mStorage = nullptr;
    135      mPtr = nullptr;
    136      mCount = 0;
    137      return;
    138    }
    139    if (uintptr_t(mStorage) % alignment) {
    140      // Our storage does not start at a <alignment>-byte boundary. Make sure
    141      // mPtr does!
    142      mPtr = (T*)(uintptr_t(mStorage) + alignment -
    143                  (uintptr_t(mStorage) % alignment));
    144    } else {
    145      mPtr = (T*)(mStorage);
    146    }
    147    // Now that mPtr is pointing to the aligned position we can use placement
    148    // |operator new| to invoke any ctors at the correct positions. For types
    149    // that have a no-op default constructor the compiler's dead code
    150    // elimination step should optimize this away.
    151    mPtr = new (mPtr) T[aCount];
    152    mCount = aCount;
    153  }
    154 
    155  void Swap(AlignedArray<T, alignment>& aOther) {
    156    std::swap(mPtr, aOther.mPtr);
    157    std::swap(mStorage, aOther.mStorage);
    158    std::swap(mCount, aOther.mCount);
    159  }
    160 
    161  size_t HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    162    return aMallocSizeOf(mStorage);
    163  }
    164 
    165  MOZ_ALWAYS_INLINE operator T*() { return mPtr; }
    166 
    167  T* mPtr;
    168 
    169 private:
    170  uint8_t* mStorage;
    171  size_t mCount;
    172 };
    173 
    174 /**
    175 * Returns aWidth * aBytesPerPixel increased, if necessary, so that it divides
    176 * exactly into |alignment|.
    177 *
    178 * Note that currently |alignment| must be a power-of-2. If for some reason we
    179 * want to support NPOT alignment we can revert back to this functions old
    180 * implementation.
    181 */
    182 template <int alignment>
    183 int32_t GetAlignedStride(int32_t aWidth, int32_t aBytesPerPixel) {
    184  static_assert(alignment > 0 && (alignment & (alignment - 1)) == 0,
    185                "This implementation currently require power-of-two alignment");
    186  const int32_t mask = alignment - 1;
    187  CheckedInt32 stride =
    188      CheckedInt32(aWidth) * CheckedInt32(aBytesPerPixel) + CheckedInt32(mask);
    189  if (stride.isValid()) {
    190    return stride.value() & ~mask;
    191  }
    192  return 0;
    193 }
    194 
    195 }  // namespace gfx
    196 }  // namespace mozilla
    197 
    198 #endif /* MOZILLA_GFX_TOOLS_H_ */