Elements whose contents start with an astral Unicode symbol disappear when CSS `...
[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 <wtf/text/StringConcatenate.h>
30
31 namespace WTF {
32
33 // StringView is a non-owning reference to a string, similar to the proposed std::string_view.
34 // Whether the string is 8-bit or 16-bit is encoded in the upper bit of the length member.
35 // This means that strings longer than 2 Gigabytes can not be represented. If that turns out to be
36 // a problem we can investigate alternative solutions.
37
38 class StringView {
39 public:
40     StringView()
41         : m_characters(nullptr)
42         , m_length(0)
43     {
44     }
45
46     StringView(const LChar* characters, unsigned length)
47     {
48         initialize(characters, length);
49     }
50
51     StringView(const UChar* characters, unsigned length)
52     {
53         initialize(characters, length);
54     }
55
56     StringView(const StringImpl& string)
57     {
58         if (string.is8Bit())
59             initialize(string.characters8(), string.length());
60         else
61             initialize(string.characters16(), string.length());
62     }
63
64     StringView(const String& string)
65     {
66         if (!string.impl()) {
67             m_characters = nullptr;
68             m_length = 0;
69             return;
70         }
71         if (string.is8Bit()) {
72             initialize(string.characters8(), string.length());
73             return;
74         }
75         initialize(string.characters16(), string.length());
76     }
77
78     static StringView empty()
79     {
80         return StringView(reinterpret_cast<const LChar*>(""), 0);
81     }
82
83     const LChar* characters8() const
84     {
85         ASSERT(is8Bit());
86
87         return static_cast<const LChar*>(m_characters);
88     }
89
90     const UChar* characters16() const
91     {
92         ASSERT(!is8Bit());
93
94         return static_cast<const UChar*>(m_characters);
95     }
96
97     void getCharactersWithUpconvert(LChar*) const;
98     void getCharactersWithUpconvert(UChar*) const;
99
100     class UpconvertedCharacters {
101     public:
102         explicit UpconvertedCharacters(const StringView&);
103         operator const UChar*() const { return m_characters; }
104         const UChar* get() const { return m_characters; }
105     private:
106         Vector<UChar, 32> m_upconvertedCharacters;
107         const UChar* m_characters;
108     };
109     UpconvertedCharacters upconvertedCharacters() const { return UpconvertedCharacters(*this); }
110
111     bool isNull() const { return !m_characters; }
112     bool isEmpty() const { return !length(); }
113     unsigned length() const { return m_length & ~is16BitStringFlag; }
114
115     explicit operator bool() const { return !isNull(); }
116
117     bool is8Bit() const { return !(m_length & is16BitStringFlag); }
118
119     StringView substring(unsigned start, unsigned length = std::numeric_limits<unsigned>::max()) const
120     {
121         if (start >= this->length())
122             return empty();
123         unsigned maxLength = this->length() - start;
124
125         if (length >= maxLength) {
126             if (!start)
127                 return *this;
128             length = maxLength;
129         }
130
131         if (is8Bit())
132             return StringView(characters8() + start, length);
133
134         return StringView(characters16() + start, length);
135     }
136
137     String toString() const
138     {
139         if (is8Bit())
140             return String(characters8(), length());
141
142         return String(characters16(), length());
143     }
144
145     float toFloat(bool& isValid)
146     {
147         if (is8Bit())
148             return charactersToFloat(characters8(), length(), &isValid);
149         return charactersToFloat(characters16(), length(), &isValid);
150     }
151
152     int toInt(bool& isValid)
153     {
154         if (is8Bit())
155             return charactersToInt(characters8(), length(), &isValid);
156         return charactersToInt(characters16(), length(), &isValid);
157     }
158
159     String toStringWithoutCopying() const
160     {
161         if (is8Bit())
162             return StringImpl::createWithoutCopying(characters8(), length());
163
164         return StringImpl::createWithoutCopying(characters16(), length());
165     }
166
167     UChar operator[](unsigned index) const
168     {
169         ASSERT(index < length());
170         if (is8Bit())
171             return characters8()[index];
172         return characters16()[index];
173     }
174
175     size_t find(UChar character, unsigned start = 0) const
176     {
177         if (is8Bit())
178             return WTF::find(characters8(), length(), character, start);
179         return WTF::find(characters16(), length(), character, start);
180     }
181
182     bool contains(UChar c) const { return find(c) != notFound; }
183
184 #if USE(CF)
185     // This function converts null strings to empty strings.
186     WTF_EXPORT_STRING_API RetainPtr<CFStringRef> createCFStringWithoutCopying() const;
187 #endif
188
189 #ifdef __OBJC__
190     // These functions convert null strings to empty strings.
191     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSString() const;
192     WTF_EXPORT_STRING_API RetainPtr<NSString> createNSStringWithoutCopying() const;
193 #endif
194
195 private:
196     void initialize(const LChar* characters, unsigned length)
197     {
198         ASSERT(!(length & is16BitStringFlag));
199         
200         m_characters = characters;
201         m_length = length;
202     }
203
204     void initialize(const UChar* characters, unsigned length)
205     {
206         ASSERT(!(length & is16BitStringFlag));
207         
208         m_characters = characters;
209         m_length = is16BitStringFlag | length;
210     }
211
212     static const unsigned is16BitStringFlag = 1u << 31;
213
214     const void* m_characters;
215     unsigned m_length;
216 };
217
218 inline void StringView::getCharactersWithUpconvert(LChar* destination) const
219 {
220     ASSERT(is8Bit());
221     memcpy(destination, characters8(), length());
222 }
223
224 inline void StringView::getCharactersWithUpconvert(UChar* destination) const
225 {
226     if (is8Bit()) {
227         const LChar* characters8 = this->characters8();
228         unsigned length = this->length();
229         for (unsigned i = 0; i < length; ++i)
230             destination[i] = characters8[i];
231         return;
232     }
233     memcpy(destination, characters16(), length() * sizeof(UChar));
234 }
235
236 inline StringView::UpconvertedCharacters::UpconvertedCharacters(const StringView& string)
237 {
238     if (!string.is8Bit()) {
239         m_characters = string.characters16();
240         return;
241     }
242     const LChar* characters8 = string.characters8();
243     unsigned length = string.length();
244     m_upconvertedCharacters.reserveInitialCapacity(length);
245     for (unsigned i = 0; i < length; ++i)
246         m_upconvertedCharacters.uncheckedAppend(characters8[i]);
247     m_characters = m_upconvertedCharacters.data();
248 }
249
250 template<> class StringTypeAdapter<StringView> {
251 public:
252     StringTypeAdapter<StringView>(StringView string)
253         : m_string(string)
254     {
255     }
256
257     unsigned length() { return m_string.length(); }
258     bool is8Bit() { return m_string.is8Bit(); }
259     void writeTo(LChar* destination) { m_string.getCharactersWithUpconvert(destination); }
260     void writeTo(UChar* destination) { m_string.getCharactersWithUpconvert(destination); }
261
262 private:
263     StringView m_string;
264 };
265
266 template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>& buffer, StringView string)
267 {
268     unsigned oldSize = buffer.size();
269     buffer.grow(oldSize + string.length());
270     string.getCharactersWithUpconvert(buffer.data() + oldSize);
271 }
272
273 } // namespace WTF
274
275 using WTF::append;
276 using WTF::StringView;
277
278 #endif // StringView_h