Title: [174271] trunk
Revision
174271
Author
mmaxfi...@apple.com
Date
2014-10-03 10:43:32 -0700 (Fri, 03 Oct 2014)

Log Message

Support modern for loops over StringViews
https://bugs.webkit.org/show_bug.cgi?id=137165

Patch by Myles C. Maxfield <mmaxfi...@apple.com> on 2014-10-03
Reviewed by Darin Adler.

This patch adds two functions, codePoints() and codeUnits(), on StringView.
These two functions return small objects which have begin() and end() functions,
which means it can be used by the modern for loop style. This small class also
has an inner iterator class which can be incremented, dereferenced, and
compared.

Using these new objects looks like this:
for (UChar codeunit : stringView.codeUnits()) { } and
for (UChar32 codepoint : stringView.codePoints()) { }.

* wtf/text/StringView.h:
(WTF::StringView::codepoints):
(WTF::StringView::codeunits):
(WTF::StringViewCodePointIterator::StringViewCodePointIterator):
(WTF::StringViewCodePointIterator::Iterator::Iterator):
(WTF::StringViewCodePointIterator::Iterator::operator*):
(WTF::StringViewCodePointIterator::Iterator::operator!=):
(WTF::StringViewCodeUnitIterator::StringViewCodeUnitIterator):
(WTF::StringViewCodeUnitIterator::Iterator::Iterator):
(WTF::StringViewCodeUnitIterator::Iterator::operator*):
(WTF::StringViewCodeUnitIterator::Iterator::operator!=):

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (174270 => 174271)


--- trunk/Source/WTF/ChangeLog	2014-10-03 17:15:51 UTC (rev 174270)
+++ trunk/Source/WTF/ChangeLog	2014-10-03 17:43:32 UTC (rev 174271)
@@ -1,3 +1,32 @@
+2014-10-03  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+        Support modern for loops over StringViews
+        https://bugs.webkit.org/show_bug.cgi?id=137165
+
+        Reviewed by Darin Adler.
+
+        This patch adds two functions, codePoints() and codeUnits(), on StringView.
+        These two functions return small objects which have begin() and end() functions,
+        which means it can be used by the modern for loop style. This small class also
+        has an inner iterator class which can be incremented, dereferenced, and
+        compared.
+
+        Using these new objects looks like this:
+        for (UChar codeunit : stringView.codeUnits()) { } and
+        for (UChar32 codepoint : stringView.codePoints()) { }.
+
+        * wtf/text/StringView.h:
+        (WTF::StringView::codepoints):
+        (WTF::StringView::codeunits):
+        (WTF::StringViewCodePointIterator::StringViewCodePointIterator):
+        (WTF::StringViewCodePointIterator::Iterator::Iterator):
+        (WTF::StringViewCodePointIterator::Iterator::operator*):
+        (WTF::StringViewCodePointIterator::Iterator::operator!=):
+        (WTF::StringViewCodeUnitIterator::StringViewCodeUnitIterator):
+        (WTF::StringViewCodeUnitIterator::Iterator::Iterator):
+        (WTF::StringViewCodeUnitIterator::Iterator::operator*):
+        (WTF::StringViewCodeUnitIterator::Iterator::operator!=):
+
 2014-09-28  Sam Weinig  <s...@webkit.org>
 
         Remove RefPtrHashMap

Modified: trunk/Source/WTF/wtf/text/StringView.h (174270 => 174271)


--- trunk/Source/WTF/wtf/text/StringView.h	2014-10-03 17:15:51 UTC (rev 174270)
+++ trunk/Source/WTF/wtf/text/StringView.h	2014-10-03 17:43:32 UTC (rev 174271)
@@ -138,6 +138,12 @@
 
     bool contains(UChar c) const { return find(c) != notFound; }
 
+    class CodePoints;
+    class CodeUnits;
+
+    CodePoints codePoints() const;
+    CodeUnits codeUnits() const;
+
 #if USE(CF)
     // This function converts null strings to empty strings.
     WTF_EXPORT_STRING_API RetainPtr<CFStringRef> createCFStringWithoutCopying() const;
@@ -200,6 +206,55 @@
     initialize(string.characters16(), string.length());
 }
 
+class StringView::CodePoints {
+public:
+    class Iterator {
+    public:
+        Iterator(const StringView&, unsigned index);
+        Iterator& operator++();
+        UChar32 operator*() const;
+        bool operator==(const Iterator&) const;
+        bool operator!=(const Iterator&) const;
+
+    private:
+        const StringView& m_stringView;
+        mutable unsigned m_index;
+#if !ASSERT_DISABLED
+        mutable bool m_alreadyIncremented;
+#endif
+    };
+
+    explicit CodePoints(const StringView&);
+    Iterator begin() const;
+    Iterator end() const;
+
+private:
+    StringView m_stringView;
+};
+
+class StringView::CodeUnits {
+public:
+    class Iterator {
+    public:
+        Iterator(const StringView&, unsigned index);
+        Iterator& operator++();
+        UChar operator*() const;
+        bool operator==(const Iterator&) const;
+        bool operator!=(const Iterator&) const;
+
+    private:
+        const StringView& m_stringView;
+        unsigned m_index;
+    };
+
+    explicit CodeUnits(const StringView&);
+    Iterator begin() const;
+    Iterator end() const;
+
+private:
+    StringView m_stringView;
+};
+
 inline void StringView::getCharactersWithUpconvert(LChar* destination) const
 {
     ASSERT(is8Bit());
@@ -294,6 +349,119 @@
     string.getCharactersWithUpconvert(buffer.data() + oldSize);
 }
 
