dps/src/Linked2List.m3


Copyright (C) 1994, Digital Equipment Corp.

MODULE Linked2Tree;

IMPORT Thread;

PROCEDURE Init (t: T) =
  BEGIN
  t.firstChild := NIL;
  t.lastChild := NIL;
  t.monitor := Thread.NewMutex();
  END Init;

PROCEDURE Prepend (t: T; e: T) =
  BEGIN
  LOCK t.monitor DO PrependWhileLocked (t, e); END;
  END Prepend;

PROCEDURE PrependWhileLocked (t: T; e: T) =
  BEGIN
  <* ASSERT (e.parent = NIL) *>  e.parent := t;
  IF t.firstChild=NIL THEN
    t.firstChild := e; t.lastChild := e;
    e.nextSibling := NIL; e.previousSibling := NIL;
   ELSE
    t.firstChild.previousSibling := e; e.next := t.firstChild;
    e.previousSibling := NIL; t.firstChild := e;
    END;
  END PrependWhileLocked;

PROCEDURE Append (t: T; e: T) =
  BEGIN
  LOCK t.monitor DO AppendWhileLocked (t, e); END;
  END Append;

PROCEDURE AppendWhileLocked (t: T; e: T) =
  BEGIN
  <* ASSERT (e.parent = NIL) *>  e.parent := t;
  IF t.first=NIL THEN
    t.firstChild := e; t.lastChild := e;
    e.nextSibling := NIL; e.previousSibling := NIL;
   ELSE
    t.last.nextSibling := e; e.previousSibling := t.lastChild;
    e.next := NIL; t.lastChild := e;
    END;
  END AppendWhileLocked;

PROCEDURE Remove (t: T; e: T) =
  BEGIN
  LOCK t.monitor DO RemoveWhileLocked (t, e); END;
  END Remove;

PROCEDURE RemoveWhileLocked (t: T; e: T) =
 VAR done: BOOLEAN;
 VAR past: E;
  BEGIN
  e.parent := NIL;
  done := FALSE;
  IF t.firstChild=e THEN
    t.firstChild := e.next;
    IF t.firstChild#NIL THEN t.firstChild.previousSibling := NIL; END;
    done := TRUE;
    END;
  IF t.lastChild=e THEN
    t.lastChild := e.previousSibling;
    IF t.lastChild#NIL THEN t.lastChild.nextSibling := NIL; END;
    done := TRUE;
    END;
  IF NOT done THEN
    past := e.next;
    e.next.previousSibling := e.previousSibling;
    e.previousSibling.next := past;
    END;
  END RemoveWhileLocked;

PROCEDURE First (t: T): E =
  BEGIN
  LOCK t.monitor DO RETURN t.firstChild; END;
  END First;

PROCEDURE Next (t: T; e: E): E =
  BEGIN
  LOCK t.monitor DO RETURN e.nextSibling; END;
  END Next;

PROCEDURE Last (t: T): E =
  BEGIN
  LOCK t.monitor DO RETURN t.lastChild; END;
  END Last;

PROCEDURE Previous (t: T; e: E): E =
  BEGIN
  LOCK t.monitor DO RETURN e.previousSibling; END;
  END Previous;

PROCEDURE InternalMoveToFirst (t: T; e: E): BOOLEAN =
  BEGIN
  LOCK t.monitor DO
    IF e = t.first THEN RETURN FALSE; END;
    RemoveWhileLocked (t, e);
    PrependWhileLocked (t, e);
    RETURN TRUE;
    END;
  END InternalMoveToFirst;

PROCEDURE InternalMoveToLast (t: T; e: T): BOOLEAN =
  BEGIN
  LOCK t.monitor DO
    IF e = t.last THEN RETURN FALSE; END;
    RemoveWhileLocked (t, e);
    AppendWhileLocked (t, e);
    RETURN TRUE;
    END;
  END InternalMoveToLast;

PROCEDURE MoveToFirst (e: T): BOOLEAN =
  BEGIN
  RETURN InternalMoveToFirst(e.parent, e);
  END MoveToFirst;

PROCEDURE MoveToLast (e: T): BOOLEAN =
  BEGIN
  RETURN InternalMoveToLast(e.parent, e);
  END MoveToLast;

  BEGIN

  END Linked2List.