summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/text/SegmentedString.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/text/SegmentedString.h')
-rw-r--r--Source/WebCore/platform/text/SegmentedString.h264
1 files changed, 201 insertions, 63 deletions
diff --git a/Source/WebCore/platform/text/SegmentedString.h b/Source/WebCore/platform/text/SegmentedString.h
index 777a65e7a..0a8ecb227 100644
--- a/Source/WebCore/platform/text/SegmentedString.h
+++ b/Source/WebCore/platform/text/SegmentedString.h
@@ -33,20 +33,32 @@ class SegmentedSubstring {
public:
SegmentedSubstring()
: m_length(0)
- , m_current(0)
, m_doNotExcludeLineNumbers(true)
+ , m_is8Bit(false)
{
+ m_data.string16Ptr = 0;
}
SegmentedSubstring(const String& str)
: m_length(str.length())
- , m_current(str.isEmpty() ? 0 : str.characters())
- , m_string(str)
, m_doNotExcludeLineNumbers(true)
+ , m_string(str)
{
+ if (m_length) {
+ if (m_string.is8Bit()) {
+ m_is8Bit = true;
+ m_data.string8Ptr = m_string.characters8();
+ } else {
+ m_is8Bit = false;
+ m_data.string16Ptr = m_string.characters16();
+ }
+ } else
+ m_is8Bit = false;
}
- void clear() { m_length = 0; m_current = 0; }
+ void clear() { m_length = 0; m_data.string16Ptr = 0; m_is8Bit = false;}
+
+ bool is8Bit() { return m_is8Bit; }
bool excludeLineNumbers() const { return !m_doNotExcludeLineNumbers; }
bool doNotExcludeLineNumbers() const { return m_doNotExcludeLineNumbers; }
@@ -57,19 +69,70 @@ public:
void appendTo(StringBuilder& builder) const
{
- if (m_string.characters() == m_current)
- builder.append(m_string);
- else
- builder.append(String(m_current, m_length));
+ int offset = m_string.length() - m_length;
+
+ if (!offset) {
+ if (m_length)
+ builder.append(m_string);
+ } else
+ builder.append(m_string.substring(offset, m_length));
+ }
+
+ UChar getCurrentChar8()
+ {
+ return *m_data.string8Ptr;
+ }
+
+ UChar getCurrentChar16()
+ {
+ return m_data.string16Ptr ? *m_data.string16Ptr : 0;
+ }
+
+ UChar incrementAndGetCurrentChar8()
+ {
+ ASSERT(m_data.string8Ptr);
+ return *++m_data.string8Ptr;
+ }
+
+ UChar incrementAndGetCurrentChar16()
+ {
+ ASSERT(m_data.string16Ptr);
+ return *++m_data.string16Ptr;
+ }
+
+ String currentSubString(unsigned length)
+ {
+ int offset = m_string.length() - m_length;
+ return m_string.substring(offset, length);
+ }
+
+ ALWAYS_INLINE UChar getCurrentChar()
+ {
+ ASSERT(m_length);
+ if (is8Bit())
+ return getCurrentChar8();
+ return getCurrentChar16();
+ }
+
+ ALWAYS_INLINE UChar incrementAndGetCurrentChar()
+ {
+ ASSERT(m_length);
+ if (is8Bit())
+ return incrementAndGetCurrentChar8();
+ return incrementAndGetCurrentChar16();
}
public:
+ union {
+ const LChar* string8Ptr;
+ const UChar* string16Ptr;
+ } m_data;
int m_length;
- const UChar* m_current;
private:
- String m_string;
bool m_doNotExcludeLineNumbers;
+ bool m_is8Bit;
+ String m_string;
};
class SegmentedString {
@@ -82,6 +145,10 @@ public:
, m_numberOfCharactersConsumedPriorToCurrentLine(0)
, m_currentLine(0)
, m_closed(false)
+ , m_empty(true)
+ , m_fastPathFlags(NoFastPath)
+ , m_advanceFunc(&SegmentedString::advanceEmpty)
+ , m_advanceAndUpdateLineNumberFunc(&SegmentedString::advanceEmpty)
{
}
@@ -89,12 +156,17 @@ public:
: m_pushedChar1(0)
, m_pushedChar2(0)
, m_currentString(str)
- , m_currentChar(m_currentString.m_current)
+ , m_currentChar(0)
, m_numberOfCharactersConsumedPriorToCurrentString(0)
, m_numberOfCharactersConsumedPriorToCurrentLine(0)
, m_currentLine(0)
, m_closed(false)
+ , m_empty(!str.length())
+ , m_fastPathFlags(NoFastPath)
{
+ if (m_currentString.m_length)
+ m_currentChar = m_currentString.getCurrentChar();
+ updateAdvanceFunctionPointers();
}
SegmentedString(const SegmentedString&);
@@ -114,14 +186,15 @@ public:
{
if (!m_pushedChar1) {
m_pushedChar1 = c;
- m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
+ m_currentChar = m_pushedChar1 ? m_pushedChar1 : m_currentString.getCurrentChar();
+ updateSlowCaseFunctionPointers();
} else {
ASSERT(!m_pushedChar2);
m_pushedChar2 = c;
}
}
- bool isEmpty() const { return !current(); }
+ bool isEmpty() const { return m_empty; }
unsigned length() const;
bool isClosed() const { return m_closed; }
@@ -132,66 +205,82 @@ public:
NotEnoughCharacters,
};
- LookAheadResult lookAhead(const String& string) { return lookAheadInline<SegmentedString::equalsLiterally>(string); }
- LookAheadResult lookAheadIgnoringCase(const String& string) { return lookAheadInline<SegmentedString::equalsIgnoringCase>(string); }
+ LookAheadResult lookAhead(const String& string) { return lookAheadInline(string, true); }
+ LookAheadResult lookAheadIgnoringCase(const String& string) { return lookAheadInline(string, false); }
void advance()
{
- if (!m_pushedChar1 && m_currentString.m_length > 1) {
- --m_currentString.m_length;
- m_currentChar = ++m_currentString.m_current;
+ if (m_fastPathFlags & Use8BitAdvance) {
+ ASSERT(!m_pushedChar1);
+ bool haveOneCharacterLeft = (--m_currentString.m_length == 1);
+ m_currentChar = m_currentString.incrementAndGetCurrentChar8();
+
+ if (!haveOneCharacterLeft)
+ return;
+
+ updateSlowCaseFunctionPointers();
+
return;
}
- advanceSlowCase();
+
+ (this->*m_advanceFunc)();
+ }
+
+ inline void advanceAndUpdateLineNumber()
+ {
+ if (m_fastPathFlags & Use8BitAdvance) {
+ ASSERT(!m_pushedChar1);
+
+ bool haveNewLine = (m_currentChar == '\n') & !!(m_fastPathFlags & Use8BitAdvanceAndUpdateLineNumbers);
+ bool haveOneCharacterLeft = (--m_currentString.m_length == 1);
+
+ m_currentChar = m_currentString.incrementAndGetCurrentChar8();
+
+ if (!(haveNewLine | haveOneCharacterLeft))
+ return;
+
+ if (haveNewLine) {
+ ++m_currentLine;
+ m_numberOfCharactersConsumedPriorToCurrentLine = m_numberOfCharactersConsumedPriorToCurrentString + m_currentString.numberOfCharactersConsumed();
+ }
+
+ if (haveOneCharacterLeft)
+ updateSlowCaseFunctionPointers();
+
+ return;
+ }
+
+ (this->*m_advanceAndUpdateLineNumberFunc)();
}
void advanceAndASSERT(UChar expectedCharacter)
{
- ASSERT_UNUSED(expectedCharacter, *current() == expectedCharacter);
+ ASSERT_UNUSED(expectedCharacter, currentChar() == expectedCharacter);
advance();
}
void advanceAndASSERTIgnoringCase(UChar expectedCharacter)
{
- ASSERT_UNUSED(expectedCharacter, WTF::Unicode::foldCase(*current()) == WTF::Unicode::foldCase(expectedCharacter));
+ ASSERT_UNUSED(expectedCharacter, WTF::Unicode::foldCase(currentChar()) == WTF::Unicode::foldCase(expectedCharacter));
advance();
}
- void advancePastNewlineAndUpdateLineNumber()
- {
- ASSERT(*current() == '\n');
- if (!m_pushedChar1 && m_currentString.m_length > 1) {
- int newLineFlag = m_currentString.doNotExcludeLineNumbers();
- m_currentLine += newLineFlag;
- if (newLineFlag)
- m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
- --m_currentString.m_length;
- m_currentChar = ++m_currentString.m_current;
- return;
- }
- advanceAndUpdateLineNumberSlowCase();
- }
-
void advancePastNonNewline()
{
- ASSERT(*current() != '\n');
- if (!m_pushedChar1 && m_currentString.m_length > 1) {
- --m_currentString.m_length;
- m_currentChar = ++m_currentString.m_current;
- return;
- }
- advanceSlowCase();
+ ASSERT(currentChar() != '\n');
+ advance();
}
-
- void advanceAndUpdateLineNumber()
+
+ void advancePastNewlineAndUpdateLineNumber()
{
+ ASSERT(currentChar() == '\n');
if (!m_pushedChar1 && m_currentString.m_length > 1) {
- int newLineFlag = (*m_currentString.m_current == '\n') & m_currentString.doNotExcludeLineNumbers();
+ int newLineFlag = m_currentString.doNotExcludeLineNumbers();
m_currentLine += newLineFlag;
if (newLineFlag)
m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
- --m_currentString.m_length;
- m_currentChar = ++m_currentString.m_current;
+ decrementAndCheckLength();
+ m_currentChar = m_currentString.incrementAndGetCurrentChar();
return;
}
advanceAndUpdateLineNumberSlowCase();
@@ -216,9 +305,7 @@ public:
String toString() const;
- const UChar& operator*() const { return *current(); }
- const UChar* operator->() const { return current(); }
-
+ UChar currentChar() const { return m_currentChar; }
// The method is moderately slow, comparing to currentLine method.
OrdinalNumber currentColumn() const;
@@ -228,30 +315,77 @@ public:
void setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength);
private:
+ enum FastPathFlags {
+ NoFastPath = 0,
+ Use8BitAdvanceAndUpdateLineNumbers = 1 << 0,
+ Use8BitAdvance = 1 << 1,
+ };
+
void append(const SegmentedSubstring&);
void prepend(const SegmentedSubstring&);
+ void advance8();
+ void advance16();
+ void advanceAndUpdateLineNumber8();
+ void advanceAndUpdateLineNumber16();
void advanceSlowCase();
void advanceAndUpdateLineNumberSlowCase();
+ void advanceEmpty();
void advanceSubstring();
- const UChar* current() const { return m_currentChar; }
+
+ void updateSlowCaseFunctionPointers();
+
+ void decrementAndCheckLength()
+ {
+ ASSERT(m_currentString.m_length > 1);
+ if (--m_currentString.m_length == 1)
+ updateSlowCaseFunctionPointers();
+ }
+
+ void updateAdvanceFunctionPointers()
+ {
+ if ((m_currentString.m_length > 1) && !m_pushedChar1) {
+ if (m_currentString.is8Bit()) {
+ m_advanceFunc = &SegmentedString::advance8;
+ m_fastPathFlags = Use8BitAdvance;
+ if (m_currentString.doNotExcludeLineNumbers()) {
+ m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumber8;
+ m_fastPathFlags |= Use8BitAdvanceAndUpdateLineNumbers;
+ } else
+ m_advanceAndUpdateLineNumberFunc = &SegmentedString::advance8;
+ return;
+ }
+
+ m_advanceFunc = &SegmentedString::advance16;
+ m_fastPathFlags = NoFastPath;
+ if (m_currentString.doNotExcludeLineNumbers())
+ m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumber16;
+ else
+ m_advanceAndUpdateLineNumberFunc = &SegmentedString::advance16;
+ return;
+ }
- static bool equalsLiterally(const UChar* str1, const UChar* str2, size_t count) { return !memcmp(str1, str2, count * sizeof(UChar)); }
- static bool equalsIgnoringCase(const UChar* str1, const UChar* str2, size_t count) { return !WTF::Unicode::umemcasecmp(str1, str2, count); }
+ if (!m_currentString.m_length && !isComposite()) {
+ m_advanceFunc = &SegmentedString::advanceEmpty;
+ m_fastPathFlags = NoFastPath;
+ m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
+ }
+
+ updateSlowCaseFunctionPointers();
+ }
- template<bool equals(const UChar* str1, const UChar* str2, size_t count)>
- inline LookAheadResult lookAheadInline(const String& string)
+ inline LookAheadResult lookAheadInline(const String& string, bool caseSensitive)
{
if (!m_pushedChar1 && string.length() <= static_cast<unsigned>(m_currentString.m_length)) {
- if (equals(string.characters(), m_currentString.m_current, string.length()))
+ String currentSubstring = m_currentString.currentSubString(string.length());
+ if (currentSubstring.startsWith(string, caseSensitive))
return DidMatch;
return DidNotMatch;
}
- return lookAheadSlowCase<equals>(string);
+ return lookAheadSlowCase(string, caseSensitive);
}
-
- template<bool equals(const UChar* str1, const UChar* str2, size_t count)>
- LookAheadResult lookAheadSlowCase(const String& string)
+
+ LookAheadResult lookAheadSlowCase(const String& string, bool caseSensitive)
{
unsigned count = string.length();
if (count > length())
@@ -260,7 +394,7 @@ private:
String consumedString = String::createUninitialized(count, consumedCharacters);
advance(count, consumedCharacters);
LookAheadResult result = DidNotMatch;
- if (equals(string.characters(), consumedCharacters, count))
+ if (consumedString.startsWith(string, caseSensitive))
result = DidMatch;
prepend(SegmentedString(consumedString));
return result;
@@ -271,12 +405,16 @@ private:
UChar m_pushedChar1;
UChar m_pushedChar2;
SegmentedSubstring m_currentString;
- const UChar* m_currentChar;
+ UChar m_currentChar;
int m_numberOfCharactersConsumedPriorToCurrentString;
int m_numberOfCharactersConsumedPriorToCurrentLine;
int m_currentLine;
Deque<SegmentedSubstring> m_substrings;
bool m_closed;
+ bool m_empty;
+ unsigned char m_fastPathFlags;
+ void (SegmentedString::*m_advanceFunc)();
+ void (SegmentedString::*m_advanceAndUpdateLineNumberFunc)();
};
}