Browse Source

Apply patch from lks (with a few adjustments). Fixes Mantis #23938.

gvector.pp:
  * more consistent formatting
  - remove "inline" directives in implementation section
  * use "Move" instead of a for-loop in Erase and Insert (while also respecting managed types) for performance improvement
  * set the removed entry in PopBack to Default(T) (also for managed types)
  * fix a bug in Erase which checked for "<= Size" instead of "< Size"

git-svn-id: trunk@23647 -
svenbarth 12 years ago
parent
commit
d76ebd0748
1 changed files with 40 additions and 34 deletions
  1. 40 34
      packages/fcl-stl/src/gvector.pp

+ 40 - 34
packages/fcl-stl/src/gvector.pp

@@ -31,8 +31,8 @@ type
     FData:TArr;
 
     procedure SetValue(Position: SizeUInt; const Value: T); inline;
-    function GetValue(Position: SizeUInt):T; inline;
-    function GetMutable(Position: SizeUInt):PT; inline;
+    function GetValue(Position: SizeUInt): T; inline;
+    function GetMutable(Position: SizeUInt): PT; inline;
     procedure IncreaseCapacity; inline;
 
   const
@@ -65,8 +65,8 @@ type
     procedure Clear; inline;
     function Front: T; inline;
     function Back: T; inline;
-    procedure Reserve(Num: SizeUInt); inline;
-    procedure Resize(Num: SizeUInt); inline;
+    procedure Reserve(Num: SizeUInt);
+    procedure Resize(Num: SizeUInt);
 
     function GetEnumerator: TVectorEnumerator; inline;
 
@@ -114,41 +114,38 @@ begin
   FData[Position]:=Value;
 end;
 
-function TVector.GetValue(Position:SizeUInt):T;inline;
+function TVector.GetValue(Position: SizeUInt): T;
 begin
   Assert(position < size, SVectorPositionOutOfRange);
   GetValue:=FData[Position];
 end;
 
-function TVector.GetMutable(Position:SizeUInt):PT;inline;
+function TVector.GetMutable(Position: SizeUInt): PT;
 begin
   Assert(position < size, SVectorPositionOutOfRange);
   GetMutable:=@FData[Position];
 end;
 
-function TVector.Front():T;inline;
+function TVector.Front(): T;
 begin
   Assert(size > 0, SAccessingElementOfEmptyVector);
   Front:=FData[0];
 end;
 
-function TVector.Back():T;inline;
+function TVector.Back(): T;
 begin
   Assert(size > 0, SAccessingElementOfEmptyVector);
   Back:=FData[FDataSize-1];
 end;
 
-function TVector.Size():SizeUInt;inline;
+function TVector.Size(): SizeUInt;
 begin
   Size:=FDataSize;
 end;
 
-function TVector.IsEmpty():boolean;inline;
+function TVector.IsEmpty(): boolean;
 begin
-  if Size()=0 then 
-    IsEmpty:=true
-  else 
-    IsEmpty:=false;
+  IsEmpty := (Size() = 0);
 end;
 
 procedure TVector.PushBack(const Value: T);
@@ -159,7 +156,7 @@ begin
   inc(FDataSize);
 end;
 
-procedure TVector.IncreaseCapacity();inline;
+procedure TVector.IncreaseCapacity();
 begin
   if FCapacity=0 then
     FCapacity:=1
@@ -173,42 +170,51 @@ begin
   Result := TVectorEnumerator.Create(self);
 end;
 
-procedure TVector.PopBack();inline;
+procedure TVector.PopBack();
 begin
-  if FDataSize>0 then
-    FDataSize:=FDataSize-1;
+  if FDataSize > 0 then
+  begin
+    dec(FDataSize);
+    // if a managed type, decrease the popped element's reference count (see http://bugs.freepascal.org/view.php?id=23938#)
+    FData[FDataSize] := Default(T);
+  end;
 end;
 
 procedure TVector.Insert(Position: SizeUInt; const Value: T);
-var i:SizeUInt;
+var
+  def: T;
 begin
-  pushBack(Value);
-  for i:=Size-1 downto Position+1 do 
+  if Position <= Size then	// allow appending a new element at end of vector (but not beyond)
   begin
-    FData[i]:=FData[i-1];
+    if FDataSize = FCapacity then
+      IncreaseCapacity;
+    if Position < FDataSize then
+      System.Move (FData[Position], FData[Position+1], (FDataSize - Position) * SizeOf(T));
+    // update inserted item
+    def := Default(T);
+    Move(def, FData[Position], SizeOf(T)); // this will clear FData[Position] without changing the reference count
+    FData[Position] := Value;
+    inc(FDataSize);
   end;
-  FData[Position]:=Value;
 end;
 
-procedure TVector.Erase(Position:SizeUInt);inline;
-var i:SizeUInt;
+procedure TVector.Erase(Position: SizeUInt);
 begin
-  if Position <= Size then 
+  if Position < Size then 
   begin
-    for i:=Position to Size-2 do
-    begin
-      FData[i]:=FData[i+1];
-    end;
-    popBack();
+    dec(FDataSize);
+    // ensure that the data we want to erase is released
+    FData[Position] := Default(T);
+    Move(FData[Position+1], FData[Position], (FDataSize - Position) * SizeOf(T));
   end;
 end;
 
-procedure TVector.Clear;inline;
+procedure TVector.Clear;
 begin
   FDataSize:=0;
 end;
 
-procedure TVector.Reserve(Num:SizeUInt);inline;
+procedure TVector.Reserve(Num: SizeUInt);
 begin
   if(Num < FCapacity) then 
     exit
@@ -220,7 +226,7 @@ begin
   end;
 end;
 
-procedure TVector.Resize(Num:SizeUInt);inline;
+procedure TVector.Resize(Num: SizeUInt);
 begin
   Reserve(Num);
   FDataSize:=Num;