tor-browser

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

FormatBuffer.h (4431B)


      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 builtin_intl_FormatBuffer_h
      8 #define builtin_intl_FormatBuffer_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/Span.h"
     12 #include "mozilla/TextUtils.h"
     13 
     14 #include <stddef.h>
     15 
     16 #include "js/AllocPolicy.h"
     17 #include "js/TypeDecls.h"
     18 #include "js/UniquePtr.h"
     19 #include "js/Vector.h"
     20 #include "vm/StringType.h"
     21 
     22 namespace js::intl {
     23 
     24 /**
     25 * A buffer for formatting unified intl data.
     26 */
     27 template <typename CharT, size_t MinInlineCapacity = 0,
     28          class AllocPolicy = TempAllocPolicy>
     29 class FormatBuffer {
     30 public:
     31  using CharType = CharT;
     32 
     33  // Allow move constructors, but not copy constructors, as this class owns a
     34  // js::Vector.
     35  FormatBuffer(FormatBuffer&& other) noexcept = default;
     36  FormatBuffer& operator=(FormatBuffer&& other) noexcept = default;
     37 
     38  explicit FormatBuffer(AllocPolicy aP = AllocPolicy())
     39      : buffer_(std::move(aP)) {
     40    // The initial capacity matches the requested minimum inline capacity, as
     41    // long as it doesn't exceed |Vector::kMaxInlineBytes / sizeof(CharT)|. If
     42    // this assertion should ever fail, either reduce |MinInlineCapacity| or
     43    // make the FormatBuffer initialization fallible.
     44    MOZ_ASSERT(buffer_.capacity() == MinInlineCapacity);
     45    if constexpr (MinInlineCapacity > 0) {
     46      // Ensure the full capacity is marked as reserved.
     47      //
     48      // Reserving the minimum inline capacity can never fail, even when
     49      // simulating OOM.
     50      MOZ_ALWAYS_TRUE(buffer_.reserve(MinInlineCapacity));
     51    }
     52  }
     53 
     54  // Implicitly convert to a Span.
     55  operator mozilla::Span<CharType>() { return buffer_; }
     56  operator mozilla::Span<const CharType>() const { return buffer_; }
     57 
     58  /**
     59   * Ensures the buffer has enough space to accommodate |size| elements.
     60   */
     61  [[nodiscard]] bool reserve(size_t size) {
     62    // Call |reserve| a second time to ensure its full capacity is marked as
     63    // reserved.
     64    return buffer_.reserve(size) && buffer_.reserve(buffer_.capacity());
     65  }
     66 
     67  /**
     68   * Returns the raw data inside the buffer.
     69   */
     70  CharType* data() { return buffer_.begin(); }
     71 
     72  /**
     73   * Returns the count of elements written into the buffer.
     74   */
     75  size_t length() const { return buffer_.length(); }
     76 
     77  /**
     78   * Returns the buffer's overall capacity.
     79   */
     80  size_t capacity() const { return buffer_.capacity(); }
     81 
     82  /**
     83   * Resizes the buffer to the given amount of written elements.
     84   */
     85  void written(size_t amount) {
     86    MOZ_ASSERT(amount <= buffer_.capacity());
     87    // This sets |buffer_|'s internal size so that it matches how much was
     88    // written. This is necessary because the write happens across FFI
     89    // boundaries.
     90    size_t curLength = length();
     91    if (amount > curLength) {
     92      buffer_.infallibleGrowByUninitialized(amount - curLength);
     93    } else {
     94      buffer_.shrinkBy(curLength - amount);
     95    }
     96  }
     97 
     98  /**
     99   * Copies the buffer's data to a JSString.
    100   */
    101  JSLinearString* toString(JSContext* cx) const {
    102    static_assert(std::is_same_v<CharT, char16_t>);
    103    return NewStringCopyN<CanGC>(cx, buffer_.begin(), buffer_.length());
    104  }
    105 
    106  /**
    107   * Copies the buffer's data to a JSString. The buffer must contain only
    108   * ASCII characters.
    109   */
    110  JSLinearString* toAsciiString(JSContext* cx) const {
    111    static_assert(std::is_same_v<CharT, char>);
    112 
    113    MOZ_ASSERT(mozilla::IsAscii(buffer_));
    114    return NewStringCopyN<CanGC>(cx, buffer_.begin(), buffer_.length());
    115  }
    116 
    117  /**
    118   * Extract this buffer's content as a null-terminated string.
    119   */
    120  UniquePtr<CharType[], JS::FreePolicy> extractStringZ() {
    121    // Adding the NUL character on an already null-terminated string is likely
    122    // an error. If there's ever a valid use case which triggers this assertion,
    123    // we should change the below code to only conditionally add '\0'.
    124    MOZ_ASSERT_IF(!buffer_.empty(), buffer_.end()[-1] != '\0');
    125 
    126    if (!buffer_.append('\0')) {
    127      return nullptr;
    128    }
    129    return UniquePtr<CharType[], JS::FreePolicy>(
    130        buffer_.extractOrCopyRawBuffer());
    131  }
    132 
    133 private:
    134  js::Vector<CharT, MinInlineCapacity, AllocPolicy> buffer_;
    135 };
    136 
    137 }  // namespace js::intl
    138 
    139 #endif /* builtin_intl_FormatBuffer_h */