Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: third_party/WebKit/Source/wtf/text/StringBuilder.h

Issue 2046353002: Use a Vector for the buffer in StringBuilder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 17 matching lines...) Expand all
28 #define StringBuilder_h 28 #define StringBuilder_h
29 29
30 #include "wtf/WTFExport.h" 30 #include "wtf/WTFExport.h"
31 #include "wtf/text/AtomicString.h" 31 #include "wtf/text/AtomicString.h"
32 #include "wtf/text/StringView.h" 32 #include "wtf/text/StringView.h"
33 #include "wtf/text/WTFString.h" 33 #include "wtf/text/WTFString.h"
34 34
35 namespace WTF { 35 namespace WTF {
36 36
37 class WTF_EXPORT StringBuilder { 37 class WTF_EXPORT StringBuilder {
38 // Disallow copying since it's expensive and we don't want code to do it by accident.
39 WTF_MAKE_NONCOPYABLE(StringBuilder); 38 WTF_MAKE_NONCOPYABLE(StringBuilder);
40
41 public: 39 public:
42 StringBuilder() 40 StringBuilder()
43 : m_bufferCharacters8(0) 41 : m_buffer(nullptr)
44 , m_length(0) 42 , m_length(0)
45 , m_is8Bit(true) 43 , m_is8Bit(true) {}
46 {
47 }
48 44
49 void append(const UChar*, unsigned); 45 ~StringBuilder() { clear(); }
50 void append(const LChar*, unsigned); 46
47 void append(const UChar*, unsigned length);
48 void append(const LChar*, unsigned length);
51 49
52 ALWAYS_INLINE void append(const char* characters, unsigned length) { append( reinterpret_cast<const LChar*>(characters), length); } 50 ALWAYS_INLINE void append(const char* characters, unsigned length) { append( reinterpret_cast<const LChar*>(characters), length); }
53 51
54 void append(const StringBuilder& other) 52 void append(const StringBuilder& other)
55 { 53 {
56 if (!other.m_length) 54 if (!other.m_length)
57 return; 55 return;
58 56
59 // If we're appending to an empty string, and there is not a buffer (res erveCapacity has not been called) 57 if (!m_length && !hasBuffer() && !other.m_string.isNull()) {
60 // then just retain the string.
61 if (!m_length && !m_buffer && !other.m_string.isNull()) {
62 m_string = other.m_string; 58 m_string = other.m_string;
63 m_length = other.m_length; 59 m_length = other.m_string.length();
60 m_is8Bit = other.m_string.is8Bit();
64 return; 61 return;
65 } 62 }
66 63
67 if (other.is8Bit()) 64 if (other.is8Bit())
68 append(other.characters8(), other.m_length); 65 append(other.characters8(), other.m_length);
69 else 66 else
70 append(other.characters16(), other.m_length); 67 append(other.characters16(), other.m_length);
71 } 68 }
72 69
73 // NOTE: The semantics of this are different than StringView(..., offset, le ngth) 70 // NOTE: The semantics of this are different than StringView(..., offset, le ngth)
(...skipping 18 matching lines...) Expand all
92 89
93 // If we're appending to an empty builder, and there is not a buffer 90 // If we're appending to an empty builder, and there is not a buffer
94 // (reserveCapacity has not been called), then share the impl if 91 // (reserveCapacity has not been called), then share the impl if
95 // possible. 92 // possible.
96 // 93 //
97 // This is important to avoid string copies inside dom operations like 94 // This is important to avoid string copies inside dom operations like
98 // Node::textContent when there's only a single Text node child, or 95 // Node::textContent when there's only a single Text node child, or
99 // inside the parser in the common case when flushing buffered text to 96 // inside the parser in the common case when flushing buffered text to
100 // a Text node. 97 // a Text node.
101 StringImpl* impl = string.sharedImpl(); 98 StringImpl* impl = string.sharedImpl();
102 if (!m_length && !m_buffer && impl) { 99 if (!m_length && !hasBuffer() && impl) {
103 m_string = impl; 100 m_string = impl;
104 m_length = impl->length(); 101 m_length = impl->length();
105 m_is8Bit = impl->is8Bit(); 102 m_is8Bit = impl->is8Bit();
106 return; 103 return;
107 } 104 }
108 105
109 if (string.is8Bit()) 106 if (string.is8Bit())
110 append(string.characters8(), string.length()); 107 append(string.characters8(), string.length());
111 else 108 else
112 append(string.characters16(), string.length()); 109 append(string.characters16(), string.length());
113 } 110 }
114 111
115 void append(UChar c) 112 void append(UChar c)
116 { 113 {
117 if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) { 114 if (m_is8Bit && c <= 0xFF) {
118 if (!m_is8Bit) { 115 append(static_cast<LChar>(c));
119 m_bufferCharacters16[m_length++] = c; 116 return;
120 return;
121 }
122
123 if (!(c & ~0xff)) {
124 m_bufferCharacters8[m_length++] = static_cast<LChar>(c);
125 return;
126 }
127 } 117 }
128 append(&c, 1); 118 ensureBuffer16();
119 m_string = String();
120 m_buffer16->append(c);
121 ++m_length;
129 } 122 }
130 123
131 void append(LChar c) 124 void append(LChar c)
132 { 125 {
133 if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) { 126 if (!m_is8Bit) {
134 if (m_is8Bit) 127 append(static_cast<UChar>(c));
135 m_bufferCharacters8[m_length++] = c; 128 return;
136 else
137 m_bufferCharacters16[m_length++] = c;
138 } else {
139 append(&c, 1);
140 } 129 }
130 ensureBuffer8();
131 m_string = String();
132 m_buffer8->append(c);
133 ++m_length;
141 } 134 }
142 135
143 void append(char c) 136 void append(char c)
144 { 137 {
145 append(static_cast<LChar>(c)); 138 append(static_cast<LChar>(c));
146 } 139 }
147 140
148 void append(UChar32 c) 141 void append(UChar32 c)
149 { 142 {
150 if (U_IS_BMP(c)) { 143 if (U_IS_BMP(c)) {
151 append(static_cast<UChar>(c)); 144 append(static_cast<UChar>(c));
152 return; 145 return;
153 } 146 }
154 append(U16_LEAD(c)); 147 append(U16_LEAD(c));
155 append(U16_TRAIL(c)); 148 append(U16_TRAIL(c));
156 } 149 }
157 150
158 void appendNumber(int); 151 void appendNumber(int);
159 void appendNumber(unsigned); 152 void appendNumber(unsigned);
160 void appendNumber(long); 153 void appendNumber(long);
161 void appendNumber(unsigned long); 154 void appendNumber(unsigned long);
162 void appendNumber(long long); 155 void appendNumber(long long);
163 void appendNumber(unsigned long long); 156 void appendNumber(unsigned long long);
164 void appendNumber(double, unsigned precision = 6, TrailingZerosTruncatingPol icy = TruncateTrailingZeros); 157 void appendNumber(double, unsigned precision = 6, TrailingZerosTruncatingPol icy = TruncateTrailingZeros);
165 158
166 String toString() 159 String toString();
167 { 160 AtomicString toAtomicString();
168 shrinkToFit(); 161 String substring(unsigned start, unsigned length) const;
169 if (m_string.isNull())
170 reifyString();
171 return m_string;
172 }
173 162
174 String substring(unsigned position, unsigned length) const 163 unsigned length() const { return m_length; }
175 {
176 if (!m_length)
177 return emptyString();
178 if (!m_string.isNull())
179 return m_string.substring(position, length);
180 return reifySubstring(position, length);
181 }
182
183 AtomicString toAtomicString() const
184 {
185 if (!m_length)
186 return emptyAtom;
187
188 // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large.
189 if (canShrink()) {
190 if (is8Bit())
191 return AtomicString(characters8(), length());
192 return AtomicString(characters16(), length());
193 }
194
195 if (!m_string.isNull())
196 return AtomicString(m_string);
197
198 DCHECK(m_buffer);
199 return AtomicString(m_buffer.get(), 0, m_length);
200 }
201
202 unsigned length() const
203 {
204 return m_length;
205 }
206
207 bool isEmpty() const { return !m_length; } 164 bool isEmpty() const { return !m_length; }
208 165
166 unsigned capacity() const;
209 void reserveCapacity(unsigned newCapacity); 167 void reserveCapacity(unsigned newCapacity);
210 168
211 unsigned capacity() const 169 // TODO(esprehn): Rename to shrink().
212 {
213 return m_buffer ? m_buffer->length() : m_length;
214 }
215
216 void resize(unsigned newSize); 170 void resize(unsigned newSize);
217 171
218 bool canShrink() const;
219
220 void shrinkToFit();
221
222 UChar operator[](unsigned i) const 172 UChar operator[](unsigned i) const
223 { 173 {
224 ASSERT_WITH_SECURITY_IMPLICATION(i < m_length); 174 ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
225 if (m_is8Bit) 175 if (m_is8Bit)
226 return characters8()[i]; 176 return characters8()[i];
227 return characters16()[i]; 177 return characters16()[i];
228 } 178 }
229 179
230 const LChar* characters8() const 180 const LChar* characters8() const
231 { 181 {
232 DCHECK(m_is8Bit); 182 DCHECK(m_is8Bit);
233 if (!m_length) 183 if (!length())
234 return 0; 184 return nullptr;
235 if (!m_string.isNull()) 185 if (!m_string.isNull())
236 return m_string.characters8(); 186 return m_string.characters8();
237 DCHECK(m_buffer); 187 DCHECK(m_buffer8);
238 return m_buffer->characters8(); 188 return m_buffer8->data();
239 } 189 }
240 190
241 const UChar* characters16() const 191 const UChar* characters16() const
242 { 192 {
243 DCHECK(!m_is8Bit); 193 DCHECK(!m_is8Bit);
244 if (!m_length) 194 if (!length())
245 return 0; 195 return nullptr;
246 if (!m_string.isNull()) 196 if (!m_string.isNull())
247 return m_string.characters16(); 197 return m_string.characters16();
248 DCHECK(m_buffer); 198 DCHECK(m_buffer16);
249 return m_buffer->characters16(); 199 return m_buffer16->data();
250 } 200 }
251 201
252 bool is8Bit() const { return m_is8Bit; } 202 bool is8Bit() const { return m_is8Bit; }
253 203
254 void clear() 204 void clear();
205 void swap(StringBuilder&);
206
207 private:
208 typedef Vector<LChar, 16> Buffer8;
209 typedef Vector<UChar, 16> Buffer16;
haraken 2016/06/27 06:36:01 I don't mind specifying a larger inline capacity f
esprehn 2016/06/27 23:36:40 Yeah we can do that, there's a bunch of StringBuil
210
211 void ensureBuffer8()
255 { 212 {
256 m_length = 0; 213 DCHECK(m_is8Bit);
257 m_string = String(); 214 if (!hasBuffer())
258 m_buffer = nullptr; 215 createBuffer8();
259 m_bufferCharacters8 = 0;
260 m_is8Bit = true;
261 } 216 }
262 217
263 void swap(StringBuilder& stringBuilder) 218 void ensureBuffer16()
264 { 219 {
265 std::swap(m_length, stringBuilder.m_length); 220 if (m_is8Bit || !hasBuffer())
haraken 2016/06/27 06:36:01 Shouldn't this be: DCHECK(!m_is8Bit); if (!ha
esprehn 2016/06/27 23:36:40 No, this is called whenever we need a 16 bit buffe
266 m_string.swap(stringBuilder.m_string); 221 createBuffer16();
267 m_buffer.swap(stringBuilder.m_buffer);
268 std::swap(m_is8Bit, stringBuilder.m_is8Bit);
269 std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
270 } 222 }
271 223
272 private: 224 void createBuffer8();
273 void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength) ; 225 void createBuffer16();
274 void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength) ;
275 void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requir edLength);
276 template <typename CharType>
277 void reallocateBuffer(unsigned requiredLength);
278 template <typename CharType>
279 ALWAYS_INLINE CharType* appendUninitialized(unsigned length);
280 template <typename CharType>
281 CharType* appendUninitializedSlow(unsigned length);
282 template <typename CharType>
283 ALWAYS_INLINE CharType * getBufferCharacters();
284 void reifyString();
285 String reifySubstring(unsigned position, unsigned length) const;
286 226
287 String m_string; // Pointers first: crbug.com/232031 227 bool hasBuffer() const { return m_buffer; }
288 RefPtr<StringImpl> m_buffer; 228
229 String m_string;
289 union { 230 union {
290 LChar* m_bufferCharacters8; 231 Buffer8* m_buffer8;
291 UChar* m_bufferCharacters16; 232 Buffer16* m_buffer16;
233 void* m_buffer;
hajimehoshi 2016/06/27 06:13:20 Where is |m_buffer| used now?
esprehn 2016/06/27 06:15:15 hasBuffer() uses it since it doesn't care about th
292 }; 234 };
293 unsigned m_length; 235 unsigned m_length;
294 bool m_is8Bit; 236 bool m_is8Bit;
295 }; 237 };
296 238
297 template <>
298 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>()
299 {
300 DCHECK(m_is8Bit);
301 return m_bufferCharacters8;
302 }
303
304 template <>
305 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>()
306 {
307 DCHECK(!m_is8Bit);
308 return m_bufferCharacters16;
309 }
310
311 template <typename CharType> 239 template <typename CharType>
312 bool equal(const StringBuilder& s, const CharType* buffer, unsigned length) 240 bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
313 { 241 {
314 if (s.length() != length) 242 if (s.length() != length)
315 return false; 243 return false;
316 244
317 if (s.is8Bit()) 245 if (s.is8Bit())
318 return equal(s.characters8(), buffer, length); 246 return equal(s.characters8(), buffer, length);
319 247
320 return equal(s.characters16(), buffer, length); 248 return equal(s.characters16(), buffer, length);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 inline bool operator==(const StringBuilder& a, const String& b) { return equal(a , b); } 310 inline bool operator==(const StringBuilder& a, const String& b) { return equal(a , b); }
383 inline bool operator!=(const StringBuilder& a, const String& b) { return !equal( a, b); } 311 inline bool operator!=(const StringBuilder& a, const String& b) { return !equal( a, b); }
384 inline bool operator==(const String& a, const StringBuilder& b) { return equal(b , a); } 312 inline bool operator==(const String& a, const StringBuilder& b) { return equal(b , a); }
385 inline bool operator!=(const String& a, const StringBuilder& b) { return !equal( b, a); } 313 inline bool operator!=(const String& a, const StringBuilder& b) { return !equal( b, a); }
386 314
387 } // namespace WTF 315 } // namespace WTF
388 316
389 using WTF::StringBuilder; 317 using WTF::StringBuilder;
390 318
391 #endif // StringBuilder_h 319 #endif // StringBuilder_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698