Fast copy of TList <T>?

北慕城南 提交于 2020-01-12 14:37:55

问题


Is there a fast way to copy a generic TList?

Copy.Capacity := List.Count;
for Item in List do
  Copy.Add (Item);

is very slow. There seems to be no way to use CopyMemory since I can't get the memory adress of the internal array (which is obvious from an information hiding viewpoint). I miss something like

List.Copy (Copy);

which uses the knowledge of the internal representation to improve performance. Can it be done?


回答1:


For the generic TList<T> it is simply not possible to implement the function you want. That's because copy the contents of T may involve more than a simple memory copy. If T contains any managed types (i.e. strings, interfaces etc.) then the reference counts on those managed objects must be incremented.

  • If your T does contain managed types then I doubt that you can do much better then the code you already have.
  • If your T does not contain any managed types then a memory copy is viable but you will need to create your own class to encapsulate this list since TList<T> is not appropriate.



回答2:


You always can reinterpret of memory.

type
  TListHack<T> = class(TEnumerable<T>)
  private
    FItems: array of T;
    FCount: Integer;
  public
    class procedure FastAdd(Source, Dest: TList<T>);
  end;

{ TListHack<T> }

class procedure TListHack<T>.FastAdd(Source, Dest: TList<T>);
var
  SourceHack: TListHack<T>;
  DestHack: TListHack<T>;
  TI: PTypeInfo;
begin
  TI := TypeInfo(T);
  if not (TI.Kind in [tkInteger, tkChar, tkFloat,
    tkSet, tkClass, tkMethod, tkWChar, tkInt64, tkClassRef, tkPointer, tkProcedure]) then
    raise Exception.CreateFmt('Type %s is not supported', [TI.Name]);

  if Source.Count = 0 then
    Exit;
  DestHack := TListHack<T>(Dest);
  SourceHack := TListHack<T>(Source);
  if Dest.Capacity < Dest.Count + Source.Count then
    Dest.Capacity := Dest.Count + Source.Count;

  Move(SourceHack.FItems[0], DestHack.FItems[Dest.Count], Source.Count * SizeOf(T));
  DestHack.FCount := DestHack.FCount + Source.Count;
end;

procedure TForm6.FormCreate(Sender: TObject);
var
  Source, Dest: TList<Integer>;
  Arr: TArray<Integer>;
begin
  Source := TList<Integer>.Create;
  Dest := TList<Integer>.Create;
  try
    Source.Add(1); Source.Add(2); Source.Add(3);
    Dest.Add(10);
    TListHack<Integer>.FastAdd(Source, Dest);
    Assert(Dest.Count = 4);
    ShowMessageFmt('%d, %d, %d, %d', [Dest[0], Dest[1], Dest[2], Dest[3]]);
  finally
    Source.Free; Dest.Free;
  end;

  TListHack<IUnknown>.FastAdd(TList<IUnknown>.Create, TLIst<IUnknown>.Create); // exception
end;

But it's very dangerously



来源:https://stackoverflow.com/questions/9479089/fast-copy-of-tlist-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!