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 "platform/text/SegmentedString.h"
25 unsigned SegmentedString::length() const
27 unsigned length = m_currentString.m_length;
34 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
35 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
37 length += it->m_length;
42 void SegmentedString::setExcludeLineNumbers()
44 m_currentString.setExcludeLineNumbers();
46 Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
47 Deque<SegmentedSubstring>::iterator e = m_substrings.end();
49 it->setExcludeLineNumbers();
53 void SegmentedString::clear()
58 m_currentString.clear();
59 m_numberOfCharactersConsumedPriorToCurrentString = 0;
60 m_numberOfCharactersConsumedPriorToCurrentLine = 0;
65 m_fastPathFlags = NoFastPath;
66 m_advanceFunc = &SegmentedString::advanceEmpty;
67 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
70 void SegmentedString::append(const SegmentedSubstring& s)
76 if (!m_currentString.m_length) {
77 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
79 updateAdvanceFunctionPointers();
81 m_substrings.append(s);
86 void SegmentedString::prepend(const SegmentedSubstring& s)
89 ASSERT(!s.numberOfCharactersConsumed());
93 // FIXME: We're assuming that the prepend were originally consumed by
94 // this SegmentedString. We're also ASSERTing that s is a fresh
95 // SegmentedSubstring. These assumptions are sufficient for our
96 // current use, but we might need to handle the more elaborate
97 // cases in the future.
98 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
99 m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
100 if (!m_currentString.m_length) {
102 updateAdvanceFunctionPointers();
104 // Shift our m_currentString into our list.
105 m_substrings.prepend(m_currentString);
107 updateAdvanceFunctionPointers();
112 void SegmentedString::close()
114 // Closing a stream twice is likely a coding mistake.
119 void SegmentedString::append(const SegmentedString& s)
122 if (s.m_pushedChar1) {
123 Vector<UChar, 2> unconsumedData;
124 unconsumedData.append(s.m_pushedChar1);
126 unconsumedData.append(s.m_pushedChar2);
127 append(SegmentedSubstring(String(unconsumedData)));
130 append(s.m_currentString);
131 if (s.isComposite()) {
132 Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
133 Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
134 for (; it != e; ++it)
137 m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
140 void SegmentedString::prepend(const SegmentedString& s)
143 ASSERT(!s.escaped());
144 if (s.isComposite()) {
145 Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
146 Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
147 for (; it != e; ++it)
150 prepend(s.m_currentString);
151 m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
154 void SegmentedString::advanceSubstring()
157 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
158 m_currentString = m_substrings.takeFirst();
159 // If we've previously consumed some characters of the non-current
160 // string, we now account for those characters as part of the current
161 // string, not as part of "prior to current string."
162 m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
163 updateAdvanceFunctionPointers();
165 m_currentString.clear();
167 m_fastPathFlags = NoFastPath;
168 m_advanceFunc = &SegmentedString::advanceEmpty;
169 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
173 String SegmentedString::toString() const
175 StringBuilder result;
177 result.append(m_pushedChar1);
179 result.append(m_pushedChar2);
181 m_currentString.appendTo(result);
183 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
184 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
185 for (; it != e; ++it)
186 it->appendTo(result);
188 return result.toString();
191 void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
193 ASSERT_WITH_SECURITY_IMPLICATION(count <= length());
194 for (unsigned i = 0; i < count; ++i) {
195 consumedCharacters[i] = currentChar();
200 void SegmentedString::advance8()
202 ASSERT(!m_pushedChar1);
203 decrementAndCheckLength();
204 m_currentChar = m_currentString.incrementAndGetCurrentChar8();
207 void SegmentedString::advance16()
209 ASSERT(!m_pushedChar1);
210 decrementAndCheckLength();
211 m_currentChar = m_currentString.incrementAndGetCurrentChar16();
214 void SegmentedString::advanceAndUpdateLineNumber8()
216 ASSERT(!m_pushedChar1);
217 ASSERT(m_currentString.getCurrentChar() == m_currentChar);
218 if (m_currentChar == '\n') {
220 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
222 decrementAndCheckLength();
223 m_currentChar = m_currentString.incrementAndGetCurrentChar8();
226 void SegmentedString::advanceAndUpdateLineNumber16()
228 ASSERT(!m_pushedChar1);
229 ASSERT(m_currentString.getCurrentChar() == m_currentChar);
230 if (m_currentChar == '\n') {
232 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
234 decrementAndCheckLength();
235 m_currentChar = m_currentString.incrementAndGetCurrentChar16();
238 void SegmentedString::advanceSlowCase()
241 m_pushedChar1 = m_pushedChar2;
245 m_currentChar = m_pushedChar1;
249 updateAdvanceFunctionPointers();
250 } else if (m_currentString.m_length) {
251 if (!--m_currentString.m_length)
253 } else if (!isComposite()) {
254 m_currentString.clear();
256 m_fastPathFlags = NoFastPath;
257 m_advanceFunc = &SegmentedString::advanceEmpty;
258 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
260 m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
263 void SegmentedString::advanceAndUpdateLineNumberSlowCase()
266 m_pushedChar1 = m_pushedChar2;
270 m_currentChar = m_pushedChar1;
274 updateAdvanceFunctionPointers();
275 } else if (m_currentString.m_length) {
276 if (m_currentString.getCurrentChar() == '\n' && m_currentString.doNotExcludeLineNumbers()) {
278 // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
279 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
281 if (!--m_currentString.m_length)
284 m_currentString.incrementAndGetCurrentChar(); // Only need the ++
285 } else if (!isComposite()) {
286 m_currentString.clear();
288 m_fastPathFlags = NoFastPath;
289 m_advanceFunc = &SegmentedString::advanceEmpty;
290 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
293 m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
296 void SegmentedString::advanceEmpty()
298 ASSERT(!m_currentString.m_length && !isComposite());
302 void SegmentedString::updateSlowCaseFunctionPointers()
304 m_fastPathFlags = NoFastPath;
305 m_advanceFunc = &SegmentedString::advanceSlowCase;
306 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase;
309 OrdinalNumber SegmentedString::currentLine() const
311 return OrdinalNumber::fromZeroBasedInt(m_currentLine);
314 OrdinalNumber SegmentedString::currentColumn() const
316 int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
317 return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn);
320 void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength)
322 m_currentLine = line.zeroBasedInt();
323 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();