diff options
Diffstat (limited to 'Source/WTF/wtf/text/WTFString.cpp')
-rw-r--r-- | Source/WTF/wtf/text/WTFString.cpp | 273 |
1 files changed, 153 insertions, 120 deletions
diff --git a/Source/WTF/wtf/text/WTFString.cpp b/Source/WTF/wtf/text/WTFString.cpp index 45ba8af52..4f49ebca1 100644 --- a/Source/WTF/wtf/text/WTFString.cpp +++ b/Source/WTF/wtf/text/WTFString.cpp @@ -35,7 +35,6 @@ #include <wtf/dtoa.h> #include <wtf/unicode/CharacterNames.h> #include <wtf/unicode/UTF8.h> -#include <wtf/unicode/Unicode.h> namespace WTF { @@ -90,64 +89,75 @@ String::String(ASCIILiteral characters) void String::append(const String& str) { + // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API. + if (str.isEmpty()) return; - // FIXME: This is extremely inefficient. So much so that we might want to take this - // out of String's API. We can make it better by optimizing the case where exactly - // one String is pointing at this StringImpl, but even then it's going to require a - // call to fastMalloc every single time. if (str.m_impl) { if (m_impl) { if (m_impl->is8Bit() && str.m_impl->is8Bit()) { LChar* data; if (str.length() > std::numeric_limits<unsigned>::max() - m_impl->length()) CRASH(); - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data); + auto newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data); memcpy(data, m_impl->characters8(), m_impl->length() * sizeof(LChar)); memcpy(data + m_impl->length(), str.characters8(), str.length() * sizeof(LChar)); - m_impl = newImpl.release(); + m_impl = WTFMove(newImpl); return; } UChar* data; if (str.length() > std::numeric_limits<unsigned>::max() - m_impl->length()) CRASH(); - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data); - memcpy(data, m_impl->deprecatedCharacters(), m_impl->length() * sizeof(UChar)); - memcpy(data + m_impl->length(), str.deprecatedCharacters(), str.length() * sizeof(UChar)); - m_impl = newImpl.release(); + auto newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data); + StringView(*m_impl).getCharactersWithUpconvert(data); + StringView(str).getCharactersWithUpconvert(data + m_impl->length()); + m_impl = WTFMove(newImpl); } else m_impl = str.m_impl; } } -template <typename CharacterType> -inline void String::appendInternal(CharacterType c) +void String::append(LChar character) { - // FIXME: This is extremely inefficient. So much so that we might want to take this - // out of String's API. We can make it better by optimizing the case where exactly - // one String is pointing at this StringImpl, but even then it's going to require a - // call to fastMalloc every single time. - if (m_impl) { - UChar* data; - if (m_impl->length() >= std::numeric_limits<unsigned>::max()) - CRASH(); - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data); - memcpy(data, m_impl->deprecatedCharacters(), m_impl->length() * sizeof(UChar)); - data[m_impl->length()] = c; - m_impl = newImpl.release(); - } else - m_impl = StringImpl::create(&c, 1); -} + // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API. -void String::append(LChar c) -{ - appendInternal(c); + if (!m_impl) { + m_impl = StringImpl::create(&character, 1); + return; + } + if (!is8Bit()) { + append(static_cast<UChar>(character)); + return; + } + if (m_impl->length() >= std::numeric_limits<unsigned>::max()) + CRASH(); + LChar* data; + auto newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data); + memcpy(data, m_impl->characters8(), m_impl->length()); + data[m_impl->length()] = character; + m_impl = WTFMove(newImpl); } -void String::append(UChar c) +void String::append(UChar character) { - appendInternal(c); + // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API. + + if (!m_impl) { + m_impl = StringImpl::create(&character, 1); + return; + } + if (character <= 0xFF && is8Bit()) { + append(static_cast<LChar>(character)); + return; + } + if (m_impl->length() >= std::numeric_limits<unsigned>::max()) + CRASH(); + UChar* data; + auto newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data); + StringView(*m_impl).getCharactersWithUpconvert(data); + data[m_impl->length()] = character; + m_impl = WTFMove(newImpl); } int codePointCompare(const String& a, const String& b) @@ -155,20 +165,49 @@ int codePointCompare(const String& a, const String& b) return codePointCompare(a.impl(), b.impl()); } -void String::insert(const String& str, unsigned pos) +void String::insert(const String& string, unsigned position) { - if (str.isEmpty()) { - if (str.isNull()) + // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API. + + unsigned lengthToInsert = string.length(); + + if (!lengthToInsert) { + if (string.isNull()) return; if (isNull()) - m_impl = str.impl(); + m_impl = string.impl(); return; } - insert(str.deprecatedCharacters(), str.length(), pos); + + if (position >= length()) { + append(string); + return; + } + + if (lengthToInsert > std::numeric_limits<unsigned>::max() - length()) + CRASH(); + + if (is8Bit() && string.is8Bit()) { + LChar* data; + auto newString = StringImpl::createUninitialized(length() + lengthToInsert, data); + StringView(*m_impl).substring(0, position).getCharactersWithUpconvert(data); + StringView(string).getCharactersWithUpconvert(data + position); + StringView(*m_impl).substring(position).getCharactersWithUpconvert(data + position + lengthToInsert); + m_impl = WTFMove(newString); + } else { + UChar* data; + auto newString = StringImpl::createUninitialized(length() + lengthToInsert, data); + StringView(*m_impl).substring(0, position).getCharactersWithUpconvert(data); + StringView(string).getCharactersWithUpconvert(data + position); + StringView(*m_impl).substring(position).getCharactersWithUpconvert(data + position + lengthToInsert); + m_impl = WTFMove(newString); + } } void String::append(const LChar* charactersToAppend, unsigned lengthToAppend) { + // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API. + if (!m_impl) { if (!charactersToAppend) return; @@ -187,24 +226,26 @@ void String::append(const LChar* charactersToAppend, unsigned lengthToAppend) if (lengthToAppend > std::numeric_limits<unsigned>::max() - strLength) CRASH(); LChar* data; - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data); + auto newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data); StringImpl::copyChars(data, m_impl->characters8(), strLength); StringImpl::copyChars(data + strLength, charactersToAppend, lengthToAppend); - m_impl = newImpl.release(); + m_impl = WTFMove(newImpl); return; } if (lengthToAppend > std::numeric_limits<unsigned>::max() - strLength) CRASH(); UChar* data; - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(length() + lengthToAppend, data); + auto newImpl = StringImpl::createUninitialized(length() + lengthToAppend, data); StringImpl::copyChars(data, m_impl->characters16(), strLength); StringImpl::copyChars(data + strLength, charactersToAppend, lengthToAppend); - m_impl = newImpl.release(); + m_impl = WTFMove(newImpl); } void String::append(const UChar* charactersToAppend, unsigned lengthToAppend) { + // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API. + if (!m_impl) { if (!charactersToAppend) return; @@ -221,39 +262,16 @@ void String::append(const UChar* charactersToAppend, unsigned lengthToAppend) if (lengthToAppend > std::numeric_limits<unsigned>::max() - strLength) CRASH(); UChar* data; - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data); + auto newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data); if (m_impl->is8Bit()) StringImpl::copyChars(data, characters8(), strLength); else StringImpl::copyChars(data, characters16(), strLength); StringImpl::copyChars(data + strLength, charactersToAppend, lengthToAppend); - m_impl = newImpl.release(); + m_impl = WTFMove(newImpl); } -void String::insert(const UChar* charactersToInsert, unsigned lengthToInsert, unsigned position) -{ - if (position >= length()) { - append(charactersToInsert, lengthToInsert); - return; - } - - ASSERT(m_impl); - - if (!lengthToInsert) - return; - - ASSERT(charactersToInsert); - UChar* data; - if (lengthToInsert > std::numeric_limits<unsigned>::max() - length()) - CRASH(); - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(length() + lengthToInsert, data); - memcpy(data, deprecatedCharacters(), position * sizeof(UChar)); - memcpy(data + position, charactersToInsert, lengthToInsert * sizeof(UChar)); - memcpy(data + position + lengthToInsert, deprecatedCharacters() + position, (length() - position) * sizeof(UChar)); - m_impl = newImpl.release(); -} - UChar32 String::characterStartingAt(unsigned i) const { if (!m_impl || i >= m_impl->length()) @@ -263,24 +281,20 @@ UChar32 String::characterStartingAt(unsigned i) const void String::truncate(unsigned position) { - if (position >= length()) - return; - UChar* data; - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(position, data); - memcpy(data, deprecatedCharacters(), position * sizeof(UChar)); - m_impl = newImpl.release(); + if (m_impl) + m_impl = m_impl->substring(0, position); } template <typename CharacterType> inline void String::removeInternal(const CharacterType* characters, unsigned position, int lengthToRemove) { CharacterType* data; - RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(length() - lengthToRemove, data); + auto newImpl = StringImpl::createUninitialized(length() - lengthToRemove, data); memcpy(data, characters, position * sizeof(CharacterType)); memcpy(data + position, characters + position + lengthToRemove, (length() - lengthToRemove - position) * sizeof(CharacterType)); - m_impl = newImpl.release(); + m_impl = WTFMove(newImpl); } void String::remove(unsigned position, int lengthToRemove) @@ -318,35 +332,58 @@ String String::substringSharingImpl(unsigned offset, unsigned length) const if (!offset && length == stringLength) return *this; - return String(StringImpl::create(m_impl, offset, length)); + return String(StringImpl::createSubstringSharingImpl(*m_impl, offset, length)); +} + +String String::convertToASCIILowercase() const +{ + // FIXME: Should this function, and the many others like it, be inlined? + if (!m_impl) + return String(); + return m_impl->convertToASCIILowercase(); +} + +String String::convertToASCIIUppercase() const +{ + // FIXME: Should this function, and the many others like it, be inlined? + if (!m_impl) + return String(); + return m_impl->convertToASCIIUppercase(); +} + +String String::convertToLowercaseWithoutLocale() const +{ + if (!m_impl) + return String(); + return m_impl->convertToLowercaseWithoutLocale(); } -String String::lower() const +String String::convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(unsigned failingIndex) const { if (!m_impl) return String(); - return m_impl->lower(); + return m_impl->convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(failingIndex); } -String String::upper() const +String String::convertToUppercaseWithoutLocale() const { if (!m_impl) return String(); - return m_impl->upper(); + return m_impl->convertToUppercaseWithoutLocale(); } -String String::lower(const AtomicString& localeIdentifier) const +String String::convertToLowercaseWithLocale(const AtomicString& localeIdentifier) const { if (!m_impl) return String(); - return m_impl->lower(localeIdentifier); + return m_impl->convertToLowercaseWithLocale(localeIdentifier); } -String String::upper(const AtomicString& localeIdentifier) const +String String::convertToUppercaseWithLocale(const AtomicString& localeIdentifier) const { if (!m_impl) return String(); - return m_impl->upper(localeIdentifier); + return m_impl->convertToUppercaseWithLocale(localeIdentifier); } String String::stripWhiteSpace() const @@ -399,7 +436,10 @@ bool String::percentage(int& result) const if ((*m_impl)[m_impl->length() - 1] != '%') return false; - result = charactersToIntStrict(m_impl->deprecatedCharacters(), m_impl->length() - 1); + if (m_impl->is8Bit()) + result = charactersToIntStrict(m_impl->characters8(), m_impl->length() - 1); + else + result = charactersToIntStrict(m_impl->characters16(), m_impl->length() - 1); return true; } @@ -427,33 +467,26 @@ Vector<UChar> String::charactersWithNullTermination() const String String::format(const char *format, ...) { -#if OS(WINCE) va_list args; va_start(args, format); - Vector<char, 256> buffer; +#if USE(CF) && !OS(WINDOWS) + if (strstr(format, "%@")) { + RetainPtr<CFStringRef> cfFormat = adoptCF(CFStringCreateWithCString(kCFAllocatorDefault, format, kCFStringEncodingUTF8)); - int bufferSize = 256; - buffer.resize(bufferSize); - for (;;) { - int written = vsnprintf(buffer.data(), bufferSize, format, args); - va_end(args); +#if COMPILER(CLANG) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + RetainPtr<CFStringRef> result = adoptCF(CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, nullptr, cfFormat.get(), args)); +#if COMPILER(CLANG) +#pragma clang diagnostic pop +#endif - if (written == 0) - return String(""); - if (written > 0) - return StringImpl::create(reinterpret_cast<const LChar*>(buffer.data()), written); - - bufferSize <<= 1; - buffer.resize(bufferSize); - va_start(args, format); + va_end(args); + return result.get(); } - -#else - va_list args; - va_start(args, format); - - Vector<char, 256> buffer; +#endif // USE(CF) && !OS(WINDOWS) // Do the format once to get the length. #if COMPILER(MSVC) @@ -461,30 +494,25 @@ String String::format(const char *format, ...) #else char ch; int result = vsnprintf(&ch, 1, format, args); - // We need to call va_end() and then va_start() again here, as the - // contents of args is undefined after the call to vsnprintf - // according to http://man.cx/snprintf(3) - // - // Not calling va_end/va_start here happens to work on lots of - // systems, but fails e.g. on 64bit Linux. - va_end(args); - va_start(args, format); #endif + va_end(args); if (result == 0) return String(""); if (result < 0) return String(); + + Vector<char, 256> buffer; unsigned len = result; buffer.grow(len + 1); + va_start(args, format); // Now do the formatting again, guaranteed to fit. vsnprintf(buffer.data(), buffer.size(), format, args); va_end(args); return StringImpl::create(reinterpret_cast<const LChar*>(buffer.data()), len); -#endif } String String::number(int number) @@ -663,12 +691,12 @@ String String::isolatedCopy() const & return m_impl->isolatedCopy(); } -String String::isolatedCopy() const && +String String::isolatedCopy() && { if (isSafeToSendToAnotherThread()) { // Since we know that our string is a temporary that will be destroyed // we can just steal the m_impl from it, thus avoiding a copy. - return String(std::move(*this)); + return String(WTFMove(*this)); } if (!m_impl) @@ -689,14 +717,14 @@ bool String::isSafeToSendToAnotherThread() const { if (!impl()) return true; + if (isEmpty()) + return true; // AtomicStrings are not safe to send between threads as ~StringImpl() // will try to remove them from the wrong AtomicStringTable. if (impl()->isAtomic()) return false; if (impl()->hasOneRef()) return true; - if (isEmpty()) - return true; return false; } @@ -802,6 +830,11 @@ CString String::utf8(ConversionMode mode) const return m_impl->utf8(mode); } +CString String::utf8() const +{ + return utf8(LenientConversion); +} + String String::make8BitFrom16BitSource(const UChar* source, size_t length) { if (!length) @@ -1181,7 +1214,7 @@ String* string(const char* s) Vector<char> asciiDebug(StringImpl* impl) { if (!impl) - return asciiDebug(String("[null]").impl()); + return asciiDebug(String(ASCIILiteral("[null]")).impl()); Vector<char> buffer; for (unsigned i = 0; i < impl->length(); ++i) { |