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