1/*
2 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
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/AtomicString.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<AtomicString::CaseConvertType type>
35ALWAYS_INLINE AtomicString AtomicString::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 atomic
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 AtomicString(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 AtomicString result;
70 result.m_string = AtomicStringImpl::add(convertedString.ptr());
71 return result;
72}
73
74AtomicString AtomicString::convertToASCIILowercase() const
75{
76 return convertASCIICase<CaseConvertType::Lower>();
77}
78
79AtomicString AtomicString::convertToASCIIUppercase() const
80{
81 return convertASCIICase<CaseConvertType::Upper>();
82}
83
84AtomicString AtomicString::number(int number)
85{
86 return numberToStringSigned<AtomicString>(number);
87}
88
89AtomicString AtomicString::number(unsigned number)
90{
91 return numberToStringUnsigned<AtomicString>(number);
92}
93
94AtomicString AtomicString::number(unsigned long number)
95{
96 return numberToStringUnsigned<AtomicString>(number);
97}
98
99AtomicString AtomicString::number(unsigned long long number)
100{
101 return numberToStringUnsigned<AtomicString>(number);
102}
103
104AtomicString AtomicString::number(float number)
105{
106 NumberToStringBuffer buffer;
107 return numberToString(number, buffer);
108}
109
110AtomicString AtomicString::number(double number)
111{
112 NumberToStringBuffer buffer;
113 return numberToString(number, buffer);
114}
115
116AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd)
117{
118 auto impl = AtomicStringImpl::addUTF8(charactersStart, charactersEnd);
119 if (!impl)
120 return nullAtom();
121 return impl.get();
122}
123
124#ifndef NDEBUG
125void AtomicString::show() const
126{
127 m_string.show();
128}
129#endif
130
131WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> nullAtomData;
132WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> emptyAtomData;
133WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> starAtomData;
134WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> xmlAtomData;
135WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> xmlnsAtomData;
136
137void AtomicString::init()
138{
139 static std::once_flag initializeKey;
140 std::call_once(initializeKey, [] {
141 // Initialization is not thread safe, so this function must be called from the main thread first.
142 ASSERT(isUIThread());
143
144 nullAtomData.construct();
145 emptyAtomData.construct("");
146 starAtomData.construct("*", AtomicString::ConstructFromLiteral);
147 xmlAtomData.construct("xml", AtomicString::ConstructFromLiteral);
148 xmlnsAtomData.construct("xmlns", AtomicString::ConstructFromLiteral);
149 });
150}
151
152} // namespace WTF
153