diff options
Diffstat (limited to 'Source/WTF/wtf/text/StringBuilder.cpp')
-rw-r--r-- | Source/WTF/wtf/text/StringBuilder.cpp | 153 |
1 files changed, 134 insertions, 19 deletions
diff --git a/Source/WTF/wtf/text/StringBuilder.cpp b/Source/WTF/wtf/text/StringBuilder.cpp index c483ba146..436015a43 100644 --- a/Source/WTF/wtf/text/StringBuilder.cpp +++ b/Source/WTF/wtf/text/StringBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved. * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,6 +28,7 @@ #include "StringBuilder.h" #include "IntegerToStringConversion.h" +#include "MathExtras.h" #include "WTFString.h" #include <wtf/dtoa.h> @@ -58,12 +59,7 @@ void StringBuilder::reifyString() const if (m_length == m_buffer->length()) m_string = m_buffer.get(); else - m_string = StringImpl::create(m_buffer, 0, m_length); - - if (m_buffer->has16BitShadow() && m_valid16BitShadowLength < m_length) - m_buffer->upconvertCharacters(m_valid16BitShadowLength, m_length); - - m_valid16BitShadowLength = m_length; + m_string = StringImpl::createSubstringSharingImpl(*m_buffer, 0, m_length); } void StringBuilder::resize(unsigned newSize) @@ -84,6 +80,7 @@ void StringBuilder::resize(unsigned newSize) allocateBuffer(m_buffer->characters16(), m_buffer->length()); } m_length = newSize; + ASSERT(m_buffer->length() >= m_length); return; } @@ -92,7 +89,7 @@ void StringBuilder::resize(unsigned newSize) ASSERT(m_length == m_string.length()); ASSERT(newSize < m_string.length()); m_length = newSize; - m_string = StringImpl::create(m_string.impl(), 0, newSize); + m_string = StringImpl::createSubstringSharingImpl(*m_string.impl(), 0, newSize); } // Allocate a new 8 bit buffer, copying in currentCharacters (these may come from either m_string @@ -101,12 +98,13 @@ void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requ { ASSERT(m_is8Bit); // Copy the existing data into a new buffer, set result to point to the end of the existing data. - RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters8); + auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters8); memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length) * sizeof(LChar)); // This can't overflow. // Update the builder state. - m_buffer = buffer.release(); + m_buffer = WTFMove(buffer); m_string = String(); + ASSERT(m_buffer->length() == requiredLength); } // Allocate a new 16 bit buffer, copying in currentCharacters (these may come from either m_string @@ -115,12 +113,13 @@ void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ { ASSERT(!m_is8Bit); // Copy the existing data into a new buffer, set result to point to the end of the existing data. - RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); + auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow. // Update the builder state. - m_buffer = buffer.release(); + m_buffer = WTFMove(buffer); m_string = String(); + ASSERT(m_buffer->length() == requiredLength); } // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit and may come @@ -128,16 +127,18 @@ void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength) { ASSERT(m_is8Bit); + ASSERT(requiredLength >= m_length); // Copy the existing data into a new buffer, set result to point to the end of the existing data. - RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); + auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); for (unsigned i = 0; i < m_length; ++i) m_bufferCharacters16[i] = currentCharacters[i]; m_is8Bit = false; // Update the builder state. - m_buffer = buffer.release(); + m_buffer = WTFMove(buffer); m_string = String(); + ASSERT(m_buffer->length() == requiredLength); } template <> @@ -151,9 +152,10 @@ void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength) ASSERT(m_buffer->is8Bit()); if (m_buffer->hasOneRef()) - m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_bufferCharacters8); + m_buffer = StringImpl::reallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters8); else allocateBuffer(m_buffer->characters8(), requiredLength); + ASSERT(m_buffer->length() == requiredLength); } template <> @@ -166,9 +168,10 @@ void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength) if (m_buffer->is8Bit()) allocateBufferUpConvert(m_buffer->characters8(), requiredLength); else if (m_buffer->hasOneRef()) - m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_bufferCharacters16); + m_buffer = StringImpl::reallocate(m_buffer.releaseNonNull(), requiredLength, m_bufferCharacters16); else allocateBuffer(m_buffer->characters16(), requiredLength); + ASSERT(m_buffer->length() == requiredLength); } void StringBuilder::reserveCapacity(unsigned newCapacity) @@ -193,6 +196,7 @@ void StringBuilder::reserveCapacity(unsigned newCapacity) allocateBuffer(m_string.characters16(), newCapacity); } } + ASSERT(!newCapacity || m_buffer->length() >= newCapacity); } // Make 'length' additional capacity be available in m_buffer, update m_string & m_length, @@ -233,11 +237,12 @@ CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength) reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength)); } else { ASSERT(m_string.length() == m_length); - allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, expandedCapacity(capacity(), requiredLength)); + allocateBuffer(m_length ? m_string.characters<CharType>() : 0, expandedCapacity(capacity(), requiredLength)); } CharType* result = getBufferCharacters<CharType>() + m_length; m_length = requiredLength; + ASSERT(m_buffer->length() >= m_length); return result; } @@ -271,10 +276,11 @@ void StringBuilder::append(const UChar* characters, unsigned length) allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), expandedCapacity(capacity(), requiredLength)); } - memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar)); + memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar)); m_length = requiredLength; } else memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_t>(length) * sizeof(UChar)); + ASSERT(m_buffer->length() >= m_length); } void StringBuilder::append(const LChar* characters, unsigned length) @@ -300,6 +306,20 @@ void StringBuilder::append(const LChar* characters, unsigned length) } } +#if USE(CF) + +void StringBuilder::append(CFStringRef string) +{ + // Fast path: avoid constructing a temporary String when possible. + if (auto* characters = CFStringGetCStringPtr(string, kCFStringEncodingISOLatin1)) { + append(reinterpret_cast<const LChar*>(characters), CFStringGetLength(string)); + return; + } + append(String(string)); +} + +#endif + void StringBuilder::appendNumber(int number) { numberToStringSigned<StringBuilder>(number, this); @@ -361,8 +381,103 @@ void StringBuilder::shrinkToFit() reallocateBuffer<LChar>(m_length); else reallocateBuffer<UChar>(m_length); - m_string = m_buffer.release(); + m_string = WTFMove(m_buffer); + } +} + +template <typename OutputCharacterType, typename InputCharacterType> +static void appendQuotedJSONStringInternalSlow(OutputCharacterType*& output, const InputCharacterType character) +{ + switch (character) { + case '\t': + *output++ = '\\'; + *output++ = 't'; + break; + case '\r': + *output++ = '\\'; + *output++ = 'r'; + break; + case '\n': + *output++ = '\\'; + *output++ = 'n'; + break; + case '\f': + *output++ = '\\'; + *output++ = 'f'; + break; + case '\b': + *output++ = '\\'; + *output++ = 'b'; + break; + default: + ASSERT(!(character & 0xFF00)); + *output++ = '\\'; + *output++ = 'u'; + *output++ = '0'; + *output++ = '0'; + *output++ = upperNibbleToLowercaseASCIIHexDigit(character); + *output++ = lowerNibbleToLowercaseASCIIHexDigit(character); + break; + } +} + +template <typename OutputCharacterType, typename InputCharacterType> +static void appendQuotedJSONStringInternal(OutputCharacterType*& output, const InputCharacterType* input, unsigned length) +{ + for (const InputCharacterType* end = input + length; input != end; ++input) { + const InputCharacterType character = *input; + if (LIKELY(character != '"' && character != '\\' && character > 0x1F)) { + *output++ = character; + continue; + } + + if (character == '"' || character == '\\') { + *output++ = '\\'; + *output++ = character; + continue; + } + + appendQuotedJSONStringInternalSlow(output, character); + } +} + +void StringBuilder::appendQuotedJSONString(const String& string) +{ + // Make sure we have enough buffer space to append this string without having + // to worry about reallocating in the middle. + // The 2 is for the '"' quotes on each end. + // The 6 is for characters that need to be \uNNNN encoded. + Checked<unsigned> stringLength = string.length(); + Checked<unsigned> maximumCapacityRequired = length(); + maximumCapacityRequired += 2 + stringLength * 6; + unsigned allocationSize = maximumCapacityRequired.unsafeGet(); + // This max() is here to allow us to allocate sizes between the range [2^31, 2^32 - 2] because roundUpToPowerOfTwo(1<<31 + some int smaller than 1<<31) == 0. + allocationSize = std::max(allocationSize, roundUpToPowerOfTwo(allocationSize)); + + if (is8Bit() && !string.is8Bit()) + allocateBufferUpConvert(m_bufferCharacters8, allocationSize); + else + reserveCapacity(allocationSize); + ASSERT(m_buffer->length() >= allocationSize); + + if (is8Bit()) { + ASSERT(string.is8Bit()); + LChar* output = m_bufferCharacters8 + m_length; + *output++ = '"'; + appendQuotedJSONStringInternal(output, string.characters8(), string.length()); + *output++ = '"'; + m_length = output - m_bufferCharacters8; + } else { + UChar* output = m_bufferCharacters16 + m_length; + *output++ = '"'; + if (string.is8Bit()) + appendQuotedJSONStringInternal(output, string.characters8(), string.length()); + else + appendQuotedJSONStringInternal(output, string.characters16(), string.length()); + *output++ = '"'; + m_length = output - m_bufferCharacters16; } + ASSERT(m_buffer->length() >= m_length); } } // namespace WTF |