Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Reindent everything (possibly breaking all branches, but for the last time)
[simgrid.git] / src / xbt / swag.c
1 /*      $Id$     */
2
3 /* Copyright (c) 2004 Arnaud Legrand. All rights reserved.                  */
4
5 /* This program is free software; you can redistribute it and/or modify it
6  * under the terms of the license (GNU LGPL) which comes with this package. */
7
8 /* Warning, this module is done to be efficient and performs tons of
9    cast and dirty things. So avoid using it unless you really know
10    what you are doing. */
11
12 /* This type should be added to a type that is to be used in such a swag */
13
14 #include "xbt/sysdep.h"
15 #include "xbt/log.h"
16 #include "xbt/swag.h"
17
18 #define PREV(obj,offset) xbt_swag_getPrev(obj,offset)
19 #define NEXT(obj,offset) xbt_swag_getNext(obj,offset)
20
21
22 /** Creates a new swag.
23  * \param offset where the hookup is located in the structure
24  * \see xbt_swag_offset
25  *
26  * Usage : xbt_swag_new(&obj.setA-&obj);
27  */
28 xbt_swag_t xbt_swag_new(size_t offset)
29 {
30   xbt_swag_t swag = xbt_new0(s_xbt_swag_t, 1);
31
32   xbt_swag_init(swag, offset);
33
34   return swag;
35 }
36
37 /**
38  * \param swag poor victim
39  *
40  * kilkil a swag but not it's content. If you do not understand why
41  * xbt_swag_free should not free its content, don't use swags.
42  */
43 void xbt_swag_free(xbt_swag_t swag)
44 {
45   free(swag);
46 }
47
48 /** Creates a new swag.
49  * \param swag the swag to initialize
50  * \param offset where the hookup is located in the structure
51  * \see xbt_swag_offset
52  *
53  * Usage : xbt_swag_init(swag,&obj.setA-&obj);
54  */
55 void xbt_swag_init(xbt_swag_t swag, size_t offset)
56 {
57   swag->tail = NULL;
58   swag->head = NULL;
59   swag->offset = offset;
60   swag->count = 0;
61 }
62
63
64 /**
65  * \param obj the objet to insert in the swag
66  * \param swag a swag
67  *
68  * insert \a obj in \a swag
69  */
70 void xbt_swag_insert(void *obj, xbt_swag_t swag)
71 {
72
73   if (xbt_swag_belongs(obj, swag))
74     return;
75
76   (swag->count)++;
77   if (swag->head == NULL) {
78     xbt_assert0(!(swag->tail), "Inconsistent swag.");
79     swag->head = obj;
80     swag->tail = obj;
81     return;
82   }
83
84   PREV(obj, swag->offset) = swag->tail;
85   NEXT(PREV(obj, swag->offset), swag->offset) = obj;
86
87   swag->tail = obj;
88 }
89
90 /**
91  * \param obj the objet to insert in the swag
92  * \param swag a swag
93  *
94  * insert (at the head... you probably had a very good reason to do
95  * that, I hope you know what you're doing) \a obj in \a swag
96  */
97 void xbt_swag_insert_at_head(void *obj, xbt_swag_t swag)
98 {
99
100   if (xbt_swag_belongs(obj, swag))
101     return;
102
103   (swag->count)++;
104   if (swag->head == NULL) {
105     xbt_assert0(!(swag->tail), "Inconsistent swag.");
106     swag->head = obj;
107     swag->tail = obj;
108     return;
109   }
110
111   NEXT(obj, swag->offset) = swag->head;
112   PREV(NEXT(obj, swag->offset), swag->offset) = obj;
113
114   swag->head = obj;
115 }
116
117 /**
118  * \param obj the objet to insert in the swag
119  * \param swag a swag
120  *
121  * insert (at the tail... you probably had a very good reason to do
122  * that, I hope you know what you're doing) \a obj in \a swag
123  */
124 void xbt_swag_insert_at_tail(void *obj, xbt_swag_t swag)
125 {
126
127   if (xbt_swag_belongs(obj, swag))
128     return;
129
130   (swag->count)++;
131   if (swag->head == NULL) {
132     xbt_assert0(!(swag->tail), "Inconsistent swag.");
133     swag->head = obj;
134     swag->tail = obj;
135     return;
136   }
137
138   PREV(obj, swag->offset) = swag->tail;
139   NEXT(PREV(obj, swag->offset), swag->offset) = obj;
140
141   swag->tail = obj;
142 }
143
144 /**
145  * \param obj the objet to remove from the swag
146  * \param swag a swag
147  * \return \a obj if it was in the \a swag and NULL otherwise
148  *
149  * removes \a obj from \a swag
150  */
151 void *xbt_swag_remove(void *obj, xbt_swag_t swag)
152 {
153   size_t offset = swag->offset;
154
155   if ((!obj) || (!swag))
156     return NULL;
157   if (!xbt_swag_belongs(obj, swag))     /* Trying to remove an object that
158                                            was not in this swag */
159     return NULL;
160
161   if (swag->head == swag->tail) {       /* special case */
162     if (swag->head != obj)      /* Trying to remove an object that was not in this swag */
163       return NULL;
164     swag->head = NULL;
165     swag->tail = NULL;
166     NEXT(obj, offset) = PREV(obj, offset) = NULL;
167   } else if (obj == swag->head) {       /* It's the head */
168     swag->head = NEXT(obj, offset);
169     PREV(swag->head, offset) = NULL;
170     NEXT(obj, offset) = NULL;
171   } else if (obj == swag->tail) {       /* It's the tail */
172     swag->tail = PREV(obj, offset);
173     NEXT(swag->tail, offset) = NULL;
174     PREV(obj, offset) = NULL;
175   } else {                      /* It's in the middle */
176     NEXT(PREV(obj, offset), offset) = NEXT(obj, offset);
177     PREV(NEXT(obj, offset), offset) = PREV(obj, offset);
178     PREV(obj, offset) = NEXT(obj, offset) = NULL;
179   }
180   (swag->count)--;
181   return obj;
182 }
183
184 /**
185  * \param swag a swag
186  * \return an object from the \a swag
187  */
188 void *xbt_swag_extract(xbt_swag_t swag)
189 {
190   size_t offset = swag->offset;
191   void *obj = NULL;
192
193   if ((!swag) || (!(swag->head)))
194     return NULL;
195
196   obj = swag->head;
197
198   if (swag->head == swag->tail) {       /* special case */
199     swag->head = swag->tail = NULL;
200     PREV(obj, offset) = NEXT(obj, offset) = NULL;
201   } else {
202     swag->head = NEXT(obj, offset);
203     PREV(swag->head, offset) = NULL;
204     NEXT(obj, offset) = NULL;
205   }
206   (swag->count)--;
207
208   return obj;
209 }
210
211 /**
212  * \param swag a swag
213  * \return the number of objects in \a swag
214  */
215 int xbt_swag_size(xbt_swag_t swag)
216 {
217   return (swag->count);
218 }
219
220 /**
221  * \param obj an object
222  * \param swag a swag
223  * \return 1 if \a obj is in the \a swag and 0 otherwise
224  */
225 int xbt_swag_belongs(void *obj, xbt_swag_t swag)
226 {
227   return ((NEXT(obj, swag->offset)) || (PREV(obj, swag->offset))
228           || (swag->head == obj));
229 }
230
231
232 #ifdef SIMGRID_TEST
233
234 XBT_TEST_SUITE("swag", "Swag data container");
235
236 typedef struct {
237   s_xbt_swag_hookup_t setA;
238   s_xbt_swag_hookup_t setB;
239   const char *name;
240 } shmurtz, s_shmurtz_t, *shmurtz_t;
241
242
243 XBT_TEST_UNIT("basic", test_swag_basic, "Basic usage")
244 {
245   shmurtz_t obj1, obj2, obj;
246   xbt_swag_t setA, setB;
247
248   obj1 = xbt_new0(s_shmurtz_t, 1);
249   obj2 = xbt_new0(s_shmurtz_t, 1);
250
251   obj1->name = "Obj 1";
252   obj2->name = "Obj 2";
253
254   xbt_test_add0("Basic usage");
255   xbt_test_log3("%p %p %ld\n", obj1, &(obj1->setB),
256                 (long) ((char *) &(obj1->setB) - (char *) obj1));
257
258   setA = xbt_swag_new(xbt_swag_offset(*obj1, setA));
259   setB = xbt_swag_new(xbt_swag_offset(*obj1, setB));
260
261   xbt_swag_insert(obj1, setA);
262   xbt_swag_insert(obj1, setB);
263   xbt_swag_insert(obj2, setA);
264   xbt_swag_insert(obj2, setB);
265
266   xbt_swag_remove(obj1, setB);
267   /*  xbt_swag_remove(obj2, setB); */
268
269   xbt_test_add0("Traverse set A");
270   xbt_swag_foreach(obj, setA) {
271     xbt_test_log1("Saw: %s", obj->name);
272   }
273
274   xbt_test_add0("Traverse set B");
275   xbt_swag_foreach(obj, setB) {
276     xbt_test_log1("Saw: %s", obj->name);
277   }
278
279   xbt_test_add0("Ensure set content and length");
280   xbt_test_assert(xbt_swag_belongs(obj1, setA));
281   xbt_test_assert(xbt_swag_belongs(obj2, setA));
282
283   xbt_test_assert(!xbt_swag_belongs(obj1, setB));
284   xbt_test_assert(xbt_swag_belongs(obj2, setB));
285
286   xbt_test_assert(xbt_swag_size(setA) == 2);
287   xbt_test_assert(xbt_swag_size(setB) == 1);
288
289   xbt_swag_free(setA);
290   xbt_swag_free(setB);
291 }
292
293 #endif /* SIMGRID_TEST */