home *** CD-ROM | disk | FTP | other *** search
/ Programmer's ROM - The Computer Language Library / programmersrom.iso / ada / misc / slist.src < prev    next >
Encoding:
Text File  |  1988-05-03  |  23.3 KB  |  595 lines

  1. ::::::::::
  2. slist.pro
  3. ::::::::::
  4. -------- SIMTEL20 Ada Software Repository Prologue ------------
  5. --                                                           -*
  6. -- Unit name    : SINGLY_LINKED_LIST
  7. -- Version      : 1.0
  8. -- Author       : Tim Harrison
  9. --              : Texas Instruments
  10. --              :
  11. --              :
  12. -- DDN Address  : THarrison@ECLB
  13. -- Copyright    : (c) 1985
  14. -- Date created :  1-Mar-85
  15. -- Release date : 15-Jul-85
  16. -- Last update  :
  17. -- Machine/System Compiled/Run on : VAX/VMS 4.1/VMS 4.1
  18. --                                                           -*
  19. ---------------------------------------------------------------
  20. --                                                           -*
  21. -- Keywords     : Singly Linked List
  22. ----------------:
  23. --
  24. -- Abstract     : This package provides an abstract singly linked list
  25. ----------------: with a single point of reference.
  26. --                                                           -*
  27. ------------------ Revision history ---------------------------
  28. --                                                           -*
  29. -- DATE         VERSION    AUTHOR                  HISTORY
  30. -- 15-May-85    1.0     Tim Harrison        Original
  31. --                                                           -*
  32. ------------------ Distribution and Copyright -----------------
  33. --                                                           -*
  34. -- This prologue must be included in all copies of this software.
  35. --
  36. -- This software is copyright by the author.
  37. --
  38. -- This software is released to the Ada community.
  39. -- This software is released to the Public Domain (note:
  40. --   software released to the Public Domain is not subject
  41. --   to copyright protection).
  42. -- Restrictions on use or distribution:  NONE
  43. --                                                           -*
  44. ------------------ Disclaimer ---------------------------------
  45. --                                                           -*
  46. -- This software and its documentation are provided "AS IS" and
  47. -- without any expressed or implied warranties whatsoever.
  48. -- No warranties as to performance, merchantability, or fitness
  49. -- for a particular purpose exist.
  50. --
  51. -- Because of the diversity of conditions and hardware under
  52. -- which this software may be used, no warranty of fitness for
  53. -- a particular purpose is offered.  The user is advised to
  54. -- test the software thoroughly before relying on it.  The user
  55. -- must assume the entire risk and liability of using this
  56. -- software.
  57. --
  58. -- In no event shall any person or organization of people be
  59. -- held responsible for any direct, indirect, consequential
  60. -- or inconsequential damages or lost profits.
  61. --                                                           -*
  62. -------------------END-PROLOGUE--------------------------------
  63. ::::::::::
  64. slist.ada
  65. ::::::::::
  66. -------- SIMTEL20 Ada Software Repository Prologue ------------
  67. --                                                           -*
  68. -- Unit name    : SINGLY_LINKED_LIST
  69. -- Version      : 1.0
  70. -- Author       : Tim Harrison
  71. --              : Texas Instruments
  72. --              :
  73. --              :
  74. -- DDN Address  : THarrison@ECLB
  75. -- Copyright    : (c) 1985
  76. -- Date created :  1-Mar-85
  77. -- Release date : 15-Jul-85
  78. -- Last update  :
  79. -- Machine/System Compiled/Run on : VAX/VMS 4.1/VMS 4.1
  80. --                                                           -*
  81. ---------------------------------------------------------------
  82. --                                                           -*
  83. -- Keywords     : Singly Linked List
  84. ----------------:
  85. --
  86. -- Abstract     : This package provides an abstract singly linked list
  87. ----------------: with a single point of reference.
  88. --                                                           -*
  89. ------------------ Revision history ---------------------------
  90. --                                                           -*
  91. -- DATE         VERSION    AUTHOR                  HISTORY
  92. -- 15-May-85    1.0     Tim Harrison        Original
  93. --                                                           -*
  94. ------------------ Distribution and Copyright -----------------
  95. --                                                           -*
  96. -- This prologue must be included in all copies of this software.
  97. --
  98. -- This software is copyright by the author.
  99. --
  100. -- This software is released to the Ada community.
  101. -- This software is released to the Public Domain (note:
  102. --   software released to the Public Domain is not subject
  103. --   to copyright protection).
  104. -- Restrictions on use or distribution:  NONE
  105. --                                                           -*
  106. ------------------ Disclaimer ---------------------------------
  107. --                                                           -*
  108. -- This software and its documentation are provided "AS IS" and
  109. -- without any expressed or implied warranties whatsoever.
  110. -- No warranties as to performance, merchantability, or fitness
  111. -- for a particular purpose exist.
  112. --
  113. -- Because of the diversity of conditions and hardware under
  114. -- which this software may be used, no warranty of fitness for
  115. -- a particular purpose is offered.  The user is advised to
  116. -- test the software thoroughly before relying on it.  The user
  117. -- must assume the entire risk and liability of using this
  118. -- software.
  119. --
  120. -- In no event shall any person or organization of people be
  121. -- held responsible for any direct, indirect, consequential
  122. -- or inconsequential damages or lost profits.
  123. --                                                           -*
  124. -------------------END-PROLOGUE--------------------------------
  125.  
  126. generic
  127.   type List_Element is private;
  128. package Singly_Linked_List is
  129. -------------------------------------------------------------------------------
  130. -- Abstract   : This package provides an abstraction for a singly linked list.
  131. -------------------------------------------------------------------------------
  132.   type List_Type is limited private;
  133.  
  134.   function Empty (List : List_Type) return Boolean;
  135. -- Indicates whether the list contains any elements.
  136.  
  137.   function Null_Node (List : List_Type) return Boolean;
  138. -- Indicates whether the "current pointer" references an element in the list.
  139.  
  140.   function Head_Node (List : List_Type) return Boolean;
  141. -- Indicates whether the "current pointer" references the head of the list.
  142.  
  143.   function Tail_Node (List : List_Type) return Boolean;
  144. -- Indicates whether the "current pointer" references the tail of the list.
  145.  
  146.   function Current_Element (List : List_Type) return List_Element;
  147. -- Returns the value of the element referenced by the "current pointer".
  148. -- Raises End_Error if Null_Node(List) = True.
  149.  
  150.   procedure First (List : in out List_Type);
  151. -- Positions the "current pointer" at the head of the list
  152. -- (even if the list is empty).
  153.  
  154.   procedure Next (List : in out List_Type);
  155. -- Positions the "current pointer" at the next element in the list.
  156. -- After the last element in the list Null_Node(List) becomes True.
  157. -- Raises End_Error if Null_Node(List) = True.
  158.  
  159.   procedure Insert_After (List : in out List_Type; Element : List_Element);
  160. -- Inserts an element after the "current pointer".
  161. -- If Null_Node(List) = True the element is appended after the tail element.
  162.  
  163.   procedure Insert_Before (List : in out List_Type; Element : List_Element);
  164. -- Inserts an element before the "current pointer".
  165. -- If Null_Node(List) = True the element is prepended before the head element.
  166.  
  167.   procedure Delete_Element (List : in out List_Type);
  168. -- Deletes the element referenced by the "current pointer" from the list.
  169. -- Upon deletion, the "current pointer" references the element after the
  170. -- deleted element.
  171. -- Raises End_Error if Null_Node(List) = True.
  172.  
  173.   generic
  174.     with procedure Transformation (Element : in out List_Element);
  175.   procedure Modify (List : List_Type);
  176. -- Permits modification of the element referenced by the "current pointer"
  177. -- where the modification doesn't require external values (e.g. incrementing
  178. -- a field of the element).
  179. -- Raises End_Error if Null_Node(List) = True.
  180.  
  181.   generic
  182.     type Update_Information is private;
  183.     with procedure Transformation (Element     : in out List_Element;
  184.                                    Information : Update_Information);
  185.   procedure Update (List : List_Type; Information : Update_Information);
  186. -- Permits modification of the element referenced by the "current pointer"
  187. -- where the modification requires external values (e.g. assigning a value
  188. -- to a field of the element).
  189. -- Raises End_Error if Null_Node(List) = True.
  190.  
  191.   pragma Inline (Empty, Null_Node, Head_Node, Tail_Node, Current_Element);
  192.  
  193.   pragma Inline (Modify, Update);
  194.  
  195.   End_Error : exception;
  196.  
  197. private
  198.  
  199.   type Node;
  200.   type Node_Access is access Node;
  201.   type Node is
  202.     record
  203.       Element : List_Element;
  204.       Next    : Node_Access;
  205.     end record;
  206.  
  207.   type List_Type is
  208.     record
  209.       Head     : Node_Access;
  210.       Tail     : Node_Access;
  211.       Previous : Node_Access;
  212.       Current  : Node_Access;
  213.     end record;
  214.  
  215. end Singly_Linked_List;
  216.  
  217.  
  218. with Unchecked_Deallocation;
  219. package body Singly_Linked_List is
  220. --------------------------------------------------------------------------
  221. -- Abstract   : This package provides an abstraction for a singly linked
  222. --              list.
  223. --------------------------------------------------------------------------
  224. -- Assumptions:
  225. --      The lists being manipulated must be in one of the following states
  226. --      both before and after execution of any subprogram in the package:
  227. --              (1) empty-list          -- Head = null, Tail = null,
  228. --                                         Previous = null, Current = null
  229. --              (2) beginning-of-list   -- Head /= null, Tail /= null
  230. --                                         Previous = null, Current = Head
  231. --              (3) inside-of-list      -- Head /= null, Tail /= null
  232. --                                         Previous.Next = Current
  233. --              (4) outside-of-list     -- Head /= null, Tail /= null
  234. --                                         Previous = null, Current = null
  235. ----------------------------------------------------------------------
  236.  
  237.   function Empty (List : List_Type) return Boolean is
  238. --------------------------------------------------------------------------
  239. -- Abstract   : Indicates whether the list contains any elements.
  240. --------------------------------------------------------------------------
  241. -- Parameters : LIST - is the list to be queried.
  242. --------------------------------------------------------------------------
  243.   begin
  244.     return (List.Head = null);
  245.   end Empty;
  246.  
  247.   function Null_Node (List : List_Type) return Boolean is
  248. --------------------------------------------------------------------------
  249. -- Abstract   : Indicates whether the "current pointer" references an
  250. --              element in the list.
  251. --------------------------------------------------------------------------
  252. -- Parameters : LIST - is the list to be queried.
  253. --------------------------------------------------------------------------
  254.   begin
  255.     return (List.Current = null);
  256.   end Null_Node;
  257.  
  258.   function Head_Node (List : List_Type) return Boolean is
  259. --------------------------------------------------------------------------
  260. -- Abstract   : Indicates whether the "current pointer" references the
  261. --              head of the list.
  262. --------------------------------------------------------------------------
  263. -- Parameters : LIST - is the list to be queried.
  264. --------------------------------------------------------------------------
  265.   begin
  266.     return (List.Current = List.Head);
  267.   end Head_Node;
  268.  
  269.   function Tail_Node (List : List_Type) return Boolean is
  270. --------------------------------------------------------------------------
  271. -- Abstract   : Indicates whether the "current pointer" references the
  272. --              tail of the list.
  273. --------------------------------------------------------------------------
  274. -- Parameters : LIST - is the list to be queried.
  275. --------------------------------------------------------------------------
  276.   begin
  277.     return (List.Current = List.Tail);
  278.   end Tail_Node;
  279.  
  280.   function Current_Element (List : List_Type) return List_Element is
  281. --------------------------------------------------------------------------
  282. -- Abstract   : Returns the value of the element referenced by the
  283. --              "current pointer".
  284. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  285. --------------------------------------------------------------------------
  286. -- Parameters : LIST - is the list to be queried.
  287. --------------------------------------------------------------------------
  288.   begin
  289.     if List.Current = null then
  290.       raise End_Error;
  291.     else
  292.       return List.Current.Element;
  293.     end if;
  294.   end Current_Element;
  295.  
  296.   procedure First (List : in out List_Type) is
  297. --------------------------------------------------------------------------
  298. -- Abstract   : Positions the "current pointer" at the head of the list
  299. --              (even if the list is empty).
  300. --------------------------------------------------------------------------
  301. -- Parameters : LIST - is the list to be modified.
  302. --------------------------------------------------------------------------
  303.   begin
  304.     List.Previous := null;
  305.     List.Current := List.Head;
  306.   end First;
  307.  
  308.   procedure Next (List : in out List_Type) is
  309. --------------------------------------------------------------------------
  310. -- Abstract   : Positions the "current pointer" at the next element in the
  311. --              list.  After the last element in the list NULL_NODE(LIST)
  312. --              becomes true.
  313. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  314. --------------------------------------------------------------------------
  315. -- Parameters : LIST - is the list to be modified.
  316. --------------------------------------------------------------------------
  317.   begin
  318.     if List.Current = null then
  319.       raise End_Error;
  320.     else
  321.       if List.Current = List.Tail then
  322.         List.Previous := null;
  323.       else
  324.         List.Previous := List.Current;
  325.       end if;
  326.       List.Current := List.Current.Next;
  327.     end if;
  328.   end Next;
  329.  
  330.   procedure Insert_After (List : in out List_Type; Element : List_Element) is
  331. --------------------------------------------------------------------------
  332. -- Abstract   : Inserts an element after the "current pointer".
  333. --              If NULL_NODE(LIST) = TRUE the element is appended after
  334. --              the tail element of the list.
  335. --------------------------------------------------------------------------
  336. -- Parameters : LIST    - is the list to be modified.
  337. --              ELEMENT - is the element to be inserted.
  338. --------------------------------------------------------------------------
  339.   begin
  340.     if List.Current = null then
  341.       List.Current := List.Tail;
  342.     end if;
  343.     if Empty (List) then
  344.       List.Head := new Node'(Element, null);
  345.       List.Tail := List.Head;
  346.       List.Previous := null;
  347.       List.Current := List.Head;
  348.     else
  349.       declare
  350.         New_Node : Node_Access := new Node'(Element, List.Current.Next);
  351.       begin
  352.         if List.Current = List.Tail then
  353.           List.Tail := New_Node;
  354.         end if;
  355.         List.Previous := List.Current;
  356.         List.Previous.Next := New_Node;
  357.         List.Current := New_Node;
  358.       end;
  359.     end if;
  360.   end Insert_After;
  361.  
  362.   procedure Insert_Before (List    : in out List_Type;
  363.                            Element : List_Element) is
  364. --------------------------------------------------------------------------
  365. -- Abstract   : Inserts an element before the "current pointer".
  366. --              If NULL_NODE(LIST) = TRUE the element is prepended before
  367. --              the head element of the list.
  368. --------------------------------------------------------------------------
  369. -- Parameters : LIST    - is the list to be modified.
  370. --              ELEMENT - is the element to be inserted.
  371. --------------------------------------------------------------------------
  372.   begin
  373.     if List.Current = null then
  374.       List.Current := List.Head;
  375.     end if;
  376.     if Empty (List) then
  377.       List.Head := new Node'(Element, null);
  378.       List.Tail := List.Head;
  379.       List.Previous := null;
  380.       List.Current := List.Head;
  381.     elsif List.Current = List.Head then
  382.       List.Head := new Node'(Element, List.Head);
  383.       List.Previous := null;
  384.       List.Current := List.Head;
  385.     else
  386.       List.Previous.Next := new Node'(Element, List.Current);
  387.       List.Current := List.Previous.Next;
  388.     end if;
  389.   end Insert_Before;
  390.  
  391.   procedure Delete_Element (List : in out List_Type) is
  392. --------------------------------------------------------------------------
  393. -- Abstract   : Deletes the element referenced by the "current pointer"
  394. --              from the list.  Upon deletion the "current pointer"
  395. --              references the element after the deleted element.
  396. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  397. --------------------------------------------------------------------------
  398. -- Parameters : LIST - is the list to be modified.
  399. --------------------------------------------------------------------------
  400.  
  401.     procedure Free is new Unchecked_Deallocation (Node, Node_Access);
  402.  
  403.   begin
  404.     if List.Current = null then
  405.       raise End_Error;
  406.     elsif List.Current = List.Head then
  407.       declare
  408.         Next_Node : Node_Access := List.Head.Next;
  409.       begin
  410.         Free (List.Head);
  411.         List.Head := Next_Node;
  412.         if List.Head = null then
  413.           List.Tail := null;
  414.         end if;
  415.         List.Current := List.Head;
  416.       end;
  417.     else
  418.       if List.Current = List.Tail then
  419.         List.Tail := List.Previous;
  420.       end if;
  421.       List.Previous.Next := List.Current.Next;
  422.       Free (List.Current);
  423.       List.Current := List.Previous.Next;
  424.       if List.Current = null then
  425.         List.Previous := null;
  426.       end if;
  427.     end if;
  428.   end Delete_Element;
  429.  
  430.   procedure Modify (List : List_Type) is
  431. --------------------------------------------------------------------------
  432. -- Abstract   : Permits modification of the element referenced by the
  433. --              "current pointer" where the modification doesn't require
  434. --              external values (e.g. incrementing a field of the element).
  435. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  436. --------------------------------------------------------------------------
  437. -- Parameters : LIST - is the list to be modified.
  438. --------------------------------------------------------------------------
  439.   begin
  440.     if List.Current = null then
  441.       raise End_Error;
  442.     else
  443.       Transformation (List.Current.Element);
  444.     end if;
  445.   end Modify;
  446.  
  447.   procedure Update (List : List_Type; Information : Update_Information) is
  448. --------------------------------------------------------------------------
  449. -- Abstract   : Permits modification of the element referenced by the
  450. --              "current pointer" where the modification requires
  451. --              external values (e.g. assigning a value to a field of
  452. --              the element).
  453. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  454. --------------------------------------------------------------------------
  455. -- Parameters : LIST        - is the list to be modified.
  456. --              INFORMATION - is the data necessary for the modification.
  457. --------------------------------------------------------------------------
  458.   begin
  459.     if List.Current = null then
  460.       raise End_Error;
  461.     else
  462.       Transformation (List.Current.Element, Information);
  463.     end if;
  464.   end Update;
  465.  
  466. end Singly_Linked_List;
  467. ::::::::::
  468. slist_test.ada
  469. ::::::::::
  470. with Text_IO,
  471.      Singly_Linked_List;
  472. use Text_IO;
  473. procedure Singly_Linked_List_Test is
  474.  
  475.   package Boolean_IO is new Enumeration_IO(Boolean);
  476.   use Boolean_IO;
  477.  
  478.   package Int_IO is new Integer_IO(Integer);
  479.   use Int_IO;
  480.  
  481.   package Integer_List is new Singly_Linked_List(Integer);
  482.   use Integer_List;
  483.  
  484.   procedure Increment(Element : in out Integer);
  485.  
  486.   procedure Increment_Element is new Integer_List.Modify(Increment);
  487.  
  488.   procedure Replace(Element : in out Integer;
  489.                     Data    : in     Integer);
  490.  
  491.   procedure Replace_Element is new Integer_List.Update(Integer, Replace);
  492.  
  493.   Command       : Character;
  494.   Done          : Boolean := False;
  495.   Element       : Integer := 0;
  496.   List          : Integer_List.List_Type;
  497.  
  498.   procedure Increment(Element : in out Integer) is
  499.   begin
  500.     Element := Element + 1;
  501.   end Increment;
  502.  
  503.   procedure Replace(Element : in out Integer;
  504.                     Data    : in     Integer) is
  505.   begin
  506.     Element := Data;
  507.   end Replace;
  508.  
  509.   procedure Print_List is
  510.   begin
  511.     if not Empty(List) then
  512.       Put_Line("The list currently contains:");
  513.     else
  514.       Put_Line("The list is empty.");
  515.     end if;
  516.     First(List);
  517.     while not Null_Node(List) loop
  518.       Put(Current_Element(List)); New_Line;
  519.       Next(List);
  520.     end loop;
  521.   end Print_List;
  522.  
  523. begin
  524.   Put_Line("Singly_Linked_List test program (Version 0.1)");
  525.   while not Done loop
  526.     New_Line;
  527.     Put_Line("Enter command (S F/N I/D M/U P/Q):");
  528.     Get(Command); Skip_Line;
  529.     begin
  530.       case Command is
  531.         when 'S' | 's' =>
  532.           if Empty(List) then
  533.             Put("-- Empty List ");
  534.           end if;
  535.           if Head_Node(List) then
  536.             Put("-- Current is at Head ");
  537.           end if;
  538.           if Tail_Node(List) then
  539.             Put("-- Current is at Tail ");
  540.           end if;
  541.           if Null_Node(List) then
  542.             Put("-- Current is Null");
  543.           else
  544.             Put("-- Current Element is" & Integer'Image(Current_Element(List)));
  545.           end if;
  546.           New_Line;
  547.         when 'F' | 'f' => First(List);
  548.         when 'N' | 'n' => Next(List);
  549.         when 'I' | 'i' =>
  550.           Put_Line("Enter position (B/efore A/fter):");
  551.           Get(Command); Skip_Line;
  552.           case Command is
  553.             when 'A' | 'a' => Insert_After(List, Element);
  554.                                 Put_Line(Integer'Image(Element) &
  555.                                         " inserted AFTER current element.");
  556.                                 Element := Integer'Succ(Element);
  557.             when 'B' | 'b' => Insert_Before(List, Element);
  558.                                 Put_Line(Integer'Image(Element) &
  559.                                         " inserted BEFORE current element.");
  560.                                 Element := Integer'Succ(Element);
  561.             when others  => null;
  562.           end case;
  563.         when 'D' | 'd' => Delete_Element(List);
  564.         when 'M' | 'm' => Increment_Element(List);
  565.         when 'U' | 'u' =>
  566.           declare
  567.             Data : Integer;
  568.           begin
  569.             loop
  570.               begin
  571.                 Put_Line("Enter replacement number:");
  572.                 Get(Data); Skip_Line;
  573.                 exit;
  574.               exception
  575.                 when others => null;
  576.               end;
  577.             end loop;
  578.             Replace_Element(List, Data);
  579.           end;
  580.         when 'P' | 'p' => Print_List;
  581.         when 'Q' | 'q' => Done := True;
  582.         when others =>
  583.           New_Line;
  584.           Put_Line("S/tatus");
  585.           Put_Line("F/irst    N/ext");
  586.           Put_Line("I/nsert   D/elete");
  587.           Put_Line("M/odify   U/pdate");
  588.           Put_Line("P/rint    Q/uit");
  589.       end case;
  590.     exception
  591.       when others => Put_Line("Exception raised.");
  592.     end;
  593.   end loop;
  594. end Singly_Linked_List_Test;
  595.