home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / Apps / DevTools / MachOViewer / Source / RCS / Queue.m,v < prev    next >
Encoding:
Text File  |  1994-05-15  |  5.6 KB  |  350 lines

  1. head     1.2;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ediger:1.2;
  6. comment  @@;
  7.  
  8.  
  9. 1.2
  10. date     94.05.15.18.56.05;  author ediger;  state Exp;
  11. branches ;
  12. next     1.1;
  13.  
  14. 1.1
  15. date     94.05.14.17.44.25;  author ediger;  state Exp;
  16. branches ;
  17. next     ;
  18.  
  19.  
  20. desc
  21. @simple stack and/or queue object implemented via doubly linked lists
  22. @
  23.  
  24.  
  25. 1.2
  26. log
  27. @speedup -free method.  keep from honking internals up on -pop and -first
  28. methods.
  29. @
  30. text
  31. @//H+
  32. //    Implementation of a LIFO stack or FIFO queue via a
  33. //    doubly-linked list.
  34. //
  35. /*    $Log:    Queue.m,v $
  36. Revision 1.1  94/05/14  17:44:25  ediger
  37. Initial revision
  38.  
  39. */
  40.  
  41. //H-
  42. #include <stdio.h>
  43. #include <unistd.h>
  44. #include <assert.h>
  45. #include <libc.h>
  46.  
  47. #include <Queue.h>
  48.  
  49. #define CHECK_CONTRACT
  50.  
  51. #ifdef CHECK_CONTRACT
  52.     #define REQUIRE(c) if(![self c]) \
  53.         [self error:"%s precondition check failed", sel_getName(_cmd)]
  54.     #define ENSURE(c) if(![self c]) \
  55.         [self error:"%s postcondition check failed", sel_getName(_cmd)]
  56. #else
  57.     #define REQUIRE(c)
  58.     #define ENSURE(c)
  59. #endif
  60.  
  61.  
  62. @@implementation Queue: Object
  63.  
  64. static char RCSQueueIdent[] = "$Id";
  65.  
  66. #ifdef CHECK_CONTRACT
  67. //M+ -(BOOL)listOK
  68. //    PURPOSE:
  69. //        Make sure that head and tail dummy nodes are OK.
  70. //        Used as pre- and post-condition for most methods when
  71. //        CHECK_CONTRACT is #defined
  72. //    EDITORIAL:
  73. //        Could walk the entire list forward and back to see
  74. //        if all the links are correct, but it doesn't.
  75. //M-
  76. -(BOOL)listOK
  77. {
  78.     return
  79.            (head != NULL) && (tail != NULL)
  80.         && (head->next != NULL)
  81.         && (tail->prev != NULL)
  82.         && (head->next->prev == head)
  83.         && (tail->prev->next == tail)
  84.     ;
  85. }
  86. #endif
  87.  
  88. //M+ - init
  89. //    PURPOSE:
  90. //        initialize internals of an object.  In this implementation, that
  91. //        means setting up dummy head and tail nodes of doubly-linked list.
  92. //M-
  93. - init
  94. {
  95.     head = (struct qs_internal_node *)malloc(sizeof(struct qs_internal_node));
  96.     assert(head != NULL);
  97.     tail = (struct qs_internal_node *)malloc(sizeof(struct qs_internal_node));
  98.     assert(tail != NULL);
  99.  
  100.     head->next = tail;
  101.     head->prev = head;
  102.     head->ptr  = NULL;
  103.  
  104.     tail->next = tail;
  105.     tail->prev = head;
  106.     tail->ptr  = NULL;
  107.  
  108.     ENSURE(listOK);
  109.  
  110.     return self;
  111. }
  112.  
  113. //M+ -push:(void *)p
  114. //    PURPOSE:
  115. //        push something onto the stack, or end of queue.
  116. //M-
  117. -push:(void *)p
  118. {
  119.     struct qs_internal_node *new;
  120.  
  121.     REQUIRE(listOK);
  122.  
  123.     new = (struct qs_internal_node *)malloc(sizeof *new);
  124.     assert(new != NULL);
  125.  
  126.     new->ptr = p;
  127.     new->prev = tail->prev;
  128.     new->next = tail;
  129.  
  130.     tail->prev = new;
  131.  
  132.     new->prev->next = new;
  133.  
  134.     ENSURE(listOK);
  135.  
  136.     return self;
  137. }
  138.  
  139. //M+ -(void *)first
  140. //    PURPOSE:
  141. //        Retrieve the first thing that was pushed onto queue.
  142. //        This is the method that makes object a FIFO.
  143. //    RETURNS:
  144. //        pointer to item stored.  If NULL was stored it will return NULL,
  145. //        but it will also return NULL if queue is empty.
  146. //    NOTE:
  147. //        Should deallocate memory used internally by the object.
  148. //M-
  149. -(void *)first
  150. {
  151.     void *ret = NULL;
  152.  
  153.     REQUIRE(listOK);
  154.  
  155.     if (head->next != tail)
  156.     {    // object has something in it.
  157.  
  158.         struct qs_internal_node *tmp = head->next;
  159.  
  160.         head->next = tmp->next;
  161.         head->next->prev = head;
  162.  
  163.         ret = tmp->ptr;
  164.  
  165.         free(tmp);
  166.     }
  167.  
  168.     ENSURE(listOK);
  169.  
  170.     return ret;
  171. }
  172.  
  173. //M+ -(void *)pop
  174. //    PURPOSE:
  175. //        Retrieve last thing that was pushed onto stack.
  176. //        Method used to make object into a LIFO.
  177. //    RETURNS:
  178. //        pointer to item stored.  If NULL was stored it will return NULL,
  179. //        but it will also return NULL if stack is empty.
  180. //
  181. //    NOTE:
  182. //        Should deallocate memory used internally by the object.
  183. //M-
  184. -(void *)pop
  185. {
  186.     void *ret = NULL;
  187.  
  188.     REQUIRE(listOK);
  189.  
  190.     if (tail->prev != head)
  191.     {    // object has something in it.
  192.  
  193.         struct qs_internal_node *tmp = tail->prev;
  194.  
  195.         tail->prev = tmp->prev;
  196.         tail->prev->next = tail;
  197.  
  198.         ret = tmp->ptr;
  199.  
  200.         free(tmp);
  201.     }
  202.  
  203.     ENSURE(listOK);
  204.  
  205.     return ret;
  206. }
  207.  
  208. //M+ -(void *)tail
  209. //    PURPOSE:
  210. //        Peek at whatever is at tail of stack.
  211. //        This is what was just "pushed" on stack.
  212. //M-
  213. -(void *)tail
  214. {
  215.     REQUIRE(listOK);
  216.     return tail->prev->ptr;
  217. }
  218.  
  219. //M+ -(void *)head
  220. //    PURPOSE:
  221. //        Peek at whatever is at head of stack.
  222. //        This is what is "first" on queue.
  223. //M-
  224. -(void *)head
  225. {
  226.     REQUIRE(listOK);
  227.     return head->next->ptr;
  228. }
  229.  
  230. //M+ -(BOOL)empty
  231. //    PURPOSE:
  232. //        Determine if stack/queue has anything in it
  233. //M-
  234. -(BOOL)isEmpty
  235. {
  236.     REQUIRE(listOK);
  237.     return (head->next == tail);
  238. }
  239.  
  240. //M+ - free
  241. //    PURPOSE:
  242. //        Deallocate memory used by the object.
  243. //    NOTES:
  244. //        Doesn't deallocate memory that is contained by the object's
  245. //        implementation.  Only deallocates memory used by the implementation.
  246. //M-
  247. - free
  248. {
  249.     REQUIRE(listOK);
  250.  
  251.     // free the list in implementation independant way
  252.     //while(![self empty])
  253.     //    [self pop];
  254.  
  255.     // free the list in way that depends on doubly-linked lists
  256.     // speed up the process, I hope.
  257.     while (head->next != tail)
  258.     {
  259.         struct qs_internal_node *tmp = head->next->next;
  260.         free(head->next);
  261.         head->next = tmp;
  262.     }
  263.  
  264.     free(head);
  265.     free(tail);
  266.  
  267.     [super free];
  268.  
  269.     return self;
  270. }
  271.  
  272. @@end
  273. @
  274.  
  275.  
  276. 1.1
  277. log
  278. @Initial revision
  279. @
  280. text
  281. @d5 4
  282. a8 1
  283. /*    $Log$
  284. d14 2
  285. a17 1
  286. #include <libc.h>
  287. d40 5
  288. a44 1
  289. //        Used as pre- and post-condition for most methods.
  290. d66 1
  291. d68 1
  292. d94 1
  293. d112 4
  294. a115 1
  295. //
  296. d121 1
  297. a121 2
  298.     void *ret;
  299.     struct qs_internal_node *tmp;
  300. d125 2
  301. a126 1
  302.     tmp = head->next;
  303. d128 1
  304. a128 2
  305.     head->next = tmp->next;
  306.     head->next->prev = head;
  307. d130 2
  308. a131 1
  309.     ret = tmp->ptr;
  310. d133 1
  311. a133 1
  312.     free(tmp);
  313. d135 3
  314. d146 4
  315. d156 1
  316. a156 2
  317.     void *ret;
  318.     struct qs_internal_node *tmp;
  319. d160 2
  320. a161 1
  321.     tmp = tail->prev;
  322. d163 1
  323. a163 2
  324.     tail->prev = tmp->prev;
  325.     tail->prev->next = tail;
  326. d165 2
  327. a166 1
  328.     ret = tmp->ptr;
  329. d168 1
  330. a168 1
  331.     free(tmp);
  332. d170 3
  333. d181 1
  334. a181 1
  335. //        This is what is "pushed" on stack.
  336. d204 1
  337. a204 1
  338. -(BOOL)empty
  339. d210 1
  340. a210 1
  341. //M+ -(BOOL)empty
  342. d214 1
  343. a214 1
  344. //        Doesn't deallocate memory that is referenced by the object's
  345. d221 12
  346. a232 2
  347.     while(![self empty])
  348.         [self pop];
  349. @
  350.