PIPS
list.c
Go to the documentation of this file.
1 /*
2 
3  $Id: list.c 1365 2016-09-24 06:08:13Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of NewGen.
8 
9  NewGen is free software: you can redistribute it and/or modify it under the
10  terms of the GNU General Public License as published by the Free Software
11  Foundation, either version 3 of the License, or any later version.
12 
13  NewGen is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16  License for more details.
17 
18  You should have received a copy of the GNU General Public License along with
19  NewGen. If not, see <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24  #include "config.h"
25 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include "genC.h"
30 #include "newgen_include.h"
31 
32 /** @defgroup newgen_list NewGen functions dealing with list objects
33 
34  The following functions implement a small library of utilities in the
35  Lisp tradition.
36 
37  Lists are pointers to chunk objects that are linked together in a single
38  forward way.
39 
40  . GEN_EQ is pointer comparison,
41  . GEN_LENGTH returns the length of the list CP, if it is not cyclic,
42  or loop forever
43  . GEN_MAPL applies (*FP) to every CDR of CP.
44  . GEN_MAP applies (*FP) to every item of the list.
45  . GEN_REDUCE successively applies (*FP) on R adn every CRD of CP.
46  . GEN_SOME aplies (*FP) to every CDR of CP and returns the first sublist
47  whose CAR verifies (*FP).
48  . GEN_INSERT_AFTER inster a new object after a specified object in the list
49  . GEN_MAPC_TABULATED applies (*FP) on every non null element of the
50  domain BINDING.
51  . GEN_FIND_TABULATED retrieves the object of KEY in the tabulated DOMAIN.
52  . GEN_FILTER_TABULATED returns a list of objects from DOMAIN that verify
53  the FILTER.
54  . GEN_FREE_LIST frees the spine of the list L.
55  . GEN_FULL_FREE_LIST frees the whole list L.
56  . GEN_NCONC physically concatenates CP1 and CP2 (returns CP1).
57  . GEN_COPY copies one gen_chunks in another.
58  . GEN_FIND_IF returns the leftmost element (extracted from the cons cell
59  by EXTRACT) of the sequence SEQ that satisfies TEST. EXTRACT should
60  be one of the car_to_domain function that are automatically generated
61  by Newgen.
62  . GEN_FIND_IF_FROM_END is equivalent to GEN_FIND_IF but returns the
63  rightmost element of SEQ.
64  . GEN_FIND returns the leftmost element (extracted from the cons cell
65  by EXTRACT) of the sequence SEQ such that TEST returns true when applied
66  to ITEM and this element. EXTRACT should be one of the car_to_domain
67  function that are automatically generated by Newgen.
68  . GEN_FIND_FROM_END is equivalent to GEN_FIND but returns the rightmost
69  element of SEQ.
70  . GEN_FIND_EQ
71  . GEN_CONCATENATE concatenates two lists. the structures of both lists are
72  duplicated.
73  . GEN_APPEND concatenates two lists. the structure of the first list is
74  duplicated.
75  . GEN_COPY_SEQ
76  . GEN_FULL_COPY_LIST
77  . GEN_COPY_STRING_LIST
78  . GEN_FREE_STRING_LIST
79  . GEN_LAST returns the last cons of a list.
80  . gen_substitute_chunk_by_list
81  . GEN_REMOVE updates the list (pointer) CPP by removing (and freeing) any
82  ocurrence of the gen_chunk OBJ.
83  . GEN_REMOVE_ONCE : Remove the first occurence of obj in list l.
84  . GEN_NTHCDR returns the N-th (beginning at 1) CDR element of L.
85  CDR(L) = GEN_NTHCDR(1,L).
86  . GEN_NTH returns the N-th (beginning at 0) car of L.
87  CAR(L) = GEN_NTH(0,L).
88  . GEN_SORT_LIST(L, compare) sorts L in place with compare (see man qsort)
89  . GEN_ONCE(ITEM, L) prepends ITEM to L if not already there.
90  . GEN_IN_LIST_P(ITEM, L) checks that item ITEM appears in list L
91  . GEN_OCCURENCES(ITEM, L) returns the number of occurences of item
92  ITEM in list L
93  . GEN_ONCE_P(L) checks that each item in list L appears only once
94  . GEN_CLOSURE()
95  . GEN_MAKE_LIST(DOMAIN, ...) makes an homogeneous list of the varargs (but
96  homogeneity is not checked)
97  . gen_list_and(list * a, list b) : Compute A = A inter B
98  . gen_list_and_not(list * a, list b) : Compute A = A inter non B
99  . gen_list_patch(list l, gen_chunk * x, gen_chunk * y) :
100  Replace all the reference to x in list l by a reference to y
101  . gen_position(void * item, list l): rank of item in list l,
102  0 if not present
103 */
104 
105 /** @{ */
106 
107 /**@return true if object are identical
108  @param obj1, the first object to test for equality
109  @param obj2, the second object to test for equality
110  */
111 bool gen_eq(const void * obj1, const void * obj2)
112 {
113  return obj1 == obj2;
114 }
115 
116 /**@return true if the list is cyclic. A list is considered cyclic if at least
117  * one element points to a previously visited element.
118  * @param list, the list to check
119  */
120 bool gen_list_cyclic_p (const list ml)
121 {
122  /* a list with 0 or 1 element is not cyclic */
123  bool cyclic_p = ! (ENDP(ml) || ENDP(CDR(ml)));
124 
125  if(cyclic_p) { /* it may be cyclic */
126  list cl; /* To ease debugging */
127  int i = 1;
128  set adresses = set_make (set_pointer);
129 
130  for (cl = ml; !ENDP(cl); POP(cl), i++) {
131  if (set_belong_p ( adresses, cl)) {
132  fprintf(stderr, "warning: cycle found");
133  fprintf(stderr, "next elem %d:'%p' already in list\n", i, cl);
134  cyclic_p = true;
135  break;
136  }
137  set_add_element (adresses, adresses, cl);
138  cyclic_p = false;
139  }
140 
141  set_free (adresses);
142  }
143 
144  return cyclic_p;
145 }
146 
147 /** @return the length of the list
148  * @param[in] l, the list to evaluate, assumed to be acyclic
149  */
150 size_t gen_length(const list l)
151 {
152  list cp = l;
153  size_t i;
154  for (i = 0; cp != NIL ; cp = cp->cdr, i++) {;}
155  return i;
156 }
157 
159 {
160  return gen_length(l)*sizeof(cons);
161 }
162 
163 /* MAP
164  */
165 void gen_mapl(gen_iter_func_t fp, const list l)
166 {
167  list cp = (list) l;
168  for (; cp != NIL ; cp = cp->cdr)
169  (*fp)(cp);
170 }
171 
172 void gen_map(gen_iter_func_t fp, const list l)
173 {
174  list cp = (list) l;
175  for (; !ENDP(cp); cp=CDR(cp))
176  (*fp)(CHUNK(CAR(cp)));
177 }
178 
179 // should be void * ?
180 void * gen_reduce(void * r, void *(*fp)(void *, const list), const list l)
181 {
182  list cp = (list) l;
183  for( ; cp != NIL ; cp = cp->cdr ) {
184  r = (*fp)( r, cp );
185  }
186  return r;
187 }
188 /* compares two lists using the functor given in parameters
189  * returns true if for all n, the n'th element of first list is equals
190  * to the n'th element of the second list
191  */
192 bool gen_equals(const list l0, const list l1,gen_eq_func_t equals)
193 {
194  list iter0=l0,iter1=l1;
195  while(!ENDP(iter0)&&!ENDP(iter1))
196  {
197  if(!equals(CHUNK(CAR(iter0)),CHUNK(CAR(iter1))))
198  return false;
199  POP(iter0);
200  POP(iter1);
201  }
202  return ENDP(iter0)&&ENDP(iter1);
203 
204 }
205 
207 {
208  list cp = (list) l;
209  for( ; cp!= NIL ; cp = cp->cdr )
210  if( (*fp)(cp))
211  return cp;
212  return NIL;
213 }
214 
215 /* SPECIAL INSERTION
216  */
218 static bool cons_of_gen_chunk(const list cp)
219 {
221 }
222 
223 void gen_insert_after(const void * no, const void * o, list l)
224 {
225  gen_chunk * new_obj = (gen_chunk*) no, * obj = (gen_chunk*) o;
226  cons *obj_cons = NIL;
228 
230  assert(!ENDP(obj_cons));
231  CDR(obj_cons) = CONS(CHUNK, new_obj, CDR(obj_cons));
232 }
233 
234 /*
235  insert object "no" before object "o" in the list "l". Return the new
236  list.
237 */
238 list gen_insert_before(const void * no, const void * o, list l)
239 {
240  gen_chunk * new_obj = (gen_chunk*) no;
241  gen_chunk * obj = (gen_chunk*) o;
242 
243  list r = NIL; /* result */
244  list c = l; /* current */
245  list p = NIL; /* previous */
246 
247  /* search obj in list */
248  for ( ; c!=NIL ; c=c->cdr)
249  if ( CHUNK(CAR(c))==obj )
250  break;
251  else
252  p = c;
253 
254  assert(!ENDP(c));
255 
256  if (p) { /* obj is not the first object of the list */
257  CDR(p) = CONS(CHUNK, new_obj, CDR(p));
258  r = l;
259  }
260  else { /* obj is the first object */
261  r = CONS(CHUNK, new_obj, c);
262  }
263  return r;
264 }
265 
266 /* insert nl before or after item in list l, both initial lists are consumed
267  @return the new list
268  */
269 list gen_insert_list(list nl, const void * item, list l, bool before)
270 {
271  // fast case
272  if (!nl) return l;
273 
274  // find insertion position in l
275  list p = NIL, c = l, head;
276  while (c && CHUNK(CAR(c))!=item)
277  p = c, c = CDR(c);
278  message_assert("item is in list", c!=NIL);
279 
280  // possibly forward one link if insertion is "after" the item
281  if (!before)
282  p = c, c = CDR(c);
283 
284  // link and set list head
285  if (p) // some previous
286  CDR(p) = nl, head = l;
287  else // no previous
288  p = nl, head = nl;
289 
290  // forward to link the tail, hold by "c"
291  while (CDR(p)) p = CDR(p);
292  CDR(p) = c;
293 
294  // done
295  return head;
296 }
297 
298 #define NEXT(cp) (((cp) == NIL) ? NIL : (cp)->cdr)
299 
300 /* @brief reverse a list in place
301  * @param cp, the list to be reversed
302  * @return the list reversed
303  */
305 {
306  cons *next, *next_next ;
307 
308  if( cp == NIL || cp->cdr == NIL ) return( cp ) ;
309 
310  next = cp->cdr ;
311  cp->cdr = NIL;
312  next_next = NEXT( next );
313 
314  for( ; next != NIL ; )
315  {
316  next->cdr = cp ;
317  cp = next ;
318  next = next_next ;
319  next_next = NEXT( next_next ) ;
320  }
321  return cp;
322 }
323 
324 /**@brief free the spine of the list
325  * @param[in,out] l, the list to free
326  */
328 {
329  list p, nextp ;
330  for( p = l ; p != NIL ; p = nextp ) {
331  nextp = p->cdr ;
332  CAR(p).p = NEWGEN_FREED; /* clean */
333  CDR(p) = (struct cons*) NEWGEN_FREED;
334  free( p );
335  }
336 }
337 
338 /**@brief physically concatenates CP1 and CP2 but do not duplicates the
339  * elements
340  * @return the concatenated list
341  * @param cp1, the first list to concatenate
342  * @param cp2, the second list to concatenate
343  */
345 {
346  cons *head = cp1 ;
347 
348  if( cp1 == NIL )
349  return( cp2 ) ;
350 
351  //message_assert ("cannot concatenate a cyclic list", gen_list_cyclic_p (cp1) == false);
352 
353  for( ; !ENDP( CDR( cp1 )) ; cp1 = CDR( cp1 ));
354 
355  CDR( cp1 ) = cp2 ;
356  return( head ) ;
357 }
358 
359 void gen_copy(void * a, void * b)
360 {
361  * (gen_chunk*)a = * (gen_chunk*)b ;
362 }
363 
364 void * gen_car(list l)
365 {
366  return CHUNK(CAR(l));
367 }
368 
369 void *
371 {
372  list pc = (list) l;
373  for (; pc!=NIL; pc=pc->cdr)
374  if ((*test)((*extract)(CAR(pc))))
375  return (*extract)(CAR(pc));
376  return gen_chunk_undefined;
377 }
378 
379 /* the last match is returned
380  */
381 void *
383  gen_extract_func_t extract)
384 {
385  list pc = (list) l;
386  void * e = gen_chunk_undefined ;
387  for (; pc!=NIL; pc=pc->cdr)
388  if ((*test)((*extract)(CAR(pc))))
389  e = (*extract)(CAR(pc));
390  return e;
391 }
392 
393 /**@return the leftmost element (extracted from the cons cell
394  * by EXTRACT) of the sequence SEQ such that TEST returns true when applied
395  * to ITEM and this element. EXTRACT should be one of the car_to_domain
396  * function that are automatically generated by Newgen.
397  */
398 void * gen_find(const void * item, const list seq,
400 {
401  list pc;
402  for (pc = seq; pc != NIL; pc = pc->cdr )
403  if ((*test)(item, (*extract)(CAR(pc))))
404  return (*extract)(CAR(pc));
405  return gen_chunk_undefined;
406 }
407 
408 void * gen_find_from_end(const void * item, const list seq,
410 {
411  list pc;
412  void * e = gen_chunk_undefined ;
413 
414  for (pc = seq; pc != NIL; pc = pc->cdr ) {
415  if ((*test)(item, (*extract)(CAR(pc))))
416  e = (*extract)(CAR(pc));
417  }
418 
419  return e;
420 }
421 
422 void * gen_find_eq(const void * item, const list seq)
423 {
424  list pc;
425  for (pc = (list) seq; pc != NIL; pc = pc->cdr )
426  if (item == CAR(pc).p)
427  return CAR(pc).p;
428  return gen_chunk_undefined;
429 }
430 
431 /**@brief concatenate two lists. the structures of both lists are duplicated.
432  * @return a new allocated list with duplicated elements
433  * @param l1, the first list to concatenate
434  * @param l2, the second list to concatenate
435  */
436 list gen_concatenate(const list l1x, const list l2x)
437 {
438  // break const declaration...
439  list l1 = (list) l1x, l2 = (list) l2x;
440  list l = NIL, q = NIL;
441 
442  if (l1 != NIL) {
443  l = q = CONS(CHUNK, CHUNK(CAR(l1)), NIL);
444  l1 = CDR(l1);
445  }
446  else if (l2 != NIL) {
447  l = q = CONS(CHUNK, CHUNK(CAR(l2)), NIL);
448  l2 = CDR(l2);
449  }
450  else {
451  return NIL;
452  }
453 
454  while (l1 != NIL) {
455  CDR(q) = CONS(CHUNK, CHUNK(CAR(l1)), NIL);
456  q = CDR(q);
457 
458  l1 = CDR(l1);
459  }
460 
461  while (l2 != NIL) {
462  CDR(q) = CONS(CHUNK, CHUNK(CAR(l2)), NIL);
463  q = CDR(q);
464 
465  l2 = CDR(l2);
466  }
467 
468  return l;
469 }
470 
471 list gen_append(list l1, const list l2)
472 {
473  cons *l = NIL, *q = NIL;
474 
475  if (l1 == NIL)
476  return(l2);
477 
478  l = q = CONS(CHUNK, CHUNK(CAR(l1)), NIL);
479  l1 = CDR(l1);
480 
481  while (l1 != NIL) {
482  CDR(q) = CONS(CHUNK, CHUNK(CAR(l1)), NIL);
483  q = CDR(q);
484 
485  l1 = CDR(l1);
486  }
487 
488  CDR(q) = l2;
489 
490  return(l);
491 }
492 
493 
494 /* Copy a list structure
495 
496  It does not copy the list elements, the new list references the
497  elements of the old one.
498 
499  @return the new list
500  */
502  /* Begin of the new list: */
503  list nlb = NIL;
504  /* Pointer to the last element of th new list: */
505  list nle = NIL;
506 
507  /* While we are not at the end of the list: */
508  while (! ENDP(l)) {
509  /* Create a new list element with the current element: */
510  list p = CONS(CHUNK, CHUNK(CAR(l)), NIL);
511 
512  if (nle == NIL)
513  /* If nle is NIL, it is the first element, so keep it as the list
514  beginning: */
515  nlb = p;
516  else
517  /* Append the new element at the end of the new list: */
518  CDR(nle) = p;
519  /* Update the end pointer: */
520  nle = p;
521  /* Look for the next element of the list to copy: */
522  l = CDR(l);
523  }
524 
525  return nlb;
526 }
527 
528 
529 /* Copy a list structure with element copy
530 
531  It does copy the list elements.
532 
533  @return the new list
534  */
536  list nlb = NIL;
537  list nle = NIL;
538 
539  while (! ENDP(l)) {
540  /* Create a new list element with a copy of the current element: */
541  list p = CONS(CHUNK, gen_copy_tree(CHUNK(CAR(l))), NIL);
542 
543  if (nle == NIL)
544  nlb = p;
545  else
546  CDR(nle) = p;
547  nle = p;
548  l = CDR(l);
549  }
550 
551  return nlb;
552 }
553 
554 
555 list /* of string */
556 gen_copy_string_list(list /* of string */ ls)
557 {
558  list l = NIL;
559  MAP(STRING, s, l = CONS(STRING, strdup(s), l), ls);
560  return gen_nreverse(l);
561 }
562 
563 void
564 gen_free_string_list(list /* of string */ ls)
565 {
566  gen_map(free, ls);
567  gen_free_list(ls);
568 }
569 
570 
571 /* Return the last element of a list
572 
573  @param[in] l is the list we want the last element
574 
575  @return the last element. If the list is empty, return an empty
576  element.
577 */
579 {
580  if (ENDP(l)) return l; /* NIL case */
581  while (!ENDP(CDR(l))) l=CDR(l); /* else go to the last */
582  return l;
583 }
584 
585 /* substitute item o by list sl in list *pl, which is modified as a
586  * side effect. The substitution is performed only once when the
587  * first o is found. List sl is physically included in list *pl. If sl
588  * is empty, item o is removed from list *pl. If o is not found in
589  * *pl, *pl is left unmodified.
590  */
591 void gen_substitute_chunk_by_list(list * pl, const void * o, list sl)
592 {
593  list * pc = pl; // current indirect pointer
594  list ppc = NULL; // pointer to the previous cons
595 
596  if(ENDP(sl))
597  gen_remove_once(pl, o);
598  else
599  while (*pc) {
600  /* If the chunk to substitute is found, substitute it */
601  if ((gen_chunk*) o == CHUNK(CAR(*pc))) {
602  list tmp = *pc;
603  list npc = CDR(*pc);
604 
605  /* Insert sl at the beggining of the new list or after ppc */
606  if(ppc==NULL) {
607  *pl = sl;
608  }
609  else {
610  CDR(ppc) = sl;
611  }
612 
613  /* Add the left over list after sl */
614  CDR(gen_last(sl)) = npc;
615 
616  /* Get rid of the useless cons */
617  CAR(tmp).p = NEWGEN_FREED;
618  CDR(tmp) = NEWGEN_FREED;
619  free(tmp);
620 
621  break;
622  }
623  else {
624  /* Move down the input list */
625  ppc = *pc;
626  pc = &CDR(*pc);
627  }
628  }
629 }
630 
631 /* substitute all item s by t in list l
632  * @return whether the substitution was performed
633  */
634 bool gen_replace_in_list(list l, const void * s, const void * t)
635 {
636  bool done = false;
637  while (l)
638  {
639  if (CHUNK(CAR(l))==s)
640  {
641  CHUNK(CAR(l)) = (gen_chunk*) t;
642  done=true;
643  }
644  l = CDR(l);
645  }
646  return done;
647 }
648 
649 /* exchange items i1 & i2 in the list
650  */
651 void gen_exchange_in_list(list l, const void * i1, const void * i2)
652 {
653  while (l)
654  {
655  if (CHUNK(CAR(l))==i1) CHUNK(CAR(l)) = (gen_chunk*) i2;
656  else if (CHUNK(CAR(l))==i2) CHUNK(CAR(l)) = (gen_chunk*) i1;
657  l = CDR(l);
658  }
659 }
660 
661 /* remove item o from list *pl which is modified as a side effect.
662  * @param once whether to do it once, or to look for all occurences.
663  */
664 static void gen_remove_from_list(list * pl, const void * o, bool once)
665 {
666  list * pc = pl;
667  while (*pc)
668  {
669  if ((gen_chunk*) o == CHUNK(CAR(*pc)))
670  {
671  list tmp = *pc;
672  *pc = CDR(*pc);
673  CAR(tmp).p = NEWGEN_FREED;
674  CDR(tmp) = NEWGEN_FREED;
675  free(tmp);
676  if (once) return;
677  }
678  else
679  pc = &CDR(*pc);
680  }
681 }
682 
683 /* remove all occurences of item o from list *cpp, which is thus modified.
684  */
685 void gen_remove(list * cpp, const void * o)
686 {
687  gen_remove_from_list(cpp, o, false);
688 }
689 
690 /* Remove the first occurence of o in list pl: */
691 void gen_remove_once(list * pl, const void * o)
692 {
693  gen_remove_from_list(pl, o, true);
694 }
695 
696 /* caution: the first item is 0!
697  * was: return( (n<=0) ? l : gen_nthcdr( n-1, CDR( l ))) ;
698  * if n>gen_length(l), NIL is returned.
699  */
700 list gen_nthcdr(int n, const list lx)
701 {
702  list l = (list) lx;
703  message_assert("valid n", n>=0);
704  for (; !ENDP(l) && n>0; l=CDR(l), n--);
705  return(l);
706 }
707 
708 /* to be used as ENTITY(gen_nth(3, l))...
709  */
710 gen_chunk gen_nth(int n, const list l)
711 {
712  list r = gen_nthcdr(n, l);
713  message_assert("not NIL", r);
714  return CAR(r);
715 }
716 
717 
718 /* Prepend an item to a list only if it is not already in the list.
719 
720  Return the list anyway.
721 */
722 list gen_once(const void * vo, list l)
723 {
724  gen_chunk * item = (gen_chunk*) vo;
725  list c;
726  for(c=l; c!=NIL; c=CDR(c))
727  if (CHUNK(CAR(c))==item) return l;
728 
729  return CONS(CHUNK, item, l);
730 }
731 
732 /* tell whether vo belongs to lx
733  */
734 bool gen_in_list_p(const void * vo, const list lx)
735 {
736  list l = (list) lx;
737  gen_chunk * item = (gen_chunk*) vo;
738  for (; !ENDP(l); POP(l))
739  if (CHUNK(CAR(l))==item) return true; /* found! */
740 
741  return false; /* else no found */
742 }
743 
744 /* count occurences of vo in l
745  */
746 int gen_occurences(const void * vo, const list l)
747 {
748  list c = (list) l;
749  int n = 0;
750  gen_chunk * item = (gen_chunk*) vo;
751  for (; !ENDP(c); POP(c))
752  if (CHUNK(CAR(c))==item) n++;
753  return n;
754 }
755 
756 /* FC: ARGH...O(n^2)!
757 */
759 {
760  list c;
761  for(c=l; c!=NIL && CDR(c)!=NIL; c=CDR(c)) {
762  gen_chunk * item = CHUNK(CAR(c));
763  if (gen_in_list_p(item , CDR(c)))
764  return false;
765  }
766  return true;
767 }
768 
769 /* free an area.
770  * @param p pointer to the zone to be freed.
771  * @param size size in bytes.
772  *
773  * Why is this function located in list.c?
774  */
775 void gen_free_area(void ** p, int size)
776 {
777  int n = size/sizeof(void*);
778  int i;
779  for (i=0; i<n; i++) {
780  *(p+i) = NEWGEN_FREED;
781  }
782  free(p);
783 }
784 
785 /* Sorts a list of gen_chunks in place, to avoid allocations...
786  * The list skeleton is not touched, but the items are replaced
787  * within the list. If some of the cons are shared, it may trouble
788  * the data and the program.
789  *
790  * See man qsort about the compare function:
791  * - 2 pointers to the data are passed,
792  * - and the result is <, =, > 0 if the comparison is lower than, equal...
793  *
794  * FC 27/12/94
795  */
797 {
798  list c;
799  int n = gen_length(l);
800  gen_chunk
801  **table = (gen_chunk**) alloc(n*sizeof(gen_chunk*)),
802  **point;
803 
804  /* the list items are first put in the temporary table,
805  */
806  for (c=l, point=table; !ENDP(c); c=CDR(c), point++)
807  *point = CHUNK(CAR(c));
808 
809  /* then sorted,
810  */
811  qsort(table, n, sizeof(gen_chunk*), compare);
812 
813  /* and the list items are updated with the sorted table
814  */
815  for (c=l, point=table; !ENDP(c); c=CDR(c), point++)
816  CHUNK(CAR(c)) = *point;
817 
818  gen_free_area((void**) table, n*sizeof(gen_chunk*));
819 }
820 
821 
822 /* void gen_closure(iterate, initial)
823  * list [of X] (*iterate)([ X, list of X ]), initial;
824  *
825  * what: computes the transitive closure of sg starting from sg.
826  * how: iterate till stability.
827  * input: an iterate function and an initial list for the closure.
828  * the iterate functions performs some computations on X
829  * and should update the list of X to be looked at at the next
830  * iteration. This list must be returned by the function.
831  * output: none.
832  * side effects:
833  * - *none* on initial...
834  * - those of iterate.
835  * bugs or features:
836  * - not idiot proof. may run into an infinite execution...
837  * - a set base implementation would be nicer, but less deterministic.
838  */
839 void gen_closure(iterate, initial)
840 list /* of X */ (*iterate)(/* X, list of X */), initial;
841 {
842  list /* of X */ l_next, l_close = gen_copy_seq(initial);
843  while (l_close)
844  {
845  l_next = NIL;
846  MAPL(cc, l_next = iterate(CHUNK(CAR(cc)), l_next), l_close);
847  gen_free_list(l_close), l_close = l_next;
848  }
849 }
850 
852 {
853  list l, current;
854  gen_chunk *item = NULL;
855  va_list args;
856  va_start(args, domain);
857  item = va_arg(args, gen_chunk*);
858  if( !item ) {
859  va_end(args);
860  return NIL;
861  }
862 
863  NEWGEN_CHECK_TYPE(domain, item);
864  l = CONS(CHUNK, item, NIL), current = l;
865  for(item = va_arg(args, gen_chunk*);item;item = va_arg(args, gen_chunk*)) {
866  NEWGEN_CHECK_TYPE(domain, item);
867  CDR(current) = CONS(CHUNK, item, NIL), POP(current);
868  }
869  va_end(args);
870  return l;
871 }
872 
873 void gen_fprint(FILE * out, string name, const list l,
874  gen_string_func_t item_name)
875 {
876  fprintf(out, "%s = ( ", name);
877  bool nitems = 0;
878  list c = l;
879  while (c)
880  {
881  if (nitems++) fprintf(out, ", ");
882  fprintf(out, "%s", item_name(CHUNK(CAR(c))));
883  c = CDR(c);
884  }
885  fprintf(out, " )\n");
886 }
887 
888 list gen_cons(const void * item, const list next)
889 {
890  list ncons = (list) alloc(sizeof(struct cons));
891  ncons->car.e = (void *) item;
892  ncons->cdr = (list) next;
893  return ncons;
894 }
895 
896 /* CONS a list with minimal type checking
897  * this cannot be done within the CONS macro because
898  * possible functions calls must not be replicated.
899  */
900 list gen_typed_cons(_int type, const void * item, const list next)
901 {
902  NEWGEN_CHECK_TYPE(type, item);
903  // also check consistency with first item in list
904  if (next!=NIL) NEWGEN_CHECK_TYPE(type, next->car.e);
905  return gen_cons(item, next);
906 }
907 
908 /* typed cons for "basic" types */
909 list gen_bool_cons(bool b, const list l)
910 {
911  return gen_cons((const void *) (intptr_t)b, l);
912 }
913 
915 {
916  return gen_cons((const void *) i, l);
917 }
918 
919 list gen_string_cons(string s, const list l)
920 {
921  return gen_cons((const void *) s, l);
922 }
923 
924 list gen_list_cons(const list i, const list l)
925 {
926  return gen_cons((const void *) i, l);
927 }
928 
929 list gen_CHUNK_cons(const gen_chunk * c, const list l)
930 {
931  return gen_cons((const void *) c, l);
932 }
933 
934 list gen_VOID_STAR_cons(const void * e, const list l)
935 {
936  return gen_cons((const void *) e, l);
937 }
938 
939 /* Compute A = A inter B: complexity in O(n2) */
940 void
941 gen_list_and(list * a, const list b)
942 {
943  if (ENDP(*a))
944  return ;
945 
946  if (!gen_in_list_p(CHUNK(CAR(*a)), b)) {
947  /* This element of a is not in list b: delete it: */
948  cons *aux = *a;
949 
950  *a = CDR(*a);
951  CAR(aux).p = NEWGEN_FREED;
952  CDR(aux) = NEWGEN_FREED;
953  free(aux);
954  gen_list_and(a, b);
955  }
956  else
957  gen_list_and(&CDR(*a), b);
958 }
959 
960 
961 /* Compute A = A inter non B: */
962 void
964 {
965  if (ENDP(*a))
966  return ;
967 
968  if (gen_in_list_p(CHUNK(CAR(*a)), b)) {
969  /* This element of a is in list b: delete it: */
970  cons *aux = *a;
971 
972  *a = CDR(*a);
973  CAR(aux).p = NEWGEN_FREED;
974  CDR(aux) = NEWGEN_FREED;
975  free(aux);
976  gen_list_and_not(a, b);
977  }
978  else
979  gen_list_and_not(&CDR(*a), b);
980 }
981 
982 
983 /* Replace all the reference to x in list l by a reference to y: */
984 void
985 gen_list_patch(list l, const void * x, const void * y)
986 {
987  MAPL(pc, {
988  if (CAR(pc).p == (gen_chunk *) x)
989  CAR(pc).p = (gen_chunk *) y;
990  }, l);
991 }
992 
993 /* Element ranks are strictly positive as for first, second, and so on. If
994  item is not in l, 0 is returned. */
995 int gen_position(const void * item, const list l)
996 {
997  list c_item = (list) l;
998  int rank = 0;
999 
1000  for(; !ENDP(c_item); POP(c_item)) {
1001  rank++;
1002  if(item==CHUNK(CAR(c_item))) {
1003  return rank;
1004  }
1005  }
1006  return 0;
1007 }
1008 
1009 /* @return exactly the first n elements from *lp as a list;
1010  * *lp points to the remaining list, as a side effect.
1011  * if gen_length(*lp) is less than n, the function aborts.
1012  * @param lp pointeur to the list.1
1013  * @param n number of items to extract.
1014  */
1016 {
1017  if (n<=0) return NIL;
1018  // else n>0, something to skip
1019  list head = *lp, last = *lp;
1020  n--;
1021  while (n--) {
1022  message_assert("still some items", last);
1023  last = CDR(last);
1024  }
1025  *lp = CDR(last);
1026  CDR(last) = NIL;
1027  return head;
1028 }
1029 
1030 
1031 /* return the common list prefix of lists l1 and l2.
1032  */
1033 list gen_common_prefix(const list l1, const list l2)
1034 {
1035  list c1 = l1, c2 = l2, prefix = NIL;
1036  // build in reverse order
1037  for (; c1 && c2 && VOID_STAR(CAR(c1)) == VOID_STAR(CAR(c2));
1038  c1 = CDR(c1), c2 = CDR(c2))
1040  // reverse
1041  return gen_nreverse(prefix);
1042 }
1043 
1044 /** @} */
1045 
1046 /******************************************************************* SWEEPING */
1047 
1048 /* sweep status
1049  */
1051  bool done; // no more updates are possible
1052  gen_sweep_direction dir; // forward or backward
1053  list initial, * phead, * ptail; // sweep parameters
1054  list last, head, tail, reversed; // internal helpers
1055 };
1056 
1057 /* initialize list l sweep in direction dir, with pointers for head & tail
1058  */
1061 {
1062  gen_sweep_state state = malloc(sizeof(struct __gen_sweep_state));
1063  message_assert("malloc ok", state != NULL);
1064 
1065  state->dir = dir;
1066  state->initial = l;
1067  state->phead = phead;
1068  state->ptail = ptail;
1069  state->done = (l == NIL);
1070 
1071  switch (dir)
1072  {
1073  case gen_sweep_forward:
1074  state->head = NIL;
1075  state->tail = l;
1076  state->last = NIL;
1077  state->reversed = NIL; // unused
1078  break;
1079 
1080  case gen_sweep_backward:
1081  state->head = l;
1082  state->tail = NIL;
1083  state->last = NIL; // unused
1084  {
1085  list nl = NIL, c = l;
1086  while (c != NIL) {
1087  nl = CONS(LIST, c, nl);
1088  c = CDR(c);
1089  }
1090  state->reversed = nl;
1091  }
1092  break;
1093 
1094  default:
1095  fprintf(stderr, "unexpected sweep direction: %d\n", dir);
1096  abort();
1097  }
1098 
1099  // update external pointers
1100  if (state->phead)
1101  *(state->phead) = state->head;
1102  if (state->ptail)
1103  *(state->ptail) = state->tail;
1104 
1105  return state;
1106 }
1107 
1109 {
1110  if (state->done)
1111  return false;
1112 
1113  switch (state->dir)
1114  {
1115  case gen_sweep_forward:
1116  // first update
1117  if (state->head == NIL)
1118  state->head = state->last = state->tail;
1119  else
1120  // relink last cons
1121  CDR(state->last) = state->tail;
1122  // set new last cons
1123  state->last = state->tail;
1124  // move forward tail
1125  state->tail = CDR(state->tail);
1126  // check for end
1127  state->done = state->tail == NIL;
1128  // cut last const
1129  if (!state->done)
1130  CDR(state->last) = NIL;
1131  break;
1132 
1133  case gen_sweep_backward:
1134  {
1135  list previous_tail = state->tail, tmp = state->reversed;
1136  // tails move backwards
1137  state->tail = LIST(CAR(state->reversed));
1138  // relink tail
1139  CDR(state->tail) = previous_tail;
1140  // move backwards
1141  state->reversed = CDR(state->reversed);
1142  // cleanup
1143  free(tmp);
1144  // last one
1145  if (state->reversed == NIL)
1146  state->head = NIL;
1147  // check for end
1148  state->done = state->head == NIL;
1149  }
1150  break;
1151 
1152  default:
1153  fprintf(stderr, "unexpected sweep direction: %d\n", state->dir);
1154  abort();
1155  }
1156 
1157  // update external pointers
1158  if (state->phead)
1159  *(state->phead) = state->head;
1160  if (state->ptail)
1161  *(state->ptail) = state->tail;
1162 
1163  return true;
1164 }
1165 
1167 {
1168  message_assert("some state", state != NULL);
1169 
1170  // complete sweep to relink the initial list
1171  state->phead = NULL;
1172  state->ptail = NULL;
1173  while (gen_sweep_update(state));
1174 
1175  // cleanup
1176  free(state);
1177 }
1178 
1179 /* That is all
1180  */
static FILE * out
Definition: alias_check.c:128
char * alloc(int size)
ALLOC is an "iron-clad" version of malloc(3).
Definition: build.c:501
#define NEWGEN_CHECK_TYPE(dom, item)
this macro does about the same as gen_check, but inlined and safer.
Definition: genC.h:313
#define LIST(x)
Definition: genC.h:93
#define CHUNK(x)
Definition: genC.h:90
#define STRING(x)
Definition: genC.h:87
#define gen_chunk_undefined
Definition: genC.h:74
#define VOID_STAR(x)
Definition: genC.h:95
void *() gen_extract_func_t(const gen_chunk)
Definition: genC.h:72
gen_chunk * gen_copy_tree(gen_chunk *obj)
Definition: genClib.c:1429
if(!(yy_init))
Definition: genread_lex.c:1029
void * malloc(YYSIZE_T)
void free(void *)
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
list gen_make_list(int domain,...)
Definition: list.c:851
void gen_fprint(FILE *out, string name, const list l, gen_string_func_t item_name)
Definition: list.c:873
list gen_insert_list(list nl, const void *item, list l, bool before)
insert nl before or after item in list l, both initial lists are consumed
Definition: list.c:269
list gen_list_head(list *lp, int n)
Definition: list.c:1015
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
void gen_exchange_in_list(list l, const void *i1, const void *i2)
exchange items i1 & i2 in the list
Definition: list.c:651
void gen_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
void gen_list_and(list *a, const list b)
Compute A = A inter B: complexity in O(n2)
Definition: list.c:941
int gen_position(const void *item, const list l)
Element ranks are strictly positive as for first, second, and so on.
Definition: list.c:995
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
void gen_remove_once(list *pl, const void *o)
Remove the first occurence of o in list pl:
Definition: list.c:691
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_concatenate(const list l1x, const list l2x)
concatenate two lists.
Definition: list.c:436
void gen_map(gen_iter_func_t fp, const list l)
Definition: list.c:172
list gen_once(const void *vo, list l)
Prepend an item to a list only if it is not already in the list.
Definition: list.c:722
struct cons cons
The structure used to build lists in NewGen.
list gen_VOID_STAR_cons(const void *e, const list l)
Definition: list.c:934
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
size_t gen_length(const list l)
Definition: list.c:150
list gen_cons(const void *item, const list next)
Definition: list.c:888
list gen_common_prefix(const list l1, const list l2)
return the common list prefix of lists l1 and l2.
Definition: list.c:1033
void gen_list_and_not(list *a, const list b)
Compute A = A inter non B:
Definition: list.c:963
bool gen_once_p(list l)
FC: ARGH...O(n^2)!
Definition: list.c:758
void gen_free_string_list(list ls)
Definition: list.c:564
void gen_copy(void *a, void *b)
#define CONS(type,x,l) gen_cons((void*) (x), (l))
Definition: list.c:359
list gen_some(gen_filter_func_t fp, const list l)
Definition: list.c:206
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
list gen_list_cons(const list i, const list l)
Definition: list.c:924
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
list gen_last(list l)
Return the last element of a list.
Definition: list.c:578
list gen_CHUNK_cons(const gen_chunk *c, const list l)
Definition: list.c:929
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
size_t list_own_allocated_memory(const list l)
Definition: list.c:158
void * gen_find_if_from_end(gen_filter_func_t test, const list l, gen_extract_func_t extract)
the last match is returned
Definition: list.c:382
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
void * gen_find_if(gen_filter_func_t test, const list l, gen_extract_func_t extract)
Definition: list.c:370
void * gen_find_eq(const void *item, const list seq)
Definition: list.c:422
list gen_nthcdr(int n, const list lx)
caution: the first item is 0! was: return( (n<=0) ? l : gen_nthcdr( n-1, CDR( l ))) ; if n>gen_length...
Definition: list.c:700
#define MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
void * gen_find(const void *item, const list seq, gen_filter2_func_t test, gen_extract_func_t extract)
Definition: list.c:398
list gen_append(list l1, const list l2)
Definition: list.c:471
bool gen_list_cyclic_p(const list ml)
Definition: list.c:120
static void gen_remove_from_list(list *pl, const void *o, bool once)
remove item o from list *pl which is modified as a side effect.
Definition: list.c:664
list gen_copy_string_list(list ls)
of string
Definition: list.c:556
void gen_mapl(gen_iter_func_t fp, const list l)
MAP.
Definition: list.c:165
int gen_occurences(const void *vo, const list l)
count occurences of vo in l
Definition: list.c:746
void * gen_reduce(void *r, void *(*fp)(void *, const list), const list l)
Definition: list.c:180
gen_chunk gen_nth(int n, const list l)
to be used as ENTITY(gen_nth(3, l))...
Definition: list.c:710
void gen_list_patch(list l, const void *x, const void *y)
Replace all the reference to x in list l by a reference to y:
Definition: list.c:985
list gen_string_cons(string s, const list l)
Definition: list.c:919
void gen_free_area(void **p, int size)
free an area.
Definition: list.c:775
#define MAP(_map_CASTER, _map_item, _map_code, _map_list)
Apply/map an instruction block on all the elements of a list (old fashioned)
Definition: newgen_list.h:226
void * gen_find_from_end(const void *item, const list seq, gen_filter2_func_t test, gen_extract_func_t extract)
Definition: list.c:408
static bool cons_of_gen_chunk(const list cp)
Definition: list.c:218
void gen_closure(list(*iterate)(), list(*initial)())
void gen_closure(iterate, initial) list [of X] (*iterate)([ X, list of X ]), initial;
Definition: list.c:839
#define NEXT(cp)
Definition: list.c:298
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535
void gen_sort_list(list l, gen_cmp_func_t compare)
Sorts a list of gen_chunks in place, to avoid allocations...
Definition: list.c:796
static gen_chunk * gen_chunk_of_cons_of_gen_chunk
SPECIAL INSERTION.
Definition: list.c:217
void gen_substitute_chunk_by_list(list *pl, const void *o, list sl)
substitute item o by list sl in list *pl, which is modified as a side effect.
Definition: list.c:591
list gen_bool_cons(bool b, const list l)
typed cons for "basic" types
Definition: list.c:909
void * gen_car(list l)
Definition: list.c:364
void gen_insert_after(const void *no, const void *o, list l)
Definition: list.c:223
bool gen_replace_in_list(list l, const void *s, const void *t)
substitute all item s by t in list l
Definition: list.c:634
list gen_insert_before(const void *no, const void *o, list l)
Definition: list.c:238
list gen_int_cons(_int i, const list l)
Definition: list.c:914
bool gen_equals(const list l0, const list l1, gen_eq_func_t equals)
compares two lists using the functor given in parameters returns true if for all n,...
Definition: list.c:192
bool gen_eq(const void *obj1, const void *obj2)
Definition: list.c:111
list gen_typed_cons(_int type, const void *item, const list next)
CONS a list with minimal type checking this cannot be done within the CONS macro because possible fun...
Definition: list.c:900
void gen_sweep_done(gen_sweep_state state)
Definition: list.c:1166
gen_sweep_state gen_sweep_init(list l, gen_sweep_direction dir, list *phead, list *ptail)
initialize list l sweep in direction dir, with pointers for head & tail
Definition: list.c:1060
bool gen_sweep_update(gen_sweep_state state)
Definition: list.c:1108
#define abort()
Definition: misc-local.h:53
static entity rank
#define assert(ex)
Definition: newgen_assert.h:41
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
#define NEWGEN_FREED
gen_sweep_direction
sweep a list...
Definition: newgen_list.h:365
@ gen_sweep_backward
Definition: newgen_list.h:365
@ gen_sweep_forward
Definition: newgen_list.h:365
void set_free(set)
Definition: set.c:332
bool set_belong_p(const set, const void *)
Definition: set.c:194
@ set_pointer
Definition: newgen_set.h:44
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
set set_add_element(set, const set, const void *)
Definition: set.c:152
bool(* gen_filter2_func_t)(const void *, const void *)
Definition: newgen_types.h:110
string(* gen_string_func_t)(const void *)
Definition: newgen_types.h:111
void(* gen_iter_func_t)(void *)
Definition: newgen_types.h:116
intptr_t _int
_INT
Definition: newgen_types.h:53
struct cons * list
Definition: newgen_types.h:106
bool(* gen_filter_func_t)(const void *)
Definition: newgen_types.h:109
bool(* gen_eq_func_t)(const void *, const void *)
Definition: newgen_types.h:115
int(* gen_cmp_func_t)(const void *, const void *)
Definition: newgen_types.h:114
static hash_table pl
properties are stored in this hash table (string -> property) for fast accesses.
Definition: properties.c:783
static const char * prefix
Pvecteur cp
pointeur sur l'egalite ou l'inegalite courante
Definition: sc_read.c:87
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
return(s1)
int aux
Definition: solpip.c:104
static char * x
Definition: split_file.c:159
#define intptr_t
Definition: stdint.in.h:294
static size_t current
Definition: string.c:115
sweep status
Definition: list.c:1050
list * phead
Definition: list.c:1053
list * ptail
Definition: list.c:1053
gen_sweep_direction dir
Definition: list.c:1052
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
struct cons * cdr
The pointer to the next element.
Definition: newgen_list.h:43
gen_chunk car
The data payload of a list element.
Definition: newgen_list.h:42
A DOMAIN union describes the structure of a user type.
A gen_chunk is used to store every object.
Definition: genC.h:58
void * e
For externals (foreign objects)
Definition: genC.h:65