summaryrefslogtreecommitdiff
path: root/Source/WTF/wtf/text/WTFString.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WTF/wtf/text/WTFString.cpp')
-rw-r--r--Source/WTF/wtf/text/WTFString.cpp273
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) {