Browse Source

* Faster DupeString by Rika. Fixes issue #39949

(cherry picked from commit 0b3c608d79fdc8e3aa1a198ad3152e7009c11336)
Michaël Van Canneyt 2 years ago
parent
commit
0f5129db70
1 changed files with 25 additions and 15 deletions
  1. 25 15
      packages/rtl-objpas/src/inc/strutils.pp

+ 25 - 15
packages/rtl-objpas/src/inc/strutils.pp

@@ -1154,24 +1154,34 @@ end;
 function DupeString(const AText: string; ACount: Integer): string;
 
 var
-  Len: SizeInt;
-  Source, Target: PByte;
-  
+  Len, BitIndex, Rp: SizeInt;
+
 begin
   Len := Length(AText);
+  if (Len = 0) or (ACount <= 0) then
+    Exit('');
+  if ACount = 1 then
+    Exit(AText);
+
   SetLength(Result, ACount * Len);
-  // Use PByte to skip implicit UniqueString, because SetLength always unique
-  Target := PByte(Result);
-  if Target = nil then // ACount = 0 or AText = ''
-    Exit;
-  // Now ACount > 0 and Len > 0
-  Source := PByte(AText);
-  repeat
-    Move(Source[0], Target[0], Len * SizeOf(Char));
-    Inc(Target, Len * SizeOf(Char));
-    Dec(ACount);
-  until ACount = 0;
-end;   
+  Rp := 0;
+
+  // Build up ACount repeats by duplicating the string built so far and adding another AText if corresponding ACount binary digit is 1.
+  // For example, ACount = 5 = %101 will, starting from the empty string:
+  // (1) duplicate (count = 0), add AText (count = 1)
+  // (0) duplicate (count = 2)
+  // (1) duplicate (count = 4), add AText (count = 5)
+  for BitIndex := BsrDWord(ACount) downto 0 do
+  begin
+    Move(Pointer(Result)^, PChar(Pointer(Result))[Rp], Rp * SizeOf(Char));
+    Inc(Rp, Rp);
+    if ACount shr BitIndex and 1 <> 0 then
+    begin
+      Move(Pointer(AText)^, PChar(Pointer(Result))[Rp], Len * SizeOf(Char));
+      Inc(Rp, Len);
+    end;
+  end;
+end;
 
 function ReverseString(const AText: string): string;