{$MODE FPC}
{$MODESWITCH RESULT}
{$MODESWITCH AUTODEREF}
{$MODESWITCH NESTEDPROCVARS}
{$MODESWITCH ADVANCEDRECORDS}
unit dlist;

interface

type
generic TList<TElement> = object
public type
  PElement = ^TElement;
  PNode = ^TNode;
  TNode = record
    Value: TElement;
    Next: PNode;
    Prev: PNode;
  end;
  TCursor = PNode;
private type
  TCursorEnumerator = object
  private
    FNode: PNode;
    function GetCurrent: PNode;
  public
    function MoveNext: Boolean;
    function GetEnumerator: TCursorEnumerator;
    property Current: PNode read GetCurrent;
  end;
  TValueEnumerator = object
  private
    FNode: PNode;
    function GetCurrent: TElement;
  public
    function MoveNext: Boolean;
    property Current: TElement read GetCurrent;
  end;
public type
  TEnumerator = TCursorEnumerator;
private
  FFirst: TNode;
  FLast: PNode;
public
  constructor Init;
  destructor Done;
  procedure Free; inline;
  procedure Clear;
  function GetFirst: TCursor; inline;
  function GetLast: TCursor; inline;
  function Insert(const Value: TElement): TCursor;
  //function Find(const Value: TElement): TCursor;
  function Remove(Cursor: TCursor): TCursor;
  function GetEnumerator: TValueEnumerator;
  function Cursors: TCursorEnumerator;
  property First: TCursor read GetFirst;
  property Last: TCursor read GetLast;

public
  // begin_interface
  function Insert(Cursor: TCursor; const Value: TElement): TCursor;
  // end_interface
end;


implementation

//{{{ TCursorEnumerator
function TList.TCursorEnumerator.GetCurrent: PNode;
begin
  Result := FNode;
end;

function TList.TCursorEnumerator.MoveNext: Boolean;
begin
  FNode := FNode^.Next;
  Result := FNode <> nil;
end;

function TList.TCursorEnumerator.GetEnumerator: TCursorEnumerator;
begin
  Result := Self;
end;
//}}}
//{{{ TValueEnumerator
function TList.TValueEnumerator.GetCurrent: TElement;
begin
  Result := FNode^.Value;
end;

function TList.TValueEnumerator.MoveNext: Boolean;
begin
  FNode := FNode^.Next;
  Result := FNode <> nil;
end;
//}}}
//{{{ TList
constructor TList.Init;
begin
  FFirst.Next := nil;
  FFirst.Prev := nil;
  FLast := @FFirst;
end;

destructor TList.Done;
begin
  Clear;
end;

procedure TList.Free;
begin
  Done;
end;

procedure TList.Clear;
begin
  while FLast <> @FFirst do
    FLast := Remove(FLast);
end;

function TList.GetFirst: TCursor;
begin
  Result := @FFirst;
end;

function TList.GetLast: TCursor;
begin
  Result := FLast;
end;

function TList.Insert(const Value: TElement): TCursor;
var
  Node: PNode;
begin
  New(Node);
  Node^.Value := Value;
  Node^.Next := nil;
  Node^.Prev := FLast;
  FLast^.Next := Node;
  FLast := Node;
  Result := Node;
end;

function TList.Insert(Cursor: TCursor; const Value: TElement): TCursor;
var
  Node: PNode;
begin
  New(Node);
  Node^.Value := Value;
  Node^.Next := Cursor^.Next;
  Node^.Prev := Cursor;
  Cursor^.Next := Node;
  if Node^.Next <> nil then
    Node^.Next^.Prev := Node;
  Result := Node;
  if Cursor = FLast then
    FLast := Result;
end;

{function TList.Find(const Value: TElement): TCursor;
begin
  for Result in Cursors do
    if Result^.Value = Value then
      Exit;
  Result := nil;
end;}

function TList.Remove(Cursor: TCursor): TCursor;
begin
  Result := Cursor^.Prev;
  Result^.Next := Cursor^.Next;
  if Result^.Next <> nil then
    Result^.Next^.Prev := Result;
  if Cursor = FLast then
    FLast := Result;
  Dispose(Cursor);
end;

function TList.GetEnumerator: TValueEnumerator;
begin
  Result.FNode := @FFirst;
end;

function TList.Cursors: TCursorEnumerator;
begin
  Result.FNode := @FFirst;
end;
//}}}

end.
