Improve use of NeverDestroyed
[WebKit-https.git] / Source / WTF / wtf / text / AtomicString.cpp
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 "AtomicString.h"
25
26 #include "IntegerToStringConversion.h"
27 #include "MainThread.h"
28 #include "dtoa.h"
29
30 namespace WTF {
31
32 template<AtomicString::CaseConvertType type>
33 ALWAYS_INLINE AtomicString AtomicString::convertASCIICase() const
34 {
35     StringImpl* impl = this->impl();
36     if (UNLIKELY(!impl))
37         return nullAtom();
38
39     // Convert short strings without allocating a new StringImpl, since
40     // there's a good chance these strings are already in the atomic
41     // string table and so no memory allocation will be required.
42     unsigned length;
43     const unsigned localBufferSize = 100;
44     if (impl->is8Bit() && (length = impl->length()) <= localBufferSize) {
45         const LChar* characters = impl->characters8();
46         unsigned failingIndex;
47         for (unsigned i = 0; i < length; ++i) {
48             if (type == CaseConvertType::Lower ? UNLIKELY(isASCIIUpper(characters[i])) : LIKELY(isASCIILower(characters[i]))) {
49                 failingIndex = i;
50                 goto SlowPath;
51             }
52         }
53         return *this;
54 SlowPath:
55         LChar localBuffer[localBufferSize];
56         for (unsigned i = 0; i < failingIndex; ++i)
57             localBuffer[i] = characters[i];
58         for (unsigned i = failingIndex; i < length; ++i)
59             localBuffer[i] = type == CaseConvertType::Lower ? toASCIILower(characters[i]) : toASCIIUpper(characters[i]);
60         return AtomicString(localBuffer, length);
61     }
62
63     Ref<StringImpl> convertedString = type == CaseConvertType::Lower ? impl->convertToASCIILowercase() : impl->convertToASCIIUppercase();
64     if (LIKELY(convertedString.ptr() == impl))
65         return *this;
66
67     AtomicString result;
68     result.m_string = AtomicStringImpl::add(convertedString.ptr());
69     return result;
70 }
71
72 AtomicString AtomicString::convertToASCIILowercase() const
73 {
74     return convertASCIICase<CaseConvertType::Lower>();
75 }
76
77 AtomicString AtomicString::convertToASCIIUppercase() const
78 {
79     return convertASCIICase<CaseConvertType::Upper>();
80 }
81
82 AtomicString AtomicString::number(int number)
83 {
84     return numberToStringSigned<AtomicString>(number);
85 }
86
87 AtomicString AtomicString::number(unsigned number)
88 {
89     return numberToStringUnsigned<AtomicString>(number);
90 }
91
92 AtomicString AtomicString::number(unsigned long number)
93 {
94     return numberToStringUnsigned<AtomicString>(number);
95 }
96
97 AtomicString AtomicString::number(unsigned long long number)
98 {
99     return numberToStringUnsigned<AtomicString>(number);
100 }
101
102 AtomicString AtomicString::number(double number)
103 {
104     NumberToStringBuffer buffer;
105     return String(numberToFixedPrecisionString(number, 6, buffer, true));
106 }
107
108 AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd)
109 {
110     auto impl = AtomicStringImpl::addUTF8(charactersStart, charactersEnd);
111     if (!impl)
112         return nullAtom();
113     return impl.get();
114 }
115
116 #ifndef NDEBUG
117 void AtomicString::show() const
118 {
119     m_string.show();
120 }
121 #endif
122
123 WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> nullAtomData;
124 WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> emptyAtomData;
125 WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> starAtomData;
126 WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> xmlAtomData;
127 WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> xmlnsAtomData;
128
129 void AtomicString::init()
130 {
131     static std::once_flag initializeKey;
132     std::call_once(initializeKey, [] {
133         // Initialization is not thread safe, so this function must be called from the main thread first.
134         ASSERT(isUIThread());
135
136         nullAtomData.construct();
137         emptyAtomData.construct("");
138         starAtomData.construct("*", AtomicString::ConstructFromLiteral);
139         xmlAtomData.construct("xml", AtomicString::ConstructFromLiteral);
140         xmlnsAtomData.construct("xmlns", AtomicString::ConstructFromLiteral);
141     });
142 }
143
144 } // namespace WTF