parseHTMLInteger() should take a StringView in parameter
[WebKit-https.git] / Source / WTF / wtf / text / StringView.h
1 /*
2  * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef StringView_h
27 #define StringView_h
28
29 #include <unicode/utypes.h>
30 #include <wtf/Forward.h>
31 #include <wtf/RetainPtr.h>
32 #include <wtf/Vector.h>
33 #include <wtf/text/CString.h>
34 #include <wtf/text/ConversionMode.h>
35 #include <wtf/text/LChar.h>
36 #include <wtf/text/StringCommon.h>
37
38 // FIXME: Enabling the StringView lifetime checking causes the MSVC build to fail. Figure out why.
39 // FIXME: Enable StringView lifetime checking once the underlying assertions have been fixed.
40 #if defined(NDEBUG) || COMPILER(MSVC) || 1
41 #define CHECK_STRINGVIEW_LIFETIME 0
42 #else
43 #define CHECK_STRINGVIEW_LIFETIME 1
44 #endif
45
46 namespace WTF {
47
48 using CharacterMatchFunction = bool (*)(UChar);
49
50 // StringView is a non-owning reference to a string, similar to the proposed std::string_view.
51
52 class StringView {
53 public:
54     StringView();
55 #if CHECK_STRINGVIEW_LIFETIME
56     ~StringView();
57     StringView(StringView&&);
58     StringView(const StringView&);
59     StringView& operator=(StringView&&);
60     StringView& operator=(const StringView&);
61 #endif
62
63     StringView(const AtomicString&);
64     StringView(const String&);
65     StringView(const StringImpl&);
66     StringView(const StringImpl*);
67     StringView(const LChar*, unsigned length);
68     StringView(const UChar*, unsigned length);
69     StringView(const char*);
70
71     static StringView empty();
72
73     unsigned length() const;
74     bool isEmpty() const;
75
76     explicit operator bool() const;
77     bool isNull() const;
78
79     UChar operator[](unsigned index) const;
80
81     class CodeUnits;
82     CodeUnits codeUnits() const;
83
84     class CodePoints;
85     CodePoints codePoints() const;
86
87     class GraphemeClusters;
88     GraphemeClusters graphemeClusters() const;
89
90     bool is8Bit() const;
91     const LChar* characters8() const;
92     const UChar* characters16() const;
93
94     String toString() const;
95     String toStringWithoutCopying() const;
96     AtomicString toAtomicString() const;
97
98 #if USE(CF)
99     // This function converts null strings to empty strings.
100     WTF_EXPORT_STRING_API RetainPtr<CFStringRef> createCFStringWithoutCopying() const;
101 #endif
102
103 #ifdef __OBJC__
104     // These functions convert null strings to empty strings.
105     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSString() const;
106     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSStringWithoutCopying() const;
107 #endif
108
109     WTF_EXPORT_STRING_API CString utf8(ConversionMode = LenientConversion) const;
110
111     class UpconvertedCharacters;
112     UpconvertedCharacters upconvertedCharacters() const;
113
114     void getCharactersWithUpconvert(LChar*) const;
115     void getCharactersWithUpconvert(UChar*) const;
116
117     StringView substring(unsigned start, unsigned length = std::numeric_limits<unsigned>::max()) const;
118
119     size_t find(UChar, unsigned start = 0) const;
120     size_t find(CharacterMatchFunction, unsigned start = 0) const;
121
122     WTF_EXPORT_STRING_API size_t find(StringView, unsigned start) const;
123
124     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringView&) const;
125     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringView&, unsigned startOffset) const;
126
127     bool contains(UChar) const;
128     WTF_EXPORT_STRING_API bool containsIgnoringASCIICase(const StringView&) const;
129     WTF_EXPORT_STRING_API bool containsIgnoringASCIICase(const StringView&, unsigned startOffset) const;
130
131     WTF_EXPORT_STRING_API bool startsWith(const StringView&) const;
132     WTF_EXPORT_STRING_API bool startsWithIgnoringASCIICase(const StringView&) const;
133
134     WTF_EXPORT_STRING_API bool endsWith(const StringView&) const;
135     WTF_EXPORT_STRING_API bool endsWithIgnoringASCIICase(const StringView&) const;
136
137     int toInt() const;
138     int toInt(bool& isValid) const;
139     int toIntStrict(bool& isValid) const;
140     float toFloat(bool& isValid) const;
141
142     static void invalidate(const StringImpl&);
143
144     struct UnderlyingString;
145
146 private:
147     friend bool equal(StringView, StringView);
148
149     void initialize(const LChar*, unsigned length);
150     void initialize(const UChar*, unsigned length);
151
152 #if CHECK_STRINGVIEW_LIFETIME
153     WTF_EXPORT_STRING_API bool underlyingStringIsValid() const;
154     WTF_EXPORT_STRING_API void setUnderlyingString(const StringImpl*);
155     WTF_EXPORT_STRING_API void setUnderlyingString(const StringView&);
156 #else
157     bool underlyingStringIsValid() const { return true; }
158     void setUnderlyingString(const StringImpl*) { }
159     void setUnderlyingString(const StringView&) { }
160 #endif
161     void clear();
162
163     const void* m_characters { nullptr };
164     unsigned m_length { 0 };
165     bool m_is8Bit { true };
166
167 #if CHECK_STRINGVIEW_LIFETIME
168     void adoptUnderlyingString(UnderlyingString*);
169     UnderlyingString* m_underlyingString { nullptr };
170 #endif
171 };
172
173 template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>&, StringView);
174
175 bool equal(StringView, StringView);
176 bool equal(StringView, const LChar*);
177 bool equal(StringView, const char*);
178
179 bool equalIgnoringASCIICase(StringView, StringView);
180 bool equalIgnoringASCIICase(StringView, const char*);
181
182 template<unsigned length> bool equalLettersIgnoringASCIICase(StringView, const char (&lowercaseLetters)[length]);
183
184 inline bool operator==(StringView a, StringView b) { return equal(a, b); }
185 inline bool operator==(StringView a, const LChar* b) { return equal(a, b); }
186 inline bool operator==(StringView a, const char* b) { return equal(a, b); }
187 inline bool operator==(const LChar* a, StringView b) { return equal(b, a); }
188 inline bool operator==(const char* a, StringView b) { return equal(b, a); }
189
190 inline bool operator!=(StringView a, StringView b) { return !equal(a, b); }
191 inline bool operator!=(StringView a, const LChar* b) { return !equal(a, b); }
192 inline bool operator!=(StringView a, const char* b) { return !equal(a, b); }
193 inline bool operator!=(const LChar* a, StringView b) { return !equal(b, a); }
194 inline bool operator!=(const char* a, StringView b) { return !equal(b, a); }
195
196 }
197
198 #include <wtf/text/AtomicString.h>
199 #include <wtf/text/WTFString.h>
200
201 namespace WTF {
202
203 inline StringView::StringView()
204 {
205     // FIXME: It's peculiar that null strings are 16-bit and empty strings return 8-bit (according to the is8Bit function).
206 }
207
208 #if CHECK_STRINGVIEW_LIFETIME
209 inline StringView::~StringView()
210 {
211     setUnderlyingString(nullptr);
212 }
213
214 inline StringView::StringView(StringView&& other)
215     : m_characters(other.m_characters)
216     , m_length(other.m_length)
217     , m_is8Bit(other.m_is8Bit)
218 {
219     ASSERT(other.underlyingStringIsValid());
220
221     other.clear();
222
223     setUnderlyingString(other);
224     other.setUnderlyingString(nullptr);
225 }
226
227 inline StringView::StringView(const StringView& other)
228     : m_characters(other.m_characters)
229     , m_length(other.m_length)
230     , m_is8Bit(other.m_is8Bit)
231 {
232     ASSERT(other.underlyingStringIsValid());
233
234     setUnderlyingString(other);
235 }
236
237 inline StringView& StringView::operator=(StringView&& other)
238 {
239     ASSERT(other.underlyingStringIsValid());
240
241     m_characters = other.m_characters;
242     m_length = other.m_length;
243     m_is8Bit = other.m_is8Bit;
244
245     other.clear();
246
247     setUnderlyingString(other);
248     other.setUnderlyingString(nullptr);
249
250     return *this;
251 }
252
253 inline StringView& StringView::operator=(const StringView& other)
254 {
255     ASSERT(other.underlyingStringIsValid());
256
257     m_characters = other.m_characters;
258     m_length = other.m_length;
259     m_is8Bit = other.m_is8Bit;
260
261     setUnderlyingString(other);
262
263     return *this;
264 }
265 #endif // CHECK_STRINGVIEW_LIFETIME
266
267 inline void StringView::initialize(const LChar* characters, unsigned length)
268 {
269     m_characters = characters;
270     m_length = length;
271     m_is8Bit = true;
272 }
273
274 inline void StringView::initialize(const UChar* characters, unsigned length)
275 {
276     m_characters = characters;
277     m_length = length;
278     m_is8Bit = false;
279 }
280
281 inline StringView::StringView(const LChar* characters, unsigned length)
282 {
283     initialize(characters, length);
284 }
285
286 inline StringView::StringView(const UChar* characters, unsigned length)
287 {
288     initialize(characters, length);
289 }
290
291 inline StringView::StringView(const char* characters)
292 {
293     initialize(reinterpret_cast<const LChar*>(characters), strlen(characters));
294 }
295
296 inline StringView::StringView(const StringImpl& string)
297 {
298     setUnderlyingString(&string);
299     if (string.is8Bit())
300         initialize(string.characters8(), string.length());
301     else
302         initialize(string.characters16(), string.length());
303 }
304
305 inline StringView::StringView(const StringImpl* string)
306 {
307     if (!string)
308         return;
309
310     setUnderlyingString(string);
311     if (string->is8Bit())
312         initialize(string->characters8(), string->length());
313     else
314         initialize(string->characters16(), string->length());
315 }
316
317 inline StringView::StringView(const String& string)
318 {
319     setUnderlyingString(string.impl());
320     if (!string.impl()) {
321         clear();
322         return;
323     }
324     if (string.is8Bit()) {
325         initialize(string.characters8(), string.length());
326         return;
327     }
328     initialize(string.characters16(), string.length());
329 }
330
331 inline StringView::StringView(const AtomicString& atomicString)
332     : StringView(atomicString.string())
333 {
334 }
335
336 inline void StringView::clear()
337 {
338     m_characters = nullptr;
339     m_length = 0;
340     m_is8Bit = true;
341 }
342
343 inline StringView StringView::empty()
344 {
345     return StringView(reinterpret_cast<const LChar*>(""), 0);
346 }
347
348 inline const LChar* StringView::characters8() const
349 {
350     ASSERT(is8Bit());
351     ASSERT(underlyingStringIsValid());
352     return static_cast<const LChar*>(m_characters);
353 }
354
355 inline const UChar* StringView::characters16() const
356 {
357     ASSERT(!is8Bit());
358     ASSERT(underlyingStringIsValid());
359     return static_cast<const UChar*>(m_characters);
360 }
361
362 class StringView::UpconvertedCharacters {
363 public:
364     explicit UpconvertedCharacters(const StringView&);
365     operator const UChar*() const { return m_characters; }
366     const UChar* get() const { return m_characters; }
367 private:
368     Vector<UChar, 32> m_upconvertedCharacters;
369     const UChar* m_characters;
370 };
371
372 inline StringView::UpconvertedCharacters StringView::upconvertedCharacters() const
373 {
374     return UpconvertedCharacters(*this);
375 }
376
377 inline bool StringView::isNull() const
378 {
379     return !m_characters;
380 }
381
382 inline bool StringView::isEmpty() const
383 {
384     return !length();
385 }
386
387 inline unsigned StringView::length() const
388 {
389     return m_length;
390 }
391
392 inline StringView::operator bool() const
393 {
394     return !isNull();
395 }
396
397 inline bool StringView::is8Bit() const
398 {
399     return m_is8Bit;
400 }
401
402 inline StringView StringView::substring(unsigned start, unsigned length) const
403 {
404     if (start >= this->length())
405         return empty();
406     unsigned maxLength = this->length() - start;
407
408     if (length >= maxLength) {
409         if (!start)
410             return *this;
411         length = maxLength;
412     }
413
414     if (is8Bit()) {
415         StringView result(characters8() + start, length);
416         result.setUnderlyingString(*this);
417         return result;
418     }
419     StringView result(characters16() + start, length);
420     result.setUnderlyingString(*this);
421     return result;
422 }
423
424 inline UChar StringView::operator[](unsigned index) const
425 {
426     ASSERT(index < length());
427     if (is8Bit())
428         return characters8()[index];
429     return characters16()[index];
430 }
431
432 inline bool StringView::contains(UChar character) const
433 {
434     return find(character) != notFound;
435 }
436
437 inline void StringView::getCharactersWithUpconvert(LChar* destination) const
438 {
439     ASSERT(is8Bit());
440     auto characters8 = this->characters8();
441     for (unsigned i = 0; i < m_length; ++i)
442         destination[i] = characters8[i];
443 }
444
445 inline void StringView::getCharactersWithUpconvert(UChar* destination) const
446 {
447     if (is8Bit()) {
448         auto characters8 = this->characters8();
449         for (unsigned i = 0; i < m_length; ++i)
450             destination[i] = characters8[i];
451         return;
452     }
453     auto characters16 = this->characters16();
454     for (unsigned i = 0; i < m_length; ++i)
455         destination[i] = characters16[i];
456 }
457
458 inline StringView::UpconvertedCharacters::UpconvertedCharacters(const StringView& string)
459 {
460     if (!string.is8Bit()) {
461         m_characters = string.characters16();
462         return;
463     }
464     const LChar* characters8 = string.characters8();
465     unsigned length = string.m_length;
466     m_upconvertedCharacters.reserveInitialCapacity(length);
467     for (unsigned i = 0; i < length; ++i)
468         m_upconvertedCharacters.uncheckedAppend(characters8[i]);
469     m_characters = m_upconvertedCharacters.data();
470 }
471
472 inline String StringView::toString() const
473 {
474     if (is8Bit())
475         return String(characters8(), m_length);
476     return String(characters16(), m_length);
477 }
478
479 inline AtomicString StringView::toAtomicString() const
480 {
481     if (is8Bit())
482         return AtomicString(characters8(), m_length);
483     return AtomicString(characters16(), m_length);
484 }
485
486 inline float StringView::toFloat(bool& isValid) const
487 {
488     if (is8Bit())
489         return charactersToFloat(characters8(), m_length, &isValid);
490     return charactersToFloat(characters16(), m_length, &isValid);
491 }
492
493 inline int StringView::toInt() const
494 {
495     bool isValid;
496     return toInt(isValid);
497 }
498
499 inline int StringView::toInt(bool& isValid) const
500 {
501     if (is8Bit())
502         return charactersToInt(characters8(), m_length, &isValid);
503     return charactersToInt(characters16(), m_length, &isValid);
504 }
505
506 inline int StringView::toIntStrict(bool& isValid) const
507 {
508     if (is8Bit())
509         return charactersToIntStrict(characters8(), m_length, &isValid);
510     return charactersToIntStrict(characters16(), m_length, &isValid);
511 }
512
513 inline String StringView::toStringWithoutCopying() const
514 {
515     if (is8Bit())
516         return StringImpl::createWithoutCopying(characters8(), m_length);
517     return StringImpl::createWithoutCopying(characters16(), m_length);
518 }
519
520 inline size_t StringView::find(UChar character, unsigned start) const
521 {
522     if (is8Bit())
523         return WTF::find(characters8(), m_length, character, start);
524     return WTF::find(characters16(), m_length, character, start);
525 }
526
527 inline size_t StringView::find(CharacterMatchFunction matchFunction, unsigned start) const
528 {
529     if (is8Bit())
530         return WTF::find(characters8(), m_length, matchFunction, start);
531     return WTF::find(characters16(), m_length, matchFunction, start);
532 }
533
534 #if !CHECK_STRINGVIEW_LIFETIME
535 inline void StringView::invalidate(const StringImpl&)
536 {
537 }
538 #endif
539
540 template<typename StringType> class StringTypeAdapter;
541
542 template<> class StringTypeAdapter<StringView> {
543 public:
544     StringTypeAdapter<StringView>(StringView string)
545         : m_string(string)
546     {
547     }
548
549     unsigned length() { return m_string.length(); }
550     bool is8Bit() { return m_string.is8Bit(); }
551     void writeTo(LChar* destination) { m_string.getCharactersWithUpconvert(destination); }
552     void writeTo(UChar* destination) { m_string.getCharactersWithUpconvert(destination); }
553
554     String toString() const { return m_string.toString(); }
555
556 private:
557     StringView m_string;
558 };
559
560 template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>& buffer, StringView string)
561 {
562     unsigned oldSize = buffer.size();
563     buffer.grow(oldSize + string.length());
564     string.getCharactersWithUpconvert(buffer.data() + oldSize);
565 }
566
567 inline bool equal(StringView a, StringView b)
568 {
569     if (a.m_characters == b.m_characters) {
570         ASSERT(a.is8Bit() == b.is8Bit());
571         return a.length() == b.length();
572     }
573         
574     return equalCommon(a, b);
575 }
576
577 inline bool equal(StringView a, const LChar* b)
578 {
579     if (!b)
580         return !a.isEmpty();
581     if (a.isEmpty())
582         return !b;
583     unsigned aLength = a.length();
584     if (a.is8Bit())
585         return equal(a.characters8(), b, aLength);
586     return equal(a.characters16(), b, aLength);
587 }
588
589 inline bool equal(StringView a, const char* b) 
590 {
591     return equal(a, reinterpret_cast<const LChar*>(b)); 
592 }
593
594 inline bool equalIgnoringASCIICase(StringView a, StringView b)
595 {
596     return equalIgnoringASCIICaseCommon(a, b);
597 }
598
599 inline bool equalIgnoringASCIICase(StringView a, const char* b)
600 {
601     return equalIgnoringASCIICaseCommon(a, b);
602 }
603
604 class StringView::GraphemeClusters {
605 public:
606     explicit GraphemeClusters(const StringView&);
607
608     class Iterator;
609     Iterator begin() const;
610     Iterator end() const;
611
612 private:
613     StringView m_stringView;
614 };
615
616 class StringView::CodePoints {
617 public:
618     explicit CodePoints(const StringView&);
619
620     class Iterator;
621     Iterator begin() const;
622     Iterator end() const;
623
624 private:
625     StringView m_stringView;
626 };
627
628 class StringView::CodeUnits {
629 public:
630     explicit CodeUnits(const StringView&);
631
632     class Iterator;
633     Iterator begin() const;
634     Iterator end() const;
635
636 private:
637     StringView m_stringView;
638 };
639
640 class StringView::GraphemeClusters::Iterator {
641 public:
642     WTF_EXPORT_PRIVATE Iterator() = delete;
643     WTF_EXPORT_PRIVATE Iterator(const StringView&, unsigned index);
644     WTF_EXPORT_PRIVATE ~Iterator();
645
646     Iterator(const Iterator&) = delete;
647     WTF_EXPORT_PRIVATE Iterator(Iterator&&);
648     Iterator& operator=(const Iterator&) = delete;
649     Iterator& operator=(Iterator&&) = delete;
650
651     WTF_EXPORT_PRIVATE StringView operator*() const;
652     WTF_EXPORT_PRIVATE Iterator& operator++();
653
654     WTF_EXPORT_PRIVATE bool operator==(const Iterator&) const;
655     WTF_EXPORT_PRIVATE bool operator!=(const Iterator&) const;
656
657 private:
658     class Impl;
659
660     std::unique_ptr<Impl> m_impl;
661 };
662
663 class StringView::CodePoints::Iterator {
664 public:
665     Iterator(const StringView&, unsigned index);
666
667     UChar32 operator*() const;
668     Iterator& operator++();
669
670     bool operator==(const Iterator&) const;
671     bool operator!=(const Iterator&) const;
672     Iterator& operator=(const Iterator&);
673
674 private:
675     std::reference_wrapper<const StringView> m_stringView;
676     Optional<unsigned> m_nextCodePointOffset;
677     UChar32 m_codePoint;
678 };
679
680 class StringView::CodeUnits::Iterator {
681 public:
682     Iterator(const StringView&, unsigned index);
683
684     UChar operator*() const;
685     Iterator& operator++();
686
687     bool operator==(const Iterator&) const;
688     bool operator!=(const Iterator&) const;
689
690 private:
691     const StringView& m_stringView;
692     unsigned m_index;
693 };
694
695 inline auto StringView::graphemeClusters() const -> GraphemeClusters
696 {
697     return GraphemeClusters(*this);
698 }
699
700 inline auto StringView::codePoints() const -> CodePoints
701 {
702     return CodePoints(*this);
703 }
704
705 inline auto StringView::codeUnits() const -> CodeUnits
706 {
707     return CodeUnits(*this);
708 }
709
710 inline StringView::GraphemeClusters::GraphemeClusters(const StringView& stringView)
711     : m_stringView(stringView)
712 {
713 }
714
715 inline auto StringView::GraphemeClusters::begin() const -> Iterator
716 {
717     return Iterator(m_stringView, 0);
718 }
719
720 inline auto StringView::GraphemeClusters::end() const -> Iterator
721 {
722     return Iterator(m_stringView, m_stringView.length());
723 }
724
725 inline StringView::CodePoints::CodePoints(const StringView& stringView)
726     : m_stringView(stringView)
727 {
728 }
729
730 inline StringView::CodePoints::Iterator::Iterator(const StringView& stringView, unsigned index)
731     : m_stringView(stringView)
732     , m_nextCodePointOffset(index)
733 {
734     operator++();
735 }
736
737 inline auto StringView::CodePoints::Iterator::operator++() -> Iterator&
738 {
739     ASSERT(m_nextCodePointOffset);
740     if (m_nextCodePointOffset.value() == m_stringView.get().length()) {
741         m_nextCodePointOffset = Nullopt;
742         return *this;
743     }
744     if (m_stringView.get().is8Bit())
745         m_codePoint = m_stringView.get().characters8()[m_nextCodePointOffset.value()++];
746     else
747         U16_NEXT(m_stringView.get().characters16(), m_nextCodePointOffset.value(), m_stringView.get().length(), m_codePoint);
748     ASSERT(m_nextCodePointOffset.value() <= m_stringView.get().length());
749     return *this;
750 }
751
752 inline auto StringView::CodePoints::Iterator::operator=(const Iterator& other) -> Iterator&
753 {
754     m_stringView = other.m_stringView;
755     m_nextCodePointOffset = other.m_nextCodePointOffset;
756     m_codePoint = other.m_codePoint;
757     return *this;
758 }
759
760 inline UChar32 StringView::CodePoints::Iterator::operator*() const
761 {
762     ASSERT(m_nextCodePointOffset);
763     return m_codePoint;
764 }
765
766 inline bool StringView::CodePoints::Iterator::operator==(const Iterator& other) const
767 {
768     ASSERT(&m_stringView.get() == &other.m_stringView.get());
769     return m_nextCodePointOffset == other.m_nextCodePointOffset;
770 }
771
772 inline bool StringView::CodePoints::Iterator::operator!=(const Iterator& other) const
773 {
774     return !(*this == other);
775 }
776
777 inline auto StringView::CodePoints::begin() const -> Iterator
778 {
779     return Iterator(m_stringView, 0);
780 }
781
782 inline auto StringView::CodePoints::end() const -> Iterator
783 {
784     return Iterator(m_stringView, m_stringView.length());
785 }
786
787 inline StringView::CodeUnits::CodeUnits(const StringView& stringView)
788     : m_stringView(stringView)
789 {
790 }
791
792 inline StringView::CodeUnits::Iterator::Iterator(const StringView& stringView, unsigned index)
793     : m_stringView(stringView)
794     , m_index(index)
795 {
796 }
797
798 inline auto StringView::CodeUnits::Iterator::operator++() -> Iterator&
799 {
800     ++m_index;
801     return *this;
802 }
803
804 inline UChar StringView::CodeUnits::Iterator::operator*() const
805 {
806     return m_stringView[m_index];
807 }
808
809 inline bool StringView::CodeUnits::Iterator::operator==(const Iterator& other) const
810 {
811     ASSERT(&m_stringView == &other.m_stringView);
812     return m_index == other.m_index;
813 }
814
815 inline bool StringView::CodeUnits::Iterator::operator!=(const Iterator& other) const
816 {
817     return !(*this == other);
818 }
819
820 inline auto StringView::CodeUnits::begin() const -> Iterator
821 {
822     return Iterator(m_stringView, 0);
823 }
824
825 inline auto StringView::CodeUnits::end() const -> Iterator
826 {
827     return Iterator(m_stringView, m_stringView.length());
828 }
829
830 template<unsigned length> inline bool equalLettersIgnoringASCIICase(StringView string, const char (&lowercaseLetters)[length])
831 {
832     return equalLettersIgnoringASCIICaseCommon(string, lowercaseLetters);
833 }
834
835 } // namespace WTF
836
837 using WTF::append;
838 using WTF::equal;
839 using WTF::StringView;
840
841 #endif // StringView_h