Commit ff1792ac authored by esprehn's avatar esprehn Committed by Commit bot

Make CString more similar to WTF::String.

Nothing uses the copy on write feature, and it's implemented in a
somewhat confusing way since mutableData() would create a copy of the
underlying buffer, but any instances created from the CString after
calling mutableData() would still share with the mutable buffer allowing
modification of all of the CString instances. Instead lets just remove
this feature.

Doing this makes CString and CStringBuffer immutable and makes their
API look very similar to String and StringImpl. A future patch will
rename CStringBuffer to CStringImpl to match.

I also threw in a bunch of documentation comments. :)

Review-Url: https://codereview.chromium.org/2345893002
Cr-Commit-Position: refs/heads/master@{#419115}
parent b79b06dd
......@@ -23,7 +23,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wtf/text/CString.h"
#include "wtf/ASCIICType.h"
......@@ -35,14 +34,17 @@ using namespace std;
namespace WTF {
PassRefPtr<CStringBuffer> CStringBuffer::createUninitialized(size_t length)
PassRefPtr<CStringBuffer> CStringBuffer::createUninitialized(size_t length, char*& data)
{
// TODO(esprehn): This doesn't account for the NUL.
RELEASE_ASSERT(length < (numeric_limits<unsigned>::max() - sizeof(CStringBuffer)));
// The +1 is for the terminating NUL character.
size_t size = sizeof(CStringBuffer) + length + 1;
CStringBuffer* stringBuffer = static_cast<CStringBuffer*>(Partitions::bufferMalloc(size, WTF_HEAP_PROFILER_TYPE_NAME(CStringBuffer)));
return adoptRef(new (stringBuffer) CStringBuffer(length));
CStringBuffer* buffer = static_cast<CStringBuffer*>(Partitions::bufferMalloc(size, WTF_HEAP_PROFILER_TYPE_NAME(CStringBuffer)));
data = reinterpret_cast<char*>(buffer + 1);
data[length] = '\0';
return adoptRef(new (buffer) CStringBuffer(length));
}
void CStringBuffer::operator delete(void* ptr)
......@@ -50,60 +52,15 @@ void CStringBuffer::operator delete(void* ptr)
Partitions::bufferFree(ptr);
}
CString::CString(const char* str)
{
if (!str)
return;
init(str, strlen(str));
}
CString::CString(const char* str, size_t length)
CString::CString(const char* chars, size_t length)
{
if (!str) {
ASSERT(!length);
if (!chars) {
DCHECK_EQ(length, 0u);
return;
}
init(str, length);
}
void CString::init(const char* str, size_t length)
{
ASSERT(str);
m_buffer = CStringBuffer::createUninitialized(length);
memcpy(m_buffer->mutableData(), str, length);
m_buffer->mutableData()[length] = '\0';
}
char* CString::mutableData()
{
copyBufferIfNeeded();
if (!m_buffer)
return 0;
return m_buffer->mutableData();
}
CString CString::newUninitialized(size_t length, char*& characterBuffer)
{
CString result;
result.m_buffer = CStringBuffer::createUninitialized(length);
char* bytes = result.m_buffer->mutableData();
bytes[length] = '\0';
characterBuffer = bytes;
return result;
}
void CString::copyBufferIfNeeded()
{
if (!m_buffer || m_buffer->hasOneRef())
return;
RefPtr<CStringBuffer> buffer = m_buffer.release();
size_t length = buffer->length();
m_buffer = CStringBuffer::createUninitialized(length);
memcpy(m_buffer->mutableData(), buffer->data(), length + 1);
char* data;
m_buffer = CStringBuffer::createUninitialized(length, data);
memcpy(data, chars, length);
}
bool CString::isSafeToSendToAnotherThread() const
......
......@@ -30,60 +30,74 @@
#include "wtf/RefCounted.h"
#include "wtf/RefPtr.h"
#include "wtf/WTFExport.h"
#include <string.h>
namespace WTF {
// CStringBuffer is the ref-counted storage class for the characters in a CString.
// The data is implicitly allocated 1 character longer than length(), as it is zero-terminated.
// CStringBuffer is an immutable ref-counted storage for the characters in a
// CString. It's analogous to a StringImpl but may contain any arbitrary
// sequence of bytes. The data is always allocated 1 longer than length() and is
// null terminated.
// TODO(esprehn): Rename to CStringImpl.
class WTF_EXPORT CStringBuffer : public RefCounted<CStringBuffer> {
WTF_MAKE_NONCOPYABLE(CStringBuffer);
public:
const char* data() { return mutableData(); }
size_t length() const { return m_length; }
private:
friend class CString;
friend class RefCounted<CStringBuffer>;
// CStringBuffers are allocated out of the WTF buffer partition.
void* operator new(size_t, void* ptr) { return ptr; }
void operator delete(void*);
static PassRefPtr<CStringBuffer> createUninitialized(size_t length);
static PassRefPtr<CStringBuffer> createUninitialized(size_t length, char*& data);
CStringBuffer(size_t length) : m_length(length) { }
char* mutableData() { return reinterpret_cast<char*>(this + 1); }
const char* data() const { return reinterpret_cast<const char*>(this + 1); }
size_t length() const { return m_length; }
private:
explicit CStringBuffer(size_t length)
: m_length(length) {}
const unsigned m_length;
};
// A container for a null-terminated char array supporting copy-on-write
// assignment. The contained char array may be null.
// A container for an immutable ref-counted null-terminated char array. This is
// analogous to a WTF::String but does not require the contained bytes to be
// valid Latin1 or UTF-16. Instead a CString can contain any arbitrary bytes.
class WTF_EXPORT CString {
USING_FAST_MALLOC(CString);
public:
CString() { }
CString(const char*);
// Construct a null string, distinguishable from an empty string.
CString() {}
// Construct a string from arbitrary bytes.
CString(const char* chars)
: CString(chars, chars ? strlen(chars) : 0) {}
CString(const char*, size_t length);
CString(CStringBuffer* buffer) : m_buffer(buffer) { }
static CString newUninitialized(size_t length, char*& characterBuffer);
const char* data() const
{
return m_buffer ? m_buffer->data() : 0;
}
char* mutableData();
size_t length() const
// Construct a string referencing an existing buffer.
CString(CStringBuffer* buffer)
: m_buffer(buffer) {}
CString(PassRefPtr<CStringBuffer> buffer)
: m_buffer(buffer) {}
// TODO(esprehn): Rename to createUninitialized.
static CString newUninitialized(size_t length, char*& data)
{
return m_buffer ? m_buffer->length() : 0;
return CStringBuffer::createUninitialized(length, data);
}
// The bytes of the string, always NUL terminated. May be null.
const char* data() const { return m_buffer ? m_buffer->data() : 0; }
// The length of the data(), *not* including the NUL terminator.
size_t length() const { return m_buffer ? m_buffer->length() : 0; }
bool isNull() const { return !m_buffer; }
bool isSafeToSendToAnotherThread() const;
// TODO(esprehn): Rename to impl() when CStringBuffer is renamed.
CStringBuffer* buffer() const { return m_buffer.get(); }
private:
void copyBufferIfNeeded();
void init(const char*, size_t length);
RefPtr<CStringBuffer> m_buffer;
};
......@@ -91,6 +105,7 @@ WTF_EXPORT bool operator==(const CString& a, const CString& b);
inline bool operator!=(const CString& a, const CString& b) { return !(a == b); }
WTF_EXPORT bool operator==(const CString& a, const char* b);
inline bool operator!=(const CString& a, const char* b) { return !(a == b); }
// Pretty printer for gtest and base/logging.*. It prepends and appends
// double-quotes, and escapes characters other than ASCII printables.
WTF_EXPORT std::ostream& operator<<(std::ostream&, const CString&);
......
......@@ -111,18 +111,6 @@ TEST(CStringTest, ZeroTerminated)
EXPECT_EQ(0, stringWithLength.data()[3]);
}
TEST(CStringTest, CopyOnWrite)
{
const char* initialString = "Webkit";
CString string(initialString);
CString copy = string;
string.mutableData()[3] = 'K';
EXPECT_TRUE(string != copy);
EXPECT_STREQ("WebKit", string.data());
EXPECT_STREQ(initialString, copy.data());
}
TEST(CStringTest, Comparison)
{
// Comparison with another CString.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment