#ifndef vm_InlineCharBuffer_inl_h
#define vm_InlineCharBuffer_inl_h
#include "vm/StringType-inl.h"
namespace js {
template <typename CharT>
struct MaximumInlineLength;
template <>
struct MaximumInlineLength<Latin1Char> {
static constexpr size_t value = JSFatInlineString::MAX_LENGTH_LATIN1;
};
template <>
struct MaximumInlineLength<char16_t> {
static constexpr size_t value = JSFatInlineString::MAX_LENGTH_TWO_BYTE;
};
template <typename CharT>
class MOZ_NON_PARAM InlineCharBuffer {
static constexpr size_t InlineCapacity = MaximumInlineLength<CharT>::value;
CharT inlineStorage[InlineCapacity];
UniquePtr<CharT[], JS::FreePolicy> heapStorage;
#ifdef DEBUG
size_t lastRequestedLength = 0;
void assertValidRequest(size_t expectedLastLength, size_t length) {
MOZ_ASSERT(length >= expectedLastLength, "cannot shrink requested length");
MOZ_ASSERT(lastRequestedLength == expectedLastLength);
lastRequestedLength = length;
}
#else
void assertValidRequest(size_t expectedLastLength, size_t length) {}
#endif
public:
CharT* get() { return heapStorage ? heapStorage.get() : inlineStorage; }
bool maybeAlloc(JSContext* cx, size_t length) {
assertValidRequest(0, length);
if (length <= InlineCapacity) {
return true;
}
MOZ_ASSERT(!heapStorage, "heap storage already allocated");
heapStorage = cx->make_pod_array<CharT>(length + 1);
return !!heapStorage;
}
bool maybeRealloc(JSContext* cx, size_t oldLength, size_t newLength) {
assertValidRequest(oldLength, newLength);
if (newLength <= InlineCapacity) {
return true;
}
if (!heapStorage) {
heapStorage = cx->make_pod_array<CharT>(newLength + 1);
if (!heapStorage) {
return false;
}
MOZ_ASSERT(oldLength <= InlineCapacity);
mozilla::PodCopy(heapStorage.get(), inlineStorage, oldLength);
return true;
}
CharT* oldChars = heapStorage.release();
CharT* newChars = cx->pod_realloc(oldChars, oldLength + 1, newLength + 1);
if (!newChars) {
js_free(oldChars);
return false;
}
heapStorage.reset(newChars);
return true;
}
JSString* toStringDontDeflate(JSContext* cx, size_t length) {
MOZ_ASSERT(length == lastRequestedLength);
if (JSInlineString::lengthFits<CharT>(length)) {
MOZ_ASSERT(
!heapStorage,
"expected only inline storage when length fits in inline string");
if (JSString* str = TryEmptyOrStaticString(cx, inlineStorage, length)) {
return str;
}
mozilla::Range<const CharT> range(inlineStorage, length);
return NewInlineString<CanGC>(cx, range);
}
MOZ_ASSERT(heapStorage,
"heap storage was not allocated for non-inline string");
heapStorage.get()[length] = '\0'; return NewStringDontDeflate<CanGC>(cx, std::move(heapStorage), length);
}
JSString* toString(JSContext* cx, size_t length) {
MOZ_ASSERT(length == lastRequestedLength);
if (JSInlineString::lengthFits<CharT>(length)) {
MOZ_ASSERT(
!heapStorage,
"expected only inline storage when length fits in inline string");
return NewStringCopyN<CanGC>(cx, inlineStorage, length);
}
MOZ_ASSERT(heapStorage,
"heap storage was not allocated for non-inline string");
heapStorage.get()[length] = '\0'; return NewString<CanGC>(cx, std::move(heapStorage), length);
}
};
}
#endif