1/*
2 * Copyright (C) 2010-2018 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <cstring>
29#include <wtf/CheckedArithmetic.h>
30#include <wtf/text/AtomString.h>
31#include <wtf/text/StringView.h>
32
33// This macro is helpful for testing how many intermediate Strings are created while evaluating an
34// expression containing operator+.
35#ifndef WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING
36#define WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() ((void)0)
37#endif
38
39namespace WTF {
40
41template<> class StringTypeAdapter<char, void> {
42public:
43 StringTypeAdapter(char character)
44 : m_character { character }
45 {
46 }
47
48 unsigned length() { return 1; }
49 bool is8Bit() { return true; }
50 template<typename CharacterType> void writeTo(CharacterType* destination) const { *destination = m_character; }
51
52private:
53 char m_character;
54};
55
56template<> class StringTypeAdapter<UChar, void> {
57public:
58 StringTypeAdapter(UChar character)
59 : m_character { character }
60 {
61 }
62
63 unsigned length() const { return 1; }
64 bool is8Bit() const { return isLatin1(m_character); }
65
66 void writeTo(LChar* destination) const
67 {
68 ASSERT(is8Bit());
69 *destination = m_character;
70 }
71
72 void writeTo(UChar* destination) const { *destination = m_character; }
73
74private:
75 UChar m_character;
76};
77
78template<> class StringTypeAdapter<const LChar*, void> {
79public:
80 StringTypeAdapter(const LChar* characters)
81 : m_characters { characters }
82 , m_length { computeLength(characters) }
83 {
84 }
85
86 unsigned length() const { return m_length; }
87 bool is8Bit() const { return true; }
88 template<typename CharacterType> void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, m_characters, m_length); }
89
90private:
91 static unsigned computeLength(const LChar* characters)
92 {
93 size_t length = std::strlen(reinterpret_cast<const char*>(characters));
94 RELEASE_ASSERT(length <= String::MaxLength);
95 return static_cast<unsigned>(length);
96 }
97
98 const LChar* m_characters;
99 unsigned m_length;
100};
101
102template<> class StringTypeAdapter<const UChar*, void> {
103public:
104 StringTypeAdapter(const UChar* characters)
105 : m_characters { characters }
106 , m_length { computeLength(characters) }
107 {
108 }
109
110 unsigned length() const { return m_length; }
111 bool is8Bit() const { return !m_length; }
112 void writeTo(LChar*) const { ASSERT(!m_length); }
113 void writeTo(UChar* destination) const { StringImpl::copyCharacters(destination, m_characters, m_length); }
114
115private:
116 static unsigned computeLength(const UChar* characters)
117 {
118 size_t length = 0;
119 while (characters[length])
120 ++length;
121 RELEASE_ASSERT(length <= String::MaxLength);
122 return static_cast<unsigned>(length);
123 }
124
125 const UChar* m_characters;
126 unsigned m_length;
127};
128
129template<> class StringTypeAdapter<const char*, void> : public StringTypeAdapter<const LChar*, void> {
130public:
131 StringTypeAdapter(const char* characters)
132 : StringTypeAdapter<const LChar*, void> { reinterpret_cast<const LChar*>(characters) }
133 {
134 }
135};
136
137template<> class StringTypeAdapter<char*, void> : public StringTypeAdapter<const char*, void> {
138public:
139 StringTypeAdapter(const char* characters)
140 : StringTypeAdapter<const char*, void> { characters }
141 {
142 }
143};
144
145template<> class StringTypeAdapter<ASCIILiteral, void> : public StringTypeAdapter<const char*, void> {
146public:
147 StringTypeAdapter(ASCIILiteral characters)
148 : StringTypeAdapter<const char*, void> { characters }
149 {
150 }
151};
152
153template<> class StringTypeAdapter<Vector<char>, void> {
154public:
155 StringTypeAdapter(const Vector<char>& vector)
156 : m_vector { vector }
157 {
158 }
159
160 size_t length() const { return m_vector.size(); }
161 bool is8Bit() const { return true; }
162 template<typename CharacterType> void writeTo(CharacterType* destination) const { StringImpl::copyCharacters(destination, characters(), length()); }
163
164private:
165 const LChar* characters() const
166 {
167 return reinterpret_cast<const LChar*>(m_vector.data());
168 }
169
170 const Vector<char>& m_vector;
171};
172
173template<> class StringTypeAdapter<String, void> {
174public:
175 StringTypeAdapter(const String& string)
176 : m_string { string }
177 {
178 }
179
180 unsigned length() const { return m_string.length(); }
181 bool is8Bit() const { return m_string.isNull() || m_string.is8Bit(); }
182 template<typename CharacterType> void writeTo(CharacterType* destination) const
183 {
184 StringView { m_string }.getCharactersWithUpconvert(destination);
185 WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING();
186 }
187
188private:
189 const String& m_string;
190};
191
192template<> class StringTypeAdapter<AtomString, void> : public StringTypeAdapter<String, void> {
193public:
194 StringTypeAdapter(const AtomString& string)
195 : StringTypeAdapter<String, void> { string.string() }
196 {
197 }
198};
199
200template<typename UnderlyingElementType> struct PaddingSpecification {
201 LChar character;
202 unsigned length;
203 UnderlyingElementType underlyingElement;
204};
205
206template<typename UnderlyingElementType> PaddingSpecification<UnderlyingElementType> pad(char character, unsigned length, UnderlyingElementType element)
207{
208 return { static_cast<LChar>(character), length, element };
209}
210
211template<typename UnderlyingElementType> class StringTypeAdapter<PaddingSpecification<UnderlyingElementType>> {
212public:
213 StringTypeAdapter(const PaddingSpecification<UnderlyingElementType>& padding)
214 : m_padding { padding }
215 , m_underlyingAdapter { m_padding.underlyingElement }
216 {
217 }
218
219 unsigned length() const { return std::max(m_padding.length, m_underlyingAdapter.length()); }
220 bool is8Bit() const { return m_underlyingAdapter.is8Bit(); }
221 template<typename CharacterType> void writeTo(CharacterType* destination) const
222 {
223 unsigned underlyingLength = m_underlyingAdapter.length();
224 unsigned count = 0;
225 if (underlyingLength < m_padding.length) {
226 count = m_padding.length - underlyingLength;
227 for (unsigned i = 0; i < count; ++i)
228 destination[i] = m_padding.character;
229 }
230 m_underlyingAdapter.writeTo(destination + count);
231 }
232
233private:
234 const PaddingSpecification<UnderlyingElementType>& m_padding;
235 StringTypeAdapter<UnderlyingElementType> m_underlyingAdapter;
236};
237
238template<typename Adapter>
239inline bool are8Bit(Adapter adapter)
240{
241 return adapter.is8Bit();
242}
243
244template<typename Adapter, typename... Adapters>
245inline bool are8Bit(Adapter adapter, Adapters ...adapters)
246{
247 return adapter.is8Bit() && are8Bit(adapters...);
248}
249
250template<typename ResultType, typename Adapter>
251inline void makeStringAccumulator(ResultType* result, Adapter adapter)
252{
253 adapter.writeTo(result);
254}
255
256template<typename ResultType, typename Adapter, typename... Adapters>
257inline void makeStringAccumulator(ResultType* result, Adapter adapter, Adapters ...adapters)
258{
259 adapter.writeTo(result);
260 makeStringAccumulator(result + adapter.length(), adapters...);
261}
262
263template<typename StringTypeAdapter, typename... StringTypeAdapters>
264String tryMakeStringFromAdapters(StringTypeAdapter adapter, StringTypeAdapters ...adapters)
265{
266 static_assert(String::MaxLength == std::numeric_limits<int32_t>::max(), "");
267 auto sum = checkedSum<int32_t>(adapter.length(), adapters.length()...);
268 if (sum.hasOverflowed())
269 return String();
270
271 unsigned length = sum.unsafeGet();
272 ASSERT(length <= String::MaxLength);
273 if (are8Bit(adapter, adapters...)) {
274 LChar* buffer;
275 RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
276 if (!resultImpl)
277 return String();
278
279 makeStringAccumulator(buffer, adapter, adapters...);
280
281 return resultImpl;
282 }
283
284 UChar* buffer;
285 RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
286 if (!resultImpl)
287 return String();
288
289 makeStringAccumulator(buffer, adapter, adapters...);
290
291 return resultImpl;
292}
293
294template<typename... StringTypes>
295String tryMakeString(StringTypes ...strings)
296{
297 return tryMakeStringFromAdapters(StringTypeAdapter<StringTypes>(strings)...);
298}
299
300template<typename... StringTypes>
301String makeString(StringTypes... strings)
302{
303 String result = tryMakeString(strings...);
304 if (!result)
305 CRASH();
306 return result;
307}
308
309} // namespace WTF
310
311using WTF::makeString;
312using WTF::pad;
313using WTF::tryMakeString;
314
315#include <wtf/text/StringOperators.h>
316