+inline auto StringView::codePoints() const -> CodePoints
+{
+    return CodePoints(*this);
+}
+
+inline auto StringView::codeUnits() const -> CodeUnits
+{
+    return CodeUnits(*this);
+}
+
+inline StringView::CodePoints::CodePoints(const StringView& stringView)
+    : m_stringView(stringView)
+{
+}
+
+inline StringView::CodePoints::Iterator::Iterator(const StringView& stringView, unsigned index)
+    : m_stringView(stringView)
+    , m_index(index)
+#if !ASSERT_DISABLED
+    , m_alreadyIncremented(false)
+#endif
+{
+}
+
+inline auto StringView::CodePoints::Iterator::operator++() -> Iterator&
+{
+#if !ASSERT_DISABLED
+    ASSERT(m_alreadyIncremented);
+    m_alreadyIncremented = false;
+#endif
+    return *this;
+}
+
+inline UChar32 StringView::CodePoints::Iterator::operator*() const
+{
+#if !ASSERT_DISABLED
+    ASSERT(!m_alreadyIncremented);
+    m_alreadyIncremented = true;
+#endif
+
+    if (m_stringView.is8Bit())
+        return m_stringView.characters8()[m_index++];
+
+    UChar32 codePoint;
+    U16_NEXT(m_stringView.characters16(), m_index, m_stringView.length(), codePoint);
+    return codePoint;
+}
+
+inline bool StringView::CodePoints::Iterator::operator==(const Iterator& other) const
+{
+    ASSERT(&m_stringView == &other.m_stringView);
+    ASSERT(!m_alreadyIncremented);
+    return m_index == other.m_index;
+}
+
+inline bool StringView::CodePoints::Iterator::operator!=(const Iterator& other) const
+{
+    return !(*this == other);
+}
+
+inline auto StringView::CodePoints::begin() const -> Iterator
+{
+    return Iterator(m_stringView, 0);
+}
+
+inline auto StringView::CodePoints::end() const -> Iterator
+{
+    return Iterator(m_stringView, m_stringView.length());
+}
+
+inline StringView::CodeUnits::CodeUnits(const StringView& stringView)
+    : m_stringView(stringView)
+{
+}
+
+inline StringView::CodeUnits::Iterator::Iterator(const StringView& stringView, unsigned index)
+    : m_stringView(stringView)
+    , m_index(index)
+{
+}
+
+inline auto StringView::CodeUnits::Iterator::operator++() -> Iterator&
+{
+    ++m_index;
+    return *this;
+}
+
+inline UChar StringView::CodeUnits::Iterator::operator*() const
+{
+    return m_stringView[m_index];
+}
+
+inline bool StringView::CodeUnits::Iterator::operator==(const Iterator& other) const
+{
+    ASSERT(&m_stringView == &other.m_stringView);
+    return m_index == other.m_index;
+}
+
+inline bool StringView::CodeUnits::Iterator::operator!=(const Iterator& other) const
+{
+    return !(*this == other);
+}
+
+inline auto StringView::CodeUnits::begin() const -> Iterator
+{
+    return Iterator(m_stringView, 0);
+}
+
+inline auto StringView::CodeUnits::end() const -> Iterator
+{
+    return Iterator(m_stringView, m_stringView.length());
+}
+
 } // namespace WTF
 
 using WTF::append;

Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp (174270 => 174271)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp	2014-10-03 17:15:51 UTC (rev 174270)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp	2014-10-03 17:43:32 UTC (rev 174271)
@@ -25,6 +25,7 @@
 
 #include "config.h"
 
+#include <wtf/text/StringBuilder.h>
 #include <wtf/text/StringView.h>
 
 namespace TestWebKitAPI {
@@ -77,4 +78,68 @@
         SUCCEED();
 }
 
+bool compareLoopIterations(StringView::CodePoints codePoints, std::vector<UChar32> expected)
+{
+    std::vector<UChar32> actual;
+    for (auto codePoint : codePoints)
+        actual.push_back(codePoint);
+    return actual == expected;
+}
+
+static bool compareLoopIterations(StringView::CodeUnits codeUnits, std::vector<UChar> expected)
+{
+    std::vector<UChar> actual;
+    for (auto codeUnit : codeUnits)
+        actual.push_back(codeUnit);
+    return actual == expected;
+}
+
+static void build(StringBuilder& builder, std::vector<UChar> input)
+{
+    builder.clear();
+    for (auto codeUnit : input)
+        builder.append(codeUnit);
+}
+
+TEST(WTF, StringViewIterators)
+{
+    compareLoopIterations(StringView().codePoints(), { });
+    compareLoopIterations(StringView().codeUnits(), { });
+
+    compareLoopIterations(StringView::empty().codePoints(), { });
+    compareLoopIterations(StringView::empty().codeUnits(), { });
+
+    compareLoopIterations(StringView(String("hello")).codePoints(), {'h', 'e', 'l', 'l', 'o'});
+    compareLoopIterations(StringView(String("hello")).codeUnits(), {'h', 'e', 'l', 'l', 'o'});
+
+    StringBuilder b;
+    build(b, {0xD800, 0xDD55}); // Surrogates for unicode code point U+10155
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x10155}));
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xDD55}));
+
+    build(b, {0xD800}); // Leading surrogate only
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800}));
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800}));
+
+    build(b, {0xD800, 0xD801}); // Two leading surrogates
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 0xD801}));
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xD801}));
+
+    build(b, {0xDD55}); // Trailing surrogate only
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xDD55}));
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xDD55}));
+
+    build(b, {0xD800, 'h'}); // Leading surrogate followed by non-surrogate
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 'h'}));
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 'h'}));
+
+    build(b, {0x0306}); // "COMBINING BREVE"
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306}));
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306}));
+
+    build(b, {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}); // Mix of single code unit and multi code unit code points
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306, 0x10155, 'h', 'e', 'l', 'o'}));
+    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}));
+}
+
 } // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to