Bug 1329019 - Allow specifying capacity to Vector::replaceRawBuffer (r=froydnj)
authorLuke Wagner <luke@mozilla.com>
Fri, 22 Sep 2017 10:34:24 -0500
changeset 435755 fd601c9bcd000f7352079cebde25c508cc62a56d
parent 435754 55b6ce9eb26d200c093ed9ee8c964580662745ad
child 435756 1f23975f1d1f2416955226d1cfcfb87c5702329c
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1329019
milestone58.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 1329019 - Allow specifying capacity to Vector::replaceRawBuffer (r=froydnj) MozReview-Commit-ID: 9Eq6PR53n4i
mfbt/Vector.h
mfbt/tests/TestVector.cpp
--- a/mfbt/Vector.h
+++ b/mfbt/Vector.h
@@ -779,16 +779,27 @@ public:
   MOZ_MUST_USE T* extractOrCopyRawBuffer();
 
   /**
    * Transfer ownership of an array of objects into the vector.  The caller
    * must have allocated the array in accordance with this vector's
    * AllocPolicy.
    *
    * N.B. This call assumes that there are no uninitialized elements in the
+   *      passed range [aP, aP + aLength). The range [aP + aLength, aP +
+   *      aCapacity) must be allocated uninitialized memory.
+   */
+  void replaceRawBuffer(T* aP, size_t aLength, size_t aCapacity);
+
+  /**
+   * Transfer ownership of an array of objects into the vector.  The caller
+   * must have allocated the array in accordance with this vector's
+   * AllocPolicy.
+   *
+   * N.B. This call assumes that there are no uninitialized elements in the
    *      passed array.
    */
   void replaceRawBuffer(T* aP, size_t aLength);
 
   /**
    * Places |aVal| at position |aP|, shifting existing elements from |aP| onward
    * one position higher.  On success, |aP| should not be reused because it'll
    * be a dangling pointer if reallocation of the vector storage occurred; the
@@ -1488,50 +1499,57 @@ Vector<T, N, AP>::extractOrCopyRawBuffer
 #ifdef DEBUG
   mTail.mReserved = 0;
 #endif
   return copy;
 }
 
 template<typename T, size_t N, class AP>
 inline void
-Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength)
+Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength, size_t aCapacity)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
 
   /* Destroy what we have. */
   Impl::destroy(beginNoCheck(), endNoCheck());
   if (!usingInlineStorage()) {
     this->free_(beginNoCheck());
   }
 
   /* Take in the new buffer. */
-  if (aLength <= kInlineCapacity) {
+  if (aCapacity <= kInlineCapacity) {
     /*
      * We convert to inline storage if possible, even though aP might
      * otherwise be acceptable.  Maybe this behaviour should be
      * specifiable with an argument to this function.
      */
     mBegin = inlineStorage();
     mLength = aLength;
     mTail.mCapacity = kInlineCapacity;
     Impl::moveConstruct(mBegin, aP, aP + aLength);
     Impl::destroy(aP, aP + aLength);
     this->free_(aP);
   } else {
     mBegin = aP;
     mLength = aLength;
-    mTail.mCapacity = aLength;
+    mTail.mCapacity = aCapacity;
   }
 #ifdef DEBUG
-  mTail.mReserved = aLength;
+  mTail.mReserved = aCapacity;
 #endif
 }
 
 template<typename T, size_t N, class AP>
+inline void
+Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength)
+{
+  replaceRawBuffer(aP, aLength, aLength);
+}
+
+template<typename T, size_t N, class AP>
 inline size_t
 Vector<T, N, AP>::sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return usingInlineStorage() ? 0 : aMallocSizeOf(beginNoCheck());
 }
 
 template<typename T, size_t N, class AP>
 inline size_t
