- implemented ull -> float conversion for x87
[libfirm] / ir / adt / pdeq.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       double ended queue of generic pointers.
23  * @author      Christian von Roques
24  * @date        1999 by getting from fiasco
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #ifdef HAVE_STDIO_H
30 # include <stdio.h>
31 #endif
32 #ifdef HAVE_STDLIB_H
33 # include <stdlib.h>
34 #endif
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #endif
38
39 #include <assert.h>
40
41 #include "fourcc.h"
42 #include "pdeq.h"
43 #include "xmalloc.h"
44 #include "align.h"
45
46 /* Pointer Double Ended Queue */
47 #define PDEQ_MAGIC1     FOURCC('P','D','E','1')
48 #define PDEQ_MAGIC2     FOURCC('P','D','E','2')
49
50 /** Size of pdeq block cache. */
51 #define TUNE_NSAVED_PDEQS 16
52
53 /**
54  * Maximal number of data items in a pdeq chunk.
55  */
56 #define NDATA ((int)((PREF_MALLOC_SIZE - offsetof (pdeq, data)) / sizeof (void *)))
57
58 #ifdef NDEBUG
59 # define VRFY(dq) ((void)0)
60 #else
61 # define VRFY(dq) assert((dq) && ((dq)->magic == PDEQ_MAGIC1))
62 #endif
63
64 /**
65  * A pointer double ended queue.
66  * This structure is used as a list chunk either.
67  */
68 struct pdeq {
69 #ifndef NDEBUG
70   unsigned magic;       /**< debug magic */
71 #endif
72   pdeq *l_end, *r_end;  /**< left and right ends of the queue */
73   pdeq *l, *r;          /**< left and right neighbor */
74   int n;                /**< number of elements in the current chunk */
75   int p;                /**< the read/write pointer */
76   const void *data[1];  /**< storage for elements */
77 };
78
79
80 /**
81  * cache of unused, pdeq blocks to speed up new_pdeq and del_pdeq.
82  * +1 for compilers that can't grok empty arrays
83  */
84 static pdeq *pdeq_block_cache[TUNE_NSAVED_PDEQS+1];
85
86 /**
87  * Number of pdeqs in pdeq_store.
88  */
89 static unsigned pdeqs_cached;
90
91 /**
92  * Free a pdeq chunk, put in into the cache if possible.
93  *
94  * @param p   The pdeq chunk.
95  */
96 static inline void free_pdeq_block (pdeq *p)
97 {
98 #ifndef NDEBUG
99   p->magic = 0xbadf00d1;
100 #endif
101   if (pdeqs_cached < TUNE_NSAVED_PDEQS) {
102     pdeq_block_cache[pdeqs_cached++] = p;
103   } else {
104     xfree (p);
105   }
106 }
107
108 /**
109  * Allocate a new pdeq chunk, get it from the cache if possible.
110  *
111  * @return A new pdeq chunk.
112  */
113 static inline pdeq *alloc_pdeq_block (void)
114 {
115   pdeq *p;
116   if (TUNE_NSAVED_PDEQS && pdeqs_cached) {
117     p = pdeq_block_cache[--pdeqs_cached];
118   } else {
119     p = xmalloc(PREF_MALLOC_SIZE);
120   }
121   return p;
122 }
123
124
125 #ifndef NDEBUG
126 /**
127  * Verify a double ended list, assert if failure.
128  *
129  * @param dq   The list to verify.
130  */
131 void _pdeq_vrfy(pdeq *dq)
132 {
133   pdeq *q;
134
135   assert (   dq
136           && (dq->magic == PDEQ_MAGIC1)
137           && (dq->l_end && dq->r_end));
138   q = dq->l_end;
139   while (q) {
140     assert (   ((q == dq) || (q->magic == PDEQ_MAGIC2))
141             && ((q == dq->l_end) ^ (q->l != NULL))
142             && ((q == dq->r_end) ^ (q->r != NULL))
143             && (!q->l || (q == q->l->r))
144             && ((q->n >= 0) && (q->n <= NDATA))
145             && ((q == dq->l_end) || (q == dq->r_end) || (q->n == NDATA))
146             && ((q->p >= 0) && (q->p < NDATA)));
147     q = q->r;
148   }
149 }
150 #endif
151
152 /* Creates a new double ended pointer list. */
153 pdeq *new_pdeq(void)
154 {
155   pdeq *dq;
156
157   dq = alloc_pdeq_block();
158
159 #ifndef NDEBUG
160   dq->magic = PDEQ_MAGIC1;
161 #endif
162   dq->l_end = dq->r_end = dq;
163   dq->l = dq->r = NULL;
164   dq->n = dq->p = 0;
165
166   VRFY(dq);
167   return dq;
168 }
169
170 /* Creates a new double ended pointer list and puts an initial pointer element in. */
171 pdeq *new_pdeq1(const void *x)
172 {
173   return pdeq_putr(new_pdeq(), x);
174 }
175
176 /* Delete a double ended pointer list. */
177 void del_pdeq(pdeq *dq)
178 {
179   pdeq *q, *qq;
180
181   VRFY(dq);
182
183   q = dq->l_end;                /* left end of chain */
184   /* pdeq trunk empty, but !pdeq_empty() ==> trunk not in chain */
185   if (dq->n == 0 && dq->l_end != dq ) {
186     free_pdeq_block(dq);
187   }
188
189   /* Free all blocks in the pdeq chain */
190   do {
191     qq = q->r;
192     free_pdeq_block(q);
193   } while ((q = qq));
194
195 }
196
197 /* Checks if a list is empty. */
198 int pdeq_empty(pdeq *dq)
199 {
200   VRFY(dq);
201   return dq->l_end->n == 0;
202 }
203
204 /* Returns the length of a double ended pointer list. */
205 int pdeq_len(pdeq *dq)
206 {
207   int n;
208   pdeq *q;
209
210   VRFY(dq);
211
212   n = 0;
213   q = dq->l_end;
214   do {
215     n += q->n;
216     q = q->r;
217   }  while (q);
218
219   return n;
220 }
221
222 /* Add a pointer to the right site of a double ended pointer list. */
223 pdeq *pdeq_putr(pdeq *dq, const void *x)
224 {
225   pdeq *rdq;
226   int n;
227
228   VRFY(dq);
229
230   rdq = dq->r_end;
231   if (rdq->n >= NDATA) {        /* tailblock full */
232     pdeq *ndq;
233
234     ndq = dq;                   /* try to reuse trunk, but ... */
235     if (dq->n) {                /* ... if trunk used */
236       /* allocate and init new block */
237       ndq = alloc_pdeq_block();
238 #ifndef NDEBUG
239       ndq->magic = PDEQ_MAGIC2;
240 #endif
241       ndq->l_end = ndq->r_end = NULL;
242     }
243
244     ndq->r = NULL;
245     ndq->l = rdq; rdq->r = ndq;
246     ndq->n = 0; ndq->p = 0;
247     dq->r_end = ndq;
248     rdq = ndq;
249   }
250
251   n = rdq->n++ + rdq->p;
252   if (n >= NDATA) n -= NDATA;
253
254   rdq->data[n] = x;
255
256   VRFY(dq);
257   return dq;
258 }
259
260 /* Add a pointer to the left site of a double ended pointer list. */
261 pdeq *pdeq_putl(pdeq *dq, const void *x)
262 {
263   pdeq *ldq;
264   int p;
265
266   VRFY(dq);
267
268   ldq = dq->l_end;
269   if (ldq->n >= NDATA) {        /* headblock full */
270     pdeq *ndq;
271
272     ndq = dq;                   /* try to reuse trunk, but ... */
273     if (dq->n) {                /* ... if trunk used */
274       /* allocate and init new block */
275       ndq = alloc_pdeq_block();
276 #ifndef NDEBUG
277       ndq->magic = PDEQ_MAGIC2;
278 #endif
279       ndq->l_end = ndq->r_end = NULL;
280     }
281
282     ndq->l = NULL;
283     ndq->r = ldq; ldq->l = ndq;
284     ndq->n = 0; ndq->p = 0;
285     dq->l_end = ndq;
286     ldq = ndq;
287   }
288
289   ldq->n++;
290   p = ldq->p - 1;
291   if (p < 0) p += NDATA;
292   ldq->p = p;
293
294   ldq->data[p] = x;
295
296   VRFY(dq);
297   return dq;
298 }
299
300 /* Retrieve a pointer from the right site of a double ended pointer list. */
301 void *pdeq_getr(pdeq *dq)
302 {
303   pdeq *rdq;
304   const void *x;
305   int n;
306
307   VRFY(dq);
308   assert(dq->l_end->n);
309
310   rdq = dq->r_end;
311   n = rdq->p + --rdq->n;
312   if (n >= NDATA) n -= NDATA;
313   x = rdq->data[n];
314
315   if (rdq->n == 0) {
316     if (rdq->l) {
317       dq->r_end = rdq->l;
318       rdq->l->r = NULL;
319       rdq->l = NULL;
320     } else {
321       dq->r_end = dq->l_end = dq;
322     }
323     if (dq != rdq) {
324       free_pdeq_block(rdq);
325     }
326   }
327
328   VRFY(dq);
329   return (void *)x;
330 }
331
332 /* Retrieve a pointer from the left site of a double ended pointer list. */
333 void *pdeq_getl(pdeq *dq)
334 {
335   pdeq *ldq;
336   const void *x;
337   int p;
338
339   VRFY(dq);
340   assert(dq->l_end->n);
341
342   ldq = dq->l_end;
343   p = ldq->p;
344   x = ldq->data[p];
345   if (++p >= NDATA) p = 0;
346   ldq->p = p;
347
348   if (--ldq->n == 0) {
349     if (ldq->r) {
350       dq->l_end = ldq->r;
351       ldq->r->l = NULL;
352       ldq->r = NULL;
353     } else {
354       dq->l_end = dq->r_end = dq;
355     }
356     if (dq != ldq) {
357       free_pdeq_block(ldq);
358     }
359   }
360
361   VRFY(dq);
362   return (void *)x;
363 }
364
365 /*
366  * Returns non-zero if a double ended pointer list
367  * contains a pointer x.
368  */
369 int pdeq_contains(pdeq *dq, const void *x)
370 {
371   pdeq *q;
372
373   VRFY(dq);
374
375   q = dq->l_end;
376   do {
377     int p, ep;
378
379     p = q->p; ep = p + q->n;
380
381     if (ep > NDATA) {
382       do {
383         if (q->data[p] == x) return 1;
384       } while (++p < NDATA);
385       p = 0;
386       ep -= NDATA;
387     }
388
389     while (p < ep) {
390       if (q->data[p++] == x) return 1;
391     }
392
393     q = q->r;
394   } while (q);
395
396   return 0;
397 }
398
399 /*
400  * Search a key in a double ended pointer list, the search
401  * is controlled by a compare function.
402  * An element is found, if the compare function returns 0.
403  * The search is started from the left site of the list.
404  */
405 void *pdeq_search(pdeq *dq, cmp_fun cmp, const void *key)
406 {
407   pdeq *q;
408   int p;
409
410   VRFY(dq);
411
412   q = dq->l_end;
413   do {
414     int ep;
415
416     p = q->p; ep = p + q->n;
417
418     if (ep > NDATA) {
419       do {
420         if (!cmp (q->data[p], key)) return (void *)q->data[p-1];
421       } while (++p < NDATA);
422       p = 0;
423       ep -= NDATA;
424     }
425
426     while (p < ep) {
427       if (!cmp (q->data[p++], key)) return (void *)q->data[p-1];
428     }
429
430     q = q->r;
431   } while (q);
432
433   return NULL;
434 }
435
436 /*
437  * Convert the double ended pointer list into a linear array beginning from
438  * left, the first element in the linear array will be the left one.
439  */
440 void **pdeq_copyl(pdeq *dq, const void **dst)
441 {
442   pdeq *q;
443   const void **d = dst;
444
445   VRFY(dq);
446
447   q = dq->l_end;
448   while (q) {
449     int p, n;
450
451     p = q->p; n = q->n;
452
453     if (n + p > NDATA) {
454       int nn = NDATA - p;
455       memcpy((void *) d, &q->data[p], nn * sizeof(void *)); d += nn;
456       p = 0; n -= nn;
457     }
458
459     memcpy((void *) d, &q->data[p], n * sizeof(void *)); d += n;
460
461     q = q->r;
462   }
463
464   return (void **)dst;
465 }
466
467 /*
468  * Convert the double ended pointer list into a linear array beginning from
469  * right, the first element in the linear array will be the right one.
470  */
471 void **pdeq_copyr(pdeq *dq, const void **dst)
472 {
473   pdeq *q;
474   const void **d = dst;
475
476   VRFY(dq);
477
478   q = dq->r_end;
479   while (q) {
480     int p, i;
481
482     p = q->p; i = q->n + p - 1;
483     if (i >= NDATA) {
484       i -= NDATA;
485       do *d++ = q->data[i]; while (--i >= 0);
486       i = NDATA - 1;
487     }
488
489     do *d++ = q->data[i]; while (--i >= p);
490
491     q = q->l;
492   }
493
494   return (void **)dst;
495 }