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 | |
32 | namespace WTF { |
33 | |
34 | template<AtomString::CaseConvertType type> |
35 | ALWAYS_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; |
56 | SlowPath: |
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 | |
74 | AtomString AtomString::convertToASCIILowercase() const |
75 | { |
76 | return convertASCIICase<CaseConvertType::Lower>(); |
77 | } |
78 | |
79 | AtomString AtomString::convertToASCIIUppercase() const |
80 | { |
81 | return convertASCIICase<CaseConvertType::Upper>(); |
82 | } |
83 | |
84 | AtomString AtomString::number(int number) |
85 | { |
86 | return numberToStringSigned<AtomString>(number); |
87 | } |
88 | |
89 | AtomString AtomString::number(unsigned number) |
90 | { |
91 | return numberToStringUnsigned<AtomString>(number); |
92 | } |
93 | |
94 | AtomString AtomString::number(unsigned long number) |
95 | { |
96 | return numberToStringUnsigned<AtomString>(number); |
97 | } |
98 | |
99 | AtomString AtomString::number(unsigned long long number) |
100 | { |
101 | return numberToStringUnsigned<AtomString>(number); |
102 | } |
103 | |
104 | AtomString AtomString::number(float number) |
105 | { |
106 | NumberToStringBuffer buffer; |
107 | return numberToString(number, buffer); |
108 | } |
109 | |
110 | AtomString AtomString::number(double number) |
111 | { |
112 | NumberToStringBuffer buffer; |
113 | return numberToString(number, buffer); |
114 | } |
115 | |
116 | AtomString 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 | |
129 | void AtomString::show() const |
130 | { |
131 | m_string.show(); |
132 | } |
133 | |
134 | #endif |
135 | |
136 | WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> nullAtomData; |
137 | WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> emptyAtomData; |
138 | WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> starAtomData; |
139 | WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> xmlAtomData; |
140 | WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomString> xmlnsAtomData; |
141 | |
142 | void 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 | |