2
Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
Boston, MA 02110-1301, USA.
20
#ifndef SegmentedString_h
21
#define SegmentedString_h
23
#include <wtf/Deque.h>
24
#include <wtf/text/StringBuilder.h>
25
#include <wtf/text/TextPosition.h>
26
#include <wtf/text/WTFString.h>
30
class SegmentedString;
32
class SegmentedSubstring {
36
, m_doNotExcludeLineNumbers(true)
39
m_data.string16Ptr = 0;
42
SegmentedSubstring(const String& str)
43
: m_length(str.length())
44
, m_doNotExcludeLineNumbers(true)
48
if (m_string.is8Bit()) {
50
m_data.string8Ptr = m_string.characters8();
53
m_data.string16Ptr = m_string.characters16();
59
void clear() { m_length = 0; m_data.string16Ptr = 0; m_is8Bit = false;}
61
bool is8Bit() { return m_is8Bit; }
63
bool excludeLineNumbers() const { return !m_doNotExcludeLineNumbers; }
64
bool doNotExcludeLineNumbers() const { return m_doNotExcludeLineNumbers; }
66
void setExcludeLineNumbers() { m_doNotExcludeLineNumbers = false; }
68
int numberOfCharactersConsumed() const { return m_string.length() - m_length; }
70
void appendTo(StringBuilder& builder) const
72
int offset = m_string.length() - m_length;
76
builder.append(m_string);
78
builder.append(m_string.substring(offset, m_length));
81
UChar getCurrentChar8()
83
return *m_data.string8Ptr;
86
UChar getCurrentChar16()
88
return m_data.string16Ptr ? *m_data.string16Ptr : 0;
91
UChar incrementAndGetCurrentChar8()
93
ASSERT(m_data.string8Ptr);
94
return *++m_data.string8Ptr;
97
UChar incrementAndGetCurrentChar16()
99
ASSERT(m_data.string16Ptr);
100
return *++m_data.string16Ptr;
103
String currentSubString(unsigned length)
105
int offset = m_string.length() - m_length;
106
return m_string.substring(offset, length);
109
ALWAYS_INLINE UChar getCurrentChar()
113
return getCurrentChar8();
114
return getCurrentChar16();
117
ALWAYS_INLINE UChar incrementAndGetCurrentChar()
121
return incrementAndGetCurrentChar8();
122
return incrementAndGetCurrentChar16();
127
const LChar* string8Ptr;
128
const UChar* string16Ptr;
133
bool m_doNotExcludeLineNumbers;
138
class SegmentedString {
144
, m_numberOfCharactersConsumedPriorToCurrentString(0)
145
, m_numberOfCharactersConsumedPriorToCurrentLine(0)
149
, m_fastPathFlags(NoFastPath)
150
, m_advanceFunc(&SegmentedString::advanceEmpty)
151
, m_advanceAndUpdateLineNumberFunc(&SegmentedString::advanceEmpty)
155
SegmentedString(const String& str)
158
, m_currentString(str)
160
, m_numberOfCharactersConsumedPriorToCurrentString(0)
161
, m_numberOfCharactersConsumedPriorToCurrentLine(0)
164
, m_empty(!str.length())
165
, m_fastPathFlags(NoFastPath)
167
if (m_currentString.m_length)
168
m_currentChar = m_currentString.getCurrentChar();
169
updateAdvanceFunctionPointers();
172
SegmentedString(const SegmentedString&);
174
const SegmentedString& operator=(const SegmentedString&);
179
void append(const SegmentedString&);
180
void prepend(const SegmentedString&);
182
bool excludeLineNumbers() const { return m_currentString.excludeLineNumbers(); }
183
void setExcludeLineNumbers();
187
if (!m_pushedChar1) {
189
m_currentChar = m_pushedChar1 ? m_pushedChar1 : m_currentString.getCurrentChar();
190
updateSlowCaseFunctionPointers();
192
ASSERT(!m_pushedChar2);
197
bool isEmpty() const { return m_empty; }
198
unsigned length() const;
200
bool isClosed() const { return m_closed; }
202
enum LookAheadResult {
208
LookAheadResult lookAhead(const String& string) { return lookAheadInline(string, true); }
209
LookAheadResult lookAheadIgnoringCase(const String& string) { return lookAheadInline(string, false); }
213
if (m_fastPathFlags & Use8BitAdvance) {
214
ASSERT(!m_pushedChar1);
215
bool haveOneCharacterLeft = (--m_currentString.m_length == 1);
216
m_currentChar = m_currentString.incrementAndGetCurrentChar8();
218
if (!haveOneCharacterLeft)
221
updateSlowCaseFunctionPointers();
226
(this->*m_advanceFunc)();
229
inline void advanceAndUpdateLineNumber()
231
if (m_fastPathFlags & Use8BitAdvance) {
232
ASSERT(!m_pushedChar1);
234
bool haveNewLine = (m_currentChar == '\n') & !!(m_fastPathFlags & Use8BitAdvanceAndUpdateLineNumbers);
235
bool haveOneCharacterLeft = (--m_currentString.m_length == 1);
237
m_currentChar = m_currentString.incrementAndGetCurrentChar8();
239
if (!(haveNewLine | haveOneCharacterLeft))
244
m_numberOfCharactersConsumedPriorToCurrentLine = m_numberOfCharactersConsumedPriorToCurrentString + m_currentString.numberOfCharactersConsumed();
247
if (haveOneCharacterLeft)
248
updateSlowCaseFunctionPointers();
253
(this->*m_advanceAndUpdateLineNumberFunc)();
256
void advanceAndASSERT(UChar expectedCharacter)
258
ASSERT_UNUSED(expectedCharacter, currentChar() == expectedCharacter);
262
void advanceAndASSERTIgnoringCase(UChar expectedCharacter)
264
ASSERT_UNUSED(expectedCharacter, WTF::Unicode::foldCase(currentChar()) == WTF::Unicode::foldCase(expectedCharacter));
268
void advancePastNonNewline()
270
ASSERT(currentChar() != '\n');
274
void advancePastNewlineAndUpdateLineNumber()
276
ASSERT(currentChar() == '\n');
277
if (!m_pushedChar1 && m_currentString.m_length > 1) {
278
int newLineFlag = m_currentString.doNotExcludeLineNumbers();
279
m_currentLine += newLineFlag;
281
m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
282
decrementAndCheckLength();
283
m_currentChar = m_currentString.incrementAndGetCurrentChar();
286
advanceAndUpdateLineNumberSlowCase();
289
// Writes the consumed characters into consumedCharacters, which must
290
// have space for at least |count| characters.
291
void advance(unsigned count, UChar* consumedCharacters);
293
bool escaped() const { return m_pushedChar1; }
295
int numberOfCharactersConsumed() const
297
int numberOfPushedCharacters = 0;
299
++numberOfPushedCharacters;
301
++numberOfPushedCharacters;
303
return m_numberOfCharactersConsumedPriorToCurrentString + m_currentString.numberOfCharactersConsumed() - numberOfPushedCharacters;
306
String toString() const;
308
UChar currentChar() const { return m_currentChar; }
310
// The method is moderately slow, comparing to currentLine method.
311
OrdinalNumber currentColumn() const;
312
OrdinalNumber currentLine() const;
313
// Sets value of line/column variables. Column is specified indirectly by a parameter columnAftreProlog
314
// which is a value of column that we should get after a prolog (first prologLength characters) has been consumed.
315
void setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength);
320
Use8BitAdvanceAndUpdateLineNumbers = 1 << 0,
321
Use8BitAdvance = 1 << 1,
324
void append(const SegmentedSubstring&);
325
void prepend(const SegmentedSubstring&);
329
void advanceAndUpdateLineNumber8();
330
void advanceAndUpdateLineNumber16();
331
void advanceSlowCase();
332
void advanceAndUpdateLineNumberSlowCase();
334
void advanceSubstring();
336
void updateSlowCaseFunctionPointers();
338
void decrementAndCheckLength()
340
ASSERT(m_currentString.m_length > 1);
341
if (--m_currentString.m_length == 1)
342
updateSlowCaseFunctionPointers();
345
void updateAdvanceFunctionPointers()
347
if ((m_currentString.m_length > 1) && !m_pushedChar1) {
348
if (m_currentString.is8Bit()) {
349
m_advanceFunc = &SegmentedString::advance8;
350
m_fastPathFlags = Use8BitAdvance;
351
if (m_currentString.doNotExcludeLineNumbers()) {
352
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumber8;
353
m_fastPathFlags |= Use8BitAdvanceAndUpdateLineNumbers;
355
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advance8;
359
m_advanceFunc = &SegmentedString::advance16;
360
m_fastPathFlags = NoFastPath;
361
if (m_currentString.doNotExcludeLineNumbers())
362
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumber16;
364
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advance16;
368
if (!m_currentString.m_length && !isComposite()) {
369
m_advanceFunc = &SegmentedString::advanceEmpty;
370
m_fastPathFlags = NoFastPath;
371
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
374
updateSlowCaseFunctionPointers();
377
inline LookAheadResult lookAheadInline(const String& string, bool caseSensitive)
379
if (!m_pushedChar1 && string.length() <= static_cast<unsigned>(m_currentString.m_length)) {
380
String currentSubstring = m_currentString.currentSubString(string.length());
381
if (currentSubstring.startsWith(string, caseSensitive))
385
return lookAheadSlowCase(string, caseSensitive);
388
LookAheadResult lookAheadSlowCase(const String& string, bool caseSensitive)
390
unsigned count = string.length();
391
if (count > length())
392
return NotEnoughCharacters;
393
UChar* consumedCharacters;
394
String consumedString = String::createUninitialized(count, consumedCharacters);
395
advance(count, consumedCharacters);
396
LookAheadResult result = DidNotMatch;
397
if (consumedString.startsWith(string, caseSensitive))
399
prepend(SegmentedString(consumedString));
403
bool isComposite() const { return !m_substrings.isEmpty(); }
407
SegmentedSubstring m_currentString;
409
int m_numberOfCharactersConsumedPriorToCurrentString;
410
int m_numberOfCharactersConsumedPriorToCurrentLine;
412
Deque<SegmentedSubstring> m_substrings;
415
unsigned char m_fastPathFlags;
416
void (SegmentedString::*m_advanceFunc)();
417
void (SegmentedString::*m_advanceAndUpdateLineNumberFunc)();