removed C99 constructs
[libfirm] / ir / ana2 / qset.c
1 /* -*- c -*- */
2
3 /*
4  * Time-stamp: <17.12.2004 20:26:51h liekweg>
5  * Project:     libFIRM
6  * File name:   ir/ana2/qset.c
7  * Purpose:     yet another set implementation
8  * Author:      Florian
9  * Modified by:
10  * Created:     Mon 18 Oct 2004
11  * CVS-ID:      $Id$
12  * Copyright:   (c) 1999-2004 Universität Karlsruhe
13  * Licence:     This file is protected by GPL -  GNU GENERAL PUBLIC LICENSE.
14  */
15
16 # include <stdio.h>
17 # include <stdlib.h>
18 # include <assert.h>
19 # include <string.h>
20 # include <sys/time.h>
21 # include <obstack.h>
22
23 # include "timing.h"
24 # include "qset.h"
25
26 /* local globals */
27 int qset_id = 0;
28
29 /* local protos */
30
31 # ifdef UNSINN
32 /* Check whether the given list of sortables is sorted. */
33 static void q_check (sortable_t*, const int);
34 # endif /* defined UNSINN */
35
36 /* Test whether the given val is among values.  Return the index of
37    val in values, or -1. */
38 static int q_test (sortable_t*, const sortable_t, const int);
39
40 /* Sort n_elems entries  in 'values' */
41 static void q_sort (sortable_t*, const int);
42
43 /* Compare funktion, meant to be qsort(3)-compatible */
44 static __inline__ int sortable_compare (const void *pa, const void *pb)
45 {
46   const int a = * (unsigned int*) pa;
47   const int b = * (unsigned int*) pb;
48
49   if (a==b) {
50     return (0);
51   }
52
53   return ((a < b) ? -1 : +1);
54 }
55
56 /*
57    Wrapper for mixed allocation
58 */
59 static void *mix_malloc (struct obstack *obst, size_t size)
60 {
61   if (NULL != obst) {
62     return (obstack_alloc (obst, size));
63   } else {
64     return (malloc (size));
65   }
66 }
67
68 /*
69   Allocate a list of sortables of the given length.
70 */
71 static sortable_t *alloc_list (const int len, struct obstack *obst)
72 {
73   sortable_t *values = (sortable_t*) mix_malloc (obst, len * sizeof (sortable_t));
74
75   memset (values, 0x00, len * sizeof (sortable_t));
76
77   return (values);
78 }
79
80 # ifdef UNSINN
81 /*
82   Create a list of sortables of the given length.
83 */
84 static sortable_t *gen_list (const int len, struct obstack *obst)
85 {
86   int i;
87   sortable_t *values = alloc_list (len, obst);
88
89   for (i = 0; i < len; i ++) {
90     values [i] = rand () >> 16;
91   }
92
93   return (values);
94 }
95 # endif /* defined UNSINN */
96
97 /*
98   Helper to q_test --- return the index of val in values, or -1
99 */
100 static int _q_test (sortable_t *values,
101                     const sortable_t val,
102                     const int lo, const int hi)
103 {
104   int mid;
105
106   /* fprintf (stdout, "%s for %d [%i:%i]\n", __FUNCTION__, val, lo, hi); */
107
108   if (lo == hi) {
109     if (EQUAL (val, values [lo])) {
110       return (lo);
111     } else {
112       return (-1);
113     }
114   }
115
116   if (COMPARE (val, values [lo])) {
117     /* too low */
118     return (-1);
119   }
120
121   if (COMPARE (values [hi], val)) {
122     /* too high */
123     return (-1);
124   }
125
126   mid = (hi + lo) / 2;
127
128   if (EQUAL (val, values [mid])) {
129     return (mid);
130   }
131
132   if (COMPARE (val, values [mid])) {
133     return (_q_test (values, val, lo, mid));
134   } else {
135     return (_q_test (values, val, mid+1, hi));
136   }
137 }
138
139 /*
140   Helper to q_sort
141 */
142 static void _q_sort (sortable_t *values, const int lo, const int hi)
143 {
144   sortable_t pivot;
145   int p_lo;
146   int p_hi;
147
148   /* handle base case: */
149   if (lo >= hi) {
150     return;
151   }
152
153   if (1 == hi - lo) {
154     if (COMPARE (values [hi], values [lo])) {
155       sortable_t tmp = values [lo];
156       values [lo] = values [hi];
157       values [hi] = tmp;
158     }
159
160     return;
161   }
162
163   pivot = values [lo];
164
165   p_lo = lo+1;
166   p_hi = hi;
167
168   while (p_lo <= p_hi) {
169     if (COMPARE (values [p_lo], pivot)) {
170       values [p_lo-1] = values [p_lo];
171
172       p_lo ++;
173     } else {
174       sortable_t tmp = values [p_lo];
175
176       values [p_lo] = values [p_hi];
177       values [p_hi] = tmp;
178
179       p_hi --;
180     }
181   }
182
183   values [p_lo-1] = pivot;
184
185   _q_sort (values, lo, p_lo-1);
186   _q_sort (values, p_lo, hi);
187 }
188
189 # ifdef UNSINN
190 /*
191   Little test harness for q_sort and friends.
192 */
193 static void test_qsort (const int n_runs, const int max_elems, const int incr)
194 {
195   int n_elems = 0;
196   int i;
197
198   fprintf (stdout, "# n_elems: q_sort time : libc qsort time\n");
199
200   while (n_elems <= max_elems) {
201     int total = 0;
202     int qtotal = 0;
203
204     for (i = 0; i < n_runs; i ++) {
205       sortable_t *list = gen_list (n_elems, NULL);
206
207       timing_t *timing = start_timing ();
208       q_sort (list, n_elems);
209       total += end_timing (timing);
210
211       q_check (list, n_elems);
212
213       free (list);
214     }
215
216     for (i = 0; i < n_runs; i ++) {
217       sortable_t *list = gen_list (n_elems, NULL);
218
219       timing_t *timing = start_timing ();
220       qsort (list, n_elems, sizeof (sortable_t), sortable_compare);
221       qtotal += end_timing (timing);
222
223       q_check (list, n_elems);
224
225       free (list);
226     }
227
228     fprintf (stdout, "%d %d %d\n", n_elems, total/n_runs, qtotal/n_runs);
229     fflush (stdout);
230     n_elems += incr;
231   }
232
233
234   fprintf (stdout, "\n");
235 }
236
237 /*
238   Little test harness for the qset implementation
239 */
240 static void test_qset (const int n_entries)
241 {
242   int i;
243   int n1, n2, n;
244
245   qset_t *q1 = qset_new (n_entries, NULL);
246   qset_t *q2 = qset_new (n_entries, NULL);
247   qset_t *q = NULL;
248
249   sortable_t *values = gen_list (n_entries, NULL);
250
251   for (i = 0; i < n_entries; i ++) {
252     qset_insert (q1, values [i]);
253     qset_insert (q2, values [i]);
254   }
255
256   fprintf (stdout, "q1: \t\t");
257   qset_print (q1, stdout);
258   qset_sort (q1);
259   qset_sort (q2);
260
261   /* TEST */
262   q2->is_sorted = FALSE;
263   qset_sort (q2);
264
265   fprintf (stdout, "q1 (sorted):\t");
266   qset_print (q1, stdout);
267
268   assert (qset_compare (q1, q2));
269
270   q = qset_union (q1, q2);
271   fprintf (stdout, "qq (union):\t");
272   qset_print (q, stdout);
273
274   n1 = qset_size (q1);
275   n2 = qset_size (q2);
276   n = qset_size (q);
277
278   fprintf (stdout, "q1.size = %i\n", n1);
279   fprintf (stdout, "q1.slots = %i\n", q1->n_slots);
280   fprintf (stdout, "q2.size = %i\n", n2);
281   fprintf (stdout, "q2.slots = %i\n", q2->n_slots);
282   fprintf (stdout, "q.size  = %i\n", n);
283   fprintf (stdout, "q.slots  = %i\n", q->n_slots);
284
285   assert (n1 == n2);
286   assert (n2 == n);
287
288   assert (qset_compare (q1, q2));
289   assert (qset_compare (q2, q));
290   assert (qset_compare (q, q1));
291
292   for (i = 0; i < n_entries; i ++) {
293     assert (qset_contains (q1, values [i]));
294     assert (qset_contains (q2, values [i]));
295     assert (qset_contains (q, values [i]));
296   }
297
298   qset_compact (q1);
299   qset_compact (q);
300
301   fprintf (stdout, "q1.size = %i\n", n1);
302   fprintf (stdout, "q1.slots = %i\n", q1->n_slots);
303   fprintf (stdout, "q2.size = %i\n", n2);
304   fprintf (stdout, "q2.slots = %i\n", q2->n_slots);
305   fprintf (stdout, "q.size  = %i\n", n);
306   fprintf (stdout, "q.slots  = %i\n", q->n_slots);
307
308   assert (qset_compare (q1, q2));
309   assert (qset_compare (q2, q));
310   assert (qset_compare (q, q1));
311
312   for (i = 0; i < n_entries; i ++) {
313     assert (qset_contains (q1, values [i]));
314     assert (qset_contains (q2, values [i]));
315     assert (qset_contains (q, values [i]));
316   }
317
318   qset_delete (q);
319   qset_delete (q1);
320   qset_delete (q2);
321 }
322 # endif /* defned UNSINN */
323
324 /* PRIVATE QSET IMPLEMENTATION */
325 /*
326    Resize a qset to (at least) the given size.
327 */
328 static void qset_resize (qset_t *qset, const int n_slots)
329 {
330   int new_size;
331   sortable_t *values = NULL;
332
333   if (qset->n_slots >= n_slots) {
334     return;
335   }
336
337   new_size = qset->n_slots;
338
339   while (new_size < n_slots) {
340     new_size *= 2;
341   }
342
343   values = alloc_list (new_size, qset->obst);
344
345   memcpy (values, qset->values, qset->n_elems * sizeof (sortable_t));
346   memset (qset->values, 0x00, qset->n_elems * sizeof (sortable_t)); /* debug only */
347
348   if (NULL == qset->obst) {
349     free (qset->values);
350   }
351
352   qset->values = values;
353   qset->n_slots = new_size;
354 }
355
356 /*
357    Print a list of sortables.
358 */
359 static void q_print (sortable_t *values, const int n_values, FILE *stream)
360 {
361   int i;
362
363   fprintf (stream, "{");
364
365   for (i = 0; i < n_values; i ++) {
366     if (0 == values [i]) {
367       fprintf (stream, "_");
368     } else {
369       fprintf (stream, "0x08%x", (int) values [i]);
370     }
371
372     if (i + 1 != n_values) {
373       fprintf (stream, ", ");
374     }
375   }
376
377   fprintf (stream, "}\n");
378 }
379
380 # ifdef UNSINN
381 /*
382   Check whether the given list of sortables is sorted.
383 */
384 static void q_check (sortable_t *values, const int n_values)
385 {
386   int i;
387
388   for (i = 1; i < n_values; i ++) {
389     assert (COMPARE (values [i-1], values [i]) ||
390             EQUAL   (values [i-1], values [i]));
391   }
392
393   for (i = 1; i < n_values; i ++) {
394     assert (-1 != q_test (values, values [i], n_values));
395   }
396 }
397 # endif /* defined UNSINN */
398
399 /*
400   Test whether the given val is among values.  Return the lowest index of val
401   in values, or -1.
402 */
403 static int q_test (sortable_t *values, const sortable_t val, const int n_elems)
404 {
405   int idx = _q_test (values, val, 0, n_elems-1);
406
407   while ((0 <= idx-1) && EQUAL (values [idx], val)) {
408     idx --;
409   }
410
411   return (idx);
412 }
413
414 /*
415   Sort entries in 'values' from index 'lo' to 'hi' (inclusive)
416 */
417 static void q_sort (sortable_t *values, const int n_elems)
418 {
419   _q_sort (values, 0, n_elems-1);
420 }
421
422 /* PUBLIC INTERFACE */
423
424 /*
425   Allocate a new qset with initial space for up to n_elems.
426   If a non-NULL obstack is given, it is used for all allocations of this qset
427   and must be initialised and deleted by the user of the qset.
428 */
429 qset_t *qset_new (const int n_elems, struct obstack *obst)
430 {
431   qset_t *qset = (qset_t*) mix_malloc (obst, sizeof (qset_t));
432
433   qset->obst = obst;
434   qset->values = alloc_list (n_elems, obst);
435   memset (qset->values, 0x00, n_elems * sizeof (sortable_t));
436
437   qset->n_slots = n_elems;
438   qset->n_elems = 0;
439   qset->is_sorted = FALSE;
440   qset->id = qset_id ++;
441
442   return (qset);
443 }
444
445 /*
446   Sort the entries of the given qset.
447 */
448 void qset_sort (qset_t *qset)
449 {
450   int occ = 0;
451   int i;
452
453   if (qset->is_sorted) {
454     return;
455   }
456
457   q_sort (qset->values, qset->n_elems);
458
459   for (i = 1; i < qset->n_elems; i ++) {
460     if (! EQUAL (qset->values [i], qset->values [occ])) {
461       qset->values [++ occ] = qset->values [i];
462     }
463   }
464
465   occ ++;
466
467   /*
468   if (qset->n_elems != occ) {
469     fprintf (stdout, "removed %i duplicates\n", qset->n_elems - occ);
470     }*/
471
472   qset->n_elems = occ;
473
474   qset->is_sorted = TRUE;
475 }
476
477 /*
478   Compact a qset to take up no more space than required.
479 */
480 void qset_compact (qset_t *qset)
481 {
482   if (NULL == qset->obst) {
483     sortable_t *values = (sortable_t*) mix_malloc (qset->obst,
484                                                    qset->n_elems * sizeof (sortable_t));
485     memcpy (values, qset->values, qset->n_elems * sizeof (sortable_t));
486
487     memset (qset->values, 0x00, qset->n_elems * sizeof (sortable_t));
488
489     free (qset->values);
490
491     qset->values = values;
492     qset->n_slots = qset->n_elems;
493   }
494 }
495
496 /*
497   Free the memory associated with the given qset
498 */
499 void qset_delete (qset_t *qset)
500 {
501   memset (qset->values, 0x00, qset->n_elems * sizeof (sortable_t));
502
503   if (NULL == qset->obst) {
504     free (qset->values);
505   }
506
507   memset (qset, 0x00, sizeof (qset_t));
508
509   if (NULL == qset->obst) {
510     free (qset);
511   }
512 }
513
514 /*
515   Test wether the given qset contains the given value.
516 */
517 int qset_contains (qset_t *qset, sortable_t val)
518 {
519   qset_sort (qset);
520
521   return (-1 != q_test (qset->values, val, qset->n_elems));
522 }
523
524 /*
525   Delete the given value from the given qset (if it exists)
526 */
527 void qset_remove (qset_t *qset, sortable_t val)
528 {
529   int idx;
530   int occ = 0;
531   int i;
532
533   qset_sort (qset);
534
535   idx = q_test (qset->values, val, qset->n_elems);
536
537   if (-1 == idx) {
538     return;
539   }
540
541   while (EQUAL (qset->values [idx + occ], val)) {
542     occ ++;
543   }
544
545   for (i = idx; i < qset->n_elems - occ; i ++) {
546     qset->values [i] = qset->values [i+occ];
547   }
548
549   qset->n_elems -= occ;
550 }
551
552 /*
553   Insert the given elem into the given qset; return nonzero iff any
554   involved values change.
555 */
556 int qset_insert (qset_t *qset, sortable_t val)
557 {
558   int i;
559   const int n_elems = qset->n_elems;
560
561   /* todo: sort, find */
562   assert (0 != val);
563
564   for (i = 0; i < n_elems; i ++) {
565     if (EQUAL (val, qset->values [i])) {
566       return (FALSE);
567     }
568   }
569
570   qset_resize (qset, qset->n_elems+1);
571
572   /* qset_print (qset, stdout); */
573   /* fprintf (stdout, "%s: must insert 0x%08x\n", __FUNCTION__, (void*) val); */
574
575   qset->values [qset->n_elems++] = val;
576   qset->is_sorted = FALSE;
577
578   return (TRUE);
579 }
580
581 /*
582   Insert all elems of qset2 into qset1; return nonzero iff any
583   involved values change. qset2 is *not* deleted.
584 */
585 int qset_insert_all (qset_t *qset1, qset_t *qset2)
586 {
587   int change = FALSE;
588   sortable_t val = qset_start (qset2);
589
590   while (0 != val) {
591     change |= qset_insert (qset1, val);
592
593     val = qset_next (qset2);
594   }
595
596   qset_sort (qset1);
597
598   return (change);
599 }
600
601 /*
602   Compare two qsets.
603 */
604 int qset_compare (qset_t *qset1, qset_t *qset2)
605 {
606   int i;
607   const int n_elems = qset1->n_elems;
608
609   qset_sort (qset1);
610   qset_sort (qset2);
611
612   if (qset1->n_elems != qset2->n_elems) {
613     return (FALSE);
614   }
615
616   for (i = 0; i < n_elems; i ++) {
617     if (qset1->values [i] != qset2->values [i]) {
618       return (FALSE);
619     }
620   }
621
622   return (TRUE);
623 }
624
625 /*
626   Returns the union of two qsets.
627 */
628 qset_t *qset_union (qset_t *qset1, qset_t *qset2)
629 {
630   qset_t *qset = (qset_t*) mix_malloc (qset1->obst, sizeof (qset_t));
631   const int n_elems = qset1->n_elems + qset2->n_elems;
632
633   qset->values = alloc_list (n_elems, qset1->obst);
634
635   memcpy (qset->values, qset1->values,
636           qset1->n_elems * sizeof (sortable_t));
637
638   memcpy (qset->values+qset1->n_elems,
639           qset2->values, qset2->n_elems * sizeof (sortable_t));
640
641   qset->obst = qset1->obst;
642   qset->n_elems = n_elems;
643   qset->n_slots = qset->n_elems;
644
645   qset_sort (qset);
646
647   return (qset);
648 }
649
650 /*
651   Report the size of the given qset.
652 */
653 int qset_size (qset_t *qset)
654 {
655   return (qset->n_elems);
656 }
657
658 /*
659   Print the given qset to the given stream.
660 */
661 void qset_print (qset_t *qset, FILE *stream)
662 {
663   q_print (qset->values, qset->n_elems, stream);
664 }
665
666 /*
667    Check wether the given qset is empty
668 */
669 int qset_is_empty (qset_t *qset)
670 {
671   return (0 == qset->n_elems);
672 }
673
674 /*
675   Initialise a new iteration over a qset
676 */
677 sortable_t *qset_start (qset_t *qset)
678 {
679   qset->cursor = 0;
680
681   sortable_t *start = qset_next (qset);
682
683   return (start);    /* works for empty sets, too */
684 }
685
686 /*
687   Step to the next element
688 */
689 sortable_t *qset_next (qset_t *qset)
690 {
691   if (qset->n_elems == qset->cursor) {
692     return (NULL);
693   }
694
695   /* quick fix to skip NULL entries */
696   while ((qset->cursor < qset->n_elems) &&
697          (NULL == qset->values [qset->cursor])) {
698     qset->cursor ++;
699   }
700
701   return (qset->values [qset->cursor++]);
702 }
703
704
705 # ifdef UNSINN
706 int qset_test_main (int argc, char **argv)
707 {
708   struct timeval tp;
709   unsigned int seed;
710
711   if (-1 == gettimeofday (&tp, NULL)) {
712     perror ("gettimeofday");
713     exit (EXIT_FAILURE);
714   }
715
716   seed = (unsigned int) tp.tv_usec;
717   srand (seed);
718
719   /* test_qsort (20, 1000000, 100000); */
720
721   test_qset (atoi (argv [1]));
722
723   exit (EXIT_SUCCESS);
724 }
725 # endif /* defined UNSINN */
726
727 /*
728   $Log$
729   Revision 1.9  2004/12/20 17:34:35  liekweg
730   fix recursion handling
731
732   Revision 1.8  2004/12/06 12:49:26  liekweg
733   virtually no change
734
735   Revision 1.7  2004/11/30 14:47:11  liekweg
736   insert report changes
737
738   Revision 1.6  2004/11/26 15:58:30  liekweg
739   don't free inside obstacks (thx, michael)
740
741   Revision 1.5  2004/11/24 14:53:56  liekweg
742   Bugfixes
743
744   Revision 1.4  2004/11/18 16:35:45  liekweg
745   Added unique ids for debugging
746
747   Revision 1.3  2004/11/09 16:45:36  liekweg
748   print pointers
749
750   Revision 1.2  2004/11/08 12:32:00  liekweg
751   Moved q_* methods into private section
752
753   Revision 1.1  2004/11/04 14:55:13  liekweg
754   added qset
755
756
757  */