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