Home | History | Annotate | Download | only in text
      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 "platform/text/SegmentedString.h"
     22 
     23 namespace WebCore {
     24 
     25 unsigned SegmentedString::length() const
     26 {
     27     unsigned length = m_currentString.m_length;
     28     if (m_pushedChar1) {
     29         ++length;
     30         if (m_pushedChar2)
     31             ++length;
     32     }
     33     if (isComposite()) {
     34         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
     35         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
     36         for (; it != e; ++it)
     37             length += it->m_length;
     38     }
     39     return length;
     40 }
     41 
     42 void SegmentedString::setExcludeLineNumbers()
     43 {
     44     m_currentString.setExcludeLineNumbers();
     45     if (isComposite()) {
     46         Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
     47         Deque<SegmentedSubstring>::iterator e = m_substrings.end();
     48         for (; it != e; ++it)
     49             it->setExcludeLineNumbers();
     50     }
     51 }
     52 
     53 void SegmentedString::clear()
     54 {
     55     m_pushedChar1 = 0;
     56     m_pushedChar2 = 0;
     57     m_currentChar = 0;
     58     m_currentString.clear();
     59     m_numberOfCharactersConsumedPriorToCurrentString = 0;
     60     m_numberOfCharactersConsumedPriorToCurrentLine = 0;
     61     m_currentLine = 0;
     62     m_substrings.clear();
     63     m_closed = false;
     64     m_empty = true;
     65     m_fastPathFlags = NoFastPath;
     66     m_advanceFunc = &SegmentedString::advanceEmpty;
     67     m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
     68 }
     69 
     70 void SegmentedString::append(const SegmentedSubstring& s)
     71 {
     72     ASSERT(!m_closed);
     73     if (!s.m_length)
     74         return;
     75 
     76     if (!m_currentString.m_length) {
     77         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
     78         m_currentString = s;
     79         updateAdvanceFunctionPointers();
     80     } else {
     81         m_substrings.append(s);
     82     }
     83     m_empty = false;
     84 }
     85 
     86 void SegmentedString::prepend(const SegmentedSubstring& s)
     87 {
     88     ASSERT(!escaped());
     89     ASSERT(!s.numberOfCharactersConsumed());
     90     if (!s.m_length)
     91         return;
     92 
     93     // FIXME: We're assuming that the prepend were originally consumed by
     94     //        this SegmentedString. We're also ASSERTing that s is a fresh
     95     //        SegmentedSubstring. These assumptions are sufficient for our
     96     //        current use, but we might need to handle the more elaborate
     97     //        cases in the future.
     98     m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
     99     m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
    100     if (!m_currentString.m_length) {
    101         m_currentString = s;
    102         updateAdvanceFunctionPointers();
    103     } else {
    104         // Shift our m_currentString into our list.
    105         m_substrings.prepend(m_currentString);
    106         m_currentString = s;
    107         updateAdvanceFunctionPointers();
    108     }
    109     m_empty = false;
    110 }
    111 
    112 void SegmentedString::close()
    113 {
    114     // Closing a stream twice is likely a coding mistake.
    115     ASSERT(!m_closed);
    116     m_closed = true;
    117 }
    118 
    119 void SegmentedString::append(const SegmentedString& s)
    120 {
    121     ASSERT(!m_closed);
    122     if (s.m_pushedChar1) {
    123         Vector<UChar, 2> unconsumedData;
    124         unconsumedData.append(s.m_pushedChar1);
    125         if (s.m_pushedChar2)
    126             unconsumedData.append(s.m_pushedChar2);
    127         append(SegmentedSubstring(String(unconsumedData)));
    128     }
    129 
    130     append(s.m_currentString);
    131     if (s.isComposite()) {
    132         Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
    133         Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
    134         for (; it != e; ++it)
    135             append(*it);
    136     }
    137     m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
    138 }
    139 
    140 void SegmentedString::prepend(const SegmentedString& s)
    141 {
    142     ASSERT(!escaped());
    143     ASSERT(!s.escaped());
    144     if (s.isComposite()) {
    145         Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
    146         Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
    147         for (; it != e; ++it)
    148             prepend(*it);
    149     }
    150     prepend(s.m_currentString);
    151     m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
    152 }
    153 
    154 void SegmentedString::advanceSubstring()
    155 {
    156     if (isComposite()) {
    157         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
    158         m_currentString = m_substrings.takeFirst();
    159         // If we've previously consumed some characters of the non-current
    160         // string, we now account for those characters as part of the current
    161         // string, not as part of "prior to current string."
    162         m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
    163         updateAdvanceFunctionPointers();
    164     } else {
    165         m_currentString.clear();
    166         m_empty = true;
    167         m_fastPathFlags = NoFastPath;
    168         m_advanceFunc = &SegmentedString::advanceEmpty;
    169         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
    170     }
    171 }
    172 
    173 String SegmentedString::toString() const
    174 {
    175     StringBuilder result;
    176     if (m_pushedChar1) {
    177         result.append(m_pushedChar1);
    178         if (m_pushedChar2)
    179             result.append(m_pushedChar2);
    180     }
    181     m_currentString.appendTo(result);
    182     if (isComposite()) {
    183         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
    184         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
    185         for (; it != e; ++it)
    186             it->appendTo(result);
    187     }
    188     return result.toString();
    189 }
    190 
    191 void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
    192 {
    193     ASSERT_WITH_SECURITY_IMPLICATION(count <= length());
    194     for (unsigned i = 0; i < count; ++i) {
    195         consumedCharacters[i] = currentChar();
    196         advance();
    197     }
    198 }
    199 
    200 void SegmentedString::advance8()
    201 {
    202     ASSERT(!m_pushedChar1);
    203     decrementAndCheckLength();
    204     m_currentChar = m_currentString.incrementAndGetCurrentChar8();
    205 }
    206 
    207 void SegmentedString::advance16()
    208 {
    209     ASSERT(!m_pushedChar1);
    210     decrementAndCheckLength();
    211     m_currentChar = m_currentString.incrementAndGetCurrentChar16();
    212 }
    213 
    214 void SegmentedString::advanceAndUpdateLineNumber8()
    215 {
    216     ASSERT(!m_pushedChar1);
    217     ASSERT(m_currentString.getCurrentChar() == m_currentChar);
    218     if (m_currentChar == '\n') {
    219         ++m_currentLine;
    220         m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
    221     }
    222     decrementAndCheckLength();
    223     m_currentChar = m_currentString.incrementAndGetCurrentChar8();
    224 }
    225 
    226 void SegmentedString::advanceAndUpdateLineNumber16()
    227 {
    228     ASSERT(!m_pushedChar1);
    229     ASSERT(m_currentString.getCurrentChar() == m_currentChar);
    230     if (m_currentChar == '\n') {
    231         ++m_currentLine;
    232         m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
    233     }
    234     decrementAndCheckLength();
    235     m_currentChar = m_currentString.incrementAndGetCurrentChar16();
    236 }
    237 
    238 void SegmentedString::advanceSlowCase()
    239 {
    240     if (m_pushedChar1) {
    241         m_pushedChar1 = m_pushedChar2;
    242         m_pushedChar2 = 0;
    243 
    244         if (m_pushedChar1) {
    245             m_currentChar = m_pushedChar1;
    246             return;
    247         }
    248 
    249         updateAdvanceFunctionPointers();
    250     } else if (m_currentString.m_length) {
    251         if (!--m_currentString.m_length)
    252             advanceSubstring();
    253     } else if (!isComposite()) {
    254         m_currentString.clear();
    255         m_empty = true;
    256         m_fastPathFlags = NoFastPath;
    257         m_advanceFunc = &SegmentedString::advanceEmpty;
    258         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
    259     }
    260     m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
    261 }
    262 
    263 void SegmentedString::advanceAndUpdateLineNumberSlowCase()
    264 {
    265     if (m_pushedChar1) {
    266         m_pushedChar1 = m_pushedChar2;
    267         m_pushedChar2 = 0;
    268 
    269         if (m_pushedChar1) {
    270             m_currentChar = m_pushedChar1;
    271             return;
    272         }
    273 
    274         updateAdvanceFunctionPointers();
    275     } else if (m_currentString.m_length) {
    276         if (m_currentString.getCurrentChar() == '\n' && m_currentString.doNotExcludeLineNumbers()) {
    277             ++m_currentLine;
    278             // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
    279             m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
    280         }
    281         if (!--m_currentString.m_length)
    282             advanceSubstring();
    283         else
    284             m_currentString.incrementAndGetCurrentChar(); // Only need the ++
    285     } else if (!isComposite()) {
    286         m_currentString.clear();
    287         m_empty = true;
    288         m_fastPathFlags = NoFastPath;
    289         m_advanceFunc = &SegmentedString::advanceEmpty;
    290         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
    291     }
    292 
    293     m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
    294 }
    295 
    296 void SegmentedString::advanceEmpty()
    297 {
    298     ASSERT(!m_currentString.m_length && !isComposite());
    299     m_currentChar = 0;
    300 }
    301 
    302 void SegmentedString::updateSlowCaseFunctionPointers()
    303 {
    304     m_fastPathFlags = NoFastPath;
    305     m_advanceFunc = &SegmentedString::advanceSlowCase;
    306     m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase;
    307 }
    308 
    309 OrdinalNumber SegmentedString::currentLine() const
    310 {
    311     return OrdinalNumber::fromZeroBasedInt(m_currentLine);
    312 }
    313 
    314 OrdinalNumber SegmentedString::currentColumn() const
    315 {
    316     int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
    317     return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn);
    318 }
    319 
    320 void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength)
    321 {
    322     m_currentLine = line.zeroBasedInt();
    323     m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();
    324 }
    325 
    326 }
    327