generic
    type List_Element is private;
package Singly_Linked_List is
    -------------------------------------------------------------------------------

    -- Abstract   : This package provides an abstraction for a singly linked list.
    -------------------------------------------------------------------------------

    type List_Type is private;
    function Empty (List : List_Type) return Boolean;
    -- Indicates whether the list contains any elements.
    function Null_Node (List : List_Type) return Boolean;
    -- Indicates whether the "current pointer" references an element in the list.
    function Head_Node (List : List_Type) return Boolean;
    -- Indicates whether the "current pointer" references the head of the list.
    function Tail_Node (List : List_Type) return Boolean;
    -- Indicates whether the "current pointer" references the tail of the list.
    function Current_Element (List : List_Type) return List_Element;
    -- Returns the value of the element referenced by the "current pointer".
    -- Raises End_Error if Null_Node(List) = True.
    procedure First (List : in out List_Type);
    -- Positions the "current pointer" at the head of the list
    -- (even if the list is empty).
    procedure Next (List : in out List_Type);
    -- Positions the "current pointer" at the next element in the list.
    -- After the last element in the list Null_Node(List) becomes True.
    -- Raises End_Error if Null_Node(List) = True.
    procedure Insert_After (List : in out List_Type; Element : List_Element);
    -- Inserts an element after the "current pointer".
    -- If Null_Node(List) = True the element is appended after the tail element.
    procedure Insert_Before (List : in out List_Type; Element : List_Element);
    -- Inserts an element before the "current pointer".
    -- If Null_Node(List) = True the element is prepended before the head element.
    procedure Delete_Element (List : in out List_Type);
    -- Deletes the element referenced by the "current pointer" from the list.
    -- Upon deletion, the "current pointer" references the element after the
    -- deleted element.
    -- Raises End_Error if Null_Node(List) = True.
    generic
        with procedure Transformation (Element : in out List_Element);
    procedure Modify (List : List_Type);
    -- Permits modification of the element referenced by the "current pointer"
    -- where the modification doesn't require external values (e.g. incrementing
    -- a field of the element).
    -- Raises End_Error if Null_Node(List) = True.
    generic
        type Update_Information is private;
        with procedure Transformation (Element : in out List_Element;
                                       Information : Update_Information);
    procedure Update (List : List_Type; Information : Update_Information);
    -- Permits modification of the element referenced by the "current pointer"
    -- where the modification requires external values (e.g. assigning a value
    -- to a field of the element).
    -- Raises End_Error if Null_Node(List) = True.
    pragma Inline (Empty, Null_Node, Head_Node, Tail_Node, Current_Element);
    pragma Inline (Modify, Update);
    End_Error : exception;
private
    type Node;
    type Node_Access is access Node;
    type Node is
        record
            Element : List_Element;
            Next : Node_Access;
        end record;
    type List_Type is
        record
            Head : Node_Access;
            Tail : Node_Access;
            Previous : Node_Access;
            Current : Node_Access;
        end record;
end Singly_Linked_List;