Bug 1551962. Add a way to create an input stream from a moved nsTArray<uint8_t>. r=froydnj
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 15 May 2019 18:28:00 +0000
changeset 532804 3300402f42393d2682e2143b886776df57c95abf
parent 532803 4275e29bc6a60262209a287acb7f9d6d3b6bc4a0
child 532805 03289d31269dd6a6bcf5adf9e236d4363a70f2ac
push id11272
push userapavel@mozilla.com
push dateThu, 16 May 2019 15:28:22 +0000
treeherdermozilla-beta@2265bfc5920d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1551962
milestone68.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 1551962. Add a way to create an input stream from a moved nsTArray<uint8_t>. r=froydnj Differential Revision: https://phabricator.services.mozilla.com/D31296
xpcom/io/nsStringStream.cpp
xpcom/io/nsStringStream.h
--- a/xpcom/io/nsStringStream.cpp
+++ b/xpcom/io/nsStringStream.cpp
@@ -17,16 +17,17 @@
 #include "nsISeekableStream.h"
 #include "nsISupportsPrimitives.h"
 #include "nsCRT.h"
 #include "prerror.h"
 #include "plstr.h"
 #include "nsIClassInfoImpl.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ipc/InputStreamUtils.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "XPCOMModule.h"
 
 using namespace mozilla::ipc;
 using mozilla::Maybe;
 using mozilla::Some;
 
@@ -49,16 +50,18 @@ class nsStringInputStream final : public
   NS_DECL_NSISUPPORTSCSTRING
   NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
   NS_DECL_NSICLONEABLEINPUTSTREAM
 
   nsStringInputStream() : mOffset(0), mMon("nsStringInputStream") { Clear(); }
 
   nsresult Init(nsCString&& aString);
 
+  nsresult Init(nsTArray<uint8_t>&& aArray);
+
  private:
   ~nsStringInputStream() {}
 
   template <typename M>
   void SerializeInternal(InputStreamParams& aParams, bool aDelayedStart,
                          uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager);
 
   uint32_t Length() const { return mData.Length(); }
@@ -67,30 +70,52 @@ class nsStringInputStream final : public
 
   void Clear() { mData.SetIsVoid(true); }
 
   bool Closed() { return mData.IsVoid(); }
 
   nsDependentCSubstring mData;
   uint32_t mOffset;
 
