1 | /* |
2 | Copyright (C) 2004-2016 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 | #include <wtf/text/StringBuilder.h> |
24 | #include <wtf/text/TextPosition.h> |
25 | |
26 | namespace WebCore { |
27 | |
28 | inline void SegmentedString::Substring::appendTo(StringBuilder& builder) const |
29 | { |
30 | builder.append(string, string.length() - length, length); |
31 | } |
32 | |
33 | SegmentedString& SegmentedString::operator=(SegmentedString&& other) |
34 | { |
35 | m_currentSubstring = WTFMove(other.m_currentSubstring); |
36 | m_otherSubstrings = WTFMove(other.m_otherSubstrings); |
37 | |
38 | m_isClosed = other.m_isClosed; |
39 | |
40 | m_currentCharacter = other.m_currentCharacter; |
41 | |
42 | m_numberOfCharactersConsumedPriorToCurrentSubstring = other.m_numberOfCharactersConsumedPriorToCurrentSubstring; |
43 | m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine; |
44 | m_currentLine = other.m_currentLine; |
45 | |
46 | m_fastPathFlags = other.m_fastPathFlags; |
47 | m_advanceWithoutUpdatingLineNumberFunction = other.m_advanceWithoutUpdatingLineNumberFunction; |
48 | m_advanceAndUpdateLineNumberFunction = other.m_advanceAndUpdateLineNumberFunction; |
49 | |
50 | other.clear(); |
51 | |
52 | return *this; |
53 | } |
54 | |
55 | unsigned SegmentedString::length() const |
56 | { |
57 | unsigned length = m_currentSubstring.length; |
58 | for (auto& substring : m_otherSubstrings) |
59 | length += substring.length; |
60 | return length; |
61 | } |
62 | |
63 | void SegmentedString::setExcludeLineNumbers() |
64 | { |
65 | if (!m_currentSubstring.doNotExcludeLineNumbers) |
66 | return; |
67 | m_currentSubstring.doNotExcludeLineNumbers = false; |
68 | for (auto& substring : m_otherSubstrings) |
69 | substring.doNotExcludeLineNumbers = false; |
70 | updateAdvanceFunctionPointers(); |
71 | } |
72 | |
73 | void SegmentedString::clear() |
74 | { |
75 | m_currentSubstring.length = 0; |
76 | m_otherSubstrings.clear(); |
77 | |
78 | m_isClosed = false; |
79 | |
80 | m_currentCharacter = 0; |
81 | |
82 | m_numberOfCharactersConsumedPriorToCurrentSubstring = 0; |
83 | m_numberOfCharactersConsumedPriorToCurrentLine = 0; |
84 | m_currentLine = 0; |
85 | |
86 | updateAdvanceFunctionPointersForEmptyString(); |
87 | } |
88 | |
89 | inline void SegmentedString::appendSubstring(Substring&& substring) |
90 | { |
91 | ASSERT(!m_isClosed); |
92 | if (!substring.length) |
93 | return; |
94 | if (m_currentSubstring.length) |
95 | m_otherSubstrings.append(WTFMove(substring)); |
96 | else { |
97 | m_numberOfCharactersConsumedPriorToCurrentSubstring += m_currentSubstring.numberOfCharactersConsumed(); |
98 | m_currentSubstring = WTFMove(substring); |
99 | m_currentCharacter = m_currentSubstring.currentCharacter(); |
100 | updateAdvanceFunctionPointers(); |
101 | } |
102 | } |
103 | |
104 | void SegmentedString::pushBack(String&& string) |
105 | { |
106 | // We never create a substring for an empty string. |
107 | ASSERT(string.length()); |
108 | |
109 | // The new substring we will create won't have the doNotExcludeLineNumbers set appropriately. |
110 | // That was lost when the characters were consumed before pushing them back. But this does |
111 | // not matter, because clients never use this for newlines. Catch that with this assertion. |
112 | ASSERT(!string.contains('\n')); |
113 | |
114 | // The characters in the string must be previously consumed characters from this segmented string. |
115 | ASSERT(string.length() <= numberOfCharactersConsumed()); |
116 | |
117 | m_numberOfCharactersConsumedPriorToCurrentSubstring += m_currentSubstring.numberOfCharactersConsumed(); |
118 | if (m_currentSubstring.length) |
119 | m_otherSubstrings.prepend(WTFMove(m_currentSubstring)); |
120 | m_currentSubstring = WTFMove(string); |
121 | m_numberOfCharactersConsumedPriorToCurrentSubstring -= m_currentSubstring.length; |
122 | m_currentCharacter = m_currentSubstring.currentCharacter(); |
123 | updateAdvanceFunctionPointers(); |
124 | } |
125 | |
126 | void SegmentedString::close() |
127 | { |
128 | ASSERT(!m_isClosed); |
129 | m_isClosed = true; |
130 | } |
131 | |
132 | void SegmentedString::append(const SegmentedString& string) |
133 | { |
134 | appendSubstring(Substring { string.m_currentSubstring }); |
135 | for (auto& substring : string.m_otherSubstrings) |
136 | m_otherSubstrings.append(substring); |
137 | } |
138 | |
139 | void SegmentedString::append(SegmentedString&& string) |
140 | { |
141 | appendSubstring(WTFMove(string.m_currentSubstring)); |
142 | for (auto& substring : string.m_otherSubstrings) |
143 | m_otherSubstrings.append(WTFMove(substring)); |
144 | } |
145 | |
146 | void SegmentedString::append(String&& string) |
147 | { |
148 | appendSubstring(WTFMove(string)); |
149 | } |
150 | |
151 | void SegmentedString::append(const String& string) |
152 | { |
153 | appendSubstring(String { string }); |
154 | } |
155 | |
156 | String SegmentedString::toString() const |
157 | { |
158 | StringBuilder result; |
159 | m_currentSubstring.appendTo(result); |
160 | for (auto& substring : m_otherSubstrings) |
161 | substring.appendTo(result); |
162 | return result.toString(); |
163 | } |
164 | |
165 | void SegmentedString::advanceWithoutUpdatingLineNumber16() |
166 | { |
167 | m_currentCharacter = *++m_currentSubstring.currentCharacter16; |
168 | decrementAndCheckLength(); |
169 | } |
170 | |
171 | void SegmentedString::advanceAndUpdateLineNumber16() |
172 | { |
173 | ASSERT(m_currentSubstring.doNotExcludeLineNumbers); |
174 | processPossibleNewline(); |
175 | m_currentCharacter = *++m_currentSubstring.currentCharacter16; |
176 | decrementAndCheckLength(); |
177 | } |
178 | |
179 | inline void SegmentedString::advancePastSingleCharacterSubstringWithoutUpdatingLineNumber() |
180 | { |
181 | ASSERT(m_currentSubstring.length == 1); |
182 | if (m_otherSubstrings.isEmpty()) { |
183 | m_currentSubstring.length = 0; |
184 | m_currentCharacter = 0; |
185 | updateAdvanceFunctionPointersForEmptyString(); |
186 | return; |
187 | } |
188 | m_numberOfCharactersConsumedPriorToCurrentSubstring += m_currentSubstring.numberOfCharactersConsumed(); |
189 | m_currentSubstring = m_otherSubstrings.takeFirst(); |
190 | // If we've previously consumed some characters of the non-current string, we now account for those |
191 | // characters as part of the current string, not as part of "prior to current string." |
192 | m_numberOfCharactersConsumedPriorToCurrentSubstring -= m_currentSubstring.numberOfCharactersConsumed(); |
193 | m_currentCharacter = m_currentSubstring.currentCharacter(); |
194 | updateAdvanceFunctionPointers(); |
195 | } |
196 | |
197 | void SegmentedString::advancePastSingleCharacterSubstring() |
198 | { |
199 | ASSERT(m_currentSubstring.length == 1); |
200 | ASSERT(m_currentSubstring.doNotExcludeLineNumbers); |
201 | processPossibleNewline(); |
202 | advancePastSingleCharacterSubstringWithoutUpdatingLineNumber(); |
203 | } |
204 | |
205 | void SegmentedString::advanceEmpty() |
206 | { |
207 | ASSERT(!m_currentSubstring.length); |
208 | ASSERT(m_otherSubstrings.isEmpty()); |
209 | ASSERT(!m_currentCharacter); |
210 | } |
211 | |
212 | void SegmentedString::updateAdvanceFunctionPointersForSingleCharacterSubstring() |
213 | { |
214 | ASSERT(m_currentSubstring.length == 1); |
215 | m_fastPathFlags = NoFastPath; |
216 | m_advanceWithoutUpdatingLineNumberFunction = &SegmentedString::advancePastSingleCharacterSubstringWithoutUpdatingLineNumber; |
217 | if (m_currentSubstring.doNotExcludeLineNumbers) |
218 | m_advanceAndUpdateLineNumberFunction = &SegmentedString::advancePastSingleCharacterSubstring; |
219 | else |
220 | m_advanceAndUpdateLineNumberFunction = &SegmentedString::advancePastSingleCharacterSubstringWithoutUpdatingLineNumber; |
221 | } |
222 | |
223 | OrdinalNumber SegmentedString::currentLine() const |
224 | { |
225 | return OrdinalNumber::fromZeroBasedInt(m_currentLine); |
226 | } |
227 | |
228 | OrdinalNumber SegmentedString::currentColumn() const |
229 | { |
230 | return OrdinalNumber::fromZeroBasedInt(numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine); |
231 | } |
232 | |
233 | void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength) |
234 | { |
235 | m_currentLine = line.zeroBasedInt(); |
236 | m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt(); |
237 | } |
238 | |
239 | SegmentedString::AdvancePastResult SegmentedString::advancePastSlowCase(const char* literal, bool lettersIgnoringASCIICase) |
240 | { |
241 | constexpr unsigned maxLength = 10; |
242 | ASSERT(!strchr(literal, '\n')); |
243 | auto length = strlen(literal); |
244 | ASSERT(length <= maxLength); |
245 | if (length > this->length()) |
246 | return NotEnoughCharacters; |
247 | UChar consumedCharacters[maxLength]; |
248 | for (unsigned i = 0; i < length; ++i) { |
249 | auto character = m_currentCharacter; |
250 | if (characterMismatch(character, literal[i], lettersIgnoringASCIICase)) { |
251 | if (i) |
252 | pushBack(String { consumedCharacters, i }); |
253 | return DidNotMatch; |
254 | } |
255 | advancePastNonNewline(); |
256 | consumedCharacters[i] = character; |
257 | } |
258 | return DidMatch; |
259 | } |
260 | |
261 | void SegmentedString::updateAdvanceFunctionPointersForEmptyString() |
262 | { |
263 | ASSERT(!m_currentSubstring.length); |
264 | ASSERT(m_otherSubstrings.isEmpty()); |
265 | ASSERT(!m_currentCharacter); |
266 | m_fastPathFlags = NoFastPath; |
267 | m_advanceWithoutUpdatingLineNumberFunction = &SegmentedString::advanceEmpty; |
268 | m_advanceAndUpdateLineNumberFunction = &SegmentedString::advanceEmpty; |
269 | } |
270 | |
271 | } |
272 | |