• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**********************************************************************
2  * File:        clst.c  (Formerly clist.c)
3  * Description: CONS cell list handling code which is not in the include file.
4  * Author:      Phil Cheatle
5  * Created:     Mon Jan 28 08:33:13 GMT 1991
6  *
7  * (C) Copyright 1991, Hewlett-Packard Ltd.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include          "mfcpch.h"     //precompiled headers
21 #include <stdlib.h>
22 #include "clst.h"
23 
24 /***********************************************************************
25  *  MEMBER FUNCTIONS OF CLASS: CLIST
26  *  ================================
27  **********************************************************************/
28 
29 /***********************************************************************
30  *							CLIST::internal_deep_clear
31  *
32  *  Used by the "deep_clear" member function of derived list
33  *  classes to destroy all the elements on the list.
34  *  The calling function passes a "zapper" function which can be called to
35  *  delete each data element of the list, regardless of its class.  This
36  *  technique permits a generic clear function to destroy elements of
37  *  different derived types correctly, without requiring virtual functions and
38  *  the consequential memory overhead.
39  **********************************************************************/
40 
41 void
internal_deep_clear(void (* zapper)(void *))42 CLIST::internal_deep_clear (     //destroy all links
43 void (*zapper) (void *)) {       //ptr to zapper functn
44   CLIST_LINK *ptr;
45   CLIST_LINK *next;
46 
47   #ifndef NDEBUG
48   if (!this)
49     NULL_OBJECT.error ("CLIST::internal_deep_clear", ABORT, NULL);
50   #endif
51 
52   if (!empty ()) {
53     ptr = last->next;            //set to first
54     last->next = NULL;           //break circle
55     last = NULL;                 //set list empty
56     while (ptr) {
57       next = ptr->next;
58       zapper (ptr->data);
59       delete(ptr);
60       ptr = next;
61     }
62   }
63 }
64 
65 
66 /***********************************************************************
67  *							CLIST::shallow_clear
68  *
69  *  Used by the destructor and the "shallow_clear" member function of derived
70  *  list classes to destroy the list.
71  *  The data elements are NOT destroyed.
72  *
73  **********************************************************************/
74 
shallow_clear()75 void CLIST::shallow_clear() {  //destroy all links
76   CLIST_LINK *ptr;
77   CLIST_LINK *next;
78 
79   #ifndef NDEBUG
80   if (!this)
81     NULL_OBJECT.error ("CLIST::shallow_clear", ABORT, NULL);
82   #endif
83 
84   if (!empty ()) {
85     ptr = last->next;            //set to first
86     last->next = NULL;           //break circle
87     last = NULL;                 //set list empty
88     while (ptr) {
89       next = ptr->next;
90       delete(ptr);
91       ptr = next;
92     }
93   }
94 }
95 
96 
97 /***********************************************************************
98  *							CLIST::internal_deep_copy
99  *
100  *  Used during explict deep copy of a list.  The "copier" function passed
101  *  allows each element to be correctly deep copied (assuming that each class
102  *  in the inheritance hierarchy does properly deep copies its members).  The
103  *  function passing technique is as for "internal_clear".
104  **********************************************************************/
105 
106 void
107                                  //ptr to copier functn
internal_deep_copy(void * (* copier)(void *),const CLIST * list)108 CLIST::internal_deep_copy (void *(*copier) (void *),
109 const CLIST * list) {            //list being copied
110   CLIST_ITERATOR from_it ((CLIST *) list);
111   CLIST_ITERATOR to_it(this);
112 
113   #ifndef NDEBUG
114   if (!this)
115     NULL_OBJECT.error ("CLIST::internal_deep_copy", ABORT, NULL);
116   if (!list)
117     BAD_PARAMETER.error ("CLIST::internal_deep_copy", ABORT,
118       "source list is NULL");
119   #endif
120 
121   for (from_it.mark_cycle_pt (); !from_it.cycled_list (); from_it.forward ())
122     to_it.add_after_then_move (copier (from_it.data ()));
123 }
124 
125 
126 /***********************************************************************
127  *							CLIST::assign_to_sublist
128  *
129  *  The list is set to a sublist of another list.  "This" list must be empty
130  *  before this function is invoked.  The two iterators passed must refer to
131  *  the same list, different from "this" one.  The sublist removed is the
132  *  inclusive list from start_it's current position to end_it's current
133  *  position.  If this range passes over the end of the source list then the
134  *  source list has its end set to the previous element of start_it.  The
135  *  extracted sublist is unaffected by the end point of the source list, its
136  *  end point is always the end_it position.
137  **********************************************************************/
138 
assign_to_sublist(CLIST_ITERATOR * start_it,CLIST_ITERATOR * end_it)139 void CLIST::assign_to_sublist(                           //to this list
140                               CLIST_ITERATOR *start_it,  //from list start
141                               CLIST_ITERATOR *end_it) {  //from list end
142   const ERRCODE LIST_NOT_EMPTY =
143     "Destination list must be empty before extracting a sublist";
144 
145   #ifndef NDEBUG
146   if (!this)
147     NULL_OBJECT.error ("CLIST::assign_to_sublist", ABORT, NULL);
148   #endif
149 
150   if (!empty ())
151     LIST_NOT_EMPTY.error ("CLIST.assign_to_sublist", ABORT, NULL);
152 
153   last = start_it->extract_sublist (end_it);
154 }
155 
156 
157 /***********************************************************************
158  *							CLIST::length
159  *
160  *  Return count of elements on list
161  **********************************************************************/
162 
length()163 inT32 CLIST::length() {  //count elements
164   CLIST_ITERATOR it(this);
165   inT32 count = 0;
166 
167   #ifndef NDEBUG
168   if (!this)
169     NULL_OBJECT.error ("CLIST::length", ABORT, NULL);
170   #endif
171 
172   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
173     count++;
174   return count;
175 }
176 
177 
178 /***********************************************************************
179  *							CLIST::sort
180  *
181  *  Sort elements on list
182  **********************************************************************/
183 
184 void
sort(int comparator (const void *,const void *))185 CLIST::sort (                    //sort elements
186 int comparator (                 //comparison routine
187 const void *, const void *)) {
188   CLIST_ITERATOR it(this);
189   inT32 count;
190   void **base;                   //ptr array to sort
191   void **current;
192   inT32 i;
193 
194   #ifndef NDEBUG
195   if (!this)
196     NULL_OBJECT.error ("CLIST::sort", ABORT, NULL);
197   #endif
198 
199   /* Allocate an array of pointers, one per list element */
200   count = length ();
201   base = (void **) malloc (count * sizeof (void *));
202 
203   /* Extract all elements, putting the pointers in the array */
204   current = base;
205   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
206     *current = it.extract ();
207     current++;
208   }
209 
210   /* Sort the pointer array */
211   qsort ((char *) base, count, sizeof (*base), comparator);
212 
213   /* Rebuild the list from the sorted pointers */
214   current = base;
215   for (i = 0; i < count; i++) {
216     it.add_to_end (*current);
217     current++;
218   }
219   free(base);
220 }
221 
222 // Assuming list has been sorted already, insert new_data to
223 // keep the list sorted according to the same comparison function.
224 // Comparision function is the same as used by sort, i.e. uses double
225 // indirection. Time is O(1) to add to beginning or end.
226 // Time is linear to add pre-sorted items to an empty list.
227 // If unique, then don't add duplicate entries.
add_sorted(int comparator (const void *,const void *),bool unique,void * new_data)228 void CLIST::add_sorted(int comparator(const void*, const void*),
229                        bool unique, void* new_data) {
230   // Check for adding at the end.
231   if (last == NULL || comparator(&last->data, &new_data) < 0) {
232     CLIST_LINK* new_element = new CLIST_LINK;
233     new_element->data = new_data;
234     if (last == NULL) {
235       new_element->next = new_element;
236     } else {
237       new_element->next = last->next;
238       last->next = new_element;
239     }
240     last = new_element;
241   } else if (!unique || last->data != new_data) {
242     // Need to use an iterator.
243     CLIST_ITERATOR it(this);
244     for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
245       void* data = it.data();
246       if (data == new_data && unique)
247         return;
248       if (comparator(&data, &new_data) > 0)
249         break;
250     }
251     if (it.cycled_list())
252       it.add_to_end(new_data);
253     else
254       it.add_before_then_move(new_data);
255   }
256 }
257 
258 /***********************************************************************
259  *							CLIST::prep_serialise
260  *
261  *  Replace the last member with a count of elements for serialisation.
262  *  This is used on list objects which are members of objects being
263  *  serialised.  The containing object has been shallow copied and this member
264  *  function is invoked on the COPY.
265  **********************************************************************/
266 
prep_serialise()267 void CLIST::prep_serialise() {
268   CLIST_ITERATOR this_it(this);
269   inT32 count = 0;
270 
271   #ifndef NDEBUG
272   if (!this)
273     NULL_OBJECT.error ("CLIST::prep_serialise", ABORT, NULL);
274   #endif
275 
276   count = 0;
277   if (!empty ())
278     for (this_it.mark_cycle_pt ();
279     !this_it.cycled_list (); this_it.forward ())
280   count++;
281   last = (CLIST_LINK *) count;
282 }
283 
284 
285 /***********************************************************************
286  *							CLIST::internal_dump
287  *
288  *  Cause each element on the list to be serialised by walking the list and
289  *  calling the element_serialiser function for each element.  The
290  *  element_serialiser simply does the appropriate coercion of the element to
291  *  its real type and then invokes the elements serialise function
292  **********************************************************************/
293 
294 void
internal_dump(FILE * f,void element_serialiser (FILE *,void *))295 CLIST::internal_dump (FILE * f, void element_serialiser (FILE *, void *)) {
296   CLIST_ITERATOR this_it(this);
297 
298   #ifndef NDEBUG
299   if (!this)
300     NULL_OBJECT.error ("CLIST::internal_dump", ABORT, NULL);
301   #endif
302 
303   if (!empty ())
304     for (this_it.mark_cycle_pt ();
305     !this_it.cycled_list (); this_it.forward ())
306   element_serialiser (f, this_it.data ());
307 }
308 
309 
310 /***********************************************************************
311  *							CLIST::internal_de_dump
312  *
313  *  Cause each element on the list to be de_serialised by extracting the count
314  *  of elements on the list, (held in the last member of the dumped version of
315  *  the list object), and then de-serialising that number of list elements,
316  *  adding each to the end of the reconstructed list.
317  **********************************************************************/
318 
319 void
internal_de_dump(FILE * f,void * element_de_serialiser (FILE *))320 CLIST::internal_de_dump (FILE * f, void *element_de_serialiser (FILE *)) {
321   inT32 count = (ptrdiff_t) last;
322   CLIST_ITERATOR this_it;
323 
324   #ifndef NDEBUG
325   if (!this)
326     NULL_OBJECT.error ("CLIST::internal_de_dump", ABORT, NULL);
327   #endif
328 
329   last = NULL;
330   this_it.set_to_list (this);
331   for (; count > 0; count--)
332     this_it.add_to_end (element_de_serialiser (f));
333 }
334 
335 
336 /***********************************************************************
337  *  MEMBER FUNCTIONS OF CLASS: CLIST_ITERATOR
338  *  =========================================
339  **********************************************************************/
340 
341 /***********************************************************************
342  *							CLIST_ITERATOR::forward
343  *
344  *  Move the iterator to the next element of the list.
345  *  REMEMBER: ALL LISTS ARE CIRCULAR.
346  **********************************************************************/
347 
forward()348 void *CLIST_ITERATOR::forward() {
349   #ifndef NDEBUG
350   if (!this)
351     NULL_OBJECT.error ("CLIST_ITERATOR::forward", ABORT, NULL);
352   if (!list)
353     NO_LIST.error ("CLIST_ITERATOR::forward", ABORT, NULL);
354   #endif
355   if (list->empty ())
356     return NULL;
357 
358   if (current) {                 //not removed so
359                                  //set previous
360     prev = current;
361     started_cycling = TRUE;
362     // In case next is deleted by another iterator, get next from current.
363     current = current->next;
364   } else {
365     if (ex_current_was_cycle_pt)
366       cycle_pt = next;
367   current = next;
368   }
369   next = current->next;
370 
371   #ifndef NDEBUG
372   if (!current)
373     NULL_DATA.error ("CLIST_ITERATOR::forward", ABORT, NULL);
374   if (!next)
375     NULL_NEXT.error ("CLIST_ITERATOR::forward", ABORT,
376                      "This is: %p  Current is: %p", this, current);
377   #endif
378   return current->data;
379 }
380 
381 
382 /***********************************************************************
383  *							CLIST_ITERATOR::data_relative
384  *
385  *  Return the data pointer to the element "offset" elements from current.
386  *  "offset" must not be less than -1.
387  *  (This function can't be INLINEd because it contains a loop)
388  **********************************************************************/
389 
data_relative(inT8 offset)390 void *CLIST_ITERATOR::data_relative(                //get data + or - ...
391                                     inT8 offset) {  //offset from current
392   CLIST_LINK *ptr;
393 
394   #ifndef NDEBUG
395   if (!this)
396     NULL_OBJECT.error ("CLIST_ITERATOR::data_relative", ABORT, NULL);
397   if (!list)
398     NO_LIST.error ("CLIST_ITERATOR::data_relative", ABORT, NULL);
399   if (list->empty ())
400     EMPTY_LIST.error ("CLIST_ITERATOR::data_relative", ABORT, NULL);
401   if (offset < -1)
402     BAD_PARAMETER.error ("CLIST_ITERATOR::data_relative", ABORT,
403       "offset < -l");
404   #endif
405 
406   if (offset == -1)
407     ptr = prev;
408   else
409     for (ptr = current ? current : prev; offset-- > 0; ptr = ptr->next);
410 
411   #ifndef NDEBUG
412   if (!ptr)
413     NULL_DATA.error ("CLIST_ITERATOR::data_relative", ABORT, NULL);
414   #endif
415 
416   return ptr->data;
417 }
418 
419 
420 /***********************************************************************
421  *							CLIST_ITERATOR::move_to_last()
422  *
423  *  Move current so that it is set to the end of the list.
424  *  Return data just in case anyone wants it.
425  *  (This function can't be INLINEd because it contains a loop)
426  **********************************************************************/
427 
move_to_last()428 void *CLIST_ITERATOR::move_to_last() {
429   #ifndef NDEBUG
430   if (!this)
431     NULL_OBJECT.error ("CLIST_ITERATOR::move_to_last", ABORT, NULL);
432   if (!list)
433     NO_LIST.error ("CLIST_ITERATOR::move_to_last", ABORT, NULL);
434   #endif
435 
436   while (current != list->last)
437     forward();
438 
439   if (current == NULL)
440     return NULL;
441   else
442     return current->data;
443 }
444 
445 
446 /***********************************************************************
447  *							CLIST_ITERATOR::exchange()
448  *
449  *  Given another iterator, whose current element is a different element on
450  *  the same list list OR an element of another list, exchange the two current
451  *  elements.  On return, each iterator points to the element which was the
452  *  other iterators current on entry.
453  *  (This function hasn't been in-lined because its a bit big!)
454  **********************************************************************/
455 
exchange(CLIST_ITERATOR * other_it)456 void CLIST_ITERATOR::exchange(                             //positions of 2 links
457                               CLIST_ITERATOR *other_it) {  //other iterator
458   const ERRCODE DONT_EXCHANGE_DELETED =
459     "Can't exchange deleted elements of lists";
460 
461   CLIST_LINK *old_current;
462 
463   #ifndef NDEBUG
464   if (!this)
465     NULL_OBJECT.error ("CLIST_ITERATOR::exchange", ABORT, NULL);
466   if (!list)
467     NO_LIST.error ("CLIST_ITERATOR::exchange", ABORT, NULL);
468   if (!other_it)
469     BAD_PARAMETER.error ("CLIST_ITERATOR::exchange", ABORT, "other_it NULL");
470   if (!(other_it->list))
471     NO_LIST.error ("CLIST_ITERATOR::exchange", ABORT, "other_it");
472   #endif
473 
474   /* Do nothing if either list is empty or if both iterators reference the same
475   link */
476 
477   if ((list->empty ()) ||
478     (other_it->list->empty ()) || (current == other_it->current))
479     return;
480 
481   /* Error if either current element is deleted */
482 
483   if (!current || !other_it->current)
484     DONT_EXCHANGE_DELETED.error ("CLIST_ITERATOR.exchange", ABORT, NULL);
485 
486   /* Now handle the 4 cases: doubleton list; non-doubleton adjacent elements
487   (other before this); non-doubleton adjacent elements (this before other);
488   non-adjacent elements. */
489 
490                                  //adjacent links
491   if ((next == other_it->current) ||
492   (other_it->next == current)) {
493                                  //doubleton list
494     if ((next == other_it->current) &&
495     (other_it->next == current)) {
496       prev = next = current;
497       other_it->prev = other_it->next = other_it->current;
498     }
499     else {                       //non-doubleton with
500                                  //adjacent links
501                                  //other before this
502       if (other_it->next == current) {
503         other_it->prev->next = current;
504         other_it->current->next = next;
505         current->next = other_it->current;
506         other_it->next = other_it->current;
507         prev = current;
508       }
509       else {                     //this before other
510         prev->next = other_it->current;
511         current->next = other_it->next;
512         other_it->current->next = current;
513         next = current;
514         other_it->prev = other_it->current;
515       }
516     }
517   }
518   else {                         //no overlap
519     prev->next = other_it->current;
520     current->next = other_it->next;
521     other_it->prev->next = current;
522     other_it->current->next = next;
523   }
524 
525   /* update end of list pointer when necessary (remember that the 2 iterators
526     may iterate over different lists!) */
527 
528   if (list->last == current)
529     list->last = other_it->current;
530   if (other_it->list->last == other_it->current)
531     other_it->list->last = current;
532 
533   if (current == cycle_pt)
534     cycle_pt = other_it->cycle_pt;
535   if (other_it->current == other_it->cycle_pt)
536     other_it->cycle_pt = cycle_pt;
537 
538   /* The actual exchange - in all cases*/
539 
540   old_current = current;
541   current = other_it->current;
542   other_it->current = old_current;
543 }
544 
545 
546 /***********************************************************************
547  *							CLIST_ITERATOR::extract_sublist()
548  *
549  *  This is a private member, used only by CLIST::assign_to_sublist.
550  *  Given another iterator for the same list, extract the links from THIS to
551  *  OTHER inclusive, link them into a new circular list, and return a
552  *  pointer to the last element.
553  *  (Can't inline this function because it contains a loop)
554  **********************************************************************/
555 
extract_sublist(CLIST_ITERATOR * other_it)556 CLIST_LINK *CLIST_ITERATOR::extract_sublist(                             //from this current
557                                             CLIST_ITERATOR *other_it) {  //to other current
558   CLIST_ITERATOR temp_it = *this;
559   CLIST_LINK *end_of_new_list;
560 
561   const ERRCODE BAD_SUBLIST = "Can't find sublist end point in original list";
562   #ifndef NDEBUG
563   const ERRCODE BAD_EXTRACTION_PTS =
564     "Can't extract sublist from points on different lists";
565   const ERRCODE DONT_EXTRACT_DELETED =
566     "Can't extract a sublist marked by deleted points";
567 
568   if (!this)
569     NULL_OBJECT.error ("CLIST_ITERATOR::extract_sublist", ABORT, NULL);
570   if (!other_it)
571     BAD_PARAMETER.error ("CLIST_ITERATOR::extract_sublist", ABORT,
572       "other_it NULL");
573   if (!list)
574     NO_LIST.error ("CLIST_ITERATOR::extract_sublist", ABORT, NULL);
575   if (list != other_it->list)
576     BAD_EXTRACTION_PTS.error ("CLIST_ITERATOR.extract_sublist", ABORT, NULL);
577   if (list->empty ())
578     EMPTY_LIST.error ("CLIST_ITERATOR::extract_sublist", ABORT, NULL);
579 
580   if (!current || !other_it->current)
581     DONT_EXTRACT_DELETED.error ("CLIST_ITERATOR.extract_sublist", ABORT,
582       NULL);
583   #endif
584 
585   ex_current_was_last = other_it->ex_current_was_last = FALSE;
586   ex_current_was_cycle_pt = FALSE;
587   other_it->ex_current_was_cycle_pt = FALSE;
588 
589   temp_it.mark_cycle_pt ();
590   do {                           //walk sublist
591     if (temp_it.cycled_list ())  //cant find end pt
592       BAD_SUBLIST.error ("CLIST_ITERATOR.extract_sublist", ABORT, NULL);
593 
594     if (temp_it.at_last ()) {
595       list->last = prev;
596       ex_current_was_last = other_it->ex_current_was_last = TRUE;
597     }
598 
599     if (temp_it.current == cycle_pt)
600       ex_current_was_cycle_pt = TRUE;
601 
602     if (temp_it.current == other_it->cycle_pt)
603       other_it->ex_current_was_cycle_pt = TRUE;
604 
605     temp_it.forward ();
606   }
607   while (temp_it.prev != other_it->current);
608 
609                                  //circularise sublist
610   other_it->current->next = current;
611   end_of_new_list = other_it->current;
612 
613                                  //sublist = whole list
614   if (prev == other_it->current) {
615     list->last = NULL;
616     prev = current = next = NULL;
617     other_it->prev = other_it->current = other_it->next = NULL;
618   }
619   else {
620     prev->next = other_it->next;
621     current = other_it->current = NULL;
622     next = other_it->next;
623     other_it->prev = prev;
624   }
625   return end_of_new_list;
626 }
627