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