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<unsigned N>
239struct Indentation {
240 unsigned operator++() { return ++value; }
241 unsigned operator++(int) { return value++; }
242 unsigned operator--() { return --value; }
243 unsigned operator--(int) { return value--; }
244
245 unsigned value { 0 };
246};
247
248
249template<unsigned N>
250struct IndentationScope {
251 IndentationScope(Indentation<N>& indentation)
252 : m_indentation(indentation)
253 {
254 ++m_indentation;
255 }
256 ~IndentationScope()
257 {
258 --m_indentation;
259 }
260
261 Indentation<N>& m_indentation;
262};
263
264template<unsigned N> class StringTypeAdapter<Indentation<N>, void> {
265public:
266 StringTypeAdapter(Indentation<N> indentation)
267 : m_indentation { indentation }
268 {
269 }
270
271 unsigned length()
272 {
273 return m_indentation.value * N;
274 }
275
276 bool is8Bit()
277 {
278 return true;
279 }
280
281 template<typename CharacterType> void writeTo(CharacterType* destination)
282 {
283 std::fill_n(destination, m_indentation.value * N, ' ');
284 }
285
286private:
287 Indentation<N> m_indentation;
288};
289
290template<typename Adapter>
291inline bool are8Bit(Adapter adapter)
292{
293 return adapter.is8Bit();
294}
295
296template<typename Adapter, typename... Adapters>
297inline bool are8Bit(Adapter adapter, Adapters ...adapters)
298{
299 return adapter.is8Bit() && are8Bit(adapters...);
300}
301
302template<typename ResultType, typename Adapter>
303inline void stringTypeAdapterAccumulator(ResultType* result, Adapter adapter)
304{
305 adapter.writeTo(result);
306}
307
308template<typename ResultType, typename Adapter, typename... Adapters>
309inline void stringTypeAdapterAccumulator(ResultType* result, Adapter adapter, Adapters ...adapters)
310{
311 adapter.writeTo(result);
312 stringTypeAdapterAccumulator(result + adapter.length(), adapters...);
313}
314
315template<typename StringTypeAdapter, typename... StringTypeAdapters>
316String tryMakeStringFromAdapters(StringTypeAdapter adapter, StringTypeAdapters ...adapters)
317{
318 static_assert(String::MaxLength == std::numeric_limits<int32_t>::max(), "");
319 auto sum = checkedSum<int32_t>(adapter.length(), adapters.length()...);
320 if (sum.hasOverflowed())
321 return String();
322
323 unsigned length = sum.unsafeGet();
324 ASSERT(length <= String::MaxLength);
325 if (are8Bit(adapter, adapters...)) {
326 LChar* buffer;
327 RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
328 if (!resultImpl)
329 return String();
330
331 stringTypeAdapterAccumulator(buffer, adapter, adapters...);
332
333 return resultImpl;
334 }
335
336 UChar* buffer;
337 RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
338 if (!resultImpl)
339 return String();
340
341 stringTypeAdapterAccumulator(buffer, adapter, adapters...);
342
343 return resultImpl;
344}
345
346template<typename... StringTypes>
347String tryMakeString(StringTypes ...strings)
348{
349 return tryMakeStringFromAdapters(StringTypeAdapter<StringTypes>(strings)...);
350}
351
352template<typename... StringTypes>
353String makeString(StringTypes... strings)
354{
355 String result = tryMakeString(strings...);
356 if (!result)
357 CRASH();
358 return result;
359}
360
361} // namespace WTF
362
363using WTF::Indentation;
364using WTF::IndentationScope;
365using WTF::makeString;
366using WTF::pad;
367using WTF::tryMakeString;
368
369#include <wtf/text/StringOperators.h>
370