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