michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef vm_StringBuffer_h michael@0: #define vm_StringBuffer_h michael@0: michael@0: #include "jscntxt.h" michael@0: michael@0: #include "js/Vector.h" michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * String builder that eagerly checks for over-allocation past the maximum michael@0: * string length. michael@0: * michael@0: * Any operation which would exceed the maximum string length causes an michael@0: * exception report on the context and results in a failed return value. michael@0: * michael@0: * Well-sized extractions (which waste no more than 1/4 of their char michael@0: * buffer space) are guaranteed for strings built by this interface. michael@0: * See |extractWellSized|. michael@0: */ michael@0: class StringBuffer michael@0: { michael@0: /* cb's buffer is taken by the new string so use ContextAllocPolicy. */ michael@0: typedef Vector CharBuffer; michael@0: michael@0: CharBuffer cb; michael@0: michael@0: ExclusiveContext *context() const { michael@0: return cb.allocPolicy().context()->asExclusiveContext(); michael@0: } michael@0: michael@0: StringBuffer(const StringBuffer &other) MOZ_DELETE; michael@0: void operator=(const StringBuffer &other) MOZ_DELETE; michael@0: michael@0: public: michael@0: explicit StringBuffer(ExclusiveContext *cx) : cb(cx) { } michael@0: michael@0: inline bool reserve(size_t len) { return cb.reserve(len); } michael@0: inline bool resize(size_t len) { return cb.resize(len); } michael@0: inline bool append(const jschar c) { return cb.append(c); } michael@0: inline bool append(const jschar *chars, size_t len) { return cb.append(chars, len); } michael@0: inline bool append(const JS::ConstCharPtr chars, size_t len) { return cb.append(chars.get(), len); } michael@0: inline bool append(const jschar *begin, const jschar *end) { return cb.append(begin, end); } michael@0: inline bool append(JSString *str); michael@0: inline bool append(JSLinearString *str); michael@0: inline bool appendN(const jschar c, size_t n) { return cb.appendN(c, n); } michael@0: inline bool appendInflated(const char *cstr, size_t len); michael@0: michael@0: template michael@0: bool append(const char (&array)[ArrayLength]) { michael@0: return cb.append(array, array + ArrayLength - 1); /* No trailing '\0'. */ michael@0: } michael@0: michael@0: /* Infallible variants usable when the corresponding space is reserved. */ michael@0: void infallibleAppend(const jschar c) { michael@0: cb.infallibleAppend(c); michael@0: } michael@0: void infallibleAppend(const jschar *chars, size_t len) { michael@0: cb.infallibleAppend(chars, len); michael@0: } michael@0: void infallibleAppend(const JS::ConstCharPtr chars, size_t len) { michael@0: cb.infallibleAppend(chars.get(), len); michael@0: } michael@0: void infallibleAppend(const jschar *begin, const jschar *end) { michael@0: cb.infallibleAppend(begin, end); michael@0: } michael@0: void infallibleAppendN(const jschar c, size_t n) { michael@0: cb.infallibleAppendN(c, n); michael@0: } michael@0: michael@0: jschar *begin() { return cb.begin(); } michael@0: jschar *end() { return cb.end(); } michael@0: const jschar *begin() const { return cb.begin(); } michael@0: const jschar *end() const { return cb.end(); } michael@0: bool empty() const { return cb.empty(); } michael@0: size_t length() const { return cb.length(); } michael@0: michael@0: /* michael@0: * Creates a string from the characters in this buffer, then (regardless michael@0: * whether string creation succeeded or failed) empties the buffer. michael@0: */ michael@0: JSFlatString *finishString(); michael@0: michael@0: /* Identical to finishString() except that an atom is created. */ michael@0: JSAtom *finishAtom(); michael@0: michael@0: /* michael@0: * Creates a raw string from the characters in this buffer. The string is michael@0: * exactly the characters in this buffer: it is *not* null-terminated michael@0: * unless the last appended character was |(jschar)0|. michael@0: */ michael@0: jschar *extractWellSized(); michael@0: }; michael@0: michael@0: inline bool michael@0: StringBuffer::append(JSLinearString *str) michael@0: { michael@0: JS::Anchor anch(str); michael@0: return cb.append(str->chars(), str->length()); michael@0: } michael@0: michael@0: inline bool michael@0: StringBuffer::append(JSString *str) michael@0: { michael@0: JSLinearString *linear = str->ensureLinear(context()); michael@0: if (!linear) michael@0: return false; michael@0: return append(linear); michael@0: } michael@0: michael@0: inline bool michael@0: StringBuffer::appendInflated(const char *cstr, size_t cstrlen) michael@0: { michael@0: size_t lengthBefore = length(); michael@0: if (!cb.growByUninitialized(cstrlen)) michael@0: return false; michael@0: InflateStringToBuffer(cstr, cstrlen, begin() + lengthBefore); michael@0: return true; michael@0: } michael@0: michael@0: /* ES5 9.8 ToString, appending the result to the string buffer. */ michael@0: extern bool michael@0: ValueToStringBufferSlow(JSContext *cx, const Value &v, StringBuffer &sb); michael@0: michael@0: inline bool michael@0: ValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb) michael@0: { michael@0: if (v.isString()) michael@0: return sb.append(v.toString()); michael@0: michael@0: return ValueToStringBufferSlow(cx, v, sb); michael@0: } michael@0: michael@0: /* ES5 9.8 ToString for booleans, appending the result to the string buffer. */ michael@0: inline bool michael@0: BooleanToStringBuffer(bool b, StringBuffer &sb) michael@0: { michael@0: return b ? sb.append("true") : sb.append("false"); michael@0: } michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif /* vm_StringBuffer_h */