1 /*
2 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3
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.
8
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.
13
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.
18 */
19
20 #include "config.h"
21 #include "SegmentedString.h"
22
23 namespace WebCore {
24
SegmentedString(const SegmentedString & other)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 {
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;
36 else
37 m_currentChar = other.m_currentChar;
38 }
39
operator =(const SegmentedString & other)40 const SegmentedString& SegmentedString::operator=(const SegmentedString& other)
41 {
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;
50 else
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;
56
57 return *this;
58 }
59
length() const60 unsigned SegmentedString::length() const
61 {
62 unsigned length = m_currentString.m_length;
63 if (m_pushedChar1) {
64 ++length;
65 if (m_pushedChar2)
66 ++length;
67 }
68 if (isComposite()) {
69 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
70 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
71 for (; it != e; ++it)
72 length += it->m_length;
73 }
74 return length;
75 }
76
setExcludeLineNumbers()77 void SegmentedString::setExcludeLineNumbers()
78 {
79 m_currentString.setExcludeLineNumbers();
80 if (isComposite()) {
81 Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
82 Deque<SegmentedSubstring>::iterator e = m_substrings.end();
83 for (; it != e; ++it)
84 it->setExcludeLineNumbers();
85 }
86 }
87
clear()88 void SegmentedString::clear()
89 {
90 m_pushedChar1 = 0;
91 m_pushedChar2 = 0;
92 m_currentChar = 0;
93 m_currentString.clear();
94 m_substrings.clear();
95 m_closed = false;
96 }
97
append(const SegmentedSubstring & s)98 void SegmentedString::append(const SegmentedSubstring& s)
99 {
100 ASSERT(!m_closed);
101 if (!s.m_length)
102 return;
103
104 if (!m_currentString.m_length) {
105 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
106 m_currentString = s;
107 } else
108 m_substrings.append(s);
109 }
110
prepend(const SegmentedSubstring & s)111 void SegmentedString::prepend(const SegmentedSubstring& s)
112 {
113 ASSERT(!escaped());
114 ASSERT(!s.numberOfCharactersConsumed());
115 if (!s.m_length)
116 return;
117
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)
126 m_currentString = s;
127 else {
128 // Shift our m_currentString into our list.
129 m_substrings.prepend(m_currentString);
130 m_currentString = s;
131 }
132 }
133
close()134 void SegmentedString::close()
135 {
136 // Closing a stream twice is likely a coding mistake.
137 ASSERT(!m_closed);
138 m_closed = true;
139 }
140
append(const SegmentedString & s)141 void SegmentedString::append(const SegmentedString& s)
142 {
143 ASSERT(!m_closed);
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)
150 append(*it);
151 }
152 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
153 }
154
prepend(const SegmentedString & s)155 void SegmentedString::prepend(const SegmentedString& s)
156 {
157 ASSERT(!escaped());
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)
163 prepend(*it);
164 }
165 prepend(s.m_currentString);
166 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
167 }
168
advanceSubstring()169 void SegmentedString::advanceSubstring()
170 {
171 if (isComposite()) {
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();
178 } else
179 m_currentString.clear();
180 }
181
toString() const182 String SegmentedString::toString() const
183 {
184 String result;
185 if (m_pushedChar1) {
186 result.append(m_pushedChar1);
187 if (m_pushedChar2)
188 result.append(m_pushedChar2);
189 }
190 m_currentString.appendTo(result);
191 if (isComposite()) {
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);
196 }
197 return result;
198 }
199
advance(unsigned count,UChar * consumedCharacters)200 void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
201 {
202 ASSERT(count <= length());
203 for (unsigned i = 0; i < count; ++i) {
204 consumedCharacters[i] = *current();
205 advance();
206 }
207 }
208
advanceSlowCase()209 void SegmentedString::advanceSlowCase()
210 {
211 if (m_pushedChar1) {
212 m_pushedChar1 = m_pushedChar2;
213 m_pushedChar2 = 0;
214 } else if (m_currentString.m_current) {
215 ++m_currentString.m_current;
216 if (--m_currentString.m_length == 0)
217 advanceSubstring();
218 }
219 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
220 }
221
advanceSlowCase(int & lineNumber)222 void SegmentedString::advanceSlowCase(int& lineNumber)
223 {
224 if (m_pushedChar1) {
225 m_pushedChar1 = m_pushedChar2;
226 m_pushedChar2 = 0;
227 } else if (m_currentString.m_current) {
228 if (*m_currentString.m_current++ == '\n' && m_currentString.doNotExcludeLineNumbers()) {
229 ++lineNumber;
230 ++m_currentLine;
231 // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
232 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
233 }
234 if (--m_currentString.m_length == 0)
235 advanceSubstring();
236 }
237 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
238 }
239
currentLine() const240 WTF::ZeroBasedNumber SegmentedString::currentLine() const
241 {
242 return WTF::ZeroBasedNumber::fromZeroBasedInt(m_currentLine);
243 }
244
currentColumn() const245 WTF::ZeroBasedNumber SegmentedString::currentColumn() const
246 {
247 int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
248 return WTF::ZeroBasedNumber::fromZeroBasedInt(zeroBasedColumn);
249 }
250
setCurrentPosition(WTF::ZeroBasedNumber line,WTF::ZeroBasedNumber columnAftreProlog,int prologLength)251 void SegmentedString::setCurrentPosition(WTF::ZeroBasedNumber line, WTF::ZeroBasedNumber columnAftreProlog, int prologLength)
252 {
253 m_currentLine = line.zeroBasedInt();
254 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();
255 }
256
257 }
258