Add OALLOC*() to make allocating from obstacks a bit nicer.
[libfirm] / ir / adt / plist.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 Simple, non circular, double linked pointer list.
23  * @note  Created because the properties of the standard circular list were not
24  *        very well suited for the interference graph implementation.
25  *        This list uses an obstack and a free-list to efficiently manage its
26  *        elements.
27  * @author  Kimon Hoffmann
28  * @date    14.07.2005
29  * @version $Id$
30  */
31 #include <stdlib.h>
32
33 #include "plist.h"
34
35 /**
36  * Helper macro that returns a new uninitialized list element by either
37  * fetching one from the free-list or allocating a new one on the lists
38  * obstack.
39  * @param list the list for which to allocate the element.
40  * @return the newly allocated, uninitialized element.
41  */
42 static plist_element_t *allocate_element(plist_t* list) {
43         plist_element_t *new_element;
44
45         if (list->first_free_element != NULL) {
46                 new_element              = list->first_free_element;
47                 list->first_free_element = new_element->next;
48                 new_element->next        = NULL;
49         }
50         else {
51                 new_element = OALLOC(list->obst, plist_element_t);
52         }
53
54         return new_element;
55 }
56
57 plist_t *plist_new(void) {
58         plist_t *list = xmalloc(sizeof(*list) + sizeof(*list->obst));
59
60         list->obst               = (struct obstack *)&list[1];
61         list->foreign_obstack    = 0;
62         list->first_element      = NULL;
63         list->last_element       = NULL;
64         list->first_free_element = NULL;
65         list->element_count      = 0;
66
67         obstack_init(list->obst);
68         return list;
69 }
70
71 plist_t *plist_obstack_new(struct obstack *obst) {
72         plist_t *list = OALLOC(obst, plist_t);
73
74         list->obst               = obst;
75         list->foreign_obstack    = 1;
76         list->first_element      = NULL;
77         list->last_element       = NULL;
78         list->first_free_element = NULL;
79         list->element_count      = 0;
80
81         return list;
82 }
83
84 void plist_free(plist_t *list) {
85         list->first_element      = NULL;
86         list->last_element       = NULL;
87         list->first_free_element = NULL;
88         list->element_count      = 0;
89
90         if (! list->foreign_obstack) {
91                 obstack_free(list->obst, NULL);
92                 xfree(list);
93         }
94 }
95
96 void plist_insert_back(plist_t *list, void *value) {
97         if (list->last_element != NULL) {
98                 plist_insert_after(list, list->last_element, value);
99         }
100         else {
101                 plist_element_t *newElement = allocate_element(list);
102
103                 newElement->data    = value;
104                 newElement->prev    = NULL;
105                 newElement->next    = NULL;
106                 list->first_element = list->last_element = newElement;
107                 list->element_count = 1;
108         }
109 }
110
111 void plist_insert_front(plist_t *list, void *value) {
112         if (list->first_element != NULL) {
113                 plist_insert_before(list, list->first_element, value);
114         }
115         else {
116                 plist_element_t *newElement = allocate_element(list);
117
118                 newElement->data    = value;
119                 newElement->prev    = NULL;
120                 newElement->next    = NULL;
121                 list->first_element = list->last_element = newElement;
122                 list->element_count = 1;
123         }
124 }
125
126 void plist_insert_before(plist_t *list, plist_element_t *element, void *value) {
127         plist_element_t *prevElement;
128         plist_element_t *newElement = allocate_element(list);
129
130         newElement->data = value;
131         newElement->next = element;
132         prevElement      = element->prev;
133         newElement->prev = prevElement;
134
135         if (prevElement != NULL) {
136                 prevElement->next = newElement;
137         }
138         else {
139                 list->first_element = newElement;
140         }
141
142         element->prev = newElement;
143         ++list->element_count;
144 }
145
146 void plist_insert_after(plist_t* list, plist_element_t* element, void* value) {
147         plist_element_t *nextElement;
148         plist_element_t *newElement = allocate_element(list);
149
150         newElement->data = value;
151         newElement->prev = element;
152         nextElement      = element->next;
153         newElement->next = nextElement;
154
155         if (nextElement != NULL) {
156                 nextElement->prev = newElement;
157         }
158         else {
159                 list->last_element = newElement;
160         }
161
162         element->next = newElement;
163         ++list->element_count;
164 }
165
166 int plist_has_value(plist_t *list, void *value) {
167         plist_element_t *iter;
168
169         for (iter = plist_first(list); iter; iter = plist_element_get_next(iter)) {
170                 if (plist_element_get_value(iter) == value)
171                         return 1;
172         }
173
174         return 0;
175 }
176
177 plist_element_t *plist_find_value(plist_t *list, void *value) {
178         plist_element_t *iter;
179
180         for (iter = plist_first(list); iter; iter = plist_element_get_next(iter)) {
181                 if (plist_element_get_value(iter) == value)
182                         return iter;
183         }
184
185         return NULL;
186 }
187
188 void plist_erase(plist_t *list, plist_element_t *element) {
189         plist_element_t *next_element = element->next;
190         plist_element_t *prev_element = element->prev;
191
192         if (next_element != NULL) {
193                 next_element->prev = prev_element;
194         }
195         else {
196                 list->last_element = prev_element;
197         }
198
199         if (prev_element != NULL) {
200                 prev_element->next = next_element;
201         }
202         else {
203                 list->first_element = next_element;
204         }
205
206         --list->element_count;
207
208         /* Clean the element and prepend it to the free list */
209         element->prev            = NULL; /* The allocation code expects prev to be NULL */
210         element->next            = list->first_free_element;
211         list->first_free_element = element;
212 }
213
214 void plist_clear(plist_t *list) {
215         plist_element_t *curr_element = list->first_element;
216
217         while (curr_element != NULL) {
218                 curr_element->prev = NULL;
219                 curr_element       = curr_element->next;
220         }
221
222         curr_element = list->last_element;
223
224         if (curr_element != NULL) {
225                 curr_element->next = list->first_free_element;
226         }
227
228         list->first_free_element = list->first_element;
229         list->first_element      = 0;
230         list->last_element       = 0;
231         list->element_count      = 0;
232 }