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