SegmentedString.cpp revision ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb
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 23namespace WebCore { 24 25SegmentedString::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_composite(other.m_composite) 31 , m_closed(other.m_closed) 32{ 33 if (other.m_currentChar == &other.m_pushedChar1) 34 m_currentChar = &m_pushedChar1; 35 else if (other.m_currentChar == &other.m_pushedChar2) 36 m_currentChar = &m_pushedChar2; 37 else 38 m_currentChar = other.m_currentChar; 39} 40 41const SegmentedString& SegmentedString::operator=(const SegmentedString &other) 42{ 43 m_pushedChar1 = other.m_pushedChar1; 44 m_pushedChar2 = other.m_pushedChar2; 45 m_currentString = other.m_currentString; 46 m_substrings = other.m_substrings; 47 m_composite = other.m_composite; 48 if (other.m_currentChar == &other.m_pushedChar1) 49 m_currentChar = &m_pushedChar1; 50 else if (other.m_currentChar == &other.m_pushedChar2) 51 m_currentChar = &m_pushedChar2; 52 else 53 m_currentChar = other.m_currentChar; 54 m_closed = other.m_closed; 55 m_numberOfCharactersConsumedPriorToCurrentString = other.m_numberOfCharactersConsumedPriorToCurrentString; 56 m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine; 57 m_currentLine = other.m_currentLine; 58 59 return *this; 60} 61 62unsigned SegmentedString::length() const 63{ 64 unsigned length = m_currentString.m_length; 65 if (m_pushedChar1) { 66 ++length; 67 if (m_pushedChar2) 68 ++length; 69 } 70 if (m_composite) { 71 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin(); 72 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end(); 73 for (; it != e; ++it) 74 length += it->m_length; 75 } 76 return length; 77} 78 79void SegmentedString::setExcludeLineNumbers() 80{ 81 m_currentString.setExcludeLineNumbers(); 82 if (m_composite) { 83 Deque<SegmentedSubstring>::iterator it = m_substrings.begin(); 84 Deque<SegmentedSubstring>::iterator e = m_substrings.end(); 85 for (; it != e; ++it) 86 it->setExcludeLineNumbers(); 87 } 88} 89 90void SegmentedString::clear() 91{ 92 m_pushedChar1 = 0; 93 m_pushedChar2 = 0; 94 m_currentChar = 0; 95 m_currentString.clear(); 96 m_substrings.clear(); 97 m_composite = false; 98 m_closed = false; 99} 100 101void SegmentedString::append(const SegmentedSubstring &s) 102{ 103 ASSERT(!m_closed); 104 if (s.m_length) { 105 if (!m_currentString.m_length) { 106 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed(); 107 m_currentString = s; 108 } else { 109 m_substrings.append(s); 110 m_composite = true; 111 } 112 } 113} 114 115void SegmentedString::prepend(const SegmentedSubstring &s) 116{ 117 ASSERT(!escaped()); 118 ASSERT(!s.numberOfCharactersConsumed()); 119 if (s.m_length) { 120 // FIXME: We're assuming that the prepend were originally consumed by 121 // this SegmentedString. We're also ASSERTing that s is a fresh 122 // SegmentedSubstring. These assumptions are sufficient for our 123 // current use, but we might need to handle the more elaborate 124 // cases in the future. 125 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed(); 126 m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length; 127 if (!m_currentString.m_length) 128 m_currentString = s; 129 else { 130 // Shift our m_currentString into our list. 131 m_substrings.prepend(m_currentString); 132 m_currentString = s; 133 m_composite = true; 134 } 135 } 136} 137 138void SegmentedString::close() 139{ 140 // Closing a stream twice is likely a coding mistake. 141 ASSERT(!m_closed); 142 m_closed = true; 143} 144 145void SegmentedString::append(const SegmentedString &s) 146{ 147 ASSERT(!m_closed); 148 ASSERT(!s.escaped()); 149 append(s.m_currentString); 150 if (s.m_composite) { 151 Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin(); 152 Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end(); 153 for (; it != e; ++it) 154 append(*it); 155 } 156 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current; 157} 158 159void SegmentedString::prepend(const SegmentedString &s) 160{ 161 ASSERT(!escaped()); 162 ASSERT(!s.escaped()); 163 if (s.m_composite) { 164 Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin(); 165 Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend(); 166 for (; it != e; ++it) 167 prepend(*it); 168 } 169 prepend(s.m_currentString); 170 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current; 171} 172 173void SegmentedString::advanceSubstring() 174{ 175 if (m_composite) { 176 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed(); 177 m_currentString = m_substrings.takeFirst(); 178 // If we've previously consumed some characters of the non-current 179 // string, we now account for those characters as part of the current 180 // string, not as part of "prior to current string." 181 m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed(); 182 if (m_substrings.isEmpty()) 183 m_composite = false; 184 } else { 185 m_currentString.clear(); 186 } 187} 188 189int SegmentedString::numberOfCharactersConsumedSlow() const 190{ 191 int result = m_numberOfCharactersConsumedPriorToCurrentString + m_currentString.numberOfCharactersConsumed(); 192 if (m_pushedChar1) { 193 --result; 194 if (m_pushedChar2) 195 --result; 196 } 197 return result; 198} 199 200String SegmentedString::toString() const 201{ 202 String result; 203 if (m_pushedChar1) { 204 result.append(m_pushedChar1); 205 if (m_pushedChar2) 206 result.append(m_pushedChar2); 207 } 208 m_currentString.appendTo(result); 209 if (m_composite) { 210 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin(); 211 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end(); 212 for (; it != e; ++it) 213 it->appendTo(result); 214 } 215 return result; 216} 217 218void SegmentedString::advance(unsigned count, UChar* consumedCharacters) 219{ 220 ASSERT(count <= length()); 221 for (unsigned i = 0; i < count; ++i) { 222 consumedCharacters[i] = *current(); 223 advance(); 224 } 225} 226 227void SegmentedString::advanceSlowCase() 228{ 229 if (m_pushedChar1) { 230 m_pushedChar1 = m_pushedChar2; 231 m_pushedChar2 = 0; 232 } else if (m_currentString.m_current) { 233 ++m_currentString.m_current; 234 if (--m_currentString.m_length == 0) 235 advanceSubstring(); 236 } 237 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current; 238} 239 240void SegmentedString::advanceSlowCase(int& lineNumber) 241{ 242 if (m_pushedChar1) { 243 m_pushedChar1 = m_pushedChar2; 244 m_pushedChar2 = 0; 245 } else if (m_currentString.m_current) { 246 if (*m_currentString.m_current++ == '\n' && m_currentString.doNotExcludeLineNumbers()) { 247 ++lineNumber; 248 ++m_currentLine; 249 // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below. 250 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1; 251 } 252 if (--m_currentString.m_length == 0) 253 advanceSubstring(); 254 } 255 m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current; 256} 257 258WTF::ZeroBasedNumber SegmentedString::currentLine() const 259{ 260 return WTF::ZeroBasedNumber::fromZeroBasedInt(m_currentLine); 261} 262 263WTF::ZeroBasedNumber SegmentedString::currentColumn() const 264{ 265 int zeroBasedColumn = numberOfCharactersConsumedSlow() - m_numberOfCharactersConsumedPriorToCurrentLine; 266 return WTF::ZeroBasedNumber::fromZeroBasedInt(zeroBasedColumn); 267} 268 269void SegmentedString::setCurrentPosition(WTF::ZeroBasedNumber line, WTF::ZeroBasedNumber columnAftreProlog, int prologLength) 270{ 271 m_currentLine = line.zeroBasedInt(); 272 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumedSlow() + prologLength - columnAftreProlog.zeroBasedInt(); 273} 274 275} 276