| /* |
| * Copyright (C) 2004-2017 Apple Inc. All rights reserved. |
| * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> |
| * Copyright (C) 2012 Google Inc. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #include "config.h" |
| #include <wtf/text/AtomicString.h> |
| |
| #include "IntegerToStringConversion.h" |
| #include <wtf/dtoa.h> |
| #include <wtf/MainThread.h> |
| |
| namespace WTF { |
| |
| template<AtomicString::CaseConvertType type> |
| ALWAYS_INLINE AtomicString AtomicString::convertASCIICase() const |
| { |
| StringImpl* impl = this->impl(); |
| if (UNLIKELY(!impl)) |
| return nullAtom(); |
| |
| // Convert short strings without allocating a new StringImpl, since |
| // there's a good chance these strings are already in the atomic |
| // string table and so no memory allocation will be required. |
| unsigned length; |
| const unsigned localBufferSize = 100; |
| if (impl->is8Bit() && (length = impl->length()) <= localBufferSize) { |
| const LChar* characters = impl->characters8(); |
| unsigned failingIndex; |
| for (unsigned i = 0; i < length; ++i) { |
| if (type == CaseConvertType::Lower ? UNLIKELY(isASCIIUpper(characters[i])) : LIKELY(isASCIILower(characters[i]))) { |
| failingIndex = i; |
| goto SlowPath; |
| } |
| } |
| return *this; |
| SlowPath: |
| LChar localBuffer[localBufferSize]; |
| for (unsigned i = 0; i < failingIndex; ++i) |
| localBuffer[i] = characters[i]; |
| for (unsigned i = failingIndex; i < length; ++i) |
| localBuffer[i] = type == CaseConvertType::Lower ? toASCIILower(characters[i]) : toASCIIUpper(characters[i]); |
| return AtomicString(localBuffer, length); |
| } |
| |
| Ref<StringImpl> convertedString = type == CaseConvertType::Lower ? impl->convertToASCIILowercase() : impl->convertToASCIIUppercase(); |
| if (LIKELY(convertedString.ptr() == impl)) |
| return *this; |
| |
| AtomicString result; |
| result.m_string = AtomicStringImpl::add(convertedString.ptr()); |
| return result; |
| } |
| |
| AtomicString AtomicString::convertToASCIILowercase() const |
| { |
| return convertASCIICase<CaseConvertType::Lower>(); |
| } |
| |
| AtomicString AtomicString::convertToASCIIUppercase() const |
| { |
| return convertASCIICase<CaseConvertType::Upper>(); |
| } |
| |
| AtomicString AtomicString::number(int number) |
| { |
| return numberToStringSigned<AtomicString>(number); |
| } |
| |
| AtomicString AtomicString::number(unsigned number) |
| { |
| return numberToStringUnsigned<AtomicString>(number); |
| } |
| |
| AtomicString AtomicString::number(unsigned long number) |
| { |
| return numberToStringUnsigned<AtomicString>(number); |
| } |
| |
| AtomicString AtomicString::number(unsigned long long number) |
| { |
| return numberToStringUnsigned<AtomicString>(number); |
| } |
| |
| AtomicString AtomicString::number(double number) |
| { |
| NumberToStringBuffer buffer; |
| return String(numberToFixedPrecisionString(number, 6, buffer, true)); |
| } |
| |
| AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd) |
| { |
| auto impl = AtomicStringImpl::addUTF8(charactersStart, charactersEnd); |
| if (!impl) |
| return nullAtom(); |
| return impl.get(); |
| } |
| |
| #ifndef NDEBUG |
| void AtomicString::show() const |
| { |
| m_string.show(); |
| } |
| #endif |
| |
| WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> nullAtomData; |
| WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> emptyAtomData; |
| WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> starAtomData; |
| WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> xmlAtomData; |
| WTF_EXPORTDATA LazyNeverDestroyed<AtomicString> xmlnsAtomData; |
| |
| void AtomicString::init() |
| { |
| static std::once_flag initializeKey; |
| std::call_once(initializeKey, [] { |
| // Initialization is not thread safe, so this function must be called from the main thread first. |
| ASSERT(isUIThread()); |
| |
| nullAtomData.construct(); |
| emptyAtomData.construct(""); |
| starAtomData.construct("*", AtomicString::ConstructFromLiteral); |
| xmlAtomData.construct("xml", AtomicString::ConstructFromLiteral); |
| xmlnsAtomData.construct("xmlns", AtomicString::ConstructFromLiteral); |
| }); |
| } |
| |
| } // namespace WTF |