Bug 1271751 - part 3 - add Move{Non,}OverlappingRegion; r=erahm
authorNathan Froyd <froydnj@gmail.com>
Fri, 08 Jul 2016 16:59:05 -0400
changeset 304270 c726b0821954d4df564983e0fd59c97ef1c271d6
parent 304269 7247f68ba1108f4d9447536060e0c27463ff78ff
child 304271 a458e6f337ce9ebbd2c96508d8c05e3a78a14ff7
push id19932
push userphilringnalda@gmail.com
push dateSat, 09 Jul 2016 16:00:45 +0000
treeherderfx-team@679118259e91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1271751
milestone50.0a1
Bug 1271751 - part 3 - add Move{Non,}OverlappingRegion; r=erahm We'll need these for future patches as we transition nsTArray to use moves for most of its operations rather than copies. The implementation of these functions are essentially cut-and-paste versions of the Copy* functions, but using moves.
xpcom/glue/nsTArray.h
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -587,16 +587,28 @@ struct nsTArray_CopyWithMemutils
     memcpy(aDest, aSrc, sizeof(nsTArrayHeader) + aCount * aElemSize);
   }
 
   static void CopyOverlappingRegion(void* aDest, const void* aSrc, size_t aCount,
                                     size_t aElemSize)
   {
     memmove(aDest, aSrc, aCount * aElemSize);
   }
+
+  static void MoveOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
+                                    size_t aElemSize)
+  {
+    memmove(aDest, aSrc, aCount * aElemSize);
+  }
+
+  static void MoveNonOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
+                                       size_t aElemSize)
+  {
+    memcpy(aDest, aSrc, aCount * aElemSize);
+  }
 };
 
 //
 // A template class that defines how to copy elements calling their constructors
 // and destructors appropriately.
 //
 template<class ElemType>
 struct nsTArray_CopyWithConstructors
@@ -649,16 +661,55 @@ struct nsTArray_CopyWithConstructors
         --srcElemEnd;
         traits::Construct(destElemEnd, *srcElemEnd);
         traits::Destruct(srcElem);
       }
     } else {
       CopyNonOverlappingRegion(aDest, aSrc, aCount, aElemSize);
     }
   }
+
+  static void MoveOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
+                                    size_t aElemSize)
+  {
+    ElemType* destElem = static_cast<ElemType*>(aDest);
+    ElemType* srcElem = static_cast<ElemType*>(aSrc);
+    ElemType* destElemEnd = destElem + aCount;
+    ElemType* srcElemEnd = srcElem + aCount;
+    if (destElem == srcElem) {
+      return;  // In practice, we don't do this.
+    } else if (srcElemEnd > destElem && srcElemEnd < destElemEnd) {
+      while (destElemEnd != destElem) {
+        --destElemEnd;
+        --srcElemEnd;
+        traits::Construct(destElemEnd, mozilla::Move(*srcElemEnd));
+        traits::Destruct(srcElem);
+      }
+    } else {
+      MoveNonOverlappingRegion(aDest, aSrc, aCount, aElemSize);
+    }
+  }
+
+  static void MoveNonOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
+                                       size_t aElemSize)
+  {
+    ElemType* destElem = static_cast<ElemType*>(aDest);
+    ElemType* srcElem = static_cast<ElemType*>(aSrc);
+    ElemType* destElemEnd = destElem + aCount;
+#ifdef DEBUG
+    ElemType* srcElemEnd = srcElem + aCount;
+    MOZ_ASSERT(srcElemEnd <= destElem || srcElemEnd > destElemEnd);
+#endif
+    while (destElem != destElemEnd) {
+      traits::Construct(destElem, mozilla::Move(*srcElem));
+      traits::Destruct(srcElem);
+      ++destElem;
+      ++srcElem;
+    }
+  }
 };
 
 //
 // The default behaviour is to use memcpy/memmove for everything.
 //
 template<class E>
 struct MOZ_NEEDS_MEMMOVABLE_TYPE nsTArray_CopyChooser
 {
@@ -1971,17 +2022,17 @@ nsTArray_Impl<E, Alloc>::AppendElements(
   }
 
   index_type len = Length();
   index_type otherLen = aArray.Length();
   if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
         len + otherLen, sizeof(elem_type)))) {
     return nullptr;
   }
-  copy_type::CopyNonOverlappingRegion(Elements() + len, aArray.Elements(), otherLen,
+  copy_type::MoveNonOverlappingRegion(Elements() + len, aArray.Elements(), otherLen,
                                       sizeof(elem_type));
   this->IncrementLength(otherLen);
   aArray.template ShiftData<Alloc>(0, otherLen, 0, sizeof(elem_type),
                                    MOZ_ALIGNOF(elem_type));
   return Elements() + len;
 }
 
 template<typename E, class Alloc>