--- a/mfbt/tests/TestVector.cpp
+++ b/mfbt/tests/TestVector.cpp
@@ -17,16 +17,17 @@ using mozilla::Vector;
 struct mozilla::detail::VectorTesting
 {
   static void testReserved();
   static void testConstRange();
   static void testEmplaceBack();
   static void testReverse();
   static void testExtractRawBuffer();
   static void testExtractOrCopyRawBuffer();
+  static void testReplaceRawBuffer();
   static void testInsert();
   static void testPodResizeToFit();
 };
 
 void
 mozilla::detail::VectorTesting::testReserved()
 {
 #ifdef DEBUG
@@ -353,16 +354,84 @@ mozilla::detail::VectorTesting::testExtr
     MOZ_RELEASE_ASSERT(buf[i].j == i);
     MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
   }
 
   free(buf);
 }
 
 void
+mozilla::detail::VectorTesting::testReplaceRawBuffer()
+{
+  S::resetCounts();
+
+  S* s = nullptr;
+
+  {
+    Vector<S> v;
+    MOZ_RELEASE_ASSERT(v.reserve(4));
+    v.infallibleEmplaceBack(1, 2);
+    v.infallibleEmplaceBack(3, 4);
+    MOZ_ASSERT(S::constructCount == 2);
+    s = v.extractRawBuffer();
+  }
+
+  MOZ_ASSERT(S::constructCount == 2);
+  MOZ_ASSERT(S::moveCount == 0);
+  MOZ_ASSERT(S::destructCount == 0);
+
+  {
+    Vector<S, 10> v;
+    v.replaceRawBuffer(s, 2);
+    MOZ_ASSERT(v.length() == 2);
+    MOZ_ASSERT(v.reserved() == 2);
+    MOZ_ASSERT(v.capacity() == 10);
+    MOZ_ASSERT(v[0].j == 1);
+    MOZ_ASSERT(v[1].j == 3);
+    MOZ_ASSERT(S::destructCount == 2);
+  }
+
+  MOZ_ASSERT(S::constructCount == 2);
+  MOZ_ASSERT(S::moveCount == 2);
+  MOZ_ASSERT(S::destructCount == 4);
+
+  S::resetCounts();
+
+  {
+    Vector<S, 2> v;
+    MOZ_RELEASE_ASSERT(v.reserve(4));
+    v.infallibleEmplaceBack(9, 10);
+    MOZ_ASSERT(S::constructCount == 1);
+    s = v.extractRawBuffer();
+    MOZ_ASSERT(S::constructCount == 1);
+    MOZ_ASSERT(S::moveCount == 0);
+  }
+
+  MOZ_ASSERT(S::destructCount == 0);
+
+  {
+    Vector<S> v;
+    v.replaceRawBuffer(s, 1, 4);
+    MOZ_ASSERT(v.length() == 1);
+    MOZ_ASSERT(v.reserved() == 4);
+    MOZ_ASSERT(v.capacity() == 4);
+    MOZ_ASSERT(v[0].j == 9);
+    for (size_t i = 0; i < 5; i++)
+      MOZ_RELEASE_ASSERT(v.emplaceBack(i, i));
+    MOZ_ASSERT(v.length() == 6);
+    MOZ_ASSERT(v.reserved() == 6);
+    MOZ_ASSERT(S::constructCount == 6);
+    MOZ_ASSERT(S::moveCount == 4);
+    MOZ_ASSERT(S::destructCount == 4);
+  }
+
+  MOZ_ASSERT(S::destructCount == 10);
+}
+
+void
 mozilla::detail::VectorTesting::testInsert()
 {
   S::resetCounts();
 
   Vector<S, 8> vec;
   MOZ_RELEASE_ASSERT(vec.reserve(8));
   for (size_t i = 0; i < 7; i++) {
     vec.infallibleEmplaceBack(i, i * i);
@@ -473,11 +542,12 @@ int
 main()
 {
   VectorTesting::testReserved();
   VectorTesting::testConstRange();
   VectorTesting::testEmplaceBack();
   VectorTesting::testReverse();
   VectorTesting::testExtractRawBuffer();
   VectorTesting::testExtractOrCopyRawBuffer();
+  VectorTesting::testReplaceRawBuffer();
   VectorTesting::testInsert();
   VectorTesting::testPodResizeToFit();
 }