+  // If we were initialized from an nsTArray, we store its data here.
+  Maybe<nsTArray<uint8_t>> mArray;
+
   mozilla::ReentrantMonitor mMon;
 };
 
 nsresult nsStringInputStream::Init(nsCString&& aString) {
   ReentrantMonitorAutoEnter lock(mMon);
 
+  mArray.reset();
   if (!mData.Assign(std::move(aString), fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mOffset = 0;
   return NS_OK;
 }
 
+nsresult nsStringInputStream::Init(nsTArray<uint8_t>&& aArray) {
+  ReentrantMonitorAutoEnter lock(mMon);
+
+  mArray.reset();
+  mArray.emplace(std::move(aArray));
+  mOffset = 0;
+
+  if (mArray->IsEmpty()) {
+    // Not sure it's safe to Rebind() with a null pointer.  Pretty
+    // sure it's not, in fact.
+    mData.Truncate();
+  } else {
+    mData.Rebind(reinterpret_cast<const char*>(mArray->Elements()),
+                 mArray->Length());
+  }
+  return NS_OK;
+}
+
 // This class needs to support threadsafe refcounting since people often
 // allocate a string stream, and then read it from a background thread.
 NS_IMPL_ADDREF(nsStringInputStream)
 NS_IMPL_RELEASE(nsStringInputStream)
 
 NS_IMPL_CLASSINFO(nsStringInputStream, nullptr, nsIClassInfo::THREADSAFE,
                   NS_STRINGINPUTSTREAM_CID)
 NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream, nsIStringInputStream,
@@ -127,16 +152,17 @@ nsStringInputStream::GetData(nsACString&
   data.Assign(mData);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::SetData(const nsACString& aData) {
   ReentrantMonitorAutoEnter lock(mMon);
 
+  mArray.reset();
   if (NS_WARN_IF(!mData.Assign(aData, fallible))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mOffset = 0;
   return NS_OK;
 }
 
@@ -153,44 +179,47 @@ nsStringInputStream::ToString(char** aRe
 NS_IMETHODIMP
 nsStringInputStream::SetData(const char* aData, int32_t aDataLen) {
   ReentrantMonitorAutoEnter lock(mMon);
 
   if (NS_WARN_IF(!aData)) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  mArray.reset();
   if (NS_WARN_IF(!mData.Assign(aData, aDataLen, fallible))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mOffset = 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::AdoptData(char* aData, int32_t aDataLen) {
   ReentrantMonitorAutoEnter lock(mMon);
 
   if (NS_WARN_IF(!aData)) {
     return NS_ERROR_INVALID_ARG;
   }
+  mArray.reset();
   mData.Adopt(aData, aDataLen);
   mOffset = 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStringInputStream::ShareData(const char* aData, int32_t aDataLen) {
   ReentrantMonitorAutoEnter lock(mMon);
 
   if (NS_WARN_IF(!aData)) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  mArray.reset();
   if (aDataLen < 0) {
     aDataLen = strlen(aData);
   }
 
   mData.Rebind(aData, aDataLen);
   mOffset = 0;
   return NS_OK;
 }
@@ -481,16 +510,31 @@ nsresult NS_NewByteInputStream(nsIInputS
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   stream.forget(aStreamResult);
   return NS_OK;
 }
 
+nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
+                               nsTArray<uint8_t>&& aArray) {
+  MOZ_ASSERT(aStreamResult, "null out ptr");
+
+  RefPtr<nsStringInputStream> stream = new nsStringInputStream();
+
+  nsresult rv = stream->Init(std::move(aArray));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  stream.forget(aStreamResult);
+  return NS_OK;
+}
+
 nsresult NS_NewCStringInputStream(nsIInputStream** aStreamResult,
                                   const nsACString& aStringToRead) {
   MOZ_ASSERT(aStreamResult, "null out ptr");
 
   RefPtr<nsStringInputStream> stream = new nsStringInputStream();
 
   nsresult rv = stream->SetData(aStringToRead);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/xpcom/io/nsStringStream.h
+++ b/xpcom/io/nsStringStream.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsStringStream_h__
 #define nsStringStream_h__
 
 #include "nsIStringStream.h"
 #include "nsString.h"
 #include "nsMemory.h"
+#include "nsTArray.h"
 
 /**
  * Implements:
  *   nsIStringInputStream
  *   nsIInputStream
  *   nsISeekableStream
  *   nsITellableStream
  *   nsISupportsCString
@@ -38,25 +39,32 @@
  * If aAssignment is NS_ASSIGNMENT_DEPEND, then the resulting stream refers
  * directly to the given buffer (aStringToRead), so the caller must ensure that
  * the buffer remains valid for the lifetime of the stream object.  Use with
  * care!!
  *
  * If aAssignment is NS_ASSIGNMENT_ADOPT, then the resulting stream refers
  * directly to the given buffer (aStringToRead) and will free aStringToRead
  * once the stream is closed.
- *
- * If aLength is less than zero, then the length of aStringToRead will be
- * determined by scanning the buffer for the first null byte.
  */
 extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
                                       mozilla::Span<const char> aStringToRead,
                                       nsAssignmentType aAssignment);
 
 /**
+ * Factory method to get an nsIInputStream from an nsTArray representing a byte
+ * buffer.  This will take ownership of the data and empty out the nsTArray.
+ *
+ * Result will implement nsIStringInputStream, nsITellableStream and
+ * nsISeekableStream.
+ */
+extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
+                                      nsTArray<uint8_t>&& aArray);
+
+/**
  * Factory method to get an nsInputStream from an nsACString.  Result will
  * implement nsIStringInputStream, nsTellableStream and nsISeekableStream.
  */
 extern nsresult NS_NewCStringInputStream(nsIInputStream** aStreamResult,
                                          const nsACString& aStringToRead);
 extern nsresult NS_NewCStringInputStream(nsIInputStream** aStreamResult,
                                          nsCString&& aStringToRead);