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