tor-browser

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

TrailingArray.h (2952B)


      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 util_TrailingArray_h
      8 #define util_TrailingArray_h
      9 
     10 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     11 
     12 #include <stddef.h>  // size_t
     13 #include <stdint.h>  // uint32_t, uintptr_t
     14 
     15 namespace js {
     16 
     17 // This is a mixin class to use for types that have trailing arrays and use
     18 // offsets to delimit them. It provides helper methods to do casting and
     19 // initialization while avoiding C++ undefined behaviour.
     20 template <typename Base>
     21 class TrailingArray {
     22 protected:
     23  // Offsets are measured in bytes relative to 'this'.
     24  using Offset = uint32_t;
     25 
     26  // Test if offset is correctly aligned for type.
     27  template <typename T>
     28  static constexpr bool isAlignedOffset(Offset offset) {
     29    return offset % alignof(T) == 0;
     30  }
     31  template <size_t N>
     32  static constexpr bool isAlignedOffset(Offset offset) {
     33    return offset % N == 0;
     34  }
     35 
     36  // Translate an offset into a concrete pointer.
     37  template <typename T>
     38  T* offsetToPointer(Offset offset) {
     39    uintptr_t base = reinterpret_cast<uintptr_t>(static_cast<Base*>(this));
     40    return reinterpret_cast<T*>(base + offset);
     41  }
     42  template <typename T>
     43  const T* offsetToPointer(Offset offset) const {
     44    uintptr_t base =
     45        reinterpret_cast<uintptr_t>(static_cast<const Base*>(this));
     46    return reinterpret_cast<const T*>(base + offset);
     47  }
     48 
     49  // Placement-new the elements of an array. This optimizes away for types with
     50  // trivial default initialization and plays nicely with compiler vectorization
     51  // passes.
     52  template <typename T>
     53  void initElements(Offset offset, size_t nelem) {
     54    MOZ_ASSERT(isAlignedOffset<T>(offset));
     55 
     56    // Address of first array element.
     57    uintptr_t elem =
     58        reinterpret_cast<uintptr_t>(static_cast<Base*>(this)) + offset;
     59 
     60    for (size_t i = 0; i < nelem; ++i) {
     61      void* raw = reinterpret_cast<void*>(elem);
     62      new (raw) T;
     63      elem += sizeof(T);
     64    }
     65  }
     66 
     67  // Compute the length of an array from its start and end offset.
     68  template <typename T>
     69  size_t numElements(Offset start, Offset end) const {
     70    constexpr size_t ElemSize = sizeof(T);
     71    return numElements<ElemSize>(start, end);
     72  }
     73  template <size_t ElemSize>
     74  size_t numElements(Offset start, Offset end) const {
     75    MOZ_ASSERT(start <= end);
     76    MOZ_ASSERT((end - start) % ElemSize == 0);
     77    return (end - start) / ElemSize;
     78  }
     79 
     80  // Constructor is protected so a derived type is required.
     81  TrailingArray() = default;
     82 
     83 public:
     84  // Type has trailing data so isn't copyable or movable.
     85  TrailingArray(const TrailingArray&) = delete;
     86  TrailingArray& operator=(const TrailingArray&) = delete;
     87 };
     88 
     89 }  // namespace js
     90 
     91 #endif  // util_TrailingArray_h