https://bugs.webkit.org/show_bug.cgi?id=67081
Source/JavaScriptCore:
This change contains the following enhancements to StringBuilder,
for convenience, performance, testability, etc.:
- Change toStringPreserveCapacity() to const
- new public methods: capacity(), swap(), toAtomicString(), canShrink()
and append(const StringBuilder&)
- == and != opearators to compare StringBuilders and a StringBuilder/String
Unit tests: Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
Reviewed by Darin Adler.
* JavaScriptCore.exp:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* wtf/text/AtomicString.cpp:
(WTF::SubstringTranslator::hash):
(WTF::SubstringTranslator::equal):
(WTF::SubstringTranslator::translate):
(WTF::AtomicString::add):
(WTF::AtomicString::addSlowCase):
* wtf/text/AtomicString.h:
(WTF::AtomicString::AtomicString):
(WTF::AtomicString::add):
* wtf/text/StringBuilder.cpp:
(WTF::StringBuilder::reifyString):
(WTF::StringBuilder::resize):
(WTF::StringBuilder::canShrink):
(WTF::StringBuilder::shrinkToFit):
* wtf/text/StringBuilder.h:
(WTF::StringBuilder::append):
(WTF::StringBuilder::toString):
(WTF::StringBuilder::toStringPreserveCapacity):
(WTF::StringBuilder::toAtomicString):
(WTF::StringBuilder::isEmpty):
(WTF::StringBuilder::capacity):
(WTF::StringBuilder::is8Bit):
(WTF::StringBuilder::swap):
(WTF::equal):
(WTF::operator==):
(WTF::operator!=):
* wtf/text/StringImpl.h:
Source/WebCore:
These changes are because we explicitly disallowed StringBuilder's
copy constructor and assignment operator, and the change of return
type of StringBuilder::toString().
Reviewed by Darin Adler.
No new tests. All layout tests and unit tests should run as before.
* platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp:
(WebCore::MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime):
* svg/SVGPathStringBuilder.h:
(WebCore::SVGPathStringBuilder::cleanup):
Source/WebKit/chromium:
This change is because we explicitly disallowed StringBuilder's
copy constructor and assignment operator.
Reviewed by Darin Adler.
No new tests. All layout tests and unit tests should run as before.
* src/WebPageSerializerImpl.cpp:
(WebKit::WebPageSerializerImpl::encodeAndFlushBuffer):
Tools:
Reviewed by Darin Adler.
* TestWebKitAPI/Tests/WTF/StringBuilder.cpp:
(TestWebKitAPI::TEST):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@105635
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-01-23 Xianzhu Wang <wangxianzhu@chromium.org>
+
+ Basic enhancements to StringBuilder
+ https://bugs.webkit.org/show_bug.cgi?id=67081
+
+ This change contains the following enhancements to StringBuilder,
+ for convenience, performance, testability, etc.:
+ - Change toStringPreserveCapacity() to const
+ - new public methods: capacity(), swap(), toAtomicString(), canShrink()
+ and append(const StringBuilder&)
+ - == and != opearators to compare StringBuilders and a StringBuilder/String
+
+ Unit tests: Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
+
+ Reviewed by Darin Adler.
+
+ * JavaScriptCore.exp:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+ * wtf/text/AtomicString.cpp:
+ (WTF::SubstringTranslator::hash):
+ (WTF::SubstringTranslator::equal):
+ (WTF::SubstringTranslator::translate):
+ (WTF::AtomicString::add):
+ (WTF::AtomicString::addSlowCase):
+ * wtf/text/AtomicString.h:
+ (WTF::AtomicString::AtomicString):
+ (WTF::AtomicString::add):
+ * wtf/text/StringBuilder.cpp:
+ (WTF::StringBuilder::reifyString):
+ (WTF::StringBuilder::resize):
+ (WTF::StringBuilder::canShrink):
+ (WTF::StringBuilder::shrinkToFit):
+ * wtf/text/StringBuilder.h:
+ (WTF::StringBuilder::append):
+ (WTF::StringBuilder::toString):
+ (WTF::StringBuilder::toStringPreserveCapacity):
+ (WTF::StringBuilder::toAtomicString):
+ (WTF::StringBuilder::isEmpty):
+ (WTF::StringBuilder::capacity):
+ (WTF::StringBuilder::is8Bit):
+ (WTF::StringBuilder::swap):
+ (WTF::equal):
+ (WTF::operator==):
+ (WTF::operator!=):
+ * wtf/text/StringImpl.h:
+
2012-01-23 Carlos Garcia Campos <cgarcia@igalia.com>
Unreviewed. Fix make distcheck.
__ZN3WTF13MetaAllocator18debugFreeSpaceSizeEv
__ZN3WTF13MetaAllocator8allocateEm
__ZN3WTF13MetaAllocatorC2Em
-__ZN3WTF13StringBuilder11reifyStringEv
__ZN3WTF13StringBuilder11shrinkToFitEv
__ZN3WTF13StringBuilder15reserveCapacityEj
__ZN3WTF13StringBuilder6appendEPKhj
__ZNK3WTF13DecimalNumber19toStringExponentialEPtj
__ZNK3WTF13DecimalNumber28bufferLengthForStringDecimalEv
__ZNK3WTF13DecimalNumber32bufferLengthForStringExponentialEv
+__ZNK3WTF13StringBuilder11reifyStringEv
+__ZNK3WTF13StringBuilder9canShrinkEv
__ZNK3WTF6String11toIntStrictEPbi
__ZNK3WTF6String12isolatedCopyEv
__ZNK3WTF6String12toUIntStrictEPbi
__ZN3WTF13StringBuilder19appendUninitializedEj
__ZN3WTF13StringBuilder14allocateBufferEPKtj
__ZN3WTF13StringBuilder11shrinkToFitEv
-__ZN3WTF13StringBuilder11reifyStringEv
+__ZNK3WTF13StringBuilder11reifyStringEv
+__ZNK3WTF13StringBuilder9canShrinkEv
__ZN3JSC7JSArray4pushEPNS_9ExecStateENS_7JSValueE
__ZN3JSC7JSArray20increaseVectorLengthEj
__ZN3WTF14tryFastReallocEPvm
?randomNumber@WTF@@YANXZ
?recompileAllJSFunctions@Debugger@JSC@@QAEXPAVJSGlobalData@2@@Z
?regExpFlags@JSC@@YA?AW4RegExpFlags@1@ABVUString@1@@Z
- ?reifyString@StringBuilder@WTF@@AAEXXZ
+ ?reifyString@StringBuilder@WTF@@ABEXXZ
?releaseDecommitted@OSAllocator@WTF@@SAXPAXI@Z
?releaseExecutableMemory@JSGlobalData@JSC@@QAEXXZ
?reportExtraMemoryCostSlowCase@Heap@JSC@@AAEXI@Z
/*
* Copyright (C) 2004, 2005, 2006, 2007, 2008 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
return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer);
}
-PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r)
+struct SubstringLocation {
+ StringImpl* baseString;
+ unsigned start;
+ unsigned length;
+};
+
+struct SubstringTranslator {
+ static unsigned hash(const SubstringLocation& buffer)
+ {
+ return StringHasher::computeHash(buffer.baseString->characters() + buffer.start, buffer.length);
+ }
+
+ static bool equal(StringImpl* const& string, const SubstringLocation& buffer)
+ {
+ return WTF::equal(string, buffer.baseString->characters() + buffer.start, buffer.length);
+ }
+
+ static void translate(StringImpl*& location, const SubstringLocation& buffer, unsigned hash)
+ {
+ location = StringImpl::create(buffer.baseString, buffer.start, buffer.length).leakRef();
+ location->setHash(hash);
+ location->setIsAtomic(true);
+ }
+};
+
+PassRefPtr<StringImpl> AtomicString::add(StringImpl* baseString, unsigned start, unsigned length)
{
- if (!r || r->isAtomic())
- return r;
+ if (!baseString)
+ return 0;
+
+ if (!length || start >= baseString->length())
+ return StringImpl::empty();
+ unsigned maxLength = baseString->length() - start;
+ if (length >= maxLength) {
+ if (!start)
+ return add(baseString);
+ length = maxLength;
+ }
+
+ SubstringLocation buffer = { baseString, start, length };
+ return addToStringTable<SubstringLocation, SubstringTranslator>(buffer);
+}
+
+PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* r)
+{
if (!r->length())
return StringImpl::empty();
ATOMICSTRING_CONVERSION AtomicString(StringImpl* imp) : m_string(add(imp)) { }
AtomicString(AtomicStringImpl* imp) : m_string(imp) { }
ATOMICSTRING_CONVERSION AtomicString(const String& s) : m_string(add(s.impl())) { }
+ AtomicString(StringImpl* baseString, unsigned start, unsigned length) : m_string(add(baseString, start, length)) { }
// Hash table deleted values, which are only constructed and never copied or destroyed.
AtomicString(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { }
ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s, unsigned length) { return add(reinterpret_cast<const char*>(s), length); };
WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(const UChar*, unsigned length, unsigned existingHash);
WTF_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(const UChar*);
- ALWAYS_INLINE PassRefPtr<StringImpl> add(StringImpl* r)
+ static PassRefPtr<StringImpl> add(StringImpl*, unsigned offset, unsigned length);
+ ALWAYS_INLINE static PassRefPtr<StringImpl> add(StringImpl* r)
{
if (!r || r->isAtomic())
return r;
/*
* 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
static const unsigned minimumCapacity = 16;
-void StringBuilder::reifyString()
+void StringBuilder::reifyString() const
{
// Check if the string already exists.
if (!m_string.isNull()) {
// If there is a buffer, we only need to duplicate it if it has more than one ref.
if (m_buffer) {
+ m_string = String(); // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer.
if (!m_buffer->hasOneRef()) {
if (m_buffer->is8Bit())
allocateBuffer(m_buffer->characters8(), m_buffer->length());
allocateBuffer(m_buffer->characters16(), m_buffer->length());
}
m_length = newSize;
- m_string = String();
return;
}
}
}
+bool StringBuilder::canShrink() const
+{
+ // Only shrink the buffer if it's less than 80% full. Need to tune this heuristic!
+ return m_buffer && m_buffer->length() > (m_length + (m_length >> 2));
+}
+
void StringBuilder::shrinkToFit()
{
- // If the buffer is at least 80% full, don't bother copying. Need to tune this heuristic!
- if (m_buffer && m_buffer->length() > (m_length + (m_length >> 2))) {
+ if (canShrink()) {
if (m_is8Bit)
reallocateBuffer<LChar>(m_length);
else
/*
* Copyright (C) 2009, 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
#ifndef StringBuilder_h
#define StringBuilder_h
-#include <wtf/Vector.h>
+#include <wtf/text/AtomicString.h>
#include <wtf/text/WTFString.h>
namespace WTF {
class StringBuilder {
+ // Disallow copying since it's expensive and we don't want code to do it by accident.
+ WTF_MAKE_NONCOPYABLE(StringBuilder);
+
public:
StringBuilder()
: m_length(0)
if (!string.length())
return;
- // If we're appending to an empty string, and there is not buffer
- // (in case reserveCapacity has been called) then just retain the
- // string.
+ // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
+ // then just retain the string.
if (!m_length && !m_buffer) {
m_string = string;
m_length = string.length();
append(string.characters16(), string.length());
}
+ void append(const StringBuilder& other)
+ {
+ if (!other.m_length)
+ return;
+
+ // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
+ // then just retain the string.
+ if (!m_length && !m_buffer && !other.m_string.isNull()) {
+ m_string = other.m_string;
+ m_length = other.m_length;
+ return;
+ }
+
+ append(other.characters(), other.m_length);
+ }
+
void append(const char* characters)
{
if (characters)
void append(char c)
{
- if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
- if (m_is8Bit)
- m_bufferCharacters8[m_length++] = (LChar)c;
- else
- m_bufferCharacters16[m_length++] = (LChar)c;
- }
- else
- append(&c, 1);
+ append(static_cast<LChar>(c));
}
String toString()
{
- if (m_string.isNull()) {
- shrinkToFit();
+ shrinkToFit();
+ if (m_string.isNull())
reifyString();
- }
return m_string;
}
- String toStringPreserveCapacity()
+ const String& toStringPreserveCapacity() const
{
if (m_string.isNull())
reifyString();
return m_string;
}
+ AtomicString toAtomicString() const
+ {
+ if (!m_length)
+ return AtomicString();
+
+ // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large.
+ if (canShrink())
+ return AtomicString(characters(), length());
+
+ if (!m_string.isNull())
+ return AtomicString(m_string);
+
+ ASSERT(m_buffer);
+ return AtomicString(m_buffer.get(), 0, m_length);
+ }
+
unsigned length() const
{
return m_length;
}
- bool isEmpty() const { return !length(); }
+ bool isEmpty() const { return !m_length; }
WTF_EXPORT_PRIVATE void reserveCapacity(unsigned newCapacity);
+ unsigned capacity() const
+ {
+ return m_buffer ? m_buffer->length() : m_length;
+ }
+
WTF_EXPORT_PRIVATE void resize(unsigned newSize);
+ WTF_EXPORT_PRIVATE bool canShrink() const;
+
WTF_EXPORT_PRIVATE void shrinkToFit();
UChar operator[](unsigned i) const
return m_buffer->characters();
}
+ bool is8Bit() const { return m_is8Bit; }
+
void clear()
{
m_length = 0;
m_valid16BitShadowLength = 0;
}
+ void swap(StringBuilder& stringBuilder)
+ {
+ std::swap(m_length, stringBuilder.m_length);
+ m_string.swap(stringBuilder.m_string);
+ m_buffer.swap(stringBuilder.m_buffer);
+ std::swap(m_is8Bit, stringBuilder.m_is8Bit);
+ std::swap(m_valid16BitShadowLength, stringBuilder.m_valid16BitShadowLength);
+ std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
+ }
+
private:
void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength);
void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
CharType* appendUninitializedSlow(unsigned length);
template <typename CharType>
ALWAYS_INLINE CharType * getBufferCharacters();
- WTF_EXPORT_PRIVATE void reifyString();
+ WTF_EXPORT_PRIVATE void reifyString() const;
unsigned m_length;
- String m_string;
+ mutable String m_string;
RefPtr<StringImpl> m_buffer;
bool m_is8Bit;
mutable unsigned m_valid16BitShadowLength;
return m_bufferCharacters16;
}
+template <typename CharType>
+bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
+{
+ if (s.length() != length)
+ return false;
+
+ if (s.is8Bit())
+ return equal(s.characters8(), buffer, length);
+
+ return equal(s.characters16(), buffer, length);
+}
+
+template <typename StringType>
+bool equal(const StringBuilder& a, const StringType& b)
+{
+ if (a.length() != b.length())
+ return false;
+
+ if (!a.length())
+ return true;
+
+ if (a.is8Bit()) {
+ if (b.is8Bit())
+ return equal(a.characters8(), b.characters8(), a.length());
+ return equal(a.characters8(), b.characters16(), a.length());
+ }
+
+ if (b.is8Bit())
+ return equal(a.characters16(), b.characters8(), a.length());
+ return equal(a.characters16(), b.characters16(), a.length());
+}
+
+inline bool operator==(const StringBuilder& a, const StringBuilder& b) { return equal(a, b); }
+inline bool operator!=(const StringBuilder& a, const StringBuilder& b) { return !equal(a, b); }
+inline bool operator==(const StringBuilder& a, const String& b) { return equal(a, b); }
+inline bool operator!=(const StringBuilder& a, const String& b) { return !equal(a, b); }
+inline bool operator==(const String& a, const StringBuilder& b) { return equal(b, a); }
+inline bool operator!=(const String& a, const StringBuilder& b) { return !equal(b, a); }
+
} // namespace WTF
using WTF::StringBuilder;
struct CStringTranslator;
struct HashAndCharactersTranslator;
struct HashAndUTF8CharactersTranslator;
+struct SubstringTranslator;
struct UCharBufferTranslator;
enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive };
friend struct WTF::CStringTranslator;
friend struct WTF::HashAndCharactersTranslator;
friend struct WTF::HashAndUTF8CharactersTranslator;
+ friend struct WTF::SubstringTranslator;
friend struct WTF::UCharBufferTranslator;
friend class AtomicStringImpl;
+2012-01-23 Xianzhu Wang <wangxianzhu@chromium.org>
+
+ Basic enhancements to StringBuilder
+ https://bugs.webkit.org/show_bug.cgi?id=67081
+
+ These changes are because we explicitly disallowed StringBuilder's
+ copy constructor and assignment operator, and the change of return
+ type of StringBuilder::toString().
+
+ Reviewed by Darin Adler.
+
+ No new tests. All layout tests and unit tests should run as before.
+
+ * platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp:
+ (WebCore::MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime):
+ * svg/SVGPathStringBuilder.h:
+ (WebCore::SVGPathStringBuilder::cleanup):
+
2012-01-23 W. James MacLean <wjmaclean@chromium.org>
[chromium] Add WebSolidColorLayer interface to draw non-textured color layers from Aura.
} else
cookieURL = movieURL;
- InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0);
+ String string = cookieBuilder.toString();
+ InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, string.charactersWithNullTermination(), 0, 0);
}
}
String result();
private:
- virtual void cleanup() { m_stringBuilder = StringBuilder(); }
+ virtual void cleanup() { m_stringBuilder.clear(); }
virtual void incrementPathSegmentCount() { }
virtual bool continueConsuming() { return true; }
+2012-01-23 Xianzhu Wang <wangxianzhu@chromium.org>
+
+ Basic enhancements to StringBuilder
+ https://bugs.webkit.org/show_bug.cgi?id=67081
+
+ This change is because we explicitly disallowed StringBuilder's
+ copy constructor and assignment operator.
+
+ Reviewed by Darin Adler.
+
+ No new tests. All layout tests and unit tests should run as before.
+
+ * src/WebPageSerializerImpl.cpp:
+ (WebKit::WebPageSerializerImpl::encodeAndFlushBuffer):
+
2012-01-23 W. James MacLean <wjmaclean@chromium.org>
[chromium] Add WebSolidColorLayer interface to draw non-textured color layers from Aura.
return;
String content = m_dataBuffer.toString();
- m_dataBuffer = StringBuilder();
+ m_dataBuffer.clear();
// Convert the unicode content to target encoding
CString encodedContent = param->textEncoding.encode(
+2012-01-23 Xianzhu Wang <wangxianzhu@chromium.org>
+
+ Basic enhancements to StringBuilder
+ https://bugs.webkit.org/show_bug.cgi?id=67081
+
+ Reviewed by Darin Adler.
+
+ * TestWebKitAPI/Tests/WTF/StringBuilder.cpp:
+ (TestWebKitAPI::TEST):
+
2012-01-23 Mario Sanchez Prada <msanchez@igalia.com>
[GTK] run-gtk-tests randomly fails while running the xprop comand
builder1.append("XYZ");
builder.append(builder1.characters(), builder1.length());
expectBuilderContent("0123456789abcdefg#0123456789abcdefg#XYZ", builder);
+
+ StringBuilder builder2;
+ builder2.reserveCapacity(100);
+ builder2.append("xyz");
+ const UChar* characters = builder2.characters();
+ builder2.append("0123456789");
+ ASSERT_EQ(characters, builder2.characters());
+ builder2.toStringPreserveCapacity(); // Test after reifyString with buffer preserved.
+ builder2.append("abcd");
+ ASSERT_EQ(characters, builder2.characters());
}
TEST(StringBuilderTest, ToString)
{
StringBuilder builder;
builder.append("0123456789");
+ unsigned capacity = builder.capacity();
String string = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
ASSERT_EQ(String("0123456789"), string);
ASSERT_EQ(string.impl(), builder.toStringPreserveCapacity().impl());
ASSERT_EQ(string.characters(), builder.characters());
// Changing the StringBuilder should not affect the original result of toStringPreserveCapacity() in case the capacity is not changed.
builder.reserveCapacity(200);
+ capacity = builder.capacity();
string = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
ASSERT_EQ(string.characters(), builder.characters());
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
builder.append("ABC");
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
// Changing the original result of toStringPreserveCapacity() should not affect the content of the StringBuilder.
+ capacity = builder.capacity();
String string1 = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
ASSERT_EQ(string1.characters(), builder.characters());
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
string1.append("DEF");
ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1);
// Resizing the StringBuilder should not affect the original result of toStringPreserveCapacity().
+ capacity = builder.capacity();
string1 = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
ASSERT_EQ(string.characters(), builder.characters());
builder.resize(10);
builder.append("###");
expectEmpty(builder);
}
+TEST(StringBuilderTest, Equal)
+{
+ StringBuilder builder1;
+ StringBuilder builder2;
+ ASSERT_TRUE(builder1 == builder2);
+ ASSERT_TRUE(equal(builder1, static_cast<LChar*>(0), 0));
+ ASSERT_TRUE(builder1 == String());
+ ASSERT_TRUE(String() == builder1);
+ ASSERT_TRUE(builder1 != String("abc"));
+
+ builder1.append("123");
+ builder1.reserveCapacity(32);
+ builder2.append("123");
+ builder1.reserveCapacity(64);
+ ASSERT_TRUE(builder1 == builder2);
+ ASSERT_TRUE(builder1 == String("123"));
+ ASSERT_TRUE(String("123") == builder1);
+
+ builder2.append("456");
+ ASSERT_TRUE(builder1 != builder2);
+ ASSERT_TRUE(builder2 != builder1);
+ ASSERT_TRUE(String("123") != builder2);
+ ASSERT_TRUE(builder2 != String("123"));
+ builder2.toString(); // Test after reifyString().
+ ASSERT_TRUE(builder1 != builder2);
+
+ builder2.resize(3);
+ ASSERT_TRUE(builder1 == builder2);
+
+ builder1.toString(); // Test after reifyString().
+ ASSERT_TRUE(builder1 == builder2);
+}
+
+TEST(StringBuilderTest, CanShrink)
+{
+ StringBuilder builder;
+ builder.reserveCapacity(256);
+ ASSERT_TRUE(builder.canShrink());
+ for (int i = 0; i < 256; i++)
+ builder.append('x');
+ ASSERT_EQ(builder.length(), builder.capacity());
+ ASSERT_FALSE(builder.canShrink());
+}
+
+TEST(StringBuilderTest, ToAtomicString)
+{
+ StringBuilder builder;
+ builder.append("123");
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(String("123"), atomicString);
+
+ builder.reserveCapacity(256);
+ ASSERT_TRUE(builder.canShrink());
+ for (int i = builder.length(); i < 128; i++)
+ builder.append('x');
+ AtomicString atomicString1 = builder.toAtomicString();
+ ASSERT_EQ(128, atomicString1.length());
+ ASSERT_EQ('x', atomicString1[127]);
+
+ // Later change of builder should not affect the atomic string.
+ for (int i = builder.length(); i < 256; i++)
+ builder.append('x');
+ ASSERT_EQ(128, atomicString1.length());
+
+ ASSERT_FALSE(builder.canShrink());
+ String string = builder.toString();
+ AtomicString atomicString2 = builder.toAtomicString();
+ // They should share the same StringImpl.
+ ASSERT_EQ(atomicString2.impl(), string.impl());
+}
+
} // namespace