Bug 1264642 - Part 1. Add CopyRawBuffer and InfallibleCopyRawBuffer to SegmentedVector
authorKan-Ru Chen <kanru@kanru.info>
Mon, 09 May 2016 14:56:09 +0800
changeset 758175 dcc20fca52700779e55243606ca09f763e7928cd
parent 752174 77cead2cd20300623eea2416bc9bce4d5021df09
child 758176 97ce9dbc8ecf8a213800738a64be8eab8e1770ee
push id123868
push userkchen@mozilla.com
push dateTue, 10 May 2016 09:29:59 +0000
treeherdertry@95a6d9ef691d [default view] [failures only]
bugs1264642
milestone49.0a1
Bug 1264642 - Part 1. Add CopyRawBuffer and InfallibleCopyRawBuffer to SegmentedVector Returns a copy of the elements in a contiguous buffer. The caller owns the returned buffer and is responsible for deallocating it consistent with the AllocPolicy. MozReview-Commit-ID: 1D1Agkmg7Mf
mfbt/SegmentedVector.h
mfbt/tests/TestSegmentedVector.cpp
--- a/mfbt/SegmentedVector.h
+++ b/mfbt/SegmentedVector.h
@@ -178,16 +178,52 @@ public:
   // infallible allocation policy. It will crash if the allocation fails.
   template<typename U>
   void InfallibleAppend(U&& aU)
   {
     bool ok = Append(mozilla::Forward<U>(aU));
     MOZ_RELEASE_ASSERT(ok);
   }
 
+  // Returns a copy of the elements in a contiguous buffer. The caller
+  // owns the returned buffer and is responsible for deallocating it
+  // consistent with the AllocPolicy.
+  //
+  // Returns nullptr if the allocation failed. (If you are using an
+  // infallible allocation policy, use InfallibleCopyRawBuffer()
+  // instead.)
+  MOZ_MUST_USE T* CopyRawBuffer()
+  {
+    T* copy = this->template pod_malloc<T>(Length());
+    if (!copy) {
+      return nullptr;
+    }
+
+    T* dst = copy;
+    for (auto segment = mSegments.getFirst();
+         segment;
+         segment = segment->getNext()) {
+      for (uint32_t i = 0; i < segment->Length(); i++) {
+        new (dst) T((*segment)[i]);
+        dst++;
+      }
+    }
+    return copy;
+  }
+
+  // You should probably only use this instead of CopyRawBuffer() if you are
+  // using an infallible allocation policy. It will crash if the allocation
+  // fails.
+  MOZ_MUST_USE T* InfallibleCopyRawBuffer()
+  {
+    T* copy = CopyRawBuffer();
+    MOZ_RELEASE_ASSERT(copy);
+    return copy;
+  }
+
   void Clear()
   {
     Segment* segment;
     while ((segment = mSegments.popFirst())) {
       segment->~Segment();
       this->free_(segment);
     }
   }
--- a/mfbt/tests/TestSegmentedVector.cpp
+++ b/mfbt/tests/TestSegmentedVector.cpp
@@ -43,16 +43,17 @@ static int gDummy;
 
 // This tests basic segmented vector construction and iteration.
 void TestBasics()
 {
   // A SegmentedVector with a POD element type.
   typedef SegmentedVector<int, 1024, InfallibleAllocPolicy> MyVector;
   MyVector v;
   int i, n;
+  int* copy;
 
   MOZ_RELEASE_ASSERT(v.IsEmpty());
 
   // Add 100 elements, then check various things.
   i = 0;
   for ( ; i < 100; i++) {
     gDummy = v.Append(mozilla::Move(i));
   }
@@ -61,30 +62,44 @@ void TestBasics()
 
   n = 0;
   for (auto iter = v.Iter(); !iter.Done(); iter.Next()) {
     MOZ_RELEASE_ASSERT(iter.Get() == n);
     n++;
   }
   MOZ_RELEASE_ASSERT(n == 100);
 
+  copy = v.InfallibleCopyRawBuffer();
+  i = 0;
+  for ( ; i < 100; i++) {
+    MOZ_RELEASE_ASSERT(copy[i] == i);
+  }
+  free(copy);
+
   // Add another 900 elements, then re-check.
   for ( ; i < 1000; i++) {
     v.InfallibleAppend(mozilla::Move(i));
   }
   MOZ_RELEASE_ASSERT(!v.IsEmpty());
   MOZ_RELEASE_ASSERT(v.Length() == 1000);
 
   n = 0;
   for (auto iter = v.Iter(); !iter.Done(); iter.Next()) {
     MOZ_RELEASE_ASSERT(iter.Get() == n);
     n++;
   }
   MOZ_RELEASE_ASSERT(n == 1000);
 
+  copy = v.InfallibleCopyRawBuffer();
+  i = 0;
+  for ( ; i < 1000; i++) {
+    MOZ_RELEASE_ASSERT(copy[i] == i);
+  }
+  free(copy);
+
   // Pop off all of the elements.
   MOZ_RELEASE_ASSERT(v.Length() == 1000);
   for (int len = (int)v.Length(); len > 0; len--) {
     MOZ_RELEASE_ASSERT(v.GetLast() == len - 1);
     v.PopLast();
   }
   MOZ_RELEASE_ASSERT(v.IsEmpty());
   MOZ_RELEASE_ASSERT(v.Length() == 0);
@@ -159,16 +174,20 @@ void TestConstructorsAndDestructors()
     NonPOD y(1);                          // explicit constructor called
     explicitCtorCalls++;
     gDummy = v.Append(mozilla::Move(y));  // move constructor called
     moveCtorCalls++;
     NonPOD z(1);                          // explicit constructor called
     explicitCtorCalls++;
     v.InfallibleAppend(mozilla::Move(z)); // move constructor called
     moveCtorCalls++;
+    NonPOD* copy = v.InfallibleCopyRawBuffer();
+    copyCtorCalls += 3;                   // copy constructor called 2 times
+    MOZ_RELEASE_ASSERT(gNumCopyCtors == copyCtorCalls);
+    free(copy);
     v.PopLast();                          // destructor called 1 time
     dtorCalls++;
     MOZ_RELEASE_ASSERT(gNumDtors == dtorCalls);
     v.Clear();                            // destructor called 2 times
     dtorCalls += 2;
 
     // Test that PopLastN() correctly calls the destructors of all the
     // elements in the segments it destroys.