3

可変データサイズの FIFO キュー (単純なもの、最初にプッシュされたもの、最初にポップ) に取り組んでいますが、設計方法がよくわかりません。そこに格納するデータ型は事前にわかっており、このクラスの各インスタンスで同じになるとしましょう。次の定義を持つレコードが格納される TList を使用することを考えていました (@David - D2007 用であるため、利用可能なGenerics.Collectionsがありません:)

type
  PListItem = ^TListItem;
  TListItem = record
    Size: Integer; // size of the data pointed by the following member
    Data: Pointer; // pointer to the target data reserved in memory
  end;

このような実装を使用します (ここでは、すべてが正常に機能するふりをしているので、例外処理は使用されません)

type
  TListQueue = class
private
  FList: TList;
public
  constructor Create;
  destructor Destroy; override;
  procedure Clear;
  procedure Push(const Value; const Size: Integer);
  procedure Pop(var Value; var Size: Integer);
end;

constructor TListQueue.Create;
begin
  inherited;
  FList := TList.Create;
end;

destructor TListQueue.Destroy;
begin
  Clear;
  FList.Free;
  inherited;
end;

procedure TListQueue.Push(const Value; const Size: Integer);
var ListItem: PListItem;
begin
  New(ListItem);
  ListItem.Size := Size;
  ListItem.Data := AllocMem(Size);
  Move(Value, ListItem.Data^, Size);
  FList.Add(ListItem);
end;

procedure TListQueue.Pop(var Value; var Size: Integer);
var ListItem: PListItem;
begin
  if FList.Count > 0 then
  begin
    ListItem := FList.Items[0];
    Size := ListItem^.Size;
    Move(ListItem.Data^, Value, ListItem.Size);
    FreeMem(ListItem.Data, ListItem.Size);
    Dispose(ListItem);
    FList.Delete(0);
  end;
end;

procedure TListQueue.Clear;
var I: Integer;
    ListItem: PListItem;
begin
  for I := 0 to FList.Count - 1 do
  begin
    ListItem := FList.Items[I];
    FreeMem(ListItem.Data, ListItem.Size);
    Dispose(ListItem);
  end;
  FList.Clear;
end;

私の質問は:

これは、数バイトから約 1MB (ストリームの場合) のサイズの FIFO キュー (文字列、ストリーム、レコードなどのデータ型) を作成する効率的な方法ですか?

どうもありがとう

4

3 に答える 3

4

Contnrs.pas にある組み込みの TQueue や TObjectQueue を使用することをお勧めします。Generics がないため、使用されるデータ型ごとに特別な TQueue を派生させることができます。これにより、プログラムの残りの部分で型の安全性が確保されますが、キャストとポインターに関連するすべてのものは queue クラス内にバンドルされます。

于 2011-08-01T10:13:49.090 に答える
3

使用しない理由:

type
  PListItem = ^TListItem;
  TListItem = record
    Size: Integer; // size of the data pointed by the following member
    Data: Pointer; // pointer to the target data reserved in memory
    Next: PListItem; // pointer to the next data entry, or nil for the last one.
  end;

var Root: PListItem = nil;また、New() と Dispose() を使用してアイテムを割り当て/割り当て解除する必要があります。リストの最後の項目を含む を追加するvar LastItem: PListItem = nil;と、項目を追加するたびにリスト全体を確認する必要がなくなります。
現代の「オブジェクトベースのソリューション」と比べるとまだ原始的ですが、FIFO ソリューションでは単一のリンクリストが非常に効率的です。エレガントすぎませんが、十分に機能します。よりエレガントにしたい場合は、このすべてを中心にクラスを構築してください!

于 2011-08-01T13:20:19.463 に答える
3

メモリ ストリームと TObjectQueue を使用します (Uwe が提案したように)。

type
  TListQueue = class
  private
    FList: TObjectQueue;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Push(const Value; const Size: Integer);
    procedure Pop(var Value; var Size: Integer);
  end;

implementation

constructor TListQueue.Create;
begin
  inherited;
  FList := TObjectQueue.Create;
end;

destructor TListQueue.Destroy;
begin
  while FList.Count > 0 do
    TMemoryStream(FList.Pop).Free;
  FreeAndNil(FList);
  inherited;
end;

procedure TListQueue.Push(const Value; const Size: Integer);
var
  LStream: TMemoryStream;
begin
  LStream := TMemoryStream.Create;
  LStream.Write(Value, Size);
  FList.Push(LStream);
end;

procedure TListQueue.Pop(var Value; var Size: Integer);
var
  LStream: TMemoryStream;
begin
  if FList.Count > 0 then
  begin
    LStream := TMemoryStream(FList.Pop);
    Size := LStream.Size;
    LStream.Position := 0;
    LStream.Read(Value, Size);
    LStream.Free;
  end;
end;
于 2011-08-01T10:28:42.987 に答える