]> granicus.if.org Git - taglib/commitdiff
ByteVector::replace performance improvements
authorMathias Panzenböck <grosser.meister.morti@gmx.net>
Mon, 1 Aug 2011 02:13:55 +0000 (04:13 +0200)
committerMathias Panzenböck <grosser.meister.morti@gmx.net>
Mon, 1 Aug 2011 02:13:55 +0000 (04:13 +0200)
taglib/toolkit/tbytevector.cpp

index 9fb77b123db616157f46426002c15232b31ec433..d90f464ff2bb76588d51b6e00ad6a2e4dfa8bed9 100644 (file)
@@ -431,28 +431,58 @@ ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &wit
   if(pattern.size() == 0 || pattern.size() > size())
     return *this;
 
-  const int patternSize = pattern.size();
-  const int withSize = with.size();
-
-  int offset = find(pattern);
-
-  while(offset >= 0) {
-
-    const int originalSize = size();
-
-    if(withSize > patternSize)
-      resize(originalSize + withSize - patternSize);
-
-    if(patternSize != withSize)
-      ::memcpy(data() + offset + withSize, mid(offset + patternSize).data(), originalSize - offset - patternSize);
-
-    if(withSize < patternSize)
-      resize(originalSize + withSize - patternSize);
+  const uint withSize = with.size();
+  const uint patternSize = pattern.size();
+  int offset = 0;
+
+  if(withSize == patternSize) {
+      // I think this case might be common enough to optimize it
+      offset = find(pattern);
+      while(offset >= 0) {
+          ::memcpy(data() + offset, with.data(), withSize);
+          offset = find(pattern, offset + withSize);
+      }
+      return *this;
+  }
 
-    ::memcpy(data() + offset, with.data(), withSize);
+  // calculate new size:
+  uint newSize = 0;
+  for(;;) {
+      int next = find(pattern, offset);
+      if(next < 0) {
+          newSize += size() - offset;
+          break;
+      }
+      newSize += (next - offset) + withSize;
+      offset = next + patternSize;
+  }
 
-    offset = find(pattern, offset + withSize);
+  // new private data of appropriate size:
+  ByteVectorPrivate *newData = new ByteVectorPrivate(newSize, 0);
+  char *target = &newData->data[0];
+  const char *source = data();
+
+  // copy modified data into new private data:
+  offset = 0;
+  for(;;) {
+    int next = find(pattern, offset);
+    if(next < 0) {
+        ::memcpy(target, source + offset, size() - offset);
+        break;
+    }
+    int chunkSize = next - offset;
+    ::memcpy(target, source + offset, chunkSize);
+    target += chunkSize;
+    ::memcpy(target, with.data(), withSize);
+    target += withSize;
+    offset += chunkSize + patternSize;
   }
+  
+  // replace private data:
+  if(d->deref())
+    delete d;
+
+  d = newData;
 
   return *this;
 }