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.
21
#include "SegmentedString.h"
25
SegmentedString::SegmentedString(const SegmentedString& other)
26
: m_pushedChar1(other.m_pushedChar1)
27
, m_pushedChar2(other.m_pushedChar2)
28
, m_currentString(other.m_currentString)
29
, m_substrings(other.m_substrings)
30
, m_closed(other.m_closed)
31
, m_empty(other.m_empty)
32
, m_fastPathFlags(other.m_fastPathFlags)
33
, m_advanceFunc(other.m_advanceFunc)
34
, m_advanceAndUpdateLineNumberFunc(other.m_advanceAndUpdateLineNumberFunc)
37
m_currentChar = m_pushedChar2;
38
else if (m_pushedChar1)
39
m_currentChar = m_pushedChar1;
41
m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
44
const SegmentedString& SegmentedString::operator=(const SegmentedString& other)
46
m_pushedChar1 = other.m_pushedChar1;
47
m_pushedChar2 = other.m_pushedChar2;
48
m_currentString = other.m_currentString;
49
m_substrings = other.m_substrings;
51
m_currentChar = m_pushedChar2;
52
else if (m_pushedChar1)
53
m_currentChar = m_pushedChar1;
55
m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
57
m_closed = other.m_closed;
58
m_empty = other.m_empty;
59
m_fastPathFlags = other.m_fastPathFlags;
60
m_numberOfCharactersConsumedPriorToCurrentString = other.m_numberOfCharactersConsumedPriorToCurrentString;
61
m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine;
62
m_currentLine = other.m_currentLine;
64
m_advanceFunc = other.m_advanceFunc;
65
m_advanceAndUpdateLineNumberFunc = other.m_advanceAndUpdateLineNumberFunc;
70
unsigned SegmentedString::length() const
72
unsigned length = m_currentString.m_length;
79
Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
80
Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
82
length += it->m_length;
87
void SegmentedString::setExcludeLineNumbers()
89
m_currentString.setExcludeLineNumbers();
91
Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
92
Deque<SegmentedSubstring>::iterator e = m_substrings.end();
94
it->setExcludeLineNumbers();
98
void SegmentedString::clear()
103
m_currentString.clear();
104
m_numberOfCharactersConsumedPriorToCurrentString = 0;
105
m_numberOfCharactersConsumedPriorToCurrentLine = 0;
107
m_substrings.clear();
110
m_fastPathFlags = NoFastPath;
111
m_advanceFunc = &SegmentedString::advanceEmpty;
112
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
115
void SegmentedString::append(const SegmentedSubstring& s)
121
if (!m_currentString.m_length) {
122
m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
124
updateAdvanceFunctionPointers();
126
m_substrings.append(s);
130
void SegmentedString::prepend(const SegmentedSubstring& s)
133
ASSERT(!s.numberOfCharactersConsumed());
137
// FIXME: We're assuming that the prepend were originally consumed by
138
// this SegmentedString. We're also ASSERTing that s is a fresh
139
// SegmentedSubstring. These assumptions are sufficient for our
140
// current use, but we might need to handle the more elaborate
141
// cases in the future.
142
m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
143
m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
144
if (!m_currentString.m_length) {
146
updateAdvanceFunctionPointers();
148
// Shift our m_currentString into our list.
149
m_substrings.prepend(m_currentString);
151
updateAdvanceFunctionPointers();
156
void SegmentedString::close()
158
// Closing a stream twice is likely a coding mistake.
163
void SegmentedString::append(const SegmentedString& s)
166
ASSERT(!s.escaped());
167
append(s.m_currentString);
168
if (s.isComposite()) {
169
Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
170
Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
171
for (; it != e; ++it)
174
m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
177
void SegmentedString::prepend(const SegmentedString& s)
180
ASSERT(!s.escaped());
181
if (s.isComposite()) {
182
Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
183
Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
184
for (; it != e; ++it)
187
prepend(s.m_currentString);
188
m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
191
void SegmentedString::advanceSubstring()
194
m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
195
m_currentString = m_substrings.takeFirst();
196
// If we've previously consumed some characters of the non-current
197
// string, we now account for those characters as part of the current
198
// string, not as part of "prior to current string."
199
m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
200
updateAdvanceFunctionPointers();
202
m_currentString.clear();
204
m_fastPathFlags = NoFastPath;
205
m_advanceFunc = &SegmentedString::advanceEmpty;
206
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
210
String SegmentedString::toString() const
212
StringBuilder result;
214
result.append(m_pushedChar1);
216
result.append(m_pushedChar2);
218
m_currentString.appendTo(result);
220
Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
221
Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
222
for (; it != e; ++it)
223
it->appendTo(result);
225
return result.toString();
228
void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
230
ASSERT(count <= length());
231
for (unsigned i = 0; i < count; ++i) {
232
consumedCharacters[i] = currentChar();
237
void SegmentedString::advance8()
239
ASSERT(!m_pushedChar1);
240
decrementAndCheckLength();
241
m_currentChar = m_currentString.incrementAndGetCurrentChar8();
244
void SegmentedString::advance16()
246
ASSERT(!m_pushedChar1);
247
decrementAndCheckLength();
248
m_currentChar = m_currentString.incrementAndGetCurrentChar16();
251
void SegmentedString::advanceAndUpdateLineNumber8()
253
ASSERT(!m_pushedChar1);
254
ASSERT(m_currentString.getCurrentChar() == m_currentChar);
255
if (m_currentChar == '\n') {
257
m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
259
decrementAndCheckLength();
260
m_currentChar = m_currentString.incrementAndGetCurrentChar8();
263
void SegmentedString::advanceAndUpdateLineNumber16()
265
ASSERT(!m_pushedChar1);
266
ASSERT(m_currentString.getCurrentChar() == m_currentChar);
267
if (m_currentChar == '\n') {
269
m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
271
decrementAndCheckLength();
272
m_currentChar = m_currentString.incrementAndGetCurrentChar16();
275
void SegmentedString::advanceSlowCase()
278
m_pushedChar1 = m_pushedChar2;
282
m_currentChar = m_pushedChar1;
286
updateAdvanceFunctionPointers();
287
} else if (m_currentString.m_length) {
288
if (--m_currentString.m_length == 0)
290
} else if (!isComposite()) {
291
m_currentString.clear();
293
m_fastPathFlags = NoFastPath;
294
m_advanceFunc = &SegmentedString::advanceEmpty;
295
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
297
m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
300
void SegmentedString::advanceAndUpdateLineNumberSlowCase()
303
m_pushedChar1 = m_pushedChar2;
307
m_currentChar = m_pushedChar1;
311
updateAdvanceFunctionPointers();
312
} else if (m_currentString.m_length) {
313
if (m_currentString.getCurrentChar() == '\n' && m_currentString.doNotExcludeLineNumbers()) {
315
// Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
316
m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
318
if (--m_currentString.m_length == 0)
321
m_currentString.incrementAndGetCurrentChar(); // Only need the ++
322
} else if (!isComposite()) {
323
m_currentString.clear();
325
m_fastPathFlags = NoFastPath;
326
m_advanceFunc = &SegmentedString::advanceEmpty;
327
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
330
m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
333
void SegmentedString::advanceEmpty()
335
ASSERT(!m_currentString.m_length && !isComposite());
339
void SegmentedString::updateSlowCaseFunctionPointers()
341
m_fastPathFlags = NoFastPath;
342
m_advanceFunc = &SegmentedString::advanceSlowCase;
343
m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase;
346
OrdinalNumber SegmentedString::currentLine() const
348
return OrdinalNumber::fromZeroBasedInt(m_currentLine);
351
OrdinalNumber SegmentedString::currentColumn() const
353
int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
354
return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn);
357
void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength)
359
m_currentLine = line.zeroBasedInt();
360
m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();