Fix some minor problems in the StringImpl header
[WebKit-https.git] / Source / WTF / wtf / text / StringView.h
1 /*
2  * Copyright (C) 2014-2017 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 <limits.h>
30 #include <unicode/utypes.h>
31 #include <wtf/Forward.h>
32 #include <wtf/RetainPtr.h>
33 #include <wtf/Vector.h>
34 #include <wtf/text/CString.h>
35 #include <wtf/text/ConversionMode.h>
36 #include <wtf/text/LChar.h>
37 #include <wtf/text/StringCommon.h>
38
39 // FIXME: Enabling the StringView lifetime checking causes the MSVC build to fail. Figure out why.
40 #if defined(NDEBUG) || COMPILER(MSVC)
41 #define CHECK_STRINGVIEW_LIFETIME 0
42 #else
43 #define CHECK_STRINGVIEW_LIFETIME 1
44 #endif
45
46 namespace WTF {
47
48 // StringView is a non-owning reference to a string, similar to the proposed std::string_view.
49
50 class StringView {
51 public:
52     StringView();
53 #if CHECK_STRINGVIEW_LIFETIME
54     ~StringView();
55     StringView(StringView&&);
56     StringView(const StringView&);
57     StringView& operator=(StringView&&);
58     StringView& operator=(const StringView&);
59 #endif
60
61     StringView(const AtomicString&);
62     StringView(const String&);
63     StringView(const StringImpl&);
64     StringView(const StringImpl*);
65     StringView(const LChar*, unsigned length);
66     StringView(const UChar*, unsigned length);
67     StringView(const char*);
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     RefPtr<AtomicStringImpl> toExistingAtomicString() const;
96
97 #if USE(CF)
98     // This function converts null strings to empty strings.
99     WTF_EXPORT_STRING_API RetainPtr<CFStringRef> createCFStringWithoutCopying() const;
100 #endif
101
102 #ifdef __OBJC__
103     // These functions convert null strings to empty strings.
104     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSString() const;
105     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSStringWithoutCopying() const;
106 #endif
107
108     WTF_EXPORT_STRING_API CString utf8(ConversionMode = LenientConversion) const;
109
110     class UpconvertedCharacters;
111     UpconvertedCharacters upconvertedCharacters() const;
112
113     void getCharactersWithUpconvert(LChar*) const;
114     void getCharactersWithUpconvert(UChar*) const;
115
116     StringView substring(unsigned start, unsigned length = std::numeric_limits<unsigned>::max()) const;
117     StringView left(unsigned len) const { return substring(0, len); }
118     StringView right(unsigned len) const { return substring(length() - len, len); }
119
120     template<typename MatchedCharacterPredicate>
121     StringView stripLeadingAndTrailingMatchedCharacters(const MatchedCharacterPredicate&);
122
123     class SplitResult;
124     SplitResult split(UChar) const;
125
126     size_t find(UChar, unsigned start = 0) const;
127     size_t find(CodeUnitMatchFunction, unsigned start = 0) const;
128
129     WTF_EXPORT_STRING_API size_t find(StringView, unsigned start) const;
130
131     size_t reverseFind(UChar, unsigned index = UINT_MAX) const;
132
133     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringView&) const;
134     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringView&, unsigned startOffset) const;
135
136     bool contains(UChar) const;
137     WTF_EXPORT_STRING_API bool containsIgnoringASCIICase(const StringView&) const;
138     WTF_EXPORT_STRING_API bool containsIgnoringASCIICase(const StringView&, unsigned startOffset) const;
139
140     WTF_EXPORT_STRING_API bool startsWith(const StringView&) const;
141     WTF_EXPORT_STRING_API bool startsWithIgnoringASCIICase(const StringView&) const;
142
143     WTF_EXPORT_STRING_API bool endsWith(const StringView&) const;
144     WTF_EXPORT_STRING_API bool endsWithIgnoringASCIICase(const StringView&) const;
145
146     int toInt() const;
147     int toInt(bool& isValid) const;
148     int toIntStrict(bool& isValid) const;
149     float toFloat(bool& isValid) const;
150
151     static void invalidate(const StringImpl&);
152
153     struct UnderlyingString;
154
155 private:
156     friend bool equal(StringView, StringView);
157
158     void initialize(const LChar*, unsigned length);
159     void initialize(const UChar*, unsigned length);
160
161     template<typename CharacterType, typename MatchedCharacterPredicate>
162     StringView stripLeadingAndTrailingMatchedCharacters(const CharacterType*, const MatchedCharacterPredicate&);
163
164 #if CHECK_STRINGVIEW_LIFETIME
165     WTF_EXPORT_STRING_API bool underlyingStringIsValid() const;
166     WTF_EXPORT_STRING_API void setUnderlyingString(const StringImpl*);
167     WTF_EXPORT_STRING_API void setUnderlyingString(const StringView&);
168 #else
169     bool underlyingStringIsValid() const { return true; }
170     void setUnderlyingString(const StringImpl*) { }
171     void setUnderlyingString(const StringView&) { }
172 #endif
173     void clear();
174
175     const void* m_characters { nullptr };
176     unsigned m_length { 0 };
177     bool m_is8Bit { true };
178
179 #if CHECK_STRINGVIEW_LIFETIME
180     void adoptUnderlyingString(UnderlyingString*);
181     UnderlyingString* m_underlyingString { nullptr };
182 #endif
183 };
184
185 template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>&, StringView);
186
187 bool equal(StringView, StringView);
188 bool equal(StringView, const LChar*);
189 bool equal(StringView, const char*);
190
191 bool equalIgnoringASCIICase(StringView, StringView);
192 bool equalIgnoringASCIICase(StringView, const char*);
193
194 template<unsigned length> bool equalLettersIgnoringASCIICase(StringView, const char (&lowercaseLetters)[length]);
195
196 inline bool operator==(StringView a, StringView b) { return equal(a, b); }
197 inline bool operator==(StringView a, const LChar* b) { return equal(a, b); }
198 inline bool operator==(StringView a, const char* b) { return equal(a, b); }
199 inline bool operator==(const LChar* a, StringView b) { return equal(b, a); }
200 inline bool operator==(const char* a, StringView b) { return equal(b, a); }
201
202 inline bool operator!=(StringView a, StringView b) { return !equal(a, b); }
203 inline bool operator!=(StringView a, const LChar* b) { return !equal(a, b); }
204 inline bool operator!=(StringView a, const char* b) { return !equal(a, b); }
205 inline bool operator!=(const LChar* a, StringView b) { return !equal(b, a); }
206 inline bool operator!=(const char* a, StringView b) { return !equal(b, a); }
207
208 }
209
210 #include <wtf/text/AtomicString.h>
211 #include <wtf/text/WTFString.h>
212
213 namespace WTF {
214
215 inline StringView::StringView()
216 {
217     // FIXME: It's peculiar that null strings are 16-bit and empty strings return 8-bit (according to the is8Bit function).
218 }
219
220 #if CHECK_STRINGVIEW_LIFETIME
221 inline StringView::~StringView()
222 {
223     setUnderlyingString(nullptr);
224 }
225
226 inline StringView::StringView(StringView&& other)
227     : m_characters(other.m_characters)
228     , m_length(other.m_length)
229     , m_is8Bit(other.m_is8Bit)
230 {
231     ASSERT(other.underlyingStringIsValid());
232
233     other.clear();
234
235     setUnderlyingString(other);
236     other.setUnderlyingString(nullptr);
237 }
238
239 inline StringView::StringView(const StringView& other)
240     : m_characters(other.m_characters)
241     , m_length(other.m_length)
242     , m_is8Bit(other.m_is8Bit)
243 {
244     ASSERT(other.underlyingStringIsValid());
245
246     setUnderlyingString(other);
247 }
248
249 inline StringView& StringView::operator=(StringView&& other)
250 {
251     ASSERT(other.underlyingStringIsValid());
252
253     m_characters = other.m_characters;
254     m_length = other.m_length;
255     m_is8Bit = other.m_is8Bit;
256
257     other.clear();
258
259     setUnderlyingString(other);
260     other.setUnderlyingString(nullptr);
261
262     return *this;
263 }
264
265 inline StringView& StringView::operator=(const StringView& other)
266 {
267     ASSERT(other.underlyingStringIsValid());
268
269     m_characters = other.m_characters;
270     m_length = other.m_length;
271     m_is8Bit = other.m_is8Bit;
272
273     setUnderlyingString(other);
274
275     return *this;
276 }
277 #endif // CHECK_STRINGVIEW_LIFETIME
278
279 inline void StringView::initialize(const LChar* characters, unsigned length)
280 {
281     m_characters = characters;
282     m_length = length;
283     m_is8Bit = true;
284 }
285
286 inline void StringView::initialize(const UChar* characters, unsigned length)
287 {
288     m_characters = characters;
289     m_length = length;
290     m_is8Bit = false;
291 }
292
293 inline StringView::StringView(const LChar* characters, unsigned length)
294 {
295     initialize(characters, length);
296 }
297
298 inline StringView::StringView(const UChar* characters, unsigned length)
299 {
300     initialize(characters, length);
301 }
302
303 inline StringView::StringView(const char* characters)
304 {
305     initialize(reinterpret_cast<const LChar*>(characters), strlen(characters));
306 }
307
308 inline StringView::StringView(const StringImpl& string)
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 StringImpl* string)
318 {
319     if (!string)
320         return;
321
322     setUnderlyingString(string);
323     if (string->is8Bit())
324         initialize(string->characters8(), string->length());
325     else
326         initialize(string->characters16(), string->length());
327 }
328
329 inline StringView::StringView(const String& string)
330 {
331     setUnderlyingString(string.impl());
332     if (!string.impl()) {
333         clear();
334         return;
335     }
336     if (string.is8Bit()) {
337         initialize(string.characters8(), string.length());
338         return;
339     }
340     initialize(string.characters16(), string.length());
341 }
342
343 inline StringView::StringView(const AtomicString& atomicString)
344     : StringView(atomicString.string())
345 {
346 }
347
348 inline void StringView::clear()
349 {
350     m_characters = nullptr;
351     m_length = 0;
352     m_is8Bit = true;
353 }
354
355 inline StringView StringView::empty()
356 {
357     return StringView(reinterpret_cast<const LChar*>(""), 0);
358 }
359
360 inline const LChar* StringView::characters8() const
361 {
362     ASSERT(is8Bit());
363     ASSERT(underlyingStringIsValid());
364     return static_cast<const LChar*>(m_characters);
365 }
366
367 inline const UChar* StringView::characters16() const
368 {
369     ASSERT(!is8Bit());
370     ASSERT(underlyingStringIsValid());
371     return static_cast<const UChar*>(m_characters);
372 }
373
374 class StringView::UpconvertedCharacters {
375 public:
376     explicit UpconvertedCharacters(const StringView&);
377     operator const UChar*() const { return m_characters; }
378     const UChar* get() const { return m_characters; }
379 private:
380     Vector<UChar, 32> m_upconvertedCharacters;
381     const UChar* m_characters;
382 };
383
384 inline StringView::UpconvertedCharacters StringView::upconvertedCharacters() const
385 {
386     return UpconvertedCharacters(*this);
387 }
388
389 inline bool StringView::isNull() const
390 {
391     return !m_characters;
392 }
393
394 inline bool StringView::isEmpty() const
395 {
396     return !length();
397 }
398
399 inline unsigned StringView::length() const
400 {
401     return m_length;
402 }
403
404 inline StringView::operator bool() const
405 {
406     return !isNull();
407 }
408
409 inline bool StringView::is8Bit() const
410 {
411     return m_is8Bit;
412 }
413
414 inline StringView StringView::substring(unsigned start, unsigned length) const
415 {
416     if (start >= this->length())
417         return empty();
418     unsigned maxLength = this->length() - start;
419
420     if (length >= maxLength) {
421         if (!start)
422             return *this;
423         length = maxLength;
424     }
425
426     if (is8Bit()) {
427         StringView result(characters8() + start, length);
428         result.setUnderlyingString(*this);
429         return result;
430     }
431     StringView result(characters16() + start, length);
432     result.setUnderlyingString(*this);
433     return result;
434 }
435
436 inline UChar StringView::operator[](unsigned index) const
437 {
438     ASSERT(index < length());
439     if (is8Bit())
440         return characters8()[index];
441     return characters16()[index];
442 }
443
444 inline bool StringView::contains(UChar character) const
445 {
446     return find(character) != notFound;
447 }
448
449 inline void StringView::getCharactersWithUpconvert(LChar* destination) const
450 {
451     ASSERT(is8Bit());
452     StringImpl::copyCharacters(destination, characters8(), m_length);
453 }
454
455 inline void StringView::getCharactersWithUpconvert(UChar* destination) const
456 {
457     if (is8Bit()) {
458         StringImpl::copyCharacters(destination, characters8(), m_length);
459         return;
460     }
461     StringImpl::copyCharacters(destination, characters16(), m_length);
462 }
463
464 inline StringView::UpconvertedCharacters::UpconvertedCharacters(const StringView& string)
465 {
466     if (!string.is8Bit()) {
467         m_characters = string.characters16();
468         return;
469     }
470     const LChar* characters8 = string.characters8();
471     unsigned length = string.m_length;
472     m_upconvertedCharacters.reserveInitialCapacity(length);
473     for (unsigned i = 0; i < length; ++i)
474         m_upconvertedCharacters.uncheckedAppend(characters8[i]);
475     m_characters = m_upconvertedCharacters.data();
476 }
477
478 inline String StringView::toString() const
479 {
480     if (is8Bit())
481         return String(characters8(), m_length);
482     return String(characters16(), m_length);
483 }
484
485 inline AtomicString StringView::toAtomicString() const
486 {
487     if (is8Bit())
488         return AtomicString(characters8(), m_length);
489     return AtomicString(characters16(), m_length);
490 }
491
492 inline RefPtr<AtomicStringImpl> StringView::toExistingAtomicString() const
493 {
494     if (is8Bit())
495         return AtomicStringImpl::lookUp(characters8(), m_length);
496     return AtomicStringImpl::lookUp(characters16(), m_length);
497 }
498
499 inline float StringView::toFloat(bool& isValid) const
500 {
501     if (is8Bit())
502         return charactersToFloat(characters8(), m_length, &isValid);
503     return charactersToFloat(characters16(), m_length, &isValid);
504 }
505
506 inline int StringView::toInt() const
507 {
508     bool isValid;
509     return toInt(isValid);
510 }
511
512 inline int StringView::toInt(bool& isValid) const
513 {
514     if (is8Bit())
515         return charactersToInt(characters8(), m_length, &isValid);
516     return charactersToInt(characters16(), m_length, &isValid);
517 }
518
519 inline int StringView::toIntStrict(bool& isValid) const
520 {
521     if (is8Bit())
522         return charactersToIntStrict(characters8(), m_length, &isValid);
523     return charactersToIntStrict(characters16(), m_length, &isValid);
524 }
525
526 inline String StringView::toStringWithoutCopying() const
527 {
528     if (is8Bit())
529         return StringImpl::createWithoutCopying(characters8(), m_length);
530     return StringImpl::createWithoutCopying(characters16(), m_length);
531 }
532
533 inline size_t StringView::find(UChar character, unsigned start) const
534 {
535     if (is8Bit())
536         return WTF::find(characters8(), m_length, character, start);
537     return WTF::find(characters16(), m_length, character, start);
538 }
539
540 inline size_t StringView::find(CodeUnitMatchFunction matchFunction, unsigned start) const
541 {
542     if (is8Bit())
543         return WTF::find(characters8(), m_length, matchFunction, start);
544     return WTF::find(characters16(), m_length, matchFunction, start);
545 }
546
547 inline size_t StringView::reverseFind(UChar character, unsigned index) const
548 {
549     if (is8Bit())
550         return WTF::reverseFind(characters8(), m_length, character, index);
551     return WTF::reverseFind(characters16(), m_length, character, index);
552 }
553
554 #if !CHECK_STRINGVIEW_LIFETIME
555 inline void StringView::invalidate(const StringImpl&)
556 {
557 }
558 #endif
559
560 template<typename StringType> class StringTypeAdapter;
561
562 template<> class StringTypeAdapter<StringView> {
563 public:
564     StringTypeAdapter<StringView>(StringView string)
565         : m_string(string)
566     {
567     }
568
569     unsigned length() { return m_string.length(); }
570     bool is8Bit() { return m_string.is8Bit(); }
571     void writeTo(LChar* destination) { m_string.getCharactersWithUpconvert(destination); }
572     void writeTo(UChar* destination) { m_string.getCharactersWithUpconvert(destination); }
573
574     String toString() const { return m_string.toString(); }
575
576 private:
577     StringView m_string;
578 };
579
580 template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>& buffer, StringView string)
581 {
582     unsigned oldSize = buffer.size();
583     buffer.grow(oldSize + string.length());
584     string.getCharactersWithUpconvert(buffer.data() + oldSize);
585 }
586
587 inline bool equal(StringView a, StringView b)
588 {
589     if (a.m_characters == b.m_characters) {
590         ASSERT(a.is8Bit() == b.is8Bit());
591         return a.length() == b.length();
592     }
593         
594     return equalCommon(a, b);
595 }
596
597 inline bool equal(StringView a, const LChar* b)
598 {
599     if (!b)
600         return !a.isEmpty();
601     if (a.isEmpty())
602         return !b;
603     unsigned aLength = a.length();
604     if (a.is8Bit())
605         return equal(a.characters8(), b, aLength);
606     return equal(a.characters16(), b, aLength);
607 }
608
609 inline bool equal(StringView a, const char* b) 
610 {
611     return equal(a, reinterpret_cast<const LChar*>(b)); 
612 }
613
614 inline bool equalIgnoringASCIICase(StringView a, StringView b)
615 {
616     return equalIgnoringASCIICaseCommon(a, b);
617 }
618
619 inline bool equalIgnoringASCIICase(StringView a, const char* b)
620 {
621     return equalIgnoringASCIICaseCommon(a, b);
622 }
623
624 class StringView::SplitResult {
625 public:
626     explicit SplitResult(StringView, UChar separator);
627
628     class Iterator;
629     Iterator begin() const;
630     Iterator end() const;
631
632 private:
633     StringView m_string;
634     UChar m_separator;
635 };
636
637 class StringView::GraphemeClusters {
638 public:
639     explicit GraphemeClusters(const StringView&);
640
641     class Iterator;
642     Iterator begin() const;
643     Iterator end() const;
644
645 private:
646     StringView m_stringView;
647 };
648
649 class StringView::CodePoints {
650 public:
651     explicit CodePoints(const StringView&);
652
653     class Iterator;
654     Iterator begin() const;
655     Iterator end() const;
656
657 private:
658     StringView m_stringView;
659 };
660
661 class StringView::CodeUnits {
662 public:
663     explicit CodeUnits(const StringView&);
664
665     class Iterator;
666     Iterator begin() const;
667     Iterator end() const;
668
669 private:
670     StringView m_stringView;
671 };
672
673 class StringView::SplitResult::Iterator {
674 public:
675     StringView operator*() const;
676
677     WTF_EXPORT_PRIVATE Iterator& operator++();
678
679     bool operator==(const Iterator&) const;
680     bool operator!=(const Iterator&) const;
681
682 private:
683     enum PositionTag { AtEnd };
684     Iterator(const SplitResult&);
685     Iterator(const SplitResult&, PositionTag);
686
687     WTF_EXPORT_PRIVATE void findNextSubstring();
688
689     friend SplitResult;
690
691     const SplitResult& m_result;
692     unsigned m_position { 0 };
693     unsigned m_length;
694 };
695
696 class StringView::GraphemeClusters::Iterator {
697 public:
698     Iterator() = delete;
699     WTF_EXPORT_PRIVATE Iterator(const StringView&, unsigned index);
700     WTF_EXPORT_PRIVATE ~Iterator();
701
702     Iterator(const Iterator&) = delete;
703     WTF_EXPORT_PRIVATE Iterator(Iterator&&);
704     Iterator& operator=(const Iterator&) = delete;
705     Iterator& operator=(Iterator&&) = delete;
706
707     WTF_EXPORT_PRIVATE StringView operator*() const;
708     WTF_EXPORT_PRIVATE Iterator& operator++();
709
710     WTF_EXPORT_PRIVATE bool operator==(const Iterator&) const;
711     WTF_EXPORT_PRIVATE bool operator!=(const Iterator&) const;
712
713 private:
714     class Impl;
715
716     std::unique_ptr<Impl> m_impl;
717 };
718
719 class StringView::CodePoints::Iterator {
720 public:
721     Iterator(const StringView&, unsigned index);
722
723     UChar32 operator*() const;
724     Iterator& operator++();
725
726     bool operator==(const Iterator&) const;
727     bool operator!=(const Iterator&) const;
728     Iterator& operator=(const Iterator&);
729
730 private:
731     std::reference_wrapper<const StringView> m_stringView;
732     std::optional<unsigned> m_nextCodePointOffset;
733     UChar32 m_codePoint;
734 };
735
736 class StringView::CodeUnits::Iterator {
737 public:
738     Iterator(const StringView&, unsigned index);
739
740     UChar operator*() const;
741     Iterator& operator++();
742
743     bool operator==(const Iterator&) const;
744     bool operator!=(const Iterator&) const;
745
746 private:
747     const StringView& m_stringView;
748     unsigned m_index;
749 };
750
751 inline auto StringView::graphemeClusters() const -> GraphemeClusters
752 {
753     return GraphemeClusters(*this);
754 }
755
756 inline auto StringView::codePoints() const -> CodePoints
757 {
758     return CodePoints(*this);
759 }
760
761 inline auto StringView::codeUnits() const -> CodeUnits
762 {
763     return CodeUnits(*this);
764 }
765
766 inline StringView::GraphemeClusters::GraphemeClusters(const StringView& stringView)
767     : m_stringView(stringView)
768 {
769 }
770
771 inline auto StringView::GraphemeClusters::begin() const -> Iterator
772 {
773     return Iterator(m_stringView, 0);
774 }
775
776 inline auto StringView::GraphemeClusters::end() const -> Iterator
777 {
778     return Iterator(m_stringView, m_stringView.length());
779 }
780
781 inline StringView::CodePoints::CodePoints(const StringView& stringView)
782     : m_stringView(stringView)
783 {
784 }
785
786 inline StringView::CodePoints::Iterator::Iterator(const StringView& stringView, unsigned index)
787     : m_stringView(stringView)
788     , m_nextCodePointOffset(index)
789 {
790     operator++();
791 }
792
793 inline auto StringView::CodePoints::Iterator::operator++() -> Iterator&
794 {
795     ASSERT(m_nextCodePointOffset);
796     if (m_nextCodePointOffset.value() == m_stringView.get().length()) {
797         m_nextCodePointOffset = std::nullopt;
798         return *this;
799     }
800     if (m_stringView.get().is8Bit())
801         m_codePoint = m_stringView.get().characters8()[m_nextCodePointOffset.value()++];
802     else
803         U16_NEXT(m_stringView.get().characters16(), m_nextCodePointOffset.value(), m_stringView.get().length(), m_codePoint);
804     ASSERT(m_nextCodePointOffset.value() <= m_stringView.get().length());
805     return *this;
806 }
807
808 inline auto StringView::CodePoints::Iterator::operator=(const Iterator& other) -> Iterator&
809 {
810     m_stringView = other.m_stringView;
811     m_nextCodePointOffset = other.m_nextCodePointOffset;
812     m_codePoint = other.m_codePoint;
813     return *this;
814 }
815
816 inline UChar32 StringView::CodePoints::Iterator::operator*() const
817 {
818     ASSERT(m_nextCodePointOffset);
819     return m_codePoint;
820 }
821
822 inline bool StringView::CodePoints::Iterator::operator==(const Iterator& other) const
823 {
824     ASSERT(&m_stringView.get() == &other.m_stringView.get());
825     return m_nextCodePointOffset == other.m_nextCodePointOffset;
826 }
827
828 inline bool StringView::CodePoints::Iterator::operator!=(const Iterator& other) const
829 {
830     return !(*this == other);
831 }
832
833 inline auto StringView::CodePoints::begin() const -> Iterator
834 {
835     return Iterator(m_stringView, 0);
836 }
837
838 inline auto StringView::CodePoints::end() const -> Iterator
839 {
840     return Iterator(m_stringView, m_stringView.length());
841 }
842
843 inline StringView::CodeUnits::CodeUnits(const StringView& stringView)
844     : m_stringView(stringView)
845 {
846 }
847
848 inline StringView::CodeUnits::Iterator::Iterator(const StringView& stringView, unsigned index)
849     : m_stringView(stringView)
850     , m_index(index)
851 {
852 }
853
854 inline auto StringView::CodeUnits::Iterator::operator++() -> Iterator&
855 {
856     ++m_index;
857     return *this;
858 }
859
860 inline UChar StringView::CodeUnits::Iterator::operator*() const
861 {
862     return m_stringView[m_index];
863 }
864
865 inline bool StringView::CodeUnits::Iterator::operator==(const Iterator& other) const
866 {
867     ASSERT(&m_stringView == &other.m_stringView);
868     return m_index == other.m_index;
869 }
870
871 inline bool StringView::CodeUnits::Iterator::operator!=(const Iterator& other) const
872 {
873     return !(*this == other);
874 }
875
876 inline auto StringView::CodeUnits::begin() const -> Iterator
877 {
878     return Iterator(m_stringView, 0);
879 }
880
881 inline auto StringView::CodeUnits::end() const -> Iterator
882 {
883     return Iterator(m_stringView, m_stringView.length());
884 }
885
886 inline auto StringView::split(UChar separator) const -> SplitResult
887 {
888     return SplitResult { *this, separator };
889 }
890
891 inline StringView::SplitResult::SplitResult(StringView stringView, UChar separator)
892     : m_string { stringView }
893     , m_separator { separator }
894 {
895 }
896
897 inline auto StringView::SplitResult::begin() const -> Iterator
898 {
899     return Iterator { *this };
900 }
901
902 inline auto StringView::SplitResult::end() const -> Iterator
903 {
904     return Iterator { *this, Iterator::AtEnd };
905 }
906
907 inline StringView::SplitResult::Iterator::Iterator(const SplitResult& result)
908     : m_result { result }
909 {
910     findNextSubstring();
911 }
912
913 inline StringView::SplitResult::Iterator::Iterator(const SplitResult& result, PositionTag)
914     : m_result { result }
915     , m_position { result.m_string.length() }
916 {
917 }
918
919 inline StringView StringView::SplitResult::Iterator::operator*() const
920 {
921     ASSERT(m_position < m_result.m_string.length());
922     return m_result.m_string.substring(m_position, m_length);
923 }
924
925 inline bool StringView::SplitResult::Iterator::operator==(const Iterator& other) const
926 {
927     ASSERT(&m_result == &other.m_result);
928     return m_position == other.m_position;
929 }
930
931 inline bool StringView::SplitResult::Iterator::operator!=(const Iterator& other) const
932 {
933     return !(*this == other);
934 }
935
936 template<typename CharacterType, typename MatchedCharacterPredicate>
937 inline StringView StringView::stripLeadingAndTrailingMatchedCharacters(const CharacterType* characters, const MatchedCharacterPredicate& predicate)
938 {
939     if (!m_length)
940         return *this;
941
942     unsigned start = 0;
943     unsigned end = m_length - 1;
944     
945     while (start <= end && predicate(characters[start]))
946         ++start;
947     
948     if (start > end)
949         return StringView::empty();
950
951     while (end && predicate(characters[end]))
952         --end;
953
954     if (!start && end == m_length - 1)
955         return *this;
956
957     StringView result(characters + start, end + 1 - start);
958     result.setUnderlyingString(*this);
959     return result;
960 }
961
962 template<typename MatchedCharacterPredicate>
963 StringView StringView::stripLeadingAndTrailingMatchedCharacters(const MatchedCharacterPredicate& predicate)
964 {
965     if (is8Bit())
966         return stripLeadingAndTrailingMatchedCharacters<LChar>(characters8(), predicate);
967     return stripLeadingAndTrailingMatchedCharacters<UChar>(characters16(), predicate);
968 }
969
970 template<unsigned length> inline bool equalLettersIgnoringASCIICase(StringView string, const char (&lowercaseLetters)[length])
971 {
972     return equalLettersIgnoringASCIICaseCommon(string, lowercaseLetters);
973 }
974
975 } // namespace WTF
976
977 using WTF::append;
978 using WTF::equal;
979 using WTF::StringView;
980
981 #endif