Browse Source

* Implement TList<T>.pack. Patch by Alexander Bagel. Fixes issue #40927

Michaël Van Canneyt 10 months ago
parent
commit
088f394440
2 changed files with 82 additions and 0 deletions
  1. 22 0
      packages/rtl-generics/src/generics.collections.pas
  2. 60 0
      tests/tbs/tb9000.pp

+ 22 - 0
packages/rtl-generics/src/generics.collections.pas

@@ -250,6 +250,7 @@ type
     type
       // bug workaround
       TEnumerator = class(TCustomListEnumerator<T>);
+      TEmptyFunc = reference to function (const L, R: T): Boolean;
 
     function GetEnumerator: TEnumerator; reintroduce;
   protected
@@ -285,6 +286,9 @@ type
     procedure InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerableWithPointers<T>); overload;
     {$ENDIF}
 
+    procedure Pack; overload;
+    procedure Pack(const IsEmpty: TEmptyFunc); overload;
+
     function Remove(const AValue: T): SizeInt;
     function RemoveItem(const Value: T; Direction: TDirection): SizeInt;
     procedure Delete(AIndex: SizeInt); inline;
@@ -1757,6 +1761,24 @@ begin
   end;
 end;
 
+procedure TList<T>.Pack;
+begin
+  Pack(
+    function(const L, R: T): Boolean
+    begin
+      Result := FComparer.Compare(L, Default(T)) = 0;
+    end);
+end;
+
+procedure TList<T>.Pack(const IsEmpty: TEmptyFunc);
+var
+  I: Integer;
+begin
+  for I := Count - 1 downto 0 do
+    if IsEmpty(List[I], Default(T)) then
+      DoRemove(I, cnRemoved);
+end;
+
 {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers}
 procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerableWithPointers<T>);
 var

+ 60 - 0
tests/tbs/tb9000.pp

@@ -0,0 +1,60 @@
+program tb9000;
+
+{$mode delphi}
+
+uses
+  Classes,
+  Generics.Collections;
+
+var
+  List: TList<Integer>;
+  ObjList: TObjectList<TObject>;
+begin
+  List := TList<Integer>.Create;
+  try
+    List.AddRange([0, 1, 0, 2, 0, 3, 3, 0, 2, 0, 1, 0]);
+    if List.Count <> 12 then Halt(1);
+
+    // remove 2
+    List.Pack(
+      function(const L, R: Integer): Boolean
+      begin
+        Result := L = 2;
+      end
+    );
+    if List.Count <> 10 then Halt(2);
+
+    // remove zeros
+    List.Pack;
+    if List.Count <> 4 then Halt(3);
+  finally
+    List.Free;
+  end;
+
+  ObjList := TObjectList<TObject>.Create;
+  try
+    ObjList.Add(TObject.Create);
+    ObjList.Add(nil);
+    ObjList.Add(TStream.Create);
+    ObjList.Add(nil);
+    ObjList.Add(TObject.Create);
+    ObjList.Add(nil);
+    ObjList.Add(TStream.Create);
+    if ObjList.Count <> 7 then Halt(4);
+
+    // remove nil
+    ObjList.Pack;
+    if ObjList.Count <> 4 then Halt(5);
+
+    // remove all TStream
+    ObjList.Pack(
+      function(const L, R: TObject): Boolean
+      begin
+        Result := L is TStream;
+      end);
+    if ObjList.Count <> 2 then Halt(6);
+
+  finally
+    ObjList.Free;
+  end;
+end.