d9ce74c8aa2124bd62183aa9668700c9986ea740
[WebKit-https.git] / Source / WTF / wtf / text / StringView.h
1 /*
2  * Copyright (C) 2014 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/LChar.h>
34 #include <wtf/text/StringCommon.h>
35
36 // FIXME: Enabling the StringView lifetime checking causes the MSVC build to fail. Figure out why.
37 // FIXME: Enable StringView lifetime checking once the underlying assertions have been fixed.
38 #if defined(NDEBUG) || COMPILER(MSVC) || 1
39 #define CHECK_STRINGVIEW_LIFETIME 0
40 #else
41 #define CHECK_STRINGVIEW_LIFETIME 1
42 #endif
43
44 namespace WTF {
45
46 // StringView is a non-owning reference to a string, similar to the proposed std::string_view.
47 // Whether the string is 8-bit or 16-bit is encoded in the upper bit of the length member.
48 // This means that strings longer than 2 gigacharacters cannot be represented.
49
50 class StringView {
51 public:
52     StringView();
53     ~StringView();
54     StringView(StringView&&);
55     StringView(const StringView&);
56     StringView& operator=(StringView&&);
57     StringView& operator=(const StringView&);
58
59     StringView(const String&);
60     StringView(const StringImpl&);
61     StringView(const LChar*, unsigned length);
62     StringView(const UChar*, unsigned length);
63
64     static StringView empty();
65
66     unsigned length() const;
67     bool isEmpty() const;
68
69     explicit operator bool() const;
70     bool isNull() const;
71
72     UChar operator[](unsigned index) const;
73
74     class CodeUnits;
75     CodeUnits codeUnits() const;
76
77     class CodePoints;
78     CodePoints codePoints() const;
79
80     bool is8Bit() const;
81     const LChar* characters8() const;
82     const UChar* characters16() const;
83
84     String toString() const;
85     String toStringWithoutCopying() const;
86
87 #if USE(CF)
88     // This function converts null strings to empty strings.
89     WTF_EXPORT_STRING_API RetainPtr<CFStringRef> createCFStringWithoutCopying() const;
90 #endif
91
92 #ifdef __OBJC__
93     // These functions convert null strings to empty strings.
94     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSString() const;
95     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSStringWithoutCopying() const;
96 #endif
97
98     class UpconvertedCharacters;
99     UpconvertedCharacters upconvertedCharacters() const;
100
101     void getCharactersWithUpconvert(LChar*) const;
102     void getCharactersWithUpconvert(UChar*) const;
103
104     StringView substring(unsigned start, unsigned length = std::numeric_limits<unsigned>::max()) const;
105
106     size_t find(UChar, unsigned start = 0) const;
107     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringView&) const;
108     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringView&, unsigned startOffset) const;
109
110     bool contains(UChar) const;
111     WTF_EXPORT_STRING_API bool containsIgnoringASCIICase(const StringView&) const;
112     WTF_EXPORT_STRING_API bool containsIgnoringASCIICase(const StringView&, unsigned startOffset) const;
113
114     WTF_EXPORT_STRING_API bool startsWith(const StringView&) const;
115     WTF_EXPORT_STRING_API bool startsWithIgnoringASCIICase(const StringView&) const;
116
117     WTF_EXPORT_STRING_API bool endsWith(const StringView&) const;
118     WTF_EXPORT_STRING_API bool endsWithIgnoringASCIICase(const StringView&) const;
119
120     int toInt(bool& isValid) const;
121     float toFloat(bool& isValid) const;
122
123     static void invalidate(const StringImpl&);
124
125     struct UnderlyingString;
126
127 private:
128     void initialize(const LChar*, unsigned length);
129     void initialize(const UChar*, unsigned length);
130
131 #if CHECK_STRINGVIEW_LIFETIME
132     WTF_EXPORT_STRING_API bool underlyingStringIsValid() const;
133     WTF_EXPORT_STRING_API void setUnderlyingString(const StringImpl*);
134     WTF_EXPORT_STRING_API void setUnderlyingString(const StringView&);
135 #else
136     bool underlyingStringIsValid() const { return true; }
137     void setUnderlyingString(const StringImpl*) { }
138     void setUnderlyingString(const StringView&) { }
139 #endif
140
141     static const unsigned is16BitStringFlag = 1u << 31;
142
143     const void* m_characters { nullptr };
144     unsigned m_length { 0 };
145
146 #if CHECK_STRINGVIEW_LIFETIME
147     void adoptUnderlyingString(UnderlyingString*);
148     UnderlyingString* m_underlyingString { nullptr };
149 #endif
150 };
151
152 template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>&, StringView);
153
154 bool equal(StringView, StringView);
155 bool equal(StringView, const LChar*);
156 bool equal(StringView, const char*);
157 bool equalIgnoringASCIICase(StringView, StringView);
158
159 inline bool operator==(StringView a, StringView b) { return equal(a, b); }
160 inline bool operator==(StringView a, const LChar* b) { return equal(a, b); }
161 inline bool operator==(StringView a, const char* b) { return equal(a, b); }
162 inline bool operator==(const LChar* a, StringView b) { return equal(b, a); }
163 inline bool operator==(const char* a, StringView b) { return equal(b, a); }
164
165 inline bool operator!=(StringView a, StringView b) { return !equal(a, b); }
166 inline bool operator!=(StringView a, const LChar* b) { return !equal(a, b); }
167 inline bool operator!=(StringView a, const char* b) { return !equal(a, b); }
168 inline bool operator!=(const LChar* a, StringView b) { return !equal(b, a); }
169 inline bool operator!=(const char* a, StringView b) { return !equal(b, a); }
170
171 }
172
173 #include <wtf/text/WTFString.h>
174
175 namespace WTF {
176
177 inline StringView::StringView()
178 {
179     // FIXME: It's peculiar that null strings are 16-bit and empty strings return 8-bit (according to the is8Bit function).
180 }
181
182 inline StringView::~StringView()
183 {
184     setUnderlyingString(nullptr);
185 }
186
187 inline StringView::StringView(StringView&& other)
188     : m_characters(other.m_characters)
189     , m_length(other.m_length)
190 {
191     ASSERT(other.underlyingStringIsValid());
192
193     other.m_characters = nullptr;
194     other.m_length = 0;
195
196     setUnderlyingString(other);
197     other.setUnderlyingString(nullptr);
198 }
199
200 inline StringView::StringView(const StringView& other)
201     : m_characters(other.m_characters)
202     , m_length(other.m_length)
203 {
204     ASSERT(other.underlyingStringIsValid());
205
206     setUnderlyingString(other);
207 }
208
209 inline StringView& StringView::operator=(StringView&& other)
210 {
211     ASSERT(other.underlyingStringIsValid());
212
213     m_characters = other.m_characters;
214     m_length = other.m_length;
215
216     other.m_characters = nullptr;
217     other.m_length = 0;
218
219     setUnderlyingString(other);
220     other.setUnderlyingString(nullptr);
221
222     return *this;
223 }
224
225 inline StringView& StringView::operator=(const StringView& other)
226 {
227     ASSERT(other.underlyingStringIsValid());
228
229     m_characters = other.m_characters;
230     m_length = other.m_length;
231
232     setUnderlyingString(other);
233
234     return *this;
235 }
236
237 inline void StringView::initialize(const LChar* characters, unsigned length)
238 {
239     // FIXME: We need a better solution here, because there is no guarantee that
240     // the length here won't be too long. Maybe at least a RELEASE_ASSERT?
241     ASSERT(!(length & is16BitStringFlag));
242     m_characters = characters;
243     m_length = length;
244 }
245
246 inline void StringView::initialize(const UChar* characters, unsigned length)
247 {
248     // FIXME: We need a better solution here, because there is no guarantee that
249     // the length here won't be too long. Maybe at least a RELEASE_ASSERT?
250     ASSERT(!(length & is16BitStringFlag));
251     m_characters = characters;
252     m_length = is16BitStringFlag | length;
253 }
254
255 inline StringView::StringView(const LChar* characters, unsigned length)
256 {
257     initialize(characters, length);
258 }
259
260 inline StringView::StringView(const UChar* characters, unsigned length)
261 {
262     initialize(characters, length);
263 }
264
265 inline StringView::StringView(const StringImpl& string)
266 {
267     setUnderlyingString(&string);
268     if (string.is8Bit())
269         initialize(string.characters8(), string.length());
270     else
271         initialize(string.characters16(), string.length());
272 }
273
274 inline StringView::StringView(const String& string)
275 {
276     setUnderlyingString(string.impl());
277     if (!string.impl()) {
278         m_characters = nullptr;
279         m_length = 0;
280         return;
281     }
282     if (string.is8Bit()) {
283         initialize(string.characters8(), string.length());
284         return;
285     }
286     initialize(string.characters16(), string.length());
287 }
288
289 inline StringView StringView::empty()
290 {
291     return StringView(reinterpret_cast<const LChar*>(""), 0);
292 }
293
294 inline const LChar* StringView::characters8() const
295 {
296     ASSERT(is8Bit());
297     ASSERT(underlyingStringIsValid());
298     return static_cast<const LChar*>(m_characters);
299 }
300
301 inline const UChar* StringView::characters16() const
302 {
303     ASSERT(!is8Bit());
304     ASSERT(underlyingStringIsValid());
305     return static_cast<const UChar*>(m_characters);
306 }
307
308 class StringView::UpconvertedCharacters {
309 public:
310     explicit UpconvertedCharacters(const StringView&);
311     operator const UChar*() const { return m_characters; }
312     const UChar* get() const { return m_characters; }
313 private:
314     Vector<UChar, 32> m_upconvertedCharacters;
315     const UChar* m_characters;
316 };
317
318 inline StringView::UpconvertedCharacters StringView::upconvertedCharacters() const
319 {
320     return UpconvertedCharacters(*this);
321 }
322
323 inline bool StringView::isNull() const
324 {
325     return !m_characters;
326 }
327
328 inline bool StringView::isEmpty() const
329 {
330     return !length();
331 }
332
333 inline unsigned StringView::length() const
334 {
335     return m_length & ~is16BitStringFlag;
336 }
337
338 inline StringView::operator bool() const
339 {
340     return !isNull();
341 }
342
343 inline bool StringView::is8Bit() const
344 {
345     return !(m_length & is16BitStringFlag);
346 }
347
348 inline StringView StringView::substring(unsigned start, unsigned length) const
349 {
350     if (start >= this->length())
351         return empty();
352     unsigned maxLength = this->length() - start;
353
354     if (length >= maxLength) {
355         if (!start)
356             return *this;
357         length = maxLength;
358     }
359
360     if (is8Bit()) {
361         StringView result(characters8() + start, length);
362         result.setUnderlyingString(*this);
363         return result;
364     }
365     StringView result(characters16() + start, length);
366     result.setUnderlyingString(*this);
367     return result;
368 }
369
370 inline UChar StringView::operator[](unsigned index) const
371 {
372     ASSERT(index < length());
373     if (is8Bit())
374         return characters8()[index];
375     return characters16()[index];
376 }
377
378 inline bool StringView::contains(UChar character) const
379 {
380     return find(character) != notFound;
381 }
382
383 inline void StringView::getCharactersWithUpconvert(LChar* destination) const
384 {
385     ASSERT(is8Bit());
386     memcpy(destination, characters8(), length());
387 }
388
389 inline void StringView::getCharactersWithUpconvert(UChar* destination) const
390 {
391     if (is8Bit()) {
392         const LChar* characters8 = this->characters8();
393         unsigned length = this->length();
394         for (unsigned i = 0; i < length; ++i)
395             destination[i] = characters8[i];
396         return;
397     }
398     memcpy(destination, characters16(), length() * sizeof(UChar));
399 }
400
401 inline StringView::UpconvertedCharacters::UpconvertedCharacters(const StringView& string)
402 {
403     if (!string.is8Bit()) {
404         m_characters = string.characters16();
405         return;
406     }
407     const LChar* characters8 = string.characters8();
408     unsigned length = string.length();
409     m_upconvertedCharacters.reserveInitialCapacity(length);
410     for (unsigned i = 0; i < length; ++i)
411         m_upconvertedCharacters.uncheckedAppend(characters8[i]);
412     m_characters = m_upconvertedCharacters.data();
413 }
414
415 inline String StringView::toString() const
416 {
417     if (is8Bit())
418         return String(characters8(), length());
419     return String(characters16(), length());
420 }
421
422 inline float StringView::toFloat(bool& isValid) const
423 {
424     if (is8Bit())
425         return charactersToFloat(characters8(), length(), &isValid);
426     return charactersToFloat(characters16(), length(), &isValid);
427 }
428
429 inline int StringView::toInt(bool& isValid) const
430 {
431     if (is8Bit())
432         return charactersToInt(characters8(), length(), &isValid);
433     return charactersToInt(characters16(), length(), &isValid);
434 }
435
436 inline String StringView::toStringWithoutCopying() const
437 {
438     if (is8Bit())
439         return StringImpl::createWithoutCopying(characters8(), length());
440     return StringImpl::createWithoutCopying(characters16(), length());
441 }
442
443 inline size_t StringView::find(UChar character, unsigned start) const
444 {
445     if (is8Bit())
446         return WTF::find(characters8(), length(), character, start);
447     return WTF::find(characters16(), length(), character, start);
448 }
449
450 #if !CHECK_STRINGVIEW_LIFETIME
451 inline void StringView::invalidate(const StringImpl&)
452 {
453 }
454 #endif
455
456 template<typename StringType> class StringTypeAdapter;
457
458 template<> class StringTypeAdapter<StringView> {
459 public:
460     StringTypeAdapter<StringView>(StringView string)
461         : m_string(string)
462     {
463     }
464
465     unsigned length() { return m_string.length(); }
466     bool is8Bit() { return m_string.is8Bit(); }
467     void writeTo(LChar* destination) { m_string.getCharactersWithUpconvert(destination); }
468     void writeTo(UChar* destination) { m_string.getCharactersWithUpconvert(destination); }
469
470 private:
471     StringView m_string;
472 };
473
474 template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>& buffer, StringView string)
475 {
476     unsigned oldSize = buffer.size();
477     buffer.grow(oldSize + string.length());
478     string.getCharactersWithUpconvert(buffer.data() + oldSize);
479 }
480
481 inline bool equal(StringView a, StringView b)
482 {
483     return equalCommon(a, b);
484 }
485
486 inline bool equal(StringView a, const LChar* b)
487 {
488     if (!b)
489         return !a.isEmpty();
490     if (a.isEmpty())
491         return !b;
492     unsigned aLength = a.length();
493     if (a.is8Bit())
494         return equal(a.characters8(), b, aLength);
495     return equal(a.characters16(), b, aLength);
496 }
497
498 inline bool equal(StringView a, const char* b) 
499 {
500     return equal(a, reinterpret_cast<const LChar*>(b)); 
501 }
502
503 inline bool equalIgnoringASCIICase(StringView a, StringView b)
504 {
505     return equalIgnoringASCIICaseCommon(a, b);
506 }
507
508 class StringView::CodePoints {
509 public:
510     explicit CodePoints(const StringView&);
511
512     class Iterator;
513     Iterator begin() const;
514     Iterator end() const;
515
516 private:
517     StringView m_stringView;
518 };
519
520 class StringView::CodeUnits {
521 public:
522     explicit CodeUnits(const StringView&);
523
524     class Iterator;
525     Iterator begin() const;
526     Iterator end() const;
527
528 private:
529     StringView m_stringView;
530 };
531
532 class StringView::CodePoints::Iterator {
533 public:
534     Iterator(const StringView&, unsigned index);
535
536     UChar32 operator*() const;
537     Iterator& operator++();
538
539     bool operator==(const Iterator&) const;
540     bool operator!=(const Iterator&) const;
541
542 private:
543     const StringView& m_stringView;
544     mutable unsigned m_index;
545 #if !ASSERT_DISABLED
546     mutable bool m_alreadyIncremented { false };
547 #endif
548 };
549
550 class StringView::CodeUnits::Iterator {
551 public:
552     Iterator(const StringView&, unsigned index);
553
554     UChar operator*() const;
555     Iterator& operator++();
556
557     bool operator==(const Iterator&) const;
558     bool operator!=(const Iterator&) const;
559
560 private:
561     const StringView& m_stringView;
562     unsigned m_index;
563 };
564
565 inline auto StringView::codePoints() const -> CodePoints
566 {
567     return CodePoints(*this);
568 }
569
570 inline auto StringView::codeUnits() const -> CodeUnits
571 {
572     return CodeUnits(*this);
573 }
574
575 inline StringView::CodePoints::CodePoints(const StringView& stringView)
576     : m_stringView(stringView)
577 {
578 }
579
580 inline StringView::CodePoints::Iterator::Iterator(const StringView& stringView, unsigned index)
581     : m_stringView(stringView)
582     , m_index(index)
583 {
584 }
585
586 inline auto StringView::CodePoints::Iterator::operator++() -> Iterator&
587 {
588 #if !ASSERT_DISABLED
589     ASSERT(m_alreadyIncremented);
590     m_alreadyIncremented = false;
591 #endif
592     return *this;
593 }
594
595 inline UChar32 StringView::CodePoints::Iterator::operator*() const
596 {
597 #if !ASSERT_DISABLED
598     ASSERT(!m_alreadyIncremented);
599     m_alreadyIncremented = true;
600 #endif
601
602     if (m_stringView.is8Bit())
603         return m_stringView.characters8()[m_index++];
604
605     UChar32 codePoint;
606     U16_NEXT(m_stringView.characters16(), m_index, m_stringView.length(), codePoint);
607     return codePoint;
608 }
609
610 inline bool StringView::CodePoints::Iterator::operator==(const Iterator& other) const
611 {
612     ASSERT(&m_stringView == &other.m_stringView);
613     ASSERT(!m_alreadyIncremented);
614     return m_index == other.m_index;
615 }
616
617 inline bool StringView::CodePoints::Iterator::operator!=(const Iterator& other) const
618 {
619     return !(*this == other);
620 }
621
622 inline auto StringView::CodePoints::begin() const -> Iterator
623 {
624     return Iterator(m_stringView, 0);
625 }
626
627 inline auto StringView::CodePoints::end() const -> Iterator
628 {
629     return Iterator(m_stringView, m_stringView.length());
630 }
631
632 inline StringView::CodeUnits::CodeUnits(const StringView& stringView)
633     : m_stringView(stringView)
634 {
635 }
636
637 inline StringView::CodeUnits::Iterator::Iterator(const StringView& stringView, unsigned index)
638     : m_stringView(stringView)
639     , m_index(index)
640 {
641 }
642
643 inline auto StringView::CodeUnits::Iterator::operator++() -> Iterator&
644 {
645     ++m_index;
646     return *this;
647 }
648
649 inline UChar StringView::CodeUnits::Iterator::operator*() const
650 {
651     return m_stringView[m_index];
652 }
653
654 inline bool StringView::CodeUnits::Iterator::operator==(const Iterator& other) const
655 {
656     ASSERT(&m_stringView == &other.m_stringView);
657     return m_index == other.m_index;
658 }
659
660 inline bool StringView::CodeUnits::Iterator::operator!=(const Iterator& other) const
661 {
662     return !(*this == other);
663 }
664
665 inline auto StringView::CodeUnits::begin() const -> Iterator
666 {
667     return Iterator(m_stringView, 0);
668 }
669
670 inline auto StringView::CodeUnits::end() const -> Iterator
671 {
672     return Iterator(m_stringView, m_stringView.length());
673 }
674
675 } // namespace WTF
676
677 using WTF::append;
678 using WTF::equal;
679 using WTF::StringView;
680
681 #endif // StringView_h