unit BiDirBuf;

{Martin Harvey 7/5/2000}

interface

uses BoundedBuf;

type
  TBufferSide = (bsSideA, bsSideB);
  TBufferOp = (boWriting, boReading);

  TBiDirBuf = class
  private
    FAtoBBuf, FBtoABuf: TBoundedBuffer;
  protected
    function GetBuf(Side: TBufferSide; Op: TBufferOp): TBoundedBuffer;
    function GetSize: integer;
    procedure SetSize(NewSize: integer);
  public
    constructor Create;
    destructor Destroy; override;
    procedure ResetState;
    function PutItem(Side: TBufferSide; Item: pointer): boolean;
    function GetItem(Side: TBufferSide): pointer;
    { Entries used function peeks buffer one is reading from, and
      Entried free function peeks buffer one is writing to. It seems
      a bit useless to allow the other two operations: why worry about
      your neighbour when you have plenty else to worry about? }
    function GetEntriesUsed(Side: TBufferSide; var Used: integer): boolean;
    function GetEntriesFree(Side: TBufferSide; var Free: integer): boolean;
  published
    property Size: integer read GetSize write SetSize;
  end;

implementation

{ TBiDirBuf }

constructor TBiDirBuf.Create;
begin
  inherited Create;
  FAToBBuf := TBoundedBuffer.Create;
  FBToABuf := TBoundedBuffer.Create;
end;

destructor TBiDirBuf.Destroy;
begin
  FAToBBuf.Free;
  FBToABuf.Free;
  inherited Destroy;
end;

procedure TBiDirBuf.ResetState;
begin
  FAToBBuf.ResetState;
  FBToABuf.ResetState;
end;

function TBiDirBuf.GetBuf(Side: TBufferSide; Op: TBufferOp): TBoundedBuffer;
begin
  if ((Side = bsSideA) and (Op = boWriting))
    or ((Side = bsSideB) and (Op = boReading)) then
    result := FAToBBuf
  else if ((Side = bsSideA) and (Op = boReading))
    or ((Side = bsSideB) and (Op = boWriting)) then
    result := FBToABuf
  else
  begin
    result := FAToBBuf;
    Assert(false);
  end;
end;

function TBidirBuf.GetSize: integer;
begin
  Assert(FAToBBuf.Size = FBToABuf.Size);
  result := FAToBBuf.Size;
end;

procedure TBiDirBuf.SetSize(NewSize: integer);
begin
  FAToBBuf.Size := NewSize;
  FBToABuf.Size := NewSize;
  Assert(FAToBBuf.Size = FBToABuf.Size);
end;

function TBiDirBuf.PutItem(Side: TBufferSide; Item: Pointer): boolean;
begin
  result := GetBuf(Side, boWriting).PutItem(Item);
end;

function TBiDirBuf.GetItem(Side: TBufferSide): Pointer;
begin
  result := GetBuf(Side, boReading).GetItem;
end;

function TBiDirBuf.GetEntriesUsed(Side: TBufferSide; var Used: integer): boolean;
begin
  result := GetBuf(Side, boReading).GetEntriesUsed(Used);
end;

function TBiDirBuf.GetEntriesFree(Side: TBufferSide; var Free: integer): boolean;
begin
  result := GetBuf(Side, boWriting).GetEntriesFree(Free);
end;

end.