Bug 638031 Allow string streams to share their string buffer r=bsmedberg f=bz
authorNeil Rashbrook <neil@parkwaycc.co.uk>
Tue, 01 Nov 2011 08:28:31 +0000
changeset 79467 f79946f0bb2a2cc3f33ba537e4edb2335de936a5
parent 79466 67d1049b0bf9d6e67370d8767695df5569e0d67a
child 79472 6e219763ddd0f9519f7b2a99c52694507f89b043
push id21406
push userneil@parkwaycc.co.uk
push dateTue, 01 Nov 2011 08:29:45 +0000
treeherdermozilla-central@f79946f0bb2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs638031
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 638031 Allow string streams to share their string buffer r=bsmedberg f=bz
xpcom/io/nsStringStream.cpp
--- a/xpcom/io/nsStringStream.cpp
+++ b/xpcom/io/nsStringStream.cpp
@@ -79,48 +79,46 @@ public:
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSISTRINGINPUTSTREAM
     NS_DECL_NSISEEKABLESTREAM
     NS_DECL_NSISUPPORTSPRIMITIVE
     NS_DECL_NSISUPPORTSCSTRING
     NS_DECL_NSIIPCSERIALIZABLE
 
     nsStringInputStream()
-        : mData(nsnull)
-        , mOffset(0)
-        , mLength(0)
-        , mOwned(false)
-    {}
+    {
+        Clear();
+    }
 
 private:
     ~nsStringInputStream()
+    {}
+
+    PRUint32 Length() const
     {
-        if (mData)
-            Clear();
+        return mData.Length();
     }
 
-    PRInt32 LengthRemaining() const
+    PRUint32 LengthRemaining() const
     {
-        return mLength - mOffset;
+        return Length() - mOffset;
     }
 
     void Clear()
     {
-        NS_ASSERTION(mData || !mOwned, "bad state");
-        if (mOwned)
-            NS_Free(const_cast<char*>(mData));
-
-        // We're about to get a new string; reset the offset.
-        mOffset = 0;
+        mData.SetIsVoid(true);
     }
 
-    const char*    mData;
-    PRUint32       mOffset;
-    PRUint32       mLength;
-    bool           mOwned;
+    bool Closed()
+    {
+        return mData.IsVoid();
+    }
+
+    nsDependentCSubstring mData;
+    PRUint32 mOffset;
 };
 
 // This class needs to support threadsafe refcounting since people often
 // allocate a string stream, and then read it from a background thread.
 NS_IMPL_THREADSAFE_ADDREF(nsStringInputStream)
 NS_IMPL_THREADSAFE_RELEASE(nsStringInputStream)
 
 NS_IMPL_CLASSINFO(nsStringInputStream, NULL, nsIClassInfo::THREADSAFE,
@@ -150,28 +148,28 @@ nsStringInputStream::GetType(PRUint16 *t
 }
 
 NS_IMETHODIMP
 nsStringInputStream::GetData(nsACString &data)
 {
     // The stream doesn't have any data when it is closed.  We could fake it
     // and return an empty string here, but it seems better to keep this return
     // value consistent with the behavior of the other 'getter' methods.
-    NS_ENSURE_TRUE(mData, NS_BASE_STREAM_CLOSED);
+    NS_ENSURE_TRUE(!Closed(), NS_BASE_STREAM_CLOSED);
 
-    data.Assign(mData, mLength);
+    data.Assign(mData);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::SetData(const nsACString &data)
 {
-    nsACString::const_iterator iter;
-    data.BeginReading(iter);
-    return SetData(iter.get(), iter.size_forward());
+    mData.Assign(data);
+    mOffset = 0;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::ToString(char **result)
 {
     // NOTE: This method may result in data loss, so we do not implement it.
     return NS_ERROR_NOT_IMPLEMENTED;
 }
@@ -179,83 +177,60 @@ nsStringInputStream::ToString(char **res
 /////////
 // nsIStringInputStream implementation
 /////////
 
 NS_IMETHODIMP
 nsStringInputStream::SetData(const char *data, PRInt32 dataLen)
 {
     NS_ENSURE_ARG_POINTER(data);
-
-    if (dataLen < 0)
-        dataLen = strlen(data);
-
-    // NOTE: We do not use nsCRT::strndup here because that does not handle
-    // null bytes in the middle of the given data.
- 
-    char *copy = static_cast<char *>(NS_Alloc(dataLen));
-    if (!copy)
-        return NS_ERROR_OUT_OF_MEMORY;
-    memcpy(copy, data, dataLen);
-
-    return AdoptData(copy, dataLen);
+    mData.Assign(data, dataLen);
+    mOffset = 0;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::AdoptData(char *data, PRInt32 dataLen)
 {
     NS_ENSURE_ARG_POINTER(data);
-
-    if (dataLen < 0)
-        dataLen = strlen(data);
-
-    Clear();
-    
-    mData = data;
-    mLength = dataLen;
-    mOwned = true;
+    mData.Adopt(data, dataLen);
+    mOffset = 0;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::ShareData(const char *data, PRInt32 dataLen)
 {
     NS_ENSURE_ARG_POINTER(data);
 
     if (dataLen < 0)
         dataLen = strlen(data);
 
-    Clear();
-    
-    mData = data;
-    mLength = dataLen;
-    mOwned = false;
+    mData.Rebind(data, data + dataLen);
+    mOffset = 0;
     return NS_OK;
 }
 
 /////////
 // nsIInputStream implementation
 /////////
 
 NS_IMETHODIMP
 nsStringInputStream::Close()
 {
     Clear();
-    mData = nsnull;
-    mLength = 0;
-    mOwned = false;
     return NS_OK;
 }
     
 NS_IMETHODIMP
 nsStringInputStream::Available(PRUint32 *aLength)
 {
     NS_ASSERTION(aLength, "null ptr");
 
-    if (!mData)
+    if (Closed())
         return NS_BASE_STREAM_CLOSED;
 
     *aLength = LengthRemaining();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount)
@@ -264,29 +239,31 @@ nsStringInputStream::Read(char* aBuf, PR
     return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
 }
 
 NS_IMETHODIMP
 nsStringInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
                                   PRUint32 aCount, PRUint32 *result)
 {
     NS_ASSERTION(result, "null ptr");
-    NS_ASSERTION(mLength >= mOffset, "bad stream state");
+    NS_ASSERTION(Length() >= mOffset, "bad stream state");
+
+    if (Closed())
+        return NS_BASE_STREAM_CLOSED;
 
     // We may be at end-of-file
     PRUint32 maxCount = LengthRemaining();
     if (maxCount == 0) {
         *result = 0;
         return NS_OK;
     }
-    NS_ASSERTION(mData, "must have data if maxCount != 0");
 
     if (aCount > maxCount)
         aCount = maxCount;
-    nsresult rv = writer(this, closure, mData + mOffset, 0, aCount, result);
+    nsresult rv = writer(this, closure, mData.BeginReading() + mOffset, 0, aCount, result);
     if (NS_SUCCEEDED(rv)) {
         NS_ASSERTION(*result <= aCount,
                      "writer should not write more than we asked it to write");
         mOffset += *result;
     }
 
     // errors returned from the writer end here!
     return NS_OK;
@@ -301,95 +278,90 @@ nsStringInputStream::IsNonBlocking(bool 
 
 /////////
 // nsISeekableStream implementation
 /////////
 
 NS_IMETHODIMP 
 nsStringInputStream::Seek(PRInt32 whence, PRInt64 offset)
 {
-    if (!mData)
+    if (Closed())
         return NS_BASE_STREAM_CLOSED;
 
     // Compute new stream position.  The given offset may be a negative value.
  
     PRInt64 newPos = offset;
     switch (whence) {
     case NS_SEEK_SET:
         break;
     case NS_SEEK_CUR:
-        newPos += (PRInt32) mOffset;
+        newPos += mOffset;
         break;
     case NS_SEEK_END:
-        newPos += (PRInt32) mLength;
+        newPos += Length();
         break;
     default:
         NS_ERROR("invalid whence");
         return NS_ERROR_INVALID_ARG;
     }
 
-    // mLength is never larger than PR_INT32_MAX due to the way it is assigned.
+    NS_ENSURE_ARG(newPos >= 0);
+    NS_ENSURE_ARG(newPos <= Length());
 
-    NS_ENSURE_ARG(newPos >= 0);
-    NS_ENSURE_ARG(newPos <= (PRInt32) mLength);
-
-    mOffset = (PRInt32) newPos;
+    mOffset = (PRUint32)newPos;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::Tell(PRInt64* outWhere)
 {
-    if (!mData)
+    if (Closed())
         return NS_BASE_STREAM_CLOSED;
 
     *outWhere = mOffset;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::SetEOF()
 {
-    if (!mData)
+    if (Closed())
         return NS_BASE_STREAM_CLOSED;
 
-    mLength = mOffset;
+    mOffset = Length();
     return NS_OK;
 }
 
 /////////
 // nsIIPCSerializable implementation
 /////////
 
 bool
 nsStringInputStream::Read(const IPC::Message *aMsg, void **aIter)
 {
     using IPC::ReadParam;
 
-    nsCAutoString value;
+    nsCString value;
 
     if (!ReadParam(aMsg, aIter, &value))
         return false;
 
-    nsresult rv = SetData(value.get(), value.Length());
+    nsresult rv = SetData(value);
     if (NS_FAILED(rv))
         return false;
 
     return true;
 }
 
 void
 nsStringInputStream::Write(IPC::Message *aMsg)
 {
     using IPC::WriteParam;
 
-    nsCAutoString value;
-    GetData(value);
-
-    WriteParam(aMsg, value);
+    WriteParam(aMsg, static_cast<const nsCString&>(PromiseFlatCString(mData)));
 }
 
 nsresult
 NS_NewByteInputStream(nsIInputStream** aStreamResult,
                       const char* aStringToRead, PRInt32 aLength,
                       nsAssignmentType aAssignment)
 {
     NS_PRECONDITION(aStreamResult, "null out ptr");
@@ -424,37 +396,36 @@ NS_NewByteInputStream(nsIInputStream** a
     *aStreamResult = stream;
     return NS_OK;
 }
 
 nsresult
 NS_NewStringInputStream(nsIInputStream** aStreamResult,
                         const nsAString& aStringToRead)
 {
-    char* data = ToNewCString(aStringToRead);  // truncates high-order bytes
-    if (!data)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    nsresult rv = NS_NewByteInputStream(aStreamResult, data,
-                                        aStringToRead.Length(),
-                                        NS_ASSIGNMENT_ADOPT);
-    if (NS_FAILED(rv))
-        NS_Free(data);
-    return rv;
+    NS_LossyConvertUTF16toASCII data(aStringToRead); // truncates high-order bytes
+    return NS_NewCStringInputStream(aStreamResult, data);
 }
 
 nsresult
 NS_NewCStringInputStream(nsIInputStream** aStreamResult,
                          const nsACString& aStringToRead)
 {
-    nsACString::const_iterator data;
-    aStringToRead.BeginReading(data);
+    NS_PRECONDITION(aStreamResult, "null out ptr");
+
+    nsStringInputStream* stream = new nsStringInputStream();
+    if (! stream)
+        return NS_ERROR_OUT_OF_MEMORY;
 
-    return NS_NewByteInputStream(aStreamResult, data.get(), data.size_forward(),
-                                 NS_ASSIGNMENT_COPY);
+    NS_ADDREF(stream);
+
+    stream->SetData(aStringToRead);
+
+    *aStreamResult = stream;
+    return NS_OK;
 }
 
 // factory method for constructing a nsStringInputStream object
 nsresult
 nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
 {
     *result = nsnull;