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