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