tor-browser

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

ProfileBufferEntrySerialization.h (44225B)


      1 /* -*- Mode: C++; tab-width: 2; 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 ProfileBufferEntrySerialization_h
      8 #define ProfileBufferEntrySerialization_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/leb128iterator.h"
     12 #include "mozilla/Likely.h"
     13 #include "mozilla/Maybe.h"
     14 #include "mozilla/ProfileBufferIndex.h"
     15 #include "mozilla/Span.h"
     16 #include "mozilla/UniquePtrExtensions.h"
     17 #include "mozilla/Variant.h"
     18 
     19 #include <string>
     20 #include <tuple>
     21 
     22 namespace mozilla {
     23 
     24 class ProfileBufferEntryWriter;
     25 
     26 // Iterator-like class used to read from an entry.
     27 // An entry may be split in two memory segments (e.g., the ends of a ring
     28 // buffer, or two chunks of a chunked buffer); it doesn't deal with this
     29 // underlying buffer, but only with one or two spans pointing at the space
     30 // where the entry lives.
     31 class ProfileBufferEntryReader {
     32 public:
     33  using Byte = uint8_t;
     34  using Length = uint32_t;
     35 
     36  using SpanOfConstBytes = Span<const Byte>;
     37 
     38  // Class to be specialized for types to be read from a profile buffer entry.
     39  // See common specializations at the bottom of this header.
     40  // The following static functions must be provided:
     41  //   static void ReadInto(EntryReader aER&, T& aT)
     42  //   {
     43  //     /* Call `aER.ReadX(...)` function to deserialize into aT, be sure to
     44  //        read exactly `Bytes(aT)`! */
     45  //   }
     46  //   static T Read(EntryReader& aER) {
     47  //     /* Call `aER.ReadX(...)` function to deserialize and return a `T`, be
     48  //        sure to read exactly `Bytes(returned value)`! */
     49  //   }
     50  template <typename T>
     51  struct Deserializer;
     52 
     53  ProfileBufferEntryReader() = default;
     54 
     55  // Reader over one Span.
     56  ProfileBufferEntryReader(SpanOfConstBytes aSpan,
     57                           ProfileBufferBlockIndex aCurrentBlockIndex,
     58                           ProfileBufferBlockIndex aNextBlockIndex)
     59      : mCurrentSpan(aSpan),
     60        mNextSpanOrEmpty(aSpan.Last(0)),
     61        mCurrentBlockIndex(aCurrentBlockIndex),
     62        mNextBlockIndex(aNextBlockIndex) {
     63    // 2nd internal Span points at the end of the 1st internal Span, to enforce
     64    // invariants.
     65    CheckInvariants();
     66  }
     67 
     68  // Reader over two Spans, the second one must not be empty.
     69  ProfileBufferEntryReader(SpanOfConstBytes aSpanHead,
     70                           SpanOfConstBytes aSpanTail,
     71                           ProfileBufferBlockIndex aCurrentBlockIndex,
     72                           ProfileBufferBlockIndex aNextBlockIndex)
     73      : mCurrentSpan(aSpanHead),
     74        mNextSpanOrEmpty(aSpanTail),
     75        mCurrentBlockIndex(aCurrentBlockIndex),
     76        mNextBlockIndex(aNextBlockIndex) {
     77    MOZ_RELEASE_ASSERT(!mNextSpanOrEmpty.IsEmpty());
     78    if (MOZ_UNLIKELY(mCurrentSpan.IsEmpty())) {
     79      // First span is already empty, skip it.
     80      mCurrentSpan = mNextSpanOrEmpty;
     81      mNextSpanOrEmpty = mNextSpanOrEmpty.Last(0);
     82    }
     83    CheckInvariants();
     84  }
     85 
     86  // Allow copying, which is needed when used as an iterator in some std
     87  // functions (e.g., string assignment), and to occasionally backtrack.
     88  // Be aware that the main profile buffer APIs give a reference to an entry
     89  // reader, and expect that reader to advance to the end of the entry, so don't
     90  // just advance copies!
     91  ProfileBufferEntryReader(const ProfileBufferEntryReader&) = default;
     92  ProfileBufferEntryReader& operator=(const ProfileBufferEntryReader&) =
     93      default;
     94 
     95  // Don't =default moving, as it doesn't bring any benefit in this class.
     96 
     97  [[nodiscard]] Length RemainingBytes() const {
     98    return mCurrentSpan.LengthBytes() + mNextSpanOrEmpty.LengthBytes();
     99  }
    100 
    101  void SetRemainingBytes(Length aBytes) {
    102    MOZ_RELEASE_ASSERT(aBytes <= RemainingBytes());
    103    if (aBytes <= mCurrentSpan.LengthBytes()) {
    104      mCurrentSpan = mCurrentSpan.First(aBytes);
    105      mNextSpanOrEmpty = mCurrentSpan.Last(0);
    106    } else {
    107      mNextSpanOrEmpty =
    108          mNextSpanOrEmpty.First(aBytes - mCurrentSpan.LengthBytes());
    109    }
    110  }
    111 
    112  [[nodiscard]] ProfileBufferBlockIndex CurrentBlockIndex() const {
    113    return mCurrentBlockIndex;
    114  }
    115 
    116  [[nodiscard]] ProfileBufferBlockIndex NextBlockIndex() const {
    117    return mNextBlockIndex;
    118  }
    119 
    120  // Create a reader of size zero, pointing at aOffset past the current position
    121  // of this Reader, so it can be used as end iterator.
    122  [[nodiscard]] ProfileBufferEntryReader EmptyIteratorAtOffset(
    123      Length aOffset) const {
    124    MOZ_RELEASE_ASSERT(aOffset <= RemainingBytes());
    125    if (MOZ_LIKELY(aOffset < mCurrentSpan.LengthBytes())) {
    126      // aOffset is before the end of mCurrentSpan.
    127      return ProfileBufferEntryReader(mCurrentSpan.Subspan(aOffset, 0),
    128                                      mCurrentBlockIndex, mNextBlockIndex);
    129    }
    130    // aOffset is right at the end of mCurrentSpan, or inside mNextSpanOrEmpty.
    131    return ProfileBufferEntryReader(
    132        mNextSpanOrEmpty.Subspan(aOffset - mCurrentSpan.LengthBytes(), 0),
    133        mCurrentBlockIndex, mNextBlockIndex);
    134  }
    135 
    136  // Be like a limited input iterator, with only `*`, prefix-`++`, `==`, `!=`.
    137  // These definitions are expected by std functions, to recognize this as an
    138  // iterator. See https://en.cppreference.com/w/cpp/iterator/iterator_traits
    139  using difference_type = std::make_signed_t<Length>;
    140  using value_type = Byte;
    141  using pointer = const Byte*;
    142  using reference = const Byte&;
    143  using iterator_category = std::input_iterator_tag;
    144 
    145  [[nodiscard]] const Byte& operator*() {
    146    // Assume the caller will read from the returned reference (and not just
    147    // take the address).
    148    MOZ_RELEASE_ASSERT(mCurrentSpan.LengthBytes() >= 1);
    149    return *(mCurrentSpan.Elements());
    150  }
    151 
    152  ProfileBufferEntryReader& operator++() {
    153    MOZ_RELEASE_ASSERT(mCurrentSpan.LengthBytes() >= 1);
    154    if (MOZ_LIKELY(mCurrentSpan.LengthBytes() > 1)) {
    155      // More than 1 byte left in mCurrentSpan, just eat it.
    156      mCurrentSpan = mCurrentSpan.From(1);
    157    } else {
    158      // mCurrentSpan will be empty, move mNextSpanOrEmpty to mCurrentSpan.
    159      mCurrentSpan = mNextSpanOrEmpty;
    160      mNextSpanOrEmpty = mNextSpanOrEmpty.Last(0);
    161    }
    162    CheckInvariants();
    163    return *this;
    164  }
    165 
    166  ProfileBufferEntryReader& operator+=(Length aBytes) {
    167    MOZ_RELEASE_ASSERT(aBytes <= RemainingBytes());
    168    if (MOZ_LIKELY(aBytes <= mCurrentSpan.LengthBytes())) {
    169      // All bytes are in mCurrentSpan.
    170      // Update mCurrentSpan past the read bytes.
    171      mCurrentSpan = mCurrentSpan.From(aBytes);
    172      if (mCurrentSpan.IsEmpty() && !mNextSpanOrEmpty.IsEmpty()) {
    173        // Don't leave mCurrentSpan empty, move non-empty mNextSpanOrEmpty into
    174        // mCurrentSpan.
    175        mCurrentSpan = mNextSpanOrEmpty;
    176        mNextSpanOrEmpty = mNextSpanOrEmpty.Last(0);
    177      }
    178    } else {
    179      // mCurrentSpan does not hold enough bytes.
    180      // This should only happen at most once: Only for double spans, and when
    181      // data crosses the gap.
    182      const Length tail =
    183          aBytes - static_cast<Length>(mCurrentSpan.LengthBytes());
    184      // Move mNextSpanOrEmpty to mCurrentSpan, past the data. So the next call
    185      // will go back to the true case above.
    186      mCurrentSpan = mNextSpanOrEmpty.From(tail);
    187      mNextSpanOrEmpty = mNextSpanOrEmpty.Last(0);
    188    }
    189    CheckInvariants();
    190    return *this;
    191  }
    192 
    193  [[nodiscard]] bool operator==(const ProfileBufferEntryReader& aOther) const {
    194    return mCurrentSpan.Elements() == aOther.mCurrentSpan.Elements();
    195  }
    196  [[nodiscard]] bool operator!=(const ProfileBufferEntryReader& aOther) const {
    197    return mCurrentSpan.Elements() != aOther.mCurrentSpan.Elements();
    198  }
    199 
    200  // Read an unsigned LEB128 number and move iterator ahead.
    201  template <typename T>
    202  [[nodiscard]] T ReadULEB128() {
    203    return ::mozilla::ReadULEB128<T>(*this);
    204  }
    205 
    206  // This struct points at a number of bytes through either one span, or two
    207  // separate spans (in the rare cases when it is split between two chunks).
    208  // So the possibilities are:
    209  // - Totally empty: { [] [] }
    210  // - First span is not empty: { [content] [] } (Most common case.)
    211  // - Both spans are not empty: { [cont] [ent] }
    212  // But something like { [] [content] } is not possible.
    213  //
    214  // Recommended usage patterns:
    215  // - Call a utility function like `CopyBytesTo` if you always need to copy the
    216  //   data to an outside buffer, e.g., to deserialize an aligned object.
    217  // - Access both spans one after the other; Note that the second one may be
    218  //   empty; and the fist could be empty as well if there is no data at all.
    219  // - Check is the second span is empty, in which case you only need to read
    220  //   the first one; and since its part of a chunk, it may be directly passed
    221  //   as an unaligned pointer or reference, thereby saving one copy. But
    222  //   remember to always handle the double-span case as well.
    223  //
    224  // Reminder: An empty span still has a non-null pointer, so it's safe to use
    225  // with functions like memcpy.
    226  struct DoubleSpanOfConstBytes {
    227    SpanOfConstBytes mFirstOrOnly;
    228    SpanOfConstBytes mSecondOrEmpty;
    229 
    230    void CheckInvariants() const {
    231      MOZ_ASSERT(mFirstOrOnly.IsEmpty() ? mSecondOrEmpty.IsEmpty() : true,
    232                 "mSecondOrEmpty should not be the only span to contain data");
    233    }
    234 
    235    DoubleSpanOfConstBytes() : mFirstOrOnly(), mSecondOrEmpty() {
    236      CheckInvariants();
    237    }
    238 
    239    DoubleSpanOfConstBytes(const Byte* aOnlyPointer, size_t aOnlyLength)
    240        : mFirstOrOnly(aOnlyPointer, aOnlyLength), mSecondOrEmpty() {
    241      CheckInvariants();
    242    }
    243 
    244    DoubleSpanOfConstBytes(const Byte* aFirstPointer, size_t aFirstLength,
    245                           const Byte* aSecondPointer, size_t aSecondLength)
    246        : mFirstOrOnly(aFirstPointer, aFirstLength),
    247          mSecondOrEmpty(aSecondPointer, aSecondLength) {
    248      CheckInvariants();
    249    }
    250 
    251    // Is there no data at all?
    252    [[nodiscard]] bool IsEmpty() const {
    253      // We only need to check the first span, because if it's empty, the second
    254      // one must be empty as well.
    255      return mFirstOrOnly.IsEmpty();
    256    }
    257 
    258    // Total length (in bytes) pointed at by both spans.
    259    [[nodiscard]] size_t LengthBytes() const {
    260      return mFirstOrOnly.LengthBytes() + mSecondOrEmpty.LengthBytes();
    261    }
    262 
    263    // Utility functions to copy all `LengthBytes()` to a given buffer.
    264    void CopyBytesTo(void* aDest) const {
    265      memcpy(aDest, mFirstOrOnly.Elements(), mFirstOrOnly.LengthBytes());
    266      if (MOZ_UNLIKELY(!mSecondOrEmpty.IsEmpty())) {
    267        memcpy(static_cast<Byte*>(aDest) + mFirstOrOnly.LengthBytes(),
    268               mSecondOrEmpty.Elements(), mSecondOrEmpty.LengthBytes());
    269      }
    270    }
    271 
    272    // If the second span is empty, only the first span may point at data.
    273    [[nodiscard]] bool IsSingleSpan() const { return mSecondOrEmpty.IsEmpty(); }
    274  };
    275 
    276  // Get Span(s) to a sequence of bytes, see `DoubleSpanOfConstBytes` for usage.
    277  // Note that the reader location is *not* updated, do `+=` on it afterwards.
    278  [[nodiscard]] DoubleSpanOfConstBytes PeekSpans(Length aBytes) const {
    279    MOZ_RELEASE_ASSERT(aBytes <= RemainingBytes());
    280    if (MOZ_LIKELY(aBytes <= mCurrentSpan.LengthBytes())) {
    281      // All `aBytes` are in the current chunk, only one span is needed.
    282      return DoubleSpanOfConstBytes{mCurrentSpan.Elements(), aBytes};
    283    }
    284    // Otherwise the first span covers then end of the current chunk, and the
    285    // second span starts in the next chunk.
    286    return DoubleSpanOfConstBytes{
    287        mCurrentSpan.Elements(), mCurrentSpan.LengthBytes(),
    288        mNextSpanOrEmpty.Elements(), aBytes - mCurrentSpan.LengthBytes()};
    289  }
    290 
    291  // Get Span(s) to a sequence of bytes, see `DoubleSpanOfConstBytes` for usage,
    292  // and move the reader forward.
    293  [[nodiscard]] DoubleSpanOfConstBytes ReadSpans(Length aBytes) {
    294    DoubleSpanOfConstBytes spans = PeekSpans(aBytes);
    295    (*this) += aBytes;
    296    return spans;
    297  }
    298 
    299  // Read a sequence of bytes, like memcpy.
    300  void ReadBytes(void* aDest, Length aBytes) {
    301    DoubleSpanOfConstBytes spans = ReadSpans(aBytes);
    302    MOZ_ASSERT(spans.LengthBytes() == aBytes);
    303    spans.CopyBytesTo(aDest);
    304  }
    305 
    306  template <typename T>
    307  void ReadIntoObject(T& aObject) {
    308    Deserializer<T>::ReadInto(*this, aObject);
    309  }
    310 
    311  // Read into one or more objects, sequentially.
    312  // `EntryReader::ReadIntoObjects()` with nothing is implicitly allowed, this
    313  // could be useful for generic programming.
    314  template <typename... Ts>
    315  void ReadIntoObjects(Ts&... aTs) {
    316    (ReadIntoObject(aTs), ...);
    317  }
    318 
    319  // Read data as an object and move iterator ahead.
    320  template <typename T>
    321  [[nodiscard]] T ReadObject() {
    322    T ob = Deserializer<T>::Read(*this);
    323    return ob;
    324  }
    325 
    326 private:
    327  friend class ProfileBufferEntryWriter;
    328 
    329  // Invariants:
    330  // - mCurrentSpan cannot be empty unless mNextSpanOrEmpty is also empty. So
    331  //   mCurrentSpan always points at the next byte to read or the end.
    332  // - If mNextSpanOrEmpty is empty, it points at the end of mCurrentSpan. So
    333  //   when reaching the end of mCurrentSpan, we can blindly move
    334  //   mNextSpanOrEmpty to mCurrentSpan and keep the invariants.
    335  SpanOfConstBytes mCurrentSpan;
    336  SpanOfConstBytes mNextSpanOrEmpty;
    337  ProfileBufferBlockIndex mCurrentBlockIndex;
    338  ProfileBufferBlockIndex mNextBlockIndex;
    339 
    340  void CheckInvariants() const {
    341    MOZ_ASSERT(!mCurrentSpan.IsEmpty() || mNextSpanOrEmpty.IsEmpty());
    342    MOZ_ASSERT(!mNextSpanOrEmpty.IsEmpty() ||
    343               (mNextSpanOrEmpty == mCurrentSpan.Last(0)));
    344  }
    345 };
    346 
    347 // Iterator-like class used to write into an entry.
    348 // An entry may be split in two memory segments (e.g., the ends of a ring
    349 // buffer, or two chunks of a chunked buffer); it doesn't deal with this
    350 // underlying buffer, but only with one or two spans pointing at the space
    351 // reserved for the entry.
    352 class ProfileBufferEntryWriter {
    353 public:
    354  using Byte = uint8_t;
    355  using Length = uint32_t;
    356 
    357  using SpanOfBytes = Span<Byte>;
    358 
    359  // Class to be specialized for types to be written in an entry.
    360  // See common specializations at the bottom of this header.
    361  // The following static functions must be provided:
    362  //   static Length Bytes(const T& aT) {
    363  //     /* Return number of bytes that will be written. */
    364  //   }
    365  //   static void Write(ProfileBufferEntryWriter& aEW,
    366  //                     const T& aT) {
    367  //     /* Call `aEW.WriteX(...)` functions to serialize aT, be sure to write
    368  //        exactly `Bytes(aT)` bytes! */
    369  //   }
    370  template <typename T>
    371  struct Serializer;
    372 
    373  ProfileBufferEntryWriter() = default;
    374 
    375  ProfileBufferEntryWriter(SpanOfBytes aSpan,
    376                           ProfileBufferBlockIndex aCurrentBlockIndex,
    377                           ProfileBufferBlockIndex aNextBlockIndex)
    378      : mCurrentSpan(aSpan),
    379        mCurrentBlockIndex(aCurrentBlockIndex),
    380        mNextBlockIndex(aNextBlockIndex) {}
    381 
    382  ProfileBufferEntryWriter(SpanOfBytes aSpanHead, SpanOfBytes aSpanTail,
    383                           ProfileBufferBlockIndex aCurrentBlockIndex,
    384                           ProfileBufferBlockIndex aNextBlockIndex)
    385      : mCurrentSpan(aSpanHead),
    386        mNextSpanOrEmpty(aSpanTail),
    387        mCurrentBlockIndex(aCurrentBlockIndex),
    388        mNextBlockIndex(aNextBlockIndex) {
    389    // Either:
    390    // - mCurrentSpan is not empty, OR
    391    // - mNextSpanOrEmpty is empty if mNextSpanOrEmpty is empty as well.
    392    MOZ_RELEASE_ASSERT(!mCurrentSpan.IsEmpty() || mNextSpanOrEmpty.IsEmpty());
    393  }
    394 
    395  // Disable copying and moving, so we can't have multiple writing heads.
    396  ProfileBufferEntryWriter(const ProfileBufferEntryWriter&) = delete;
    397  ProfileBufferEntryWriter& operator=(const ProfileBufferEntryWriter&) = delete;
    398  ProfileBufferEntryWriter(ProfileBufferEntryWriter&&) = delete;
    399  ProfileBufferEntryWriter& operator=(ProfileBufferEntryWriter&&) = delete;
    400 
    401  void Set() {
    402    mCurrentSpan = SpanOfBytes{};
    403    mNextSpanOrEmpty = SpanOfBytes{};
    404    mCurrentBlockIndex = nullptr;
    405    mNextBlockIndex = nullptr;
    406  }
    407 
    408  void Set(SpanOfBytes aSpan, ProfileBufferBlockIndex aCurrentBlockIndex,
    409           ProfileBufferBlockIndex aNextBlockIndex) {
    410    mCurrentSpan = aSpan;
    411    mNextSpanOrEmpty = SpanOfBytes{};
    412    mCurrentBlockIndex = aCurrentBlockIndex;
    413    mNextBlockIndex = aNextBlockIndex;
    414  }
    415 
    416  void Set(SpanOfBytes aSpan0, SpanOfBytes aSpan1,
    417           ProfileBufferBlockIndex aCurrentBlockIndex,
    418           ProfileBufferBlockIndex aNextBlockIndex) {
    419    mCurrentSpan = aSpan0;
    420    mNextSpanOrEmpty = aSpan1;
    421    mCurrentBlockIndex = aCurrentBlockIndex;
    422    mNextBlockIndex = aNextBlockIndex;
    423    // Either:
    424    // - mCurrentSpan is not empty, OR
    425    // - mNextSpanOrEmpty is empty if mNextSpanOrEmpty is empty as well.
    426    MOZ_RELEASE_ASSERT(!mCurrentSpan.IsEmpty() || mNextSpanOrEmpty.IsEmpty());
    427  }
    428 
    429  [[nodiscard]] Length RemainingBytes() const {
    430    return mCurrentSpan.LengthBytes() + mNextSpanOrEmpty.LengthBytes();
    431  }
    432 
    433  [[nodiscard]] ProfileBufferBlockIndex CurrentBlockIndex() const {
    434    return mCurrentBlockIndex;
    435  }
    436 
    437  [[nodiscard]] ProfileBufferBlockIndex NextBlockIndex() const {
    438    return mNextBlockIndex;
    439  }
    440 
    441  // Be like a limited output iterator, with only `*` and prefix-`++`.
    442  // These definitions are expected by std functions, to recognize this as an
    443  // iterator. See https://en.cppreference.com/w/cpp/iterator/iterator_traits
    444  using value_type = Byte;
    445  using pointer = Byte*;
    446  using reference = Byte&;
    447  using iterator_category = std::output_iterator_tag;
    448 
    449  [[nodiscard]] Byte& operator*() {
    450    MOZ_RELEASE_ASSERT(RemainingBytes() >= 1);
    451    return *(
    452        (MOZ_LIKELY(!mCurrentSpan.IsEmpty()) ? mCurrentSpan : mNextSpanOrEmpty)
    453            .Elements());
    454  }
    455 
    456  ProfileBufferEntryWriter& operator++() {
    457    if (MOZ_LIKELY(mCurrentSpan.LengthBytes() >= 1)) {
    458      // There is at least 1 byte in mCurrentSpan, eat it.
    459      mCurrentSpan = mCurrentSpan.From(1);
    460    } else {
    461      // mCurrentSpan is empty, move mNextSpanOrEmpty (past the first byte) to
    462      // mCurrentSpan.
    463      MOZ_RELEASE_ASSERT(mNextSpanOrEmpty.LengthBytes() >= 1);
    464      mCurrentSpan = mNextSpanOrEmpty.From(1);
    465      mNextSpanOrEmpty = mNextSpanOrEmpty.First(0);
    466    }
    467    return *this;
    468  }
    469 
    470  ProfileBufferEntryWriter& operator+=(Length aBytes) {
    471    // Note: This is a rare operation. The code below is a copy of `WriteBytes`
    472    // but without the `memcpy`s.
    473    MOZ_RELEASE_ASSERT(aBytes <= RemainingBytes());
    474    if (MOZ_LIKELY(aBytes <= mCurrentSpan.LengthBytes())) {
    475      // Data fits in mCurrentSpan.
    476      // Update mCurrentSpan. It may become empty, so in case of a double span,
    477      // the next call will go to the false case below.
    478      mCurrentSpan = mCurrentSpan.From(aBytes);
    479    } else {
    480      // Data does not fully fit in mCurrentSpan.
    481      // This should only happen at most once: Only for double spans, and when
    482      // data crosses the gap or starts there.
    483      const Length tail =
    484          aBytes - static_cast<Length>(mCurrentSpan.LengthBytes());
    485      // Move mNextSpanOrEmpty to mCurrentSpan, past the data. So the next call
    486      // will go back to the true case above.
    487      mCurrentSpan = mNextSpanOrEmpty.From(tail);
    488      mNextSpanOrEmpty = mNextSpanOrEmpty.First(0);
    489    }
    490    return *this;
    491  }
    492 
    493  // Number of bytes needed to represent `aValue` in unsigned LEB128.
    494  template <typename T>
    495  [[nodiscard]] static unsigned ULEB128Size(T aValue) {
    496    return ::mozilla::ULEB128Size(aValue);
    497  }
    498 
    499  // Write number as unsigned LEB128 and move iterator ahead.
    500  template <typename T>
    501  void WriteULEB128(T aValue) {
    502    ::mozilla::WriteULEB128(aValue, *this);
    503  }
    504 
    505  // Number of bytes needed to serialize objects.
    506  template <typename... Ts>
    507  [[nodiscard]] static Length SumBytes(const Ts&... aTs) {
    508    return (0 + ... + Serializer<Ts>::Bytes(aTs));
    509  }
    510 
    511  // Write a sequence of bytes, like memcpy.
    512  void WriteBytes(const void* aSrc, Length aBytes) {
    513    MOZ_RELEASE_ASSERT(aBytes <= RemainingBytes());
    514    if (MOZ_LIKELY(aBytes <= mCurrentSpan.LengthBytes())) {
    515      // Data fits in mCurrentSpan.
    516      memcpy(mCurrentSpan.Elements(), aSrc, aBytes);
    517      // Update mCurrentSpan. It may become empty, so in case of a double span,
    518      // the next call will go to the false case below.
    519      mCurrentSpan = mCurrentSpan.From(aBytes);
    520    } else {
    521      // Data does not fully fit in mCurrentSpan.
    522      // This should only happen at most once: Only for double spans, and when
    523      // data crosses the gap or starts there.
    524      // Split data between the end of mCurrentSpan and the beginning of
    525      // mNextSpanOrEmpty. (mCurrentSpan could be empty, it's ok to do a memcpy
    526      // because Span::Elements() is never null.)
    527      memcpy(mCurrentSpan.Elements(), aSrc, mCurrentSpan.LengthBytes());
    528      const Length tail =
    529          aBytes - static_cast<Length>(mCurrentSpan.LengthBytes());
    530      memcpy(mNextSpanOrEmpty.Elements(),
    531             reinterpret_cast<const Byte*>(aSrc) + mCurrentSpan.LengthBytes(),
    532             tail);
    533      // Move mNextSpanOrEmpty to mCurrentSpan, past the data. So the next call
    534      // will go back to the true case above.
    535      mCurrentSpan = mNextSpanOrEmpty.From(tail);
    536      mNextSpanOrEmpty = mNextSpanOrEmpty.First(0);
    537    }
    538  }
    539 
    540  void WriteFromReader(ProfileBufferEntryReader& aReader, Length aBytes) {
    541    MOZ_RELEASE_ASSERT(aBytes <= RemainingBytes());
    542    MOZ_RELEASE_ASSERT(aBytes <= aReader.RemainingBytes());
    543    Length read0 = std::min(
    544        aBytes, static_cast<Length>(aReader.mCurrentSpan.LengthBytes()));
    545    if (read0 != 0) {
    546      WriteBytes(aReader.mCurrentSpan.Elements(), read0);
    547    }
    548    Length read1 = aBytes - read0;
    549    if (read1 != 0) {
    550      WriteBytes(aReader.mNextSpanOrEmpty.Elements(), read1);
    551    }
    552    aReader += aBytes;
    553  }
    554 
    555  // Write a single object by using the appropriate Serializer.
    556  template <typename T>
    557  void WriteObject(const T& aObject) {
    558    Serializer<T>::Write(*this, aObject);
    559  }
    560 
    561  // Write one or more objects, sequentially.
    562  // Allow `EntryWrite::WriteObjects()` with nothing, this could be useful
    563  // for generic programming.
    564  template <typename... Ts>
    565  void WriteObjects(const Ts&... aTs) {
    566    (WriteObject(aTs), ...);
    567  }
    568 
    569 private:
    570  // The two spans covering the memory still to be written.
    571  SpanOfBytes mCurrentSpan;
    572  SpanOfBytes mNextSpanOrEmpty;
    573  ProfileBufferBlockIndex mCurrentBlockIndex;
    574  ProfileBufferBlockIndex mNextBlockIndex;
    575 };
    576 
    577 // ============================================================================
    578 // Serializer and Deserializer ready-to-use specializations.
    579 
    580 // ----------------------------------------------------------------------------
    581 // Trivially-copyable types (default)
    582 
    583 // The default implementation works for all trivially-copyable types (e.g.,
    584 // PODs).
    585 //
    586 // Usage: `aEW.WriteObject(123);`.
    587 //
    588 // Raw pointers, though trivially-copyable, are explicitly forbidden when
    589 // writing (to avoid unexpected leaks/UAFs), instead use one of
    590 // `WrapProfileBufferLiteralCStringPointer`, `WrapProfileBufferUnownedCString`,
    591 // or `WrapProfileBufferRawPointer` as needed.
    592 template <typename T>
    593 struct ProfileBufferEntryWriter::Serializer {
    594  static_assert(std::is_trivially_copyable_v<T>,
    595                "Serializer only works with trivially-copyable types by "
    596                "default, use/add specialization for other types.");
    597 
    598  static constexpr Length Bytes(const T&) { return sizeof(T); }
    599 
    600  static void Write(ProfileBufferEntryWriter& aEW, const T& aT) {
    601    static_assert(!std::is_pointer<T>::value,
    602                  "Serializer won't write raw pointers by default, use "
    603                  "WrapProfileBufferRawPointer or other.");
    604    aEW.WriteBytes(&aT, sizeof(T));
    605  }
    606 };
    607 
    608 // Usage: `aER.ReadObject<int>();` or `int x; aER.ReadIntoObject(x);`.
    609 template <typename T>
    610 struct ProfileBufferEntryReader::Deserializer {
    611  static_assert(std::is_trivially_copyable_v<T>,
    612                "Deserializer only works with trivially-copyable types by "
    613                "default, use/add specialization for other types.");
    614 
    615  static void ReadInto(ProfileBufferEntryReader& aER, T& aT) {
    616    aER.ReadBytes(&aT, sizeof(T));
    617  }
    618 
    619  static T Read(ProfileBufferEntryReader& aER) {
    620    // Note that this creates a default `T` first, and then overwrites it with
    621    // bytes from the buffer. Trivially-copyable types support this without UB.
    622    T ob;
    623    ReadInto(aER, ob);
    624    return ob;
    625  }
    626 };
    627 
    628 // ----------------------------------------------------------------------------
    629 // Strip const/volatile/reference from types.
    630 
    631 // Automatically strip `const`.
    632 template <typename T>
    633 struct ProfileBufferEntryWriter::Serializer<const T>
    634    : public ProfileBufferEntryWriter::Serializer<T> {};
    635 
    636 template <typename T>
    637 struct ProfileBufferEntryReader::Deserializer<const T>
    638    : public ProfileBufferEntryReader::Deserializer<T> {};
    639 
    640 // Automatically strip `volatile`.
    641 template <typename T>
    642 struct ProfileBufferEntryWriter::Serializer<volatile T>
    643    : public ProfileBufferEntryWriter::Serializer<T> {};
    644 
    645 template <typename T>
    646 struct ProfileBufferEntryReader::Deserializer<volatile T>
    647    : public ProfileBufferEntryReader::Deserializer<T> {};
    648 
    649 // Automatically strip `lvalue-reference`.
    650 template <typename T>
    651 struct ProfileBufferEntryWriter::Serializer<T&>
    652    : public ProfileBufferEntryWriter::Serializer<T> {};
    653 
    654 template <typename T>
    655 struct ProfileBufferEntryReader::Deserializer<T&>
    656    : public ProfileBufferEntryReader::Deserializer<T> {};
    657 
    658 // Automatically strip `rvalue-reference`.
    659 template <typename T>
    660 struct ProfileBufferEntryWriter::Serializer<T&&>
    661    : public ProfileBufferEntryWriter::Serializer<T> {};
    662 
    663 template <typename T>
    664 struct ProfileBufferEntryReader::Deserializer<T&&>
    665    : public ProfileBufferEntryReader::Deserializer<T> {};
    666 
    667 // ----------------------------------------------------------------------------
    668 // ProfileBufferBlockIndex
    669 
    670 // ProfileBufferBlockIndex, serialized as the underlying value.
    671 template <>
    672 struct ProfileBufferEntryWriter::Serializer<ProfileBufferBlockIndex> {
    673  static constexpr Length Bytes(const ProfileBufferBlockIndex& aBlockIndex) {
    674    return sizeof(ProfileBufferBlockIndex);
    675  }
    676 
    677  static void Write(ProfileBufferEntryWriter& aEW,
    678                    const ProfileBufferBlockIndex& aBlockIndex) {
    679    aEW.WriteBytes(&aBlockIndex, sizeof(aBlockIndex));
    680  }
    681 };
    682 
    683 template <>
    684 struct ProfileBufferEntryReader::Deserializer<ProfileBufferBlockIndex> {
    685  static void ReadInto(ProfileBufferEntryReader& aER,
    686                       ProfileBufferBlockIndex& aBlockIndex) {
    687    aER.ReadBytes(&aBlockIndex, sizeof(aBlockIndex));
    688  }
    689 
    690  static ProfileBufferBlockIndex Read(ProfileBufferEntryReader& aER) {
    691    ProfileBufferBlockIndex blockIndex;
    692    ReadInto(aER, blockIndex);
    693    return blockIndex;
    694  }
    695 };
    696 
    697 // ----------------------------------------------------------------------------
    698 // Literal C string pointer
    699 
    700 // Wrapper around a pointer to a literal C string.
    701 template <size_t NonTerminalCharacters>
    702 struct ProfileBufferLiteralCStringPointer {
    703  const char* mCString;
    704 };
    705 
    706 // Wrap a pointer to a literal C string.
    707 template <size_t CharactersIncludingTerminal>
    708 ProfileBufferLiteralCStringPointer<CharactersIncludingTerminal - 1>
    709 WrapProfileBufferLiteralCStringPointer(
    710    const char (&aCString)[CharactersIncludingTerminal]) {
    711  return {aCString};
    712 }
    713 
    714 // Literal C strings, serialized as the raw pointer because it is unique and
    715 // valid for the whole program lifetime.
    716 //
    717 // Usage: `aEW.WriteObject(WrapProfileBufferLiteralCStringPointer("hi"));`.
    718 //
    719 // No deserializer is provided for this type, instead it must be deserialized as
    720 // a raw pointer: `aER.ReadObject<const char*>();`
    721 template <size_t CharactersIncludingTerminal>
    722 struct ProfileBufferEntryReader::Deserializer<
    723    ProfileBufferLiteralCStringPointer<CharactersIncludingTerminal>> {
    724  static constexpr Length Bytes(
    725      const ProfileBufferLiteralCStringPointer<CharactersIncludingTerminal>&) {
    726    // We're only storing a pointer, its size is independent from the pointer
    727    // value.
    728    return sizeof(const char*);
    729  }
    730 
    731  static void Write(
    732      ProfileBufferEntryWriter& aEW,
    733      const ProfileBufferLiteralCStringPointer<CharactersIncludingTerminal>&
    734          aWrapper) {
    735    // Write the pointer *value*, not the string contents.
    736    aEW.WriteBytes(aWrapper.mCString, sizeof(aWrapper.mCString));
    737  }
    738 };
    739 
    740 // ----------------------------------------------------------------------------
    741 // C string contents
    742 
    743 // Wrapper around a pointer to a C string whose contents will be serialized.
    744 struct ProfileBufferUnownedCString {
    745  const char* mCString;
    746 };
    747 
    748 // Wrap a pointer to a C string whose contents will be serialized.
    749 inline ProfileBufferUnownedCString WrapProfileBufferUnownedCString(
    750    const char* aCString) {
    751  return {aCString};
    752 }
    753 
    754 // The contents of a (probably) unowned C string are serialized as the number of
    755 // characters (encoded as ULEB128) and all the characters in the string. The
    756 // terminal '\0' is omitted.
    757 //
    758 // Usage: `aEW.WriteObject(WrapProfileBufferUnownedCString(str.c_str()))`.
    759 //
    760 // No deserializer is provided for this pointer type, instead it must be
    761 // deserialized as one of the other string types that manages its contents,
    762 // e.g.: `aER.ReadObject<std::string>();`
    763 template <>
    764 struct ProfileBufferEntryWriter::Serializer<ProfileBufferUnownedCString> {
    765  static Length Bytes(const ProfileBufferUnownedCString& aS) {
    766    const auto len = strlen(aS.mCString);
    767    return ULEB128Size(len) + len;
    768  }
    769 
    770  static void Write(ProfileBufferEntryWriter& aEW,
    771                    const ProfileBufferUnownedCString& aS) {
    772    const auto len = strlen(aS.mCString);
    773    aEW.WriteULEB128(len);
    774    aEW.WriteBytes(aS.mCString, len);
    775  }
    776 };
    777 
    778 // ----------------------------------------------------------------------------
    779 // Raw pointers
    780 
    781 // Wrapper around a pointer to be serialized as the raw pointer value.
    782 template <typename T>
    783 struct ProfileBufferRawPointer {
    784  T* mRawPointer;
    785 };
    786 
    787 // Wrap a pointer to be serialized as the raw pointer value.
    788 template <typename T>
    789 ProfileBufferRawPointer<T> WrapProfileBufferRawPointer(T* aRawPointer) {
    790  return {aRawPointer};
    791 }
    792 
    793 // Raw pointers are serialized as the raw pointer value.
    794 //
    795 // Usage: `aEW.WriteObject(WrapProfileBufferRawPointer(ptr));`
    796 //
    797 // The wrapper is compulsory when writing pointers (to avoid unexpected
    798 // leaks/UAFs), but reading can be done straight into a raw pointer object,
    799 // e.g.: `aER.ReadObject<Foo*>;`.
    800 template <typename T>
    801 struct ProfileBufferEntryWriter::Serializer<ProfileBufferRawPointer<T>> {
    802  template <typename U>
    803  static constexpr Length Bytes(const U&) {
    804    return sizeof(T*);
    805  }
    806 
    807  static void Write(ProfileBufferEntryWriter& aEW,
    808                    const ProfileBufferRawPointer<T>& aWrapper) {
    809    aEW.WriteBytes(&aWrapper.mRawPointer, sizeof(aWrapper.mRawPointer));
    810  }
    811 };
    812 
    813 // Usage: `aER.ReadObject<Foo*>;` or `Foo* p; aER.ReadIntoObject(p);`, no
    814 // wrapper necessary.
    815 template <typename T>
    816 struct ProfileBufferEntryReader::Deserializer<ProfileBufferRawPointer<T>> {
    817  static void ReadInto(ProfileBufferEntryReader& aER,
    818                       ProfileBufferRawPointer<T>& aPtr) {
    819    aER.ReadBytes(&aPtr.mRawPointer, sizeof(aPtr));
    820  }
    821 
    822  static ProfileBufferRawPointer<T> Read(ProfileBufferEntryReader& aER) {
    823    ProfileBufferRawPointer<T> rawPointer;
    824    ReadInto(aER, rawPointer);
    825    return rawPointer;
    826  }
    827 };
    828 
    829 // ----------------------------------------------------------------------------
    830 // std::string contents
    831 
    832 // std::string contents are serialized as the number of characters (encoded as
    833 // ULEB128) and all the characters in the string. The terminal '\0' is omitted.
    834 //
    835 // Usage: `std::string s = ...; aEW.WriteObject(s);`
    836 template <typename CHAR>
    837 struct ProfileBufferEntryWriter::Serializer<std::basic_string<CHAR>> {
    838  static Length Bytes(const std::basic_string<CHAR>& aS) {
    839    const Length len = static_cast<Length>(aS.length());
    840    return ULEB128Size(len) + len;
    841  }
    842 
    843  static void Write(ProfileBufferEntryWriter& aEW,
    844                    const std::basic_string<CHAR>& aS) {
    845    const Length len = static_cast<Length>(aS.length());
    846    aEW.WriteULEB128(len);
    847    aEW.WriteBytes(aS.c_str(), len * sizeof(CHAR));
    848  }
    849 };
    850 
    851 // Usage: `std::string s = aEW.ReadObject<std::string>(s);` or
    852 // `std::string s; aER.ReadIntoObject(s);`
    853 template <typename CHAR>
    854 struct ProfileBufferEntryReader::Deserializer<std::basic_string<CHAR>> {
    855  static void ReadCharsInto(ProfileBufferEntryReader& aER,
    856                            std::basic_string<CHAR>& aS, size_t aLength) {
    857    // Assign to `aS` by using iterators.
    858    // (`aER+0` so we get the same iterator type as `aER+len`.)
    859    aS.assign(aER, aER.EmptyIteratorAtOffset(aLength));
    860    aER += aLength;
    861  }
    862 
    863  static void ReadInto(ProfileBufferEntryReader& aER,
    864                       std::basic_string<CHAR>& aS) {
    865    ReadCharsInto(
    866        aER, aS,
    867        aER.ReadULEB128<typename std::basic_string<CHAR>::size_type>());
    868  }
    869 
    870  static std::basic_string<CHAR> ReadChars(ProfileBufferEntryReader& aER,
    871                                           size_t aLength) {
    872    // Construct a string by using iterators.
    873    // (`aER+0` so we get the same iterator type as `aER+len`.)
    874    std::basic_string<CHAR> s(aER, aER.EmptyIteratorAtOffset(aLength));
    875    aER += aLength;
    876    return s;
    877  }
    878 
    879  static std::basic_string<CHAR> Read(ProfileBufferEntryReader& aER) {
    880    return ReadChars(
    881        aER, aER.ReadULEB128<typename std::basic_string<CHAR>::size_type>());
    882  }
    883 };
    884 
    885 // ----------------------------------------------------------------------------
    886 // mozilla::UniqueFreePtr<CHAR>
    887 
    888 // UniqueFreePtr<CHAR>, which points at a string allocated with `malloc`
    889 // (typically generated by `strdup()`), is serialized as the number of
    890 // *bytes* (encoded as ULEB128) and all the characters in the string. The
    891 // null terminator is omitted.
    892 // `CHAR` can be any type that has a specialization for
    893 // `std::char_traits<CHAR>::length(const CHAR*)`.
    894 //
    895 // Note: A nullptr pointer will be serialized like an empty string, so when
    896 // deserializing it will result in an allocated buffer only containing a
    897 // single null terminator.
    898 template <typename CHAR>
    899 struct ProfileBufferEntryWriter::Serializer<UniqueFreePtr<CHAR>> {
    900  static Length Bytes(const UniqueFreePtr<CHAR>& aS) {
    901    if (!aS) {
    902      // Null pointer, store it as if it was an empty string (so: 0 bytes).
    903      return ULEB128Size(0u);
    904    }
    905    // Note that we store the size in *bytes*, not in number of characters.
    906    const auto bytes = std::char_traits<CHAR>::length(aS.get()) * sizeof(CHAR);
    907    return ULEB128Size(bytes) + bytes;
    908  }
    909 
    910  static void Write(ProfileBufferEntryWriter& aEW,
    911                    const UniqueFreePtr<CHAR>& aS) {
    912    if (!aS) {
    913      // Null pointer, store it as if it was an empty string (so we write a
    914      // length of 0 bytes).
    915      aEW.WriteULEB128(0u);
    916      return;
    917    }
    918    // Note that we store the size in *bytes*, not in number of characters.
    919    const auto bytes = std::char_traits<CHAR>::length(aS.get()) * sizeof(CHAR);
    920    aEW.WriteULEB128(bytes);
    921    aEW.WriteBytes(aS.get(), bytes);
    922  }
    923 };
    924 
    925 template <typename CHAR>
    926 struct ProfileBufferEntryReader::Deserializer<UniqueFreePtr<CHAR>> {
    927  static void ReadInto(ProfileBufferEntryReader& aER, UniqueFreePtr<CHAR>& aS) {
    928    aS = Read(aER);
    929  }
    930 
    931  static UniqueFreePtr<CHAR> Read(ProfileBufferEntryReader& aER) {
    932    // Read the number of *bytes* that follow.
    933    const auto bytes = aER.ReadULEB128<size_t>();
    934    // We need a buffer of the non-const character type.
    935    using NC_CHAR = std::remove_const_t<CHAR>;
    936    // We allocate the required number of bytes, plus one extra character for
    937    // the null terminator.
    938    NC_CHAR* buffer = static_cast<NC_CHAR*>(malloc(bytes + sizeof(NC_CHAR)));
    939    // Copy the characters into the buffer.
    940    aER.ReadBytes(buffer, bytes);
    941    // And append a null terminator.
    942    buffer[bytes / sizeof(NC_CHAR)] = NC_CHAR(0);
    943    return UniqueFreePtr<CHAR>(buffer);
    944  }
    945 };
    946 
    947 // ----------------------------------------------------------------------------
    948 // std::tuple
    949 
    950 // std::tuple is serialized as a sequence of each recursively-serialized item.
    951 //
    952 // This is equivalent to manually serializing each item, so reading/writing
    953 // tuples is equivalent to reading/writing their elements in order, e.g.:
    954 // ```
    955 // std::tuple<int, std::string> is = ...;
    956 // aEW.WriteObject(is); // Write the tuple, equivalent to:
    957 // aEW.WriteObject(/* int */ std::get<0>(is), /* string */ std::get<1>(is));
    958 // ...
    959 // // Reading back can be done directly into a tuple:
    960 // auto is = aER.ReadObject<std::tuple<int, std::string>>();
    961 // // Or each item could be read separately:
    962 // auto i = aER.ReadObject<int>(); auto s = aER.ReadObject<std::string>();
    963 // ```
    964 template <typename... Ts>
    965 struct ProfileBufferEntryWriter::Serializer<std::tuple<Ts...>> {
    966 private:
    967  template <size_t... Is>
    968  static Length TupleBytes(const std::tuple<Ts...>& aTuple,
    969                           std::index_sequence<Is...>) {
    970    return (0 + ... + SumBytes(std::get<Is>(aTuple)));
    971  }
    972 
    973  template <size_t... Is>
    974  static void TupleWrite(ProfileBufferEntryWriter& aEW,
    975                         const std::tuple<Ts...>& aTuple,
    976                         std::index_sequence<Is...>) {
    977    (aEW.WriteObject(std::get<Is>(aTuple)), ...);
    978  }
    979 
    980 public:
    981  static Length Bytes(const std::tuple<Ts...>& aTuple) {
    982    // Generate a 0..N-1 index pack, we'll add the sizes of each item.
    983    return TupleBytes(aTuple, std::index_sequence_for<Ts...>());
    984  }
    985 
    986  static void Write(ProfileBufferEntryWriter& aEW,
    987                    const std::tuple<Ts...>& aTuple) {
    988    // Generate a 0..N-1 index pack, we'll write each item.
    989    TupleWrite(aEW, aTuple, std::index_sequence_for<Ts...>());
    990  }
    991 };
    992 
    993 template <typename... Ts>
    994 struct ProfileBufferEntryReader::Deserializer<std::tuple<Ts...>> {
    995  template <size_t I>
    996  static void TupleIReadInto(ProfileBufferEntryReader& aER,
    997                             std::tuple<Ts...>& aTuple) {
    998    aER.ReadIntoObject(std::get<I>(aTuple));
    999  }
   1000 
   1001  template <size_t... Is>
   1002  static void TupleReadInto(ProfileBufferEntryReader& aER,
   1003                            std::tuple<Ts...>& aTuple,
   1004                            std::index_sequence<Is...>) {
   1005    (TupleIReadInto<Is>(aER, aTuple), ...);
   1006  }
   1007 
   1008  static void ReadInto(ProfileBufferEntryReader& aER,
   1009                       std::tuple<Ts...>& aTuple) {
   1010    TupleReadInto(aER, aTuple, std::index_sequence_for<Ts...>());
   1011  }
   1012 
   1013  static std::tuple<Ts...> Read(ProfileBufferEntryReader& aER) {
   1014    // Note that this creates default `Ts` first, and then overwrites them.
   1015    std::tuple<Ts...> ob;
   1016    ReadInto(aER, ob);
   1017    return ob;
   1018  }
   1019 };
   1020 // ----------------------------------------------------------------------------
   1021 // mozilla::Span
   1022 
   1023 // Span. All elements are serialized in sequence.
   1024 // The caller is assumed to know the number of elements (they may manually
   1025 // write&read it before the span if needed).
   1026 // Similar to tuples, reading/writing spans is equivalent to reading/writing
   1027 // their elements in order.
   1028 template <class T, size_t N>
   1029 struct ProfileBufferEntryWriter::Serializer<Span<T, N>> {
   1030  static Length Bytes(const Span<T, N>& aSpan) {
   1031    Length bytes = 0;
   1032    for (const T& element : aSpan) {
   1033      bytes += SumBytes(element);
   1034    }
   1035    return bytes;
   1036  }
   1037 
   1038  static void Write(ProfileBufferEntryWriter& aEW, const Span<T, N>& aSpan) {
   1039    for (const T& element : aSpan) {
   1040      aEW.WriteObject(element);
   1041    }
   1042  }
   1043 };
   1044 
   1045 template <class T, size_t N>
   1046 struct ProfileBufferEntryReader::Deserializer<Span<T, N>> {
   1047  // Read elements back into span pointing at a pre-allocated buffer.
   1048  static void ReadInto(ProfileBufferEntryReader& aER, Span<T, N>& aSpan) {
   1049    for (T& element : aSpan) {
   1050      aER.ReadIntoObject(element);
   1051    }
   1052  }
   1053 
   1054  // A Span does not own its data, this would probably leak so we forbid this.
   1055  static Span<T, N> Read(ProfileBufferEntryReader& aER) = delete;
   1056 };
   1057 
   1058 // ----------------------------------------------------------------------------
   1059 // mozilla::Maybe
   1060 
   1061 // Maybe<T> is serialized as one byte containing either 'm' (Nothing),
   1062 // or 'M' followed by the recursively-serialized `T` object.
   1063 template <typename T>
   1064 struct ProfileBufferEntryWriter::Serializer<Maybe<T>> {
   1065  static Length Bytes(const Maybe<T>& aMaybe) {
   1066    // 1 byte to store nothing/something flag, then object size if present.
   1067    return aMaybe.isNothing() ? 1 : (1 + SumBytes(aMaybe.ref()));
   1068  }
   1069 
   1070  static void Write(ProfileBufferEntryWriter& aEW, const Maybe<T>& aMaybe) {
   1071    // 'm'/'M' is just an arbitrary 1-byte value to distinguish states.
   1072    if (aMaybe.isNothing()) {
   1073      aEW.WriteObject<char>('m');
   1074    } else {
   1075      aEW.WriteObject<char>('M');
   1076      // Use the Serializer for the contained type.
   1077      aEW.WriteObject(aMaybe.ref());
   1078    }
   1079  }
   1080 };
   1081 
   1082 template <typename T>
   1083 struct ProfileBufferEntryReader::Deserializer<Maybe<T>> {
   1084  static void ReadInto(ProfileBufferEntryReader& aER, Maybe<T>& aMaybe) {
   1085    char c = aER.ReadObject<char>();
   1086    if (c == 'm') {
   1087      aMaybe.reset();
   1088    } else {
   1089      MOZ_ASSERT(c == 'M');
   1090      // If aMaybe is empty, create a default `T` first, to be overwritten.
   1091      // Otherwise we'll just overwrite whatever was already there.
   1092      if (aMaybe.isNothing()) {
   1093        aMaybe.emplace();
   1094      }
   1095      // Use the Deserializer for the contained type.
   1096      aER.ReadIntoObject(aMaybe.ref());
   1097    }
   1098  }
   1099 
   1100  static Maybe<T> Read(ProfileBufferEntryReader& aER) {
   1101    Maybe<T> maybe;
   1102    char c = aER.ReadObject<char>();
   1103    MOZ_ASSERT(c == 'M' || c == 'm');
   1104    if (c == 'M') {
   1105      // Note that this creates a default `T` inside the Maybe first, and then
   1106      // overwrites it.
   1107      maybe = Some(T{});
   1108      // Use the Deserializer for the contained type.
   1109      aER.ReadIntoObject(maybe.ref());
   1110    }
   1111    return maybe;
   1112  }
   1113 };
   1114 
   1115 // ----------------------------------------------------------------------------
   1116 // mozilla::Variant
   1117 
   1118 // Variant is serialized as the tag (0-based index of the stored type, encoded
   1119 // as ULEB128), and the recursively-serialized object.
   1120 template <typename... Ts>
   1121 struct ProfileBufferEntryWriter::Serializer<Variant<Ts...>> {
   1122 public:
   1123  static Length Bytes(const Variant<Ts...>& aVariantTs) {
   1124    return aVariantTs.match([](auto aIndex, const auto& aAlternative) {
   1125      return ULEB128Size(aIndex) + SumBytes(aAlternative);
   1126    });
   1127  }
   1128 
   1129  static void Write(ProfileBufferEntryWriter& aEW,
   1130                    const Variant<Ts...>& aVariantTs) {
   1131    aVariantTs.match([&aEW](auto aIndex, const auto& aAlternative) {
   1132      aEW.WriteULEB128(aIndex);
   1133      aEW.WriteObject(aAlternative);
   1134    });
   1135  }
   1136 };
   1137 
   1138 template <typename... Ts>
   1139 struct ProfileBufferEntryReader::Deserializer<Variant<Ts...>> {
   1140 private:
   1141  // Called from the fold expression in `VariantReadInto()`, only the selected
   1142  // variant will deserialize the object.
   1143  template <size_t I>
   1144  static void VariantIReadInto(ProfileBufferEntryReader& aER,
   1145                               Variant<Ts...>& aVariantTs, unsigned aTag) {
   1146    if (I == aTag) {
   1147      // Ensure the variant contains the target type. Note that this may create
   1148      // a default object.
   1149      if (!aVariantTs.template is<I>()) {
   1150        aVariantTs = Variant<Ts...>(VariantIndex<I>{});
   1151      }
   1152      aER.ReadIntoObject(aVariantTs.template as<I>());
   1153    }
   1154  }
   1155 
   1156  template <size_t... Is>
   1157  static void VariantReadInto(ProfileBufferEntryReader& aER,
   1158                              Variant<Ts...>& aVariantTs,
   1159                              std::index_sequence<Is...>) {
   1160    unsigned tag = aER.ReadULEB128<unsigned>();
   1161    (VariantIReadInto<Is>(aER, aVariantTs, tag), ...);
   1162  }
   1163 
   1164 public:
   1165  static void ReadInto(ProfileBufferEntryReader& aER,
   1166                       Variant<Ts...>& aVariantTs) {
   1167    // Generate a 0..N-1 index pack, the selected variant will deserialize
   1168    // itself.
   1169    VariantReadInto(aER, aVariantTs, std::index_sequence_for<Ts...>());
   1170  }
   1171 
   1172  static Variant<Ts...> Read(ProfileBufferEntryReader& aER) {
   1173    // Note that this creates a default `Variant` of the first type, and then
   1174    // overwrites it. Consider using `ReadInto` for more control if needed.
   1175    Variant<Ts...> variant(VariantIndex<0>{});
   1176    ReadInto(aER, variant);
   1177    return variant;
   1178  }
   1179 };
   1180 
   1181 }  // namespace mozilla
   1182 
   1183 #endif  // ProfileBufferEntrySerialization_h