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)
32 if (other.m_currentChar == &other.m_pushedChar1)
33 m_currentChar = &m_pushedChar1;
34 else if (other.m_currentChar == &other.m_pushedChar2)
35 m_currentChar = &m_pushedChar2;
37 m_currentChar = other.m_currentChar;
40 const SegmentedString& SegmentedString::operator=(const SegmentedString& other)
42 m_pushedChar1 = other.m_pushedChar1;
43 m_pushedChar2 = other.m_pushedChar2;
44 m_currentString = other.m_currentString;
45 m_substrings = other.m_substrings;
46 if (other.m_currentChar == &other.m_pushedChar1)
47 m_currentChar = &m_pushedChar1;
48 else if (other.m_currentChar == &other.m_pushedChar2)
49 m_currentChar = &m_pushedChar2;
51 m_currentChar = other.m_currentChar;
52 m_closed = other.m_closed;
53 m_numberOfCharactersConsumedPriorToCurrentString = other.m_numberOfCharactersConsumedPriorToCurrentString;
54 m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine;
55 m_currentLine = other.m_currentLine;
60 unsigned SegmentedString::length() const
62 unsigned length = m_currentString.m_length;
69 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
70 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
72 length += it->m_length;
77 void SegmentedString::setExcludeLineNumbers()
79 m_currentString.setExcludeLineNumbers();
81 Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
82 Deque<SegmentedSubstring>::iterator e = m_substrings.end();
84 it->setExcludeLineNumbers();
88 void SegmentedString::clear()
93 m_currentString.clear();
98 void SegmentedString::append(const SegmentedSubstring& s)
104 if (!m_currentString.m_length) {
105 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
108 m_substrings.append(s);
111 void SegmentedString::prepend(const SegmentedSubstring& s)
114 ASSERT(!s.numberOfCharactersConsumed());
118 // FIXME: We're assuming that the prepend were originally consumed by
119 // this SegmentedString. We're also ASSERTing that s is a fresh
120 // SegmentedSubstring. These assumptions are sufficient for our
121 // current use, but we might need to handle the more elaborate
122 // cases in the future.
123 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
124 m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
125 if (!m_currentString.m_length)
128 // Shift our m_currentString into our list.
129 m_substrings.prepend(m_currentString);
134 void SegmentedString::close()
136 // Closing a stream twice is likely a coding mistake.
141 void SegmentedString::append(const SegmentedString& s)
144 ASSERT(!s.escaped());
145 append(s.m_currentString);
146 if (s.isComposite()) {
147 Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
148 Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
149 for (; it != e; ++it)
152 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
155 void SegmentedString::prepend(const SegmentedString& s)
158 ASSERT(!s.escaped());
159 if (s.isComposite()) {
160 Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
161 Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
162 for (; it != e; ++it)
165 prepend(s.m_currentString);
166 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
169 void SegmentedString::advanceSubstring()
172 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
173 m_currentString = m_substrings.takeFirst();
174 // If we've previously consumed some characters of the non-current
175 // string, we now account for those characters as part of the current
176 // string, not as part of "prior to current string."
177 m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
179 m_currentString.clear();
182 String SegmentedString::toString() const
186 result.append(m_pushedChar1);
188 result.append(m_pushedChar2);
190 m_currentString.appendTo(result);
192 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
193 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
194 for (; it != e; ++it)
195 it->appendTo(result);
200 void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
202 ASSERT(count <= length());
203 for (unsigned i = 0; i < count; ++i) {
204 consumedCharacters[i] = *current();
209 void SegmentedString::advanceSlowCase()
212 m_pushedChar1 = m_pushedChar2;
214 } else if (m_currentString.m_current) {
215 ++m_currentString.m_current;
216 if (--m_currentString.m_length == 0)
219 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
222 void SegmentedString::advanceSlowCase(int& lineNumber)
225 m_pushedChar1 = m_pushedChar2;
227 } else if (m_currentString.m_current) {
228 if (*m_currentString.m_current++ == '\n' && m_currentString.doNotExcludeLineNumbers()) {
231 // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
232 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
234 if (--m_currentString.m_length == 0)
237 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
240 WTF::ZeroBasedNumber SegmentedString::currentLine() const
242 return WTF::ZeroBasedNumber::fromZeroBasedInt(m_currentLine);
245 WTF::ZeroBasedNumber SegmentedString::currentColumn() const
247 int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
248 return WTF::ZeroBasedNumber::fromZeroBasedInt(zeroBasedColumn);
251 void SegmentedString::setCurrentPosition(WTF::ZeroBasedNumber line, WTF::ZeroBasedNumber columnAftreProlog, int prologLength)
253 m_currentLine = line.zeroBasedInt();
254 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();