8813512aee77a919765ba475b674b832b244a7fe
[libfirm] / ir / ana2 / qset.c
1 /* -*- c -*- */
2
3 /*
4  * Time-stamp: <23.11.2004 13:26:21h 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   free (qset->values);
348
349   qset->values = values;
350   qset->n_slots = new_size;
351 }
352
353 /*
354    Print a list of sortables.
355 */
356 static void q_print (sortable_t *values, const int n_values, FILE *stream)
357 {
358   int i;
359
360   fprintf (stream, "{");
361
362   for (i = 0; i < n_values; i ++) {
363     if (0 == values [i]) {
364       fprintf (stream, "_");
365     } else {
366       fprintf (stream, "0x08%x", (int) values [i]);
367     }
368
369     if (i + 1 != n_values) {
370       fprintf (stream, ", ");
371     }
372   }
373
374   fprintf (stream, "}\n");
375 }
376
377 # ifdef UNSINN
378 /*
379   Check whether the given list of sortables is sorted.
380 */
381 static void q_check (sortable_t *values, const int n_values)
382 {
383   int i;
384
385   for (i = 1; i < n_values; i ++) {
386     assert (COMPARE (values [i-1], values [i]) ||
387             EQUAL   (values [i-1], values [i]));
388   }
389
390   for (i = 1; i < n_values; i ++) {
391     assert (-1 != q_test (values, values [i], n_values));
392   }
393 }
394 # endif /* defined UNSINN */
395
396 /*
397   Test whether the given val is among values.  Return the lowest index of val
398   in values, or -1.
399 */
400 static int q_test (sortable_t *values, const sortable_t val, const int n_elems)
401 {
402   int idx = _q_test (values, val, 0, n_elems-1);
403
404   while ((0 <= idx-1) && EQUAL (values [idx], val)) {
405     idx --;
406   }
407
408   return (idx);
409 }
410
411 /*
412   Sort entries in 'values' from index 'lo' to 'hi' (inclusive)
413 */
414 static void q_sort (sortable_t *values, const int n_elems)
415 {
416   _q_sort (values, 0, n_elems-1);
417 }
418
419 /*
420   Merge two sorted lists.  Keep duplicates (if present)
421 */
422 static sortable_t *q_merge (sortable_t *list1, const int n1_elems,
423                             sortable_t *list2, const int n2_elems,
424                             struct obstack *obst)
425 {
426   const int n_elems = n1_elems + n2_elems;
427   sortable_t *res = alloc_list (n_elems, obst);
428
429   int i1 = 0;
430   int i2 = 0;
431   int i  = 0;
432
433   while ((i < n_elems) && (i1 < n1_elems) && (i2 < n2_elems)) {
434     if (COMPARE (list1 [i1], list2 [i2])) {
435       res [i ++] = list1 [i1 ++];
436     } else {
437       res [i ++] = list2 [i2 ++];
438     }
439   }
440
441   while (i1 < n1_elems) {
442     res [i ++] = list1 [i1 ++];
443   }
444
445   while (i2 < n2_elems) {
446     res [i ++] = list2 [i2 ++];
447   }
448
449   return (res);
450 }
451
452 /* PUBLIC INTERFACE */
453
454 /*
455   Allocate a new qset with initial space for up to n_elems.
456   If a non-NULL obstack is given, it is used for all allocations of this qset
457   and must be initialised and deleted by the user of the qset.
458 */
459 qset_t *qset_new (const int n_elems, struct obstack *obst)
460 {
461   qset_t *qset = (qset_t*) mix_malloc (obst, sizeof (qset_t));
462
463   qset->obst = obst;
464   qset->values = alloc_list (n_elems, obst);
465   memset (qset->values, 0x00, n_elems * sizeof (sortable_t));
466
467   qset->n_slots = n_elems;
468   qset->n_elems = 0;
469   qset->is_sorted = FALSE;
470   qset->id = qset_id ++;
471
472   return (qset);
473 }
474
475 /*
476   Sort the entries of the given qset.
477 */
478 void qset_sort (qset_t *qset)
479 {
480   int occ = 0;
481   int i;
482
483   if (qset->is_sorted) {
484     return;
485   }
486
487   q_sort (qset->values, qset->n_elems);
488
489   for (i = 1; i < qset->n_elems; i ++) {
490     if (! EQUAL (qset->values [i], qset->values [occ])) {
491       qset->values [++ occ] = qset->values [i];
492     }
493   }
494
495   occ ++;
496
497   /*
498   if (qset->n_elems != occ) {
499     fprintf (stdout, "removed %i duplicates\n", qset->n_elems - occ);
500     }*/
501
502   qset->n_elems = occ;
503
504   qset->is_sorted = TRUE;
505 }
506
507 /*
508   Compact a qset to take up no more space than required.
509 */
510 void qset_compact (qset_t *qset)
511 {
512   sortable_t *values = (sortable_t*) mix_malloc (qset->obst,
513                                                  qset->n_elems * sizeof (sortable_t));
514   memcpy (values, qset->values, qset->n_elems * sizeof (sortable_t));
515
516   memset (qset->values, 0x00, qset->n_elems * sizeof (sortable_t));
517   free (qset->values);
518
519   qset->values = values;
520   qset->n_slots = qset->n_elems;
521 }
522
523 /*
524   Free the memory associated with the given qset
525 */
526 void qset_delete (qset_t *qset)
527 {
528   memset (qset->values, 0x00, qset->n_elems * sizeof (sortable_t));
529
530   if (NULL == qset->obst) {
531     free (qset->values);
532   }
533
534   memset (qset, 0x00, sizeof (qset_t));
535
536   if (NULL == qset->obst) {
537     free (qset);
538   }
539 }
540
541 /*
542   Test wether the given qset contains the given value.
543 */
544 int qset_contains (qset_t *qset, sortable_t val)
545 {
546   qset_sort (qset);
547
548   return (-1 != q_test (qset->values, val, qset->n_elems));
549 }
550
551 /*
552   Delete the given value from the given qset (if it exists)
553 */
554 void qset_remove (qset_t *qset, sortable_t val)
555 {
556   int idx;
557   int occ = 0;
558   int i;
559
560   qset_sort (qset);
561
562   idx = q_test (qset->values, val, qset->n_elems);
563
564   if (-1 == idx) {
565     return;
566   }
567
568   while (EQUAL (qset->values [idx + occ], val)) {
569     occ ++;
570   }
571
572   for (i = idx; i < qset->n_elems - occ; i ++) {
573     qset->values [i] = qset->values [i+occ];
574   }
575
576   qset->n_elems -= occ;
577 }
578
579 /*
580   Insert the given elem into the given qset.
581 */
582 void qset_insert (qset_t *qset, sortable_t val)
583 {
584   int i;
585   const int n_elems = qset->n_elems;
586
587   /* todo: sort, find */
588   assert (0 != val);
589
590   for (i = 0; i < n_elems; i ++) {
591     if (EQUAL (val, qset->values [i])) {
592       return;
593     }
594   }
595
596   qset_resize (qset, qset->n_elems+1);
597
598   qset->values [qset->n_elems++] = val;
599   qset->is_sorted = FALSE;
600 }
601
602 /*
603   Insert all elems of qset2 into qset1. qset2 is *not* deleted.
604 */
605 void qset_insert_all (qset_t *qset1, qset_t *qset2)
606 {
607   sortable_t *values = qset1->values;
608   const int n_elems = qset1->n_slots;
609
610   qset_sort (qset1);
611   qset_sort (qset2);
612
613   qset1->values = q_merge (qset1->values, qset1->n_elems,
614                            qset2->values, qset2->n_elems,
615                            qset1->obst);
616
617   qset1->n_elems = qset1->n_elems + qset2->n_elems;
618   qset1->n_slots = qset1->n_elems;
619
620   qset_sort (qset1);
621
622   memset (values, 0x00, n_elems * sizeof (sortable_t));
623   free (values);
624 }
625
626 /*
627   Compare two qsets.
628 */
629 int qset_compare (qset_t *qset1, qset_t *qset2)
630 {
631   int i;
632   const int n_elems = qset1->n_elems;
633
634   qset_sort (qset1);
635   qset_sort (qset2);
636
637   if (qset1->n_elems != qset2->n_elems) {
638     return (FALSE);
639   }
640
641   for (i = 0; i < n_elems; i ++) {
642     if (qset1->values [i] != qset2->values [i]) {
643       return (FALSE);
644     }
645   }
646
647   return (TRUE);
648 }
649
650 /*
651   Returns the union of two qsets.
652 */
653 qset_t *qset_union (qset_t *qset1, qset_t *qset2)
654 {
655   qset_t *qset = (qset_t*) mix_malloc (qset1->obst, sizeof (qset_t));
656   const int n_elems = qset1->n_elems + qset2->n_elems;
657
658   qset->values = alloc_list (n_elems, qset1->obst);
659
660   memcpy (qset->values, qset1->values,
661           qset1->n_elems * sizeof (sortable_t));
662
663   memcpy (qset->values+qset1->n_elems,
664           qset2->values, qset2->n_elems * sizeof (sortable_t));
665
666   qset->obst = qset1->obst;
667   qset->n_elems = n_elems;
668   qset->n_slots = qset->n_elems;
669
670   qset_sort (qset);
671
672   return (qset);
673 }
674
675 /*
676   Report the size of the given qset.
677 */
678 int qset_size (qset_t *qset)
679 {
680   return (qset->n_elems);
681 }
682
683 /*
684   Print the given qset to the given stream.
685 */
686 void qset_print (qset_t *qset, FILE *stream)
687 {
688   q_print (qset->values, qset->n_elems, stream);
689 }
690
691 /*
692    Check wether the given qset is empty
693 */
694 int qset_is_empty (qset_t *qset)
695 {
696   return (0 == qset->n_elems);
697 }
698
699 /*
700   Initialise a new iteration over a qset
701 */
702 sortable_t *qset_start (qset_t *qset)
703 {
704   qset->cursor = 0;
705
706   return (qset_next (qset));    /* works for empty sets, too */
707 }
708
709 /*
710   Step to the next element
711 */
712 sortable_t *qset_next (qset_t *qset)
713 {
714   if (qset->n_elems == qset->cursor) {
715     return (NULL);
716   }
717
718   /* quick fix to skip NULL entries */
719   while ((qset->cursor < qset->n_elems) &&
720          (NULL == qset->values [qset->cursor])) {
721     qset->cursor ++;
722   }
723
724   return (qset->values [qset->cursor++]);
725 }
726
727
728 # ifdef UNSINN
729 int qset_test_main (int argc, char **argv)
730 {
731   struct timeval tp;
732   unsigned int seed;
733
734   if (-1 == gettimeofday (&tp, NULL)) {
735     perror ("gettimeofday");
736     exit (EXIT_FAILURE);
737   }
738
739   seed = (unsigned int) tp.tv_usec;
740   srand (seed);
741
742   /* test_qsort (20, 1000000, 100000); */
743
744   test_qset (atoi (argv [1]));
745
746   exit (EXIT_SUCCESS);
747 }
748 # endif /* defined UNSINN */
749
750 /*
751   $Log$
752   Revision 1.5  2004/11/24 14:53:56  liekweg
753   Bugfixes
754
755   Revision 1.4  2004/11/18 16:35:45  liekweg
756   Added unique ids for debugging
757
758   Revision 1.3  2004/11/09 16:45:36  liekweg
759   print pointers
760
761   Revision 1.2  2004/11/08 12:32:00  liekweg
762   Moved q_* methods into private section
763
764   Revision 1.1  2004/11/04 14:55:13  liekweg
765   added qset
766
767
768  */