blob: 7f3539ebaea2d7db777d4f23c576fcc688a826b3 [file] [log] [blame]
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "platform/wtf/text/StringBuilder.h"
#include "platform/wtf/dtoa.h"
#include "platform/wtf/text/IntegerToStringConversion.h"
#include "platform/wtf/text/WTFString.h"
#include <algorithm>
namespace WTF {
String StringBuilder::ToString() {
if (!length_)
return g_empty_string;
if (string_.IsNull()) {
if (is8_bit_)
string_ = String(Characters8(), length_);
else
string_ = String(Characters16(), length_);
ClearBuffer();
}
return string_;
}
AtomicString StringBuilder::ToAtomicString() {
if (!length_)
return g_empty_atom;
if (string_.IsNull()) {
if (is8_bit_)
string_ = AtomicString(Characters8(), length_);
else
string_ = AtomicString(Characters16(), length_);
ClearBuffer();
}
return AtomicString(string_);
}
String StringBuilder::Substring(unsigned start, unsigned length) const {
if (start >= length_)
return g_empty_string;
if (!string_.IsNull())
return string_.Substring(start, length);
length = std::min(length, length_ - start);
if (is8_bit_)
return String(Characters8() + start, length);
return String(Characters16() + start, length);
}
void StringBuilder::Swap(StringBuilder& builder) {
std::swap(string_, builder.string_);
std::swap(buffer_, builder.buffer_);
std::swap(length_, builder.length_);
std::swap(is8_bit_, builder.is8_bit_);
}
void StringBuilder::ClearBuffer() {
if (is8_bit_)
delete buffer8_;
else
delete buffer16_;
buffer_ = nullptr;
}
void StringBuilder::Clear() {
ClearBuffer();
string_ = String();
length_ = 0;
is8_bit_ = true;
}
unsigned StringBuilder::Capacity() const {
if (!HasBuffer())
return 0;
if (is8_bit_)
return buffer8_->capacity();
return buffer16_->capacity();
}
void StringBuilder::ReserveCapacity(unsigned new_capacity) {
if (is8_bit_)
EnsureBuffer8(new_capacity);
else
EnsureBuffer16(new_capacity);
}
void StringBuilder::Resize(unsigned new_size) {
DCHECK_LE(new_size, length_);
string_ = string_.Left(new_size);
length_ = new_size;
if (HasBuffer()) {
if (is8_bit_)
buffer8_->resize(new_size);
else
buffer16_->resize(new_size);
}
}
void StringBuilder::CreateBuffer8(unsigned added_size) {
DCHECK(!HasBuffer());
DCHECK(is8_bit_);
buffer8_ = new Buffer8;
// createBuffer is called right before appending addedSize more bytes. We
// want to ensure we have enough space to fit m_string plus the added
// size.
//
// We also ensure that we have at least the initialBufferSize of extra space
// for appending new bytes to avoid future mallocs for appending short
// strings or single characters. This is a no-op if m_length == 0 since
// initialBufferSize() is the same as the inline capacity of the vector.
// This allows doing append(string); append('\0') without extra mallocs.
buffer8_->ReserveInitialCapacity(length_ +
std::max(added_size, InitialBufferSize()));
length_ = 0;
Append(string_);
string_ = String();
}
void StringBuilder::CreateBuffer16(unsigned added_size) {
DCHECK(is8_bit_ || !HasBuffer());
Buffer8 buffer8;
unsigned length = length_;
if (buffer8_) {
buffer8_->swap(buffer8);
delete buffer8_;
}
buffer16_ = new Buffer16;
// See createBuffer8's call to reserveInitialCapacity for why we do this.
buffer16_->ReserveInitialCapacity(length_ +
std::max(added_size, InitialBufferSize()));
is8_bit_ = false;
length_ = 0;
if (!buffer8.IsEmpty()) {
Append(buffer8.data(), length);
return;
}
Append(string_);
string_ = String();
}
void StringBuilder::Append(const UChar* characters, unsigned length) {
if (!length)
return;
DCHECK(characters);
// If there's only one char we use append(UChar) instead since it will
// check for latin1 and avoid converting to 16bit if possible.
if (length == 1) {
Append(*characters);
return;
}
EnsureBuffer16(length);
buffer16_->Append(characters, length);
length_ += length;
}
void StringBuilder::Append(const LChar* characters, unsigned length) {
if (!length)
return;
DCHECK(characters);
if (is8_bit_) {
EnsureBuffer8(length);
buffer8_->Append(characters, length);
length_ += length;
return;
}
EnsureBuffer16(length);
buffer16_->Append(characters, length);
length_ += length;
}
template <typename IntegerType>
static void AppendIntegerInternal(StringBuilder& builder, IntegerType input) {
IntegerToStringConverter<IntegerType> converter(input);
builder.Append(converter.Characters8(), converter.length());
}
void StringBuilder::AppendNumber(int number) {
AppendIntegerInternal(*this, number);
}
void StringBuilder::AppendNumber(unsigned number) {
AppendIntegerInternal(*this, number);
}
void StringBuilder::AppendNumber(long number) {
AppendIntegerInternal(*this, number);
}
void StringBuilder::AppendNumber(unsigned long number) {
AppendIntegerInternal(*this, number);
}
void StringBuilder::AppendNumber(long long number) {
AppendIntegerInternal(*this, number);
}
void StringBuilder::AppendNumber(unsigned long long number) {
AppendIntegerInternal(*this, number);
}
void StringBuilder::AppendNumber(double number, unsigned precision) {
NumberToStringBuffer buffer;
Append(NumberToFixedPrecisionString(number, precision, buffer));
}
void StringBuilder::erase(unsigned index) {
if (index >= length_)
return;
if (is8_bit_) {
EnsureBuffer8(0);
buffer8_->EraseAt(index);
} else {
EnsureBuffer16(0);
buffer16_->EraseAt(index);
}
--length_;
}
} // namespace WTF