Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
873724b433ae45349e2f0cbc378649362f7744d3
[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  * \param swag a swag
212  * \return the number of objects in \a swag
213  */
214 int xbt_swag_size(xbt_swag_t swag)
215 {
216   return (swag->count);
217 }
218
219 /** 
220  * \param obj an object
221  * \param swag a swag
222  * \return 1 if \a obj is in the \a swag and 0 otherwise
223  */
224 int xbt_swag_belongs(void *obj, xbt_swag_t swag)
225 {
226   return ((NEXT(obj, swag->offset)) || (PREV(obj, swag->offset))
227           || (swag->head == obj));
228 }
229
230
231 #ifdef SIMGRID_TEST
232
233 XBT_TEST_SUITE("swag","Swag data container");
234
235 typedef struct {
236   s_xbt_swag_hookup_t setA;
237   s_xbt_swag_hookup_t setB;
238   const char *name;
239 } shmurtz, s_shmurtz_t, *shmurtz_t;
240
241
242 XBT_TEST_UNIT("basic",test_swag_basic,"Basic usage") {
243   shmurtz_t obj1, obj2, obj;
244   xbt_swag_t setA,setB;
245
246   obj1 = calloc(1,sizeof(s_shmurtz_t));
247   obj2 = calloc(1,sizeof(s_shmurtz_t));
248
249   obj1->name="Obj 1";
250   obj2->name="Obj 2";
251
252   xbt_test_add0("Basic usage");
253   xbt_test_log3("%p %p %ld\n",obj1,&(obj1->setB),
254                 (long)((char *)&(obj1->setB) - (char *)obj1));
255
256   setA = xbt_swag_new(xbt_swag_offset(*obj1,setA));
257   setB = xbt_swag_new(xbt_swag_offset(*obj1,setB));
258
259   xbt_swag_insert(obj1, setA);
260   xbt_swag_insert(obj1, setB);
261   xbt_swag_insert(obj2, setA);
262   xbt_swag_insert(obj2, setB);
263
264   xbt_swag_remove(obj1, setB);
265   /*  xbt_swag_remove(obj2, setB);*/
266
267   xbt_test_add0("Traverse set A");
268   xbt_swag_foreach(obj,setA) {
269     xbt_test_log1("Saw: %s",obj->name);
270   }
271
272   xbt_test_add0("Traverse set B");
273   xbt_swag_foreach(obj,setB) {
274     xbt_test_log1("Saw: %s",obj->name);
275   }
276
277   xbt_test_add0("Ensure set content and length");
278   xbt_test_assert(  xbt_swag_belongs(obj1,setA));
279   xbt_test_assert(  xbt_swag_belongs(obj2,setA));
280
281   xbt_test_assert(! xbt_swag_belongs(obj1,setB));
282   xbt_test_assert(  xbt_swag_belongs(obj2,setB));
283
284   xbt_test_assert(xbt_swag_size(setA) == 2);
285   xbt_test_assert(xbt_swag_size(setB) == 1);
286    
287   xbt_swag_free(setA);
288   xbt_swag_free(setB);
289 }
290
291 #endif /* SIMGRID_TEST */