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
26namespace WebCore {
27
28inline void SegmentedString::Substring::appendTo(StringBuilder& builder) const
29{
30 builder.append(string, string.length() - length, length);
31}
32
33SegmentedString& 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
55unsigned 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
63void 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
73void 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
89inline 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
104void 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
126void SegmentedString::close()
127{
128 ASSERT(!m_isClosed);
129 m_isClosed = true;
130}
131
132void 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
139void 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
146void SegmentedString::append(String&& string)
147{
148 appendSubstring(WTFMove(string));
149}
150
151void SegmentedString::append(const String& string)
152{
153 appendSubstring(String { string });
154}
155
156String 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
165void SegmentedString::advanceWithoutUpdatingLineNumber16()
166{
167 m_currentCharacter = *++m_currentSubstring.currentCharacter16;
168 decrementAndCheckLength();
169}
170
171void SegmentedString::advanceAndUpdateLineNumber16()
172{
173 ASSERT(m_currentSubstring.doNotExcludeLineNumbers);
174 processPossibleNewline();
175 m_currentCharacter = *++m_currentSubstring.currentCharacter16;
176 decrementAndCheckLength();
177}
178
179inline 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
197void SegmentedString::advancePastSingleCharacterSubstring()
198{
199 ASSERT(m_currentSubstring.length == 1);
200 ASSERT(m_currentSubstring.doNotExcludeLineNumbers);
201 processPossibleNewline();
202 advancePastSingleCharacterSubstringWithoutUpdatingLineNumber();
203}
204
205void SegmentedString::advanceEmpty()
206{
207 ASSERT(!m_currentSubstring.length);
208 ASSERT(m_otherSubstrings.isEmpty());
209 ASSERT(!m_currentCharacter);
210}
211
212void 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
223OrdinalNumber SegmentedString::currentLine() const
224{
225 return OrdinalNumber::fromZeroBasedInt(m_currentLine);
226}
227
228OrdinalNumber SegmentedString::currentColumn() const
229{
230 return OrdinalNumber::fromZeroBasedInt(numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine);
231}
232
233void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength)
234{
235 m_currentLine = line.zeroBasedInt();
236 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();
237}
238
239SegmentedString::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
261void 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