Bug 1264642 - Part 3. Add BufferList::MoveFallible. r=billm
☠☠ backed out by b25d09b7fab5 ☠ ☠
authorKan-Ru Chen <kanru@kanru.info>
Thu, 14 Jul 2016 16:27:29 +0800
changeset 353198 9f434697ef2ecece5b93ad07093b85667d2018e3
parent 353197 06fc278fcedf5fa20ec0b569643933cb3fc71983
child 353199 7c60fc4144fb682ae99c4068464fddf69791834f
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1264642
milestone51.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 1264642 - Part 3. Add BufferList::MoveFallible. r=billm It works like a move constructor but it's fallible. It can also move data to different but compatible AllocPolicy. MozReview-Commit-ID: LAbPWCwnrr6
mfbt/BufferList.h
mfbt/tests/TestBufferList.cpp
--- a/mfbt/BufferList.h
+++ b/mfbt/BufferList.h
@@ -47,16 +47,19 @@ class BufferList : private AllocPolicy
 
     Segment(Segment&&) = default;
     Segment& operator=(Segment&&) = default;
 
     char* Start() const { return mData; }
     char* End() const { return mData + mSize; }
   };
 
+  template<typename OtherAllocPolicy>
+  friend class BufferList;
+
  public:
   // For the convenience of callers, all segments are required to be a multiple
   // of 8 bytes in capacity. Also, every buffer except the last one is required
   // to be full (i.e., size == capacity). Therefore, a byte at offset N within
   // the BufferList and stored in memory at an address A will satisfy
   // (N % Align == A % Align) if Align == 2, 4, or 8.
   //
   // NB: FlattenBytes can create non-full segments in the middle of the
@@ -253,16 +256,25 @@ class BufferList : private AllocPolicy
   // aIter. Borrow can fail, in which case *aSuccess will be false upon
   // return. The borrowed BufferList can use a different AllocPolicy than the
   // original one. However, it is not responsible for freeing buffers, so the
   // AllocPolicy is only used for the buffer vector.
   template<typename BorrowingAllocPolicy>
   BufferList<BorrowingAllocPolicy> Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
                                           BorrowingAllocPolicy aAP = BorrowingAllocPolicy());
 
+  // Return a new BufferList and move storage from this BufferList to it. The
+  // new BufferList owns the buffers. Move can fail, in which case *aSuccess
+  // will be false upon return. The new BufferList can use a different
+  // AllocPolicy than the original one. The new OtherAllocPolicy is responsible
+  // for freeing buffers, so the OtherAllocPolicy must use freeing method
+  // compatible to the original one.
+  template<typename OtherAllocPolicy>
+  BufferList<OtherAllocPolicy> MoveFallible(bool* aSuccess, OtherAllocPolicy aAP = OtherAllocPolicy());
+
   // Return a new BufferList that adopts the byte range starting at Iter so that
   // range [aIter, aIter + aSize) is transplanted to the returned BufferList.
   // Contents of the buffer before aIter + aSize is left undefined.
   // Extract can fail, in which case *aSuccess will be false upon return. The
   // moved buffers are erased from the original BufferList. In case of extract
   // fails, the original BufferList is intact.  All other iterators except aIter
   // are invalidated.
   // This method requires aIter and aSize to be 8-byte aligned.
@@ -423,29 +435,53 @@ BufferList<AllocPolicy>::Borrow(IterImpl
                                 BorrowingAllocPolicy aAP)
 {
   BufferList<BorrowingAllocPolicy> result(aAP);
 
   size_t size = aSize;
   while (size) {
     size_t toAdvance = std::min(size, aIter.RemainingInSegment());
 
-    if (!toAdvance || !result.mSegments.append(Segment(aIter.mData, toAdvance, toAdvance))) {
+    if (!toAdvance || !result.mSegments.append(typename BufferList<BorrowingAllocPolicy>::Segment(aIter.mData, toAdvance, toAdvance))) {
       *aSuccess = false;
       return result;
     }
     aIter.Advance(*this, toAdvance);
     size -= toAdvance;
   }
 
   result.mSize = aSize;
   *aSuccess = true;
   return result;
 }
 
+template<typename AllocPolicy> template<typename OtherAllocPolicy>
+BufferList<OtherAllocPolicy>
+BufferList<AllocPolicy>::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP)
+{
+  BufferList<OtherAllocPolicy> result(0, 0, mStandardCapacity, aAP);
+
+  IterImpl iter = Iter();
+  while (!iter.Done()) {
+    size_t toAdvance = iter.RemainingInSegment();
+
+    if (!toAdvance || !result.mSegments.append(typename BufferList<OtherAllocPolicy>::Segment(iter.mData, toAdvance, toAdvance))) {
+      *aSuccess = false;
+      return result;
+    }
+    iter.Advance(*this, toAdvance);
+  }
+
+  result.mSize = mSize;
+  mSegments.clear();
+  mSize = 0;
+  *aSuccess = true;
+  return result;
+}
+
 template<typename AllocPolicy>
 BufferList<AllocPolicy>
 BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
 {
   MOZ_RELEASE_ASSERT(aSize);
   MOZ_RELEASE_ASSERT(mOwning);
   MOZ_ASSERT(aSize % kSegmentAlignment == 0);
   MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0);
--- a/mfbt/tests/TestBufferList.cpp
+++ b/mfbt/tests/TestBufferList.cpp
@@ -208,24 +208,38 @@ int main(void)
   bl = mozilla::Move(bl2);
   MOZ_RELEASE_ASSERT(bl2.Size() == 0);
   MOZ_RELEASE_ASSERT(bl2.Iter().Done());
 
   iter = bl.Iter();
   MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3));
   MOZ_RELEASE_ASSERT(iter.Done());
 
+  // MoveFallible
+
+  bool success;
+  bl2 = bl.MoveFallible<InfallibleAllocPolicy>(&success);
+  MOZ_RELEASE_ASSERT(success);
+  MOZ_RELEASE_ASSERT(bl.Size() == 0);
+  MOZ_RELEASE_ASSERT(bl.Iter().Done());
+  MOZ_RELEASE_ASSERT(bl2.Size() == kSmallWrite * 3);
+
+  iter = bl2.Iter();
+  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kSmallWrite * 3));
+  MOZ_RELEASE_ASSERT(iter.Done());
+
+  bl = bl2.MoveFallible<InfallibleAllocPolicy>(&success);
+
   // Borrowing.
 
   const size_t kBorrowStart = 4;
   const size_t kBorrowSize = 24;
 
   iter = bl.Iter();
   iter.Advance(bl, kBorrowStart);
-  bool success;
   bl2 = bl.Borrow<InfallibleAllocPolicy>(iter, kBorrowSize, &success);
   MOZ_RELEASE_ASSERT(success);
   MOZ_RELEASE_ASSERT(bl2.Size() == kBorrowSize);
 
   MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3 - kBorrowSize - kBorrowStart));
   MOZ_RELEASE_ASSERT(iter.Done());
 
   iter = bl2.Iter();