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 860701 : {
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 : inline bool checkLength(size_t length);
38 7662743 : JSContext *context() const { return cb.allocPolicy().context(); }
39 : jschar *extractWellSized();
40 :
41 : StringBuffer(const StringBuffer &other) MOZ_DELETE;
42 : void operator=(const StringBuffer &other) MOZ_DELETE;
43 :
44 : public:
45 860701 : explicit StringBuffer(JSContext *cx) : cb(cx) { }
46 :
47 : inline bool reserve(size_t len);
48 : inline bool resize(size_t len);
49 : inline bool append(const jschar c);
50 : inline bool append(const jschar *chars, size_t len);
51 : inline bool append(const jschar *begin, const jschar *end);
52 : inline bool append(JSString *str);
53 : inline bool append(JSLinearString *str);
54 : inline bool appendN(const jschar c, size_t n);
55 : inline bool appendInflated(const char *cstr, size_t len);
56 :
57 : template <size_t ArrayLength>
58 159966 : bool append(const char (&array)[ArrayLength]) {
59 159966 : return cb.append(array, array + ArrayLength - 1); /* No trailing '\0'. */
60 : }
61 :
62 : /* Infallible variants usable when the corresponding space is reserved. */
63 1298 : void infallibleAppend(const jschar c) {
64 1298 : cb.infallibleAppend(c);
65 1298 : }
66 3750008 : void infallibleAppend(const jschar *chars, size_t len) {
67 3750008 : cb.infallibleAppend(chars, len);
68 3750008 : }
69 18 : void infallibleAppend(const jschar *begin, const jschar *end) {
70 18 : cb.infallibleAppend(begin, end);
71 18 : }
72 : void infallibleAppendN(const jschar c, size_t n) {
73 : cb.infallibleAppendN(c, n);
74 : }
75 :
76 745324 : jschar *begin() { return cb.begin(); }
77 : jschar *end() { return cb.end(); }
78 30825 : const jschar *begin() const { return cb.begin(); }
79 11275 : const jschar *end() const { return cb.end(); }
80 362403 : bool empty() const { return cb.empty(); }
81 : inline size_t length() const;
82 :
83 : /*
84 : * Creates a string from the characters in this buffer, then (regardless
85 : * whether string creation succeeded or failed) empties the buffer.
86 : */
87 : JSFixedString *finishString();
88 :
89 : /* Identical to finishString() except that an atom is created. */
90 : JSAtom *finishAtom();
91 : };
92 :
93 : inline bool
94 1270676 : StringBuffer::append(JSLinearString *str)
95 : {
96 2541352 : JS::Anchor<JSString *> anch(str);
97 1270676 : return cb.append(str->chars(), str->length());
98 : }
99 :
100 : inline bool
101 1268757 : StringBuffer::append(JSString *str)
102 : {
103 1268757 : JSLinearString *linear = str->ensureLinear(context());
104 1268757 : if (!linear)
105 0 : return false;
106 1268757 : return append(linear);
107 : }
108 :
109 : inline size_t
110 2654547 : StringBuffer::length() const
111 : {
112 2654547 : return cb.length();
113 : }
114 :
115 : inline bool
116 717944 : StringBuffer::appendInflated(const char *cstr, size_t cstrlen)
117 : {
118 717944 : size_t lengthBefore = length();
119 717944 : if (!cb.growByUninitialized(cstrlen))
120 0 : return false;
121 1435888 : DebugOnly<size_t> oldcstrlen = cstrlen;
122 : DebugOnly<bool> ok = InflateStringToBuffer(context(), cstr, cstrlen,
123 1435888 : begin() + lengthBefore, &cstrlen);
124 717944 : JS_ASSERT(ok && oldcstrlen == cstrlen);
125 717944 : return true;
126 : }
127 :
128 : } /* namespace js */
129 :
130 : #endif /* StringBuffer_h___ */
|