Changeset 174271 in webkit


Ignore:
Timestamp:
Oct 3, 2014, 10:43:32 AM (11 years ago)
Author:
mmaxfield@apple.com
Message:

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

Patch by Myles C. Maxfield <mmaxfield@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!=):

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r174268 r174271  
     12014-10-03  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Support modern for loops over StringViews
     4        https://bugs.webkit.org/show_bug.cgi?id=137165
     5
     6        Reviewed by Darin Adler.
     7
     8        This patch adds two functions, codePoints() and codeUnits(), on StringView.
     9        These two functions return small objects which have begin() and end() functions,
     10        which means it can be used by the modern for loop style. This small class also
     11        has an inner iterator class which can be incremented, dereferenced, and
     12        compared.
     13
     14        Using these new objects looks like this:
     15        for (UChar codeunit : stringView.codeUnits()) { } and
     16        for (UChar32 codepoint : stringView.codePoints()) { }.
     17
     18        * wtf/text/StringView.h:
     19        (WTF::StringView::codepoints):
     20        (WTF::StringView::codeunits):
     21        (WTF::StringViewCodePointIterator::StringViewCodePointIterator):
     22        (WTF::StringViewCodePointIterator::Iterator::Iterator):
     23        (WTF::StringViewCodePointIterator::Iterator::operator*):
     24        (WTF::StringViewCodePointIterator::Iterator::operator!=):
     25        (WTF::StringViewCodeUnitIterator::StringViewCodeUnitIterator):
     26        (WTF::StringViewCodeUnitIterator::Iterator::Iterator):
     27        (WTF::StringViewCodeUnitIterator::Iterator::operator*):
     28        (WTF::StringViewCodeUnitIterator::Iterator::operator!=):
     29
    1302014-09-28  Sam Weinig  <sam@webkit.org>
    231
  • trunk/Source/WTF/wtf/text/StringView.h

    r174234 r174271  
    139139    bool contains(UChar c) const { return find(c) != notFound; }
    140140
     141    class CodePoints;
     142    class CodeUnits;
     143
     144    CodePoints codePoints() const;
     145    CodeUnits codeUnits() const;
     146
    141147#if USE(CF)
    142148    // This function converts null strings to empty strings.
     
    200206    initialize(string.characters16(), string.length());
    201207}
     208
     209class StringView::CodePoints {
     210public:
     211    class Iterator {
     212    public:
     213        Iterator(const StringView&, unsigned index);
     214        Iterator& operator++();
     215        UChar32 operator*() const;
     216        bool operator==(const Iterator&) const;
     217        bool operator!=(const Iterator&) const;
     218
     219    private:
     220        const StringView& m_stringView;
     221        mutable unsigned m_index;
     222#if !ASSERT_DISABLED
     223        mutable bool m_alreadyIncremented;
     224#endif
     225    };
     226
     227    explicit CodePoints(const StringView&);
     228    Iterator begin() const;
     229    Iterator end() const;
     230
     231private:
     232    StringView m_stringView;
     233};
     234
     235class StringView::CodeUnits {
     236public:
     237    class Iterator {
     238    public:
     239        Iterator(const StringView&, unsigned index);
     240        Iterator& operator++();
     241        UChar operator*() const;
     242        bool operator==(const Iterator&) const;
     243        bool operator!=(const Iterator&) const;
     244
     245    private:
     246        const StringView& m_stringView;
     247        unsigned m_index;
     248    };
     249
     250    explicit CodeUnits(const StringView&);
     251    Iterator begin() const;
     252    Iterator end() const;
     253
     254private:
     255    StringView m_stringView;
     256};
    202257
    203258inline void StringView::getCharactersWithUpconvert(LChar* destination) const
     
    295350}
    296351
     352inline auto StringView::codePoints() const -> CodePoints
     353{
     354    return CodePoints(*this);
     355}
     356
     357inline auto StringView::codeUnits() const -> CodeUnits
     358{
     359    return CodeUnits(*this);
     360}
     361
     362inline StringView::CodePoints::CodePoints(const StringView& stringView)
     363    : m_stringView(stringView)
     364{
     365}
     366
     367inline StringView::CodePoints::Iterator::Iterator(const StringView& stringView, unsigned index)
     368    : m_stringView(stringView)
     369    , m_index(index)
     370#if !ASSERT_DISABLED
     371    , m_alreadyIncremented(false)
     372#endif
     373{
     374}
     375
     376inline auto StringView::CodePoints::Iterator::operator++() -> Iterator&
     377{
     378#if !ASSERT_DISABLED
     379    ASSERT(m_alreadyIncremented);
     380    m_alreadyIncremented = false;
     381#endif
     382    return *this;
     383}
     384
     385inline UChar32 StringView::CodePoints::Iterator::operator*() const
     386{
     387#if !ASSERT_DISABLED
     388    ASSERT(!m_alreadyIncremented);
     389    m_alreadyIncremented = true;
     390#endif
     391
     392    if (m_stringView.is8Bit())
     393        return m_stringView.characters8()[m_index++];
     394
     395    UChar32 codePoint;
     396    U16_NEXT(m_stringView.characters16(), m_index, m_stringView.length(), codePoint);
     397    return codePoint;
     398}
     399
     400inline bool StringView::CodePoints::Iterator::operator==(const Iterator& other) const
     401{
     402    ASSERT(&m_stringView == &other.m_stringView);
     403    ASSERT(!m_alreadyIncremented);
     404    return m_index == other.m_index;
     405}
     406
     407inline bool StringView::CodePoints::Iterator::operator!=(const Iterator& other) const
     408{
     409    return !(*this == other);
     410}
     411
     412inline auto StringView::CodePoints::begin() const -> Iterator
     413{
     414    return Iterator(m_stringView, 0);
     415}
     416
     417inline auto StringView::CodePoints::end() const -> Iterator
     418{
     419    return Iterator(m_stringView, m_stringView.length());
     420}
     421
     422inline StringView::CodeUnits::CodeUnits(const StringView& stringView)
     423    : m_stringView(stringView)
     424{
     425}
     426
     427inline StringView::CodeUnits::Iterator::Iterator(const StringView& stringView, unsigned index)
     428    : m_stringView(stringView)
     429    , m_index(index)
     430{
     431}
     432
     433inline auto StringView::CodeUnits::Iterator::operator++() -> Iterator&
     434{
     435    ++m_index;
     436    return *this;
     437}
     438
     439inline UChar StringView::CodeUnits::Iterator::operator*() const
     440{
     441    return m_stringView[m_index];
     442}
     443
     444inline bool StringView::CodeUnits::Iterator::operator==(const Iterator& other) const
     445{
     446    ASSERT(&m_stringView == &other.m_stringView);
     447    return m_index == other.m_index;
     448}
     449
     450inline bool StringView::CodeUnits::Iterator::operator!=(const Iterator& other) const
     451{
     452    return !(*this == other);
     453}
     454
     455inline auto StringView::CodeUnits::begin() const -> Iterator
     456{
     457    return Iterator(m_stringView, 0);
     458}
     459
     460inline auto StringView::CodeUnits::end() const -> Iterator
     461{
     462    return Iterator(m_stringView, m_stringView.length());
     463}
     464
    297465} // namespace WTF
    298466
  • trunk/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp

    r167209 r174271  
    2626#include "config.h"
    2727
     28#include <wtf/text/StringBuilder.h>
    2829#include <wtf/text/StringView.h>
    2930
     
    7879}
    7980
     81bool compareLoopIterations(StringView::CodePoints codePoints, std::vector<UChar32> expected)
     82{
     83    std::vector<UChar32> actual;
     84    for (auto codePoint : codePoints)
     85        actual.push_back(codePoint);
     86    return actual == expected;
     87}
     88
     89static bool compareLoopIterations(StringView::CodeUnits codeUnits, std::vector<UChar> expected)
     90{
     91    std::vector<UChar> actual;
     92    for (auto codeUnit : codeUnits)
     93        actual.push_back(codeUnit);
     94    return actual == expected;
     95}
     96
     97static void build(StringBuilder& builder, std::vector<UChar> input)
     98{
     99    builder.clear();
     100    for (auto codeUnit : input)
     101        builder.append(codeUnit);
     102}
     103
     104TEST(WTF, StringViewIterators)
     105{
     106    compareLoopIterations(StringView().codePoints(), { });
     107    compareLoopIterations(StringView().codeUnits(), { });
     108
     109    compareLoopIterations(StringView::empty().codePoints(), { });
     110    compareLoopIterations(StringView::empty().codeUnits(), { });
     111
     112    compareLoopIterations(StringView(String("hello")).codePoints(), {'h', 'e', 'l', 'l', 'o'});
     113    compareLoopIterations(StringView(String("hello")).codeUnits(), {'h', 'e', 'l', 'l', 'o'});
     114
     115    StringBuilder b;
     116    build(b, {0xD800, 0xDD55}); // Surrogates for unicode code point U+10155
     117    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x10155}));
     118    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xDD55}));
     119
     120    build(b, {0xD800}); // Leading surrogate only
     121    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800}));
     122    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800}));
     123
     124    build(b, {0xD800, 0xD801}); // Two leading surrogates
     125    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 0xD801}));
     126    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xD801}));
     127
     128    build(b, {0xDD55}); // Trailing surrogate only
     129    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xDD55}));
     130    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xDD55}));
     131
     132    build(b, {0xD800, 'h'}); // Leading surrogate followed by non-surrogate
     133    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 'h'}));
     134    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 'h'}));
     135
     136    build(b, {0x0306}); // "COMBINING BREVE"
     137    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306}));
     138    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306}));
     139
     140    build(b, {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}); // Mix of single code unit and multi code unit code points
     141    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306, 0x10155, 'h', 'e', 'l', 'o'}));
     142    EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}));
     143}
     144
    80145} // namespace TestWebKitAPI
Note: See TracChangeset for help on using the changeset viewer.