mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 13:57:32 +00:00
Bug 1711902 - Add a FormatBuffer for use in SpiderMonkey; r=anba
Differential Revision: https://phabricator.services.mozilla.com/D116911
This commit is contained in:
parent
9534c128ad
commit
efe295fd94
@ -5,38 +5,68 @@
|
||||
#define intl_components_gtest_TestBuffer_h_
|
||||
|
||||
#include <string_view>
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
namespace mozilla::intl {
|
||||
|
||||
/**
|
||||
* This buffer class is useful for testing formatting operations.
|
||||
* A test buffer for interfacing with unified intl classes.
|
||||
* Closely resembles the FormatBuffer class, but without
|
||||
* JavaScript-specific implementation details.
|
||||
*/
|
||||
template <typename C>
|
||||
template <typename C, size_t inlineCapacity = 0>
|
||||
class TestBuffer {
|
||||
public:
|
||||
using CharType = C;
|
||||
|
||||
bool allocate(size_t aSize) {
|
||||
mBuffer.resize(aSize);
|
||||
return true;
|
||||
}
|
||||
// Only allow moves, and not copies, as this class owns the mozilla::Vector.
|
||||
TestBuffer(TestBuffer&& other) noexcept = default;
|
||||
TestBuffer& operator=(TestBuffer&& other) noexcept = default;
|
||||
|
||||
CharType* data() { return mBuffer.data(); }
|
||||
explicit TestBuffer(const size_t aSize = 0) { reserve(aSize); }
|
||||
|
||||
size_t size() const { return mBuffer.size(); }
|
||||
/**
|
||||
* Ensures the buffer has enough space to accommodate |aSize| elemtns.
|
||||
*/
|
||||
bool reserve(const size_t aSize) { return mBuffer.reserve(aSize); }
|
||||
|
||||
/**
|
||||
* Returns the raw data inside the buffer.
|
||||
*/
|
||||
CharType* data() { return mBuffer.begin(); }
|
||||
|
||||
/**
|
||||
* Returns the count of elements in written to the buffer.
|
||||
*/
|
||||
size_t length() const { return mBuffer.length(); }
|
||||
|
||||
/**
|
||||
* Returns the buffer's overall capacity.
|
||||
*/
|
||||
size_t capacity() const { return mBuffer.capacity(); }
|
||||
|
||||
void written(size_t aAmount) { mWritten = aAmount; }
|
||||
|
||||
template <typename C2>
|
||||
std::basic_string_view<const C2> get_string_view() {
|
||||
return std::basic_string_view<const C2>(
|
||||
reinterpret_cast<const C2*>(mBuffer.data()), mWritten);
|
||||
/**
|
||||
* Resizes the buffer to the given amount of written elements.
|
||||
* This is necessary because the buffer gets written to across
|
||||
* FFI boundaries, so this needs to happen in a separate step.
|
||||
*/
|
||||
void written(size_t aAmount) {
|
||||
MOZ_ASSERT(aAmount <= mBuffer.capacity());
|
||||
mozilla::DebugOnly<bool> result = mBuffer.resizeUninitialized(aAmount);
|
||||
MOZ_ASSERT(result);
|
||||
}
|
||||
|
||||
std::vector<C> mBuffer;
|
||||
size_t mWritten = 0;
|
||||
/**
|
||||
* Get a string view into the buffer, which is useful for test assertions.
|
||||
*/
|
||||
template <typename C2>
|
||||
std::basic_string_view<const C2> get_string_view() {
|
||||
return std::basic_string_view<const C2>(reinterpret_cast<const C2*>(data()),
|
||||
length());
|
||||
}
|
||||
|
||||
Vector<C, inlineCapacity> mBuffer{};
|
||||
};
|
||||
|
||||
} // namespace mozilla::intl
|
||||
|
@ -48,7 +48,7 @@ static ICUResult FillBufferWithICUCall(Buffer& buffer,
|
||||
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
||||
MOZ_ASSERT(length >= 0);
|
||||
|
||||
if (!buffer.allocate(length)) {
|
||||
if (!buffer.reserve(length)) {
|
||||
return Err(ICUError::OutOfMemory);
|
||||
}
|
||||
|
||||
@ -110,13 +110,13 @@ template <typename Buffer>
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!utf8TargetBuffer.allocate(3 * utf16Span.Length())) {
|
||||
if (!utf8TargetBuffer.reserve(3 * utf16Span.Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t amount = ConvertUtf16toUtf8(
|
||||
utf16Span, Span(reinterpret_cast<char*>(std::data(utf8TargetBuffer)),
|
||||
std::size(utf8TargetBuffer)));
|
||||
utf16Span, Span(reinterpret_cast<char*>(utf8TargetBuffer.data()),
|
||||
utf8TargetBuffer.capacity()));
|
||||
|
||||
utf8TargetBuffer.written(amount);
|
||||
|
||||
|
@ -397,7 +397,7 @@ class NumberFormat final {
|
||||
} else {
|
||||
// ICU provides APIs which accept a buffer, but they just copy from an
|
||||
// internal buffer behind the scenes anyway.
|
||||
if (!buffer.allocate(result.size())) {
|
||||
if (!buffer.reserve(result.size())) {
|
||||
return Err(FormatError::OutOfMemory);
|
||||
}
|
||||
PodCopy(static_cast<char16_t*>(buffer.data()), result.data(),
|
||||
|
@ -22,7 +22,7 @@ class SizeableUTF8Buffer {
|
||||
public:
|
||||
using CharType = uint8_t;
|
||||
|
||||
bool allocate(size_t size) {
|
||||
bool reserve(size_t size) {
|
||||
mBuffer.reset(reinterpret_cast<CharType*>(malloc(size)));
|
||||
mCapacity = size;
|
||||
return true;
|
||||
@ -30,7 +30,7 @@ class SizeableUTF8Buffer {
|
||||
|
||||
CharType* data() { return mBuffer.get(); }
|
||||
|
||||
size_t size() const { return mCapacity; }
|
||||
size_t capacity() const { return mCapacity; }
|
||||
|
||||
void written(size_t amount) { mWritten = amount; }
|
||||
|
||||
|
104
js/src/builtin/intl/FormatBuffer.h
Normal file
104
js/src/builtin/intl/FormatBuffer.h
Normal file
@ -0,0 +1,104 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef builtin_intl_FormatBuffer_h
|
||||
#define builtin_intl_FormatBuffer_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Range.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gc/Allocator.h"
|
||||
#include "js/AllocPolicy.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
namespace js::intl {
|
||||
|
||||
/**
|
||||
* A buffer for formatting unified intl data.
|
||||
*/
|
||||
template <typename CharT, size_t MinInlineCapacity = 0>
|
||||
class FormatBuffer {
|
||||
public:
|
||||
using CharType = CharT;
|
||||
|
||||
// Allow move constructors, but not copy constructors, as this class owns a
|
||||
// js::Vector.
|
||||
FormatBuffer(FormatBuffer&& other) noexcept = default;
|
||||
FormatBuffer& operator=(FormatBuffer&& other) noexcept = default;
|
||||
|
||||
explicit FormatBuffer(JSContext* cx) : cx_(cx), buffer_(cx) {
|
||||
MOZ_ASSERT(cx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the buffer has enough space to accommodate |size| elements.
|
||||
*/
|
||||
[[nodiscard]] bool reserve(const size_t size) {
|
||||
return buffer_.reserve(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data inside the buffer.
|
||||
*/
|
||||
CharType* data() { return buffer_.begin(); }
|
||||
|
||||
/**
|
||||
* Returns the count of elements written into the buffer.
|
||||
*/
|
||||
size_t length() const { return buffer_.length(); }
|
||||
|
||||
/**
|
||||
* Returns the buffer's overall capacity.
|
||||
*/
|
||||
size_t capacity() const { return buffer_.capacity(); }
|
||||
|
||||
/**
|
||||
* Resizes the buffer to the given amount of written elements.
|
||||
*/
|
||||
void written(size_t amount) {
|
||||
MOZ_ASSERT(amount <= buffer_.capacity());
|
||||
// This sets |buffer_|'s internal size so that it matches how much was
|
||||
// written. This is necessary because the write happens across FFI
|
||||
// boundaries.
|
||||
mozilla::DebugOnly<bool> result = buffer_.resizeUninitialized(amount);
|
||||
MOZ_ASSERT(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the buffer's data to a JSString.
|
||||
*
|
||||
* TODO(#1715842) - This should be more explicit on needing to handle OOM
|
||||
* errors. In this case it returns a nullptr that must be checked, but it may
|
||||
* not be obvious.
|
||||
*/
|
||||
JSString* toString() const {
|
||||
if constexpr (std::is_same_v<CharT, uint8_t> ||
|
||||
std::is_same_v<CharT, unsigned char> ||
|
||||
std::is_same_v<CharT, char>) {
|
||||
// Handle the UTF-8 encoding case.
|
||||
return NewStringCopyUTF8N<CanGC>(
|
||||
cx_, mozilla::Range(reinterpret_cast<unsigned char>(buffer_.begin()),
|
||||
buffer_.length()));
|
||||
} else {
|
||||
// Handle the UTF-16 encoding case.
|
||||
static_assert(std::is_same_v<CharT, char16_t>);
|
||||
return NewStringCopyN<CanGC>(cx_, buffer_.begin(), buffer_.length());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
JSContext* cx_;
|
||||
js::Vector<CharT, MinInlineCapacity> buffer_;
|
||||
};
|
||||
|
||||
} // namespace js::intl
|
||||
|
||||
#endif /* builtin_intl_FormatBuffer_h */
|
Loading…
x
Reference in New Issue
Block a user