1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef StringBuffer_h___
8 : #define StringBuffer_h___
9 :
10 : #include "mozilla/Attributes.h"
11 :
12 : #include "jscntxt.h"
13 : #include "jspubtd.h"
14 :
15 : #include "js/Vector.h"
16 :
17 : namespace js {
18 :
19 : /*
20 : * String builder that eagerly checks for over-allocation past the maximum
21 : * string length.
22 : *
23 : * Any operation which would exceed the maximum string length causes an
24 : * exception report on the context and results in a failed return value.
25 : *
26 : * Well-sized extractions (which waste no more than 1/4 of their char
27 : * buffer space) are guaranteed for strings built by this interface.
28 : * See |extractWellSized|.
29 : */
30 : class StringBuffer
31 542119 : {
32 : /* cb's buffer is taken by the new string so use ContextAllocPolicy. */
33 : typedef Vector<jschar, 32, ContextAllocPolicy> CharBuffer;
34 :
35 : CharBuffer cb;
36 :
37 1205824 : JSContext *context() const { return cb.allocPolicy().context(); }
38 : jschar *extractWellSized();
39 :
40 : StringBuffer(const StringBuffer &other) MOZ_DELETE;
41 : void operator=(const StringBuffer &other) MOZ_DELETE;
42 :
43 : public:
44 542119 : explicit StringBuffer(JSContext *cx) : cb(cx) { }
45 :
46 1766504 : inline bool reserve(size_t len) { return cb.reserve(len); }
47 : inline bool resize(size_t len) { return cb.resize(len); }
48 11475 : inline bool append(const jschar c) { return cb.append(c); }
49 724320 : inline bool append(const jschar *chars, size_t len) { return cb.append(chars, len); }
50 54 : inline bool append(const jschar *begin, const jschar *end) { return cb.append(begin, end); }
51 : inline bool append(JSString *str);
52 : inline bool append(JSLinearString *str);
53 216 : inline bool appendN(const jschar c, size_t n) { return cb.appendN(c, n); }
54 : inline bool appendInflated(const char *cstr, size_t len);
55 :
56 : template <size_t ArrayLength>
57 122205 : bool append(const char (&array)[ArrayLength]) {
58 122205 : return cb.append(array, array + ArrayLength - 1); /* No trailing '\0'. */
59 : }
60 :
61 : /* Infallible variants usable when the corresponding space is reserved. */
62 1278 : void infallibleAppend(const jschar c) {
63 1278 : cb.infallibleAppend(c);
64 1278 : }
65 3532992 : void infallibleAppend(const jschar *chars, size_t len) {
66 3532992 : cb.infallibleAppend(chars, len);
67 3532992 : }
68 18 : void infallibleAppend(const jschar *begin, const jschar *end) {
69 18 : cb.infallibleAppend(begin, end);
70 18 : }
71 : void infallibleAppendN(const jschar c, size_t n) {
72 : cb.infallibleAppendN(c, n);
73 : }
74 :
75 196454 : jschar *begin() { return cb.begin(); }
76 : jschar *end() { return cb.end(); }
77 19574 : const jschar *begin() const { return cb.begin(); }
78 36 : const jschar *end() const { return cb.end(); }
79 5697 : bool empty() const { return cb.empty(); }
80 2000925 : size_t length() const { return cb.length(); }
81 :
82 : /*
83 : * Creates a string from the characters in this buffer, then (regardless
84 : * whether string creation succeeded or failed) empties the buffer.
85 : */
86 : JSFixedString *finishString();
87 :
88 : /* Identical to finishString() except that an atom is created. */
89 : JSAtom *finishAtom();
90 : };
91 :
92 : inline bool
93 672967 : StringBuffer::append(JSLinearString *str)
94 : {
95 1345934 : JS::Anchor<JSString *> anch(str);
96 672967 : return cb.append(str->chars(), str->length());
97 : }
98 :
99 : inline bool
100 669997 : StringBuffer::append(JSString *str)
101 : {
102 669997 : JSLinearString *linear = str->ensureLinear(context());
103 669997 : if (!linear)
104 0 : return false;
105 669997 : return append(linear);
106 : }
107 :
108 : inline bool
109 196418 : StringBuffer::appendInflated(const char *cstr, size_t cstrlen)
110 : {
111 196418 : size_t lengthBefore = length();
112 196418 : if (!cb.growByUninitialized(cstrlen))
113 0 : return false;
114 392836 : DebugOnly<size_t> oldcstrlen = cstrlen;
115 : DebugOnly<bool> ok = InflateStringToBuffer(context(), cstr, cstrlen,
116 392836 : begin() + lengthBefore, &cstrlen);
117 196418 : JS_ASSERT(ok && oldcstrlen == cstrlen);
118 196418 : return true;
119 : }
120 :
121 : /* ES5 9.8 ToString, appending the result to the string buffer. */
122 : extern bool
123 : ValueToStringBufferSlow(JSContext *cx, const Value &v, StringBuffer &sb);
124 :
125 : inline bool
126 875483 : ValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
127 : {
128 875483 : if (v.isString())
129 665109 : return sb.append(v.toString());
130 :
131 210374 : return ValueToStringBufferSlow(cx, v, sb);
132 : }
133 :
134 : /* ES5 9.8 ToString for booleans, appending the result to the string buffer. */
135 : inline bool
136 47871 : BooleanToStringBuffer(JSContext *cx, bool b, StringBuffer &sb)
137 : {
138 47871 : return b ? sb.append("true") : sb.append("false");
139 : }
140 :
141 : } /* namespace js */
142 :
143 : #endif /* StringBuffer_h___ */
|