diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /js/src/vm/StringBuffer.h | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/vm/StringBuffer.h')
-rw-r--r-- | js/src/vm/StringBuffer.h | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/js/src/vm/StringBuffer.h b/js/src/vm/StringBuffer.h new file mode 100644 index 000000000..19da43526 --- /dev/null +++ b/js/src/vm/StringBuffer.h @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 vm_StringBuffer_h +#define vm_StringBuffer_h + +#include "mozilla/DebugOnly.h" +#include "mozilla/MaybeOneOf.h" + +#include "jscntxt.h" + +#include "js/Vector.h" + +namespace js { + +/* + * String builder that eagerly checks for over-allocation past the maximum + * string length. + * + * Any operation which would exceed the maximum string length causes an + * exception report on the context and results in a failed return value. + * + * Well-sized extractions (which waste no more than 1/4 of their char + * buffer space) are guaranteed for strings built by this interface. + * See |extractWellSized|. + */ +class StringBuffer +{ + /* + * The Vector's buffer may be either stolen or copied, so we need to use + * TempAllocPolicy and account for the memory manually when stealing. + */ + typedef Vector<Latin1Char, 64> Latin1CharBuffer; + typedef Vector<char16_t, 32> TwoByteCharBuffer; + + ExclusiveContext* cx; + + /* + * If Latin1 strings are enabled, cb starts out as a Latin1CharBuffer. When + * a TwoByte char is appended, inflateChars() constructs a TwoByteCharBuffer + * and copies the Latin1 chars. + */ + mozilla::MaybeOneOf<Latin1CharBuffer, TwoByteCharBuffer> cb; + +#ifdef DEBUG + /* + * Make sure ensureTwoByteChars() is called before calling + * infallibleAppend(char16_t). + */ + bool hasEnsuredTwoByteChars_; +#endif + + /* Number of reserve()'d chars, see inflateChars. */ + size_t reserved_; + + StringBuffer(const StringBuffer& other) = delete; + void operator=(const StringBuffer& other) = delete; + + MOZ_ALWAYS_INLINE bool isLatin1() const { return cb.constructed<Latin1CharBuffer>(); } + MOZ_ALWAYS_INLINE bool isTwoByte() const { return !isLatin1(); } + + MOZ_ALWAYS_INLINE Latin1CharBuffer& latin1Chars() { return cb.ref<Latin1CharBuffer>(); } + MOZ_ALWAYS_INLINE TwoByteCharBuffer& twoByteChars() { return cb.ref<TwoByteCharBuffer>(); } + + MOZ_ALWAYS_INLINE const Latin1CharBuffer& latin1Chars() const { + return cb.ref<Latin1CharBuffer>(); + } + MOZ_ALWAYS_INLINE const TwoByteCharBuffer& twoByteChars() const { + return cb.ref<TwoByteCharBuffer>(); + } + + MOZ_MUST_USE bool inflateChars(); + + public: + explicit StringBuffer(ExclusiveContext* cx) + : cx(cx) +#ifdef DEBUG + , hasEnsuredTwoByteChars_(false) +#endif + , reserved_(0) + { + cb.construct<Latin1CharBuffer>(cx); + } + + void clear() { + if (isLatin1()) + latin1Chars().clear(); + else + twoByteChars().clear(); + } + MOZ_MUST_USE bool reserve(size_t len) { + if (len > reserved_) + reserved_ = len; + return isLatin1() ? latin1Chars().reserve(len) : twoByteChars().reserve(len); + } + MOZ_MUST_USE bool resize(size_t len) { + return isLatin1() ? latin1Chars().resize(len) : twoByteChars().resize(len); + } + bool empty() const { + return isLatin1() ? latin1Chars().empty() : twoByteChars().empty(); + } + size_t length() const { + return isLatin1() ? latin1Chars().length() : twoByteChars().length(); + } + char16_t getChar(size_t idx) const { + return isLatin1() ? latin1Chars()[idx] : twoByteChars()[idx]; + } + + MOZ_MUST_USE bool ensureTwoByteChars() { + if (isLatin1() && !inflateChars()) + return false; + +#ifdef DEBUG + hasEnsuredTwoByteChars_ = true; +#endif + return true; + } + + MOZ_MUST_USE bool append(const char16_t c) { + if (isLatin1()) { + if (c <= JSString::MAX_LATIN1_CHAR) + return latin1Chars().append(Latin1Char(c)); + if (!inflateChars()) + return false; + } + return twoByteChars().append(c); + } + MOZ_MUST_USE bool append(Latin1Char c) { + return isLatin1() ? latin1Chars().append(c) : twoByteChars().append(c); + } + MOZ_MUST_USE bool append(char c) { + return append(Latin1Char(c)); + } + + inline MOZ_MUST_USE bool append(const char16_t* begin, const char16_t* end); + + MOZ_MUST_USE bool append(const char16_t* chars, size_t len) { + return append(chars, chars + len); + } + + MOZ_MUST_USE bool append(const Latin1Char* begin, const Latin1Char* end) { + return isLatin1() ? latin1Chars().append(begin, end) : twoByteChars().append(begin, end); + } + MOZ_MUST_USE bool append(const Latin1Char* chars, size_t len) { + return append(chars, chars + len); + } + + MOZ_MUST_USE bool append(const JS::ConstCharPtr chars, size_t len) { + return append(chars.get(), chars.get() + len); + } + MOZ_MUST_USE bool appendN(Latin1Char c, size_t n) { + return isLatin1() ? latin1Chars().appendN(c, n) : twoByteChars().appendN(c, n); + } + + inline MOZ_MUST_USE bool append(JSString* str); + inline MOZ_MUST_USE bool append(JSLinearString* str); + inline MOZ_MUST_USE bool appendSubstring(JSString* base, size_t off, size_t len); + inline MOZ_MUST_USE bool appendSubstring(JSLinearString* base, size_t off, size_t len); + + MOZ_MUST_USE bool append(const char* chars, size_t len) { + return append(reinterpret_cast<const Latin1Char*>(chars), len); + } + + template <size_t ArrayLength> + MOZ_MUST_USE bool append(const char (&array)[ArrayLength]) { + return append(array, ArrayLength - 1); /* No trailing '\0'. */ + } + + /* Infallible variants usable when the corresponding space is reserved. */ + void infallibleAppend(Latin1Char c) { + if (isLatin1()) + latin1Chars().infallibleAppend(c); + else + twoByteChars().infallibleAppend(c); + } + void infallibleAppend(char c) { + infallibleAppend(Latin1Char(c)); + } + void infallibleAppend(const Latin1Char* chars, size_t len) { + if (isLatin1()) + latin1Chars().infallibleAppend(chars, len); + else + twoByteChars().infallibleAppend(chars, len); + } + void infallibleAppend(const char* chars, size_t len) { + infallibleAppend(reinterpret_cast<const Latin1Char*>(chars), len); + } + + void infallibleAppendSubstring(JSLinearString* base, size_t off, size_t len); + + /* + * Because inflation is fallible, these methods should only be used after + * calling ensureTwoByteChars(). + */ + void infallibleAppend(const char16_t* chars, size_t len) { + MOZ_ASSERT(hasEnsuredTwoByteChars_); + twoByteChars().infallibleAppend(chars, len); + } + void infallibleAppend(char16_t c) { + MOZ_ASSERT(hasEnsuredTwoByteChars_); + twoByteChars().infallibleAppend(c); + } + + bool isUnderlyingBufferLatin1() const { return isLatin1(); } + + char16_t* rawTwoByteBegin() { return twoByteChars().begin(); } + char16_t* rawTwoByteEnd() { return twoByteChars().end(); } + const char16_t* rawTwoByteBegin() const { return twoByteChars().begin(); } + const char16_t* rawTwoByteEnd() const { return twoByteChars().end(); } + + Latin1Char* rawLatin1Begin() { return latin1Chars().begin(); } + Latin1Char* rawLatin1End() { return latin1Chars().end(); } + const Latin1Char* rawLatin1Begin() const { return latin1Chars().begin(); } + const Latin1Char* rawLatin1End() const { return latin1Chars().end(); } + + /* + * Creates a string from the characters in this buffer, then (regardless + * whether string creation succeeded or failed) empties the buffer. + */ + JSFlatString* finishString(); + + /* Identical to finishString() except that an atom is created. */ + JSAtom* finishAtom(); + + /* + * Creates a raw string from the characters in this buffer. The string is + * exactly the characters in this buffer (inflated to TwoByte), it is *not* + * null-terminated unless the last appended character was '\0'. + */ + char16_t* stealChars(); +}; + +inline bool +StringBuffer::append(const char16_t* begin, const char16_t* end) +{ + MOZ_ASSERT(begin <= end); + if (isLatin1()) { + while (true) { + if (begin >= end) + return true; + if (*begin > JSString::MAX_LATIN1_CHAR) + break; + if (!latin1Chars().append(*begin)) + return false; + ++begin; + } + if (!inflateChars()) + return false; + } + return twoByteChars().append(begin, end); +} + +inline bool +StringBuffer::append(JSLinearString* str) +{ + JS::AutoCheckCannotGC nogc; + if (isLatin1()) { + if (str->hasLatin1Chars()) + return latin1Chars().append(str->latin1Chars(nogc), str->length()); + if (!inflateChars()) + return false; + } + return str->hasLatin1Chars() + ? twoByteChars().append(str->latin1Chars(nogc), str->length()) + : twoByteChars().append(str->twoByteChars(nogc), str->length()); +} + +inline void +StringBuffer::infallibleAppendSubstring(JSLinearString* base, size_t off, size_t len) +{ + MOZ_ASSERT(off + len <= base->length()); + MOZ_ASSERT_IF(base->hasTwoByteChars(), isTwoByte()); + + JS::AutoCheckCannotGC nogc; + if (base->hasLatin1Chars()) + infallibleAppend(base->latin1Chars(nogc) + off, len); + else + infallibleAppend(base->twoByteChars(nogc) + off, len); +} + +inline bool +StringBuffer::appendSubstring(JSLinearString* base, size_t off, size_t len) +{ + MOZ_ASSERT(off + len <= base->length()); + + JS::AutoCheckCannotGC nogc; + if (isLatin1()) { + if (base->hasLatin1Chars()) + return latin1Chars().append(base->latin1Chars(nogc) + off, len); + if (!inflateChars()) + return false; + } + return base->hasLatin1Chars() + ? twoByteChars().append(base->latin1Chars(nogc) + off, len) + : twoByteChars().append(base->twoByteChars(nogc) + off, len); +} + +inline bool +StringBuffer::appendSubstring(JSString* base, size_t off, size_t len) +{ + JSLinearString* linear = base->ensureLinear(cx); + if (!linear) + return false; + + return appendSubstring(linear, off, len); +} + +inline bool +StringBuffer::append(JSString* str) +{ + JSLinearString* linear = str->ensureLinear(cx); + if (!linear) + return false; + + return append(linear); +} + +/* ES5 9.8 ToString, appending the result to the string buffer. */ +extern bool +ValueToStringBufferSlow(JSContext* cx, const Value& v, StringBuffer& sb); + +inline bool +ValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb) +{ + if (v.isString()) + return sb.append(v.toString()); + + return ValueToStringBufferSlow(cx, v, sb); +} + +/* ES5 9.8 ToString for booleans, appending the result to the string buffer. */ +inline bool +BooleanToStringBuffer(bool b, StringBuffer& sb) +{ + return b ? sb.append("true") : sb.append("false"); +} + +} /* namespace js */ + +#endif /* vm_StringBuffer_h */ |