1/*
2 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Patrick Gansterer <[email protected]>
4 * Copyright (C) 2012 Google Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24#include <wtf/text/AtomString.h>
25
26#include <mutex>
27#include <wtf/MainThread.h>
28#include <wtf/text/IntegerToStringConversion.h>
29
30#include <wtf/dtoa.h>
31
32namespace WTF {
33
34template<AtomString::CaseConvertType type>
35ALWAYS_INLINE AtomString AtomString::convertASCIICase() const
36{
37 StringImpl* impl = this->impl();
38 if (UNLIKELY(!impl))
39 return nullAtom();
40
41 // Convert short strings without allocating a new StringImpl, since
42 // there's a good chance these strings are already in the atom
43 // string table and so no memory allocation will be required.
44 unsigned length;
45 const unsigned localBufferSize = 100;
46 if (impl->is8Bit() && (length = impl->length()) <= localBufferSize) {
47 const LChar* characters = impl->characters8();
48 unsigned failingIndex;
49 for (unsigned i = 0; i < length; ++i) {
50 if (type == CaseConvertType::Lower ? UNLIKELY(isASCIIUpper(characters[i])) : LIKELY(isASCIILower(characters[i]))) {
51 failingIndex = i;
52 goto SlowPath;
53 }
54 }
55 return *this;
56SlowPath:
57 LChar localBuffer[localBufferSize];
58 for (unsigned i = 0; i < failingIndex; ++i)
59 localBuffer[i] = characters[i];
60 for (unsigned i = failingIndex; i < length; ++i)
61 localBuffer[i] = type == CaseConvertType::Lower ? toASCIILower(characters[i]) : toASCIIUpper(characters[i]);
62 return AtomString(localBuffer, length);
63 }
64
65 Ref<StringImpl> convertedString = type == CaseConvertType::Lower ? impl->convertToASCIILowercase() : impl->convertToASCIIUppercase();
66 if (LIKELY(convertedString.ptr() == impl))
67 return *this;
68
69 AtomString result;
70 result.m_string = AtomStringImpl::add(convertedString.ptr());
71 return result;
72}
73
74AtomString AtomString::convertToASCIILowercase() const
75{
76 return convertASCIICase<CaseConvertType::Lower>();
77}
78
79AtomString AtomString::convertToASCIIUppercase() const
80{
81 return convertASCIICase<CaseConvertType::Upper>();
82}
83
84AtomString AtomString::number(int number)
85{
86 return numberToStringSigned<AtomString>(number);
87}
88
89AtomString AtomString::number(unsigned number)
90{
91 return numberToStringUnsigned<AtomString>(number);
92}
93
94AtomString AtomString::number(unsigned long number)
95{
96 return numberToStringUnsigned<AtomString>(number);
97}
98
99AtomString AtomString::number(unsigned long long number)
100{
101 return numberToStringUnsigned<AtomString>(number);
102}
103
104AtomString AtomString::number(float number)
105{
106 NumberToStringBuffer buffer;
107 return numberToString(number, buffer);
108}
109
110AtomString AtomString::number(double number)
111{
112 NumberToStringBuffer buffer;
113 return numberToString(number, buffer);
114}
115
116AtomString AtomString::fromUTF8Internal(const char* start, const char* end)
117{
118 ASSERT(start);
119
120 // Caller needs to handle empty string.
121 ASSERT(!end || end > start);
122 ASSERT(end || start[0]);
123
124 return AtomStringImpl::addUTF8(start, end ? end : start + std::strlen(start));
125}
126
127#ifndef NDEBUG
128
129void AtomString::show() const
130{
131 m_string.show();
132}
133
134#endif
135
136WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> nullAtomData;
137WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> emptyAtomData;
138WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> starAtomData;
139WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> xmlAtomData;
140WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> xmlnsAtomData;
141
142void AtomString::init()
143{
144 static std::once_flag initializeKey;
145 std::call_once(initializeKey, [] {
146 // Initialization is not thread safe, so this function must be called from the main thread first.
147 ASSERT(isUIThread());
148
149 nullAtomData.construct();
150 emptyAtomData.construct("");
151 starAtomData.construct("*", AtomString::ConstructFromLiteral);
152 xmlAtomData.construct("xml", AtomString::ConstructFromLiteral);
153 xmlnsAtomData.construct("xmlns", AtomString::ConstructFromLiteral);
154 });
155}
156
157} // namespace WTF
158