Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
proper use of the HAVE_TRACING variable defined by Cmake through -Dtracing=on
[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
19 /** Creates a new swag.
20  * \param offset where the hookup is located in the structure
21  * \see xbt_swag_offset
22  *
23  * Usage : xbt_swag_new(&obj.setA-&obj);
24  */
25 XBT_INLINE xbt_swag_t xbt_swag_new(size_t offset)
26 {
27   xbt_swag_t swag = xbt_new0(s_xbt_swag_t, 1);
28
29   xbt_swag_init(swag, offset);
30
31   return swag;
32 }
33
34 /**
35  * \param swag poor victim
36  *
37  * kilkil a swag but not it's content. If you do not understand why
38  * xbt_swag_free should not free its content, don't use swags.
39  */
40 XBT_INLINE void xbt_swag_free(xbt_swag_t swag)
41 {
42   free(swag);
43 }
44
45 /** Creates a new swag.
46  * \param swag the swag to initialize
47  * \param offset where the hookup is located in the structure
48  * \see xbt_swag_offset
49  *
50  * Usage : xbt_swag_init(swag,&obj.setA-&obj);
51  */
52 XBT_INLINE void xbt_swag_init(xbt_swag_t swag, size_t offset)
53 {
54   swag->tail = NULL;
55   swag->head = NULL;
56   swag->offset = offset;
57   swag->count = 0;
58 }
59
60
61 /**
62  * \param obj the objet to insert in the swag
63  * \param swag a swag
64  *
65  * insert \a obj in \a swag
66  */
67 XBT_INLINE void xbt_swag_insert(void *obj, xbt_swag_t swag)
68 {
69
70   if (xbt_swag_belongs(obj, swag))
71     return;
72
73   (swag->count)++;
74   if (swag->head == NULL) {
75     xbt_assert0(!(swag->tail), "Inconsistent swag.");
76     swag->head = obj;
77     swag->tail = obj;
78     return;
79   }
80
81   xbt_swag_getPrev(obj, swag->offset) = swag->tail;
82   xbt_swag_getNext(xbt_swag_getPrev(obj, swag->offset), swag->offset) = obj;
83
84   swag->tail = obj;
85 }
86
87 /**
88  * \param obj the objet to insert in the swag
89  * \param swag a swag
90  *
91  * insert (at the head... you probably had a very good reason to do
92  * that, I hope you know what you're doing) \a obj in \a swag
93  */
94 XBT_INLINE void xbt_swag_insert_at_head(void *obj, xbt_swag_t swag)
95 {
96
97   if (xbt_swag_belongs(obj, swag))
98     return;
99
100   (swag->count)++;
101   if (swag->head == NULL) {
102     xbt_assert0(!(swag->tail), "Inconsistent swag.");
103     swag->head = obj;
104     swag->tail = obj;
105     return;
106   }
107
108   xbt_swag_getNext(obj, swag->offset) = swag->head;
109   xbt_swag_getPrev(xbt_swag_getNext(obj, swag->offset), swag->offset) = obj;
110
111   swag->head = obj;
112 }
113
114 /**
115  * \param obj the objet to insert in the swag
116  * \param swag a swag
117  *
118  * insert (at the tail... you probably had a very good reason to do
119  * that, I hope you know what you're doing) \a obj in \a swag
120  */
121 XBT_INLINE void xbt_swag_insert_at_tail(void *obj, xbt_swag_t swag)
122 {
123
124   if (xbt_swag_belongs(obj, swag))
125     return;
126
127   (swag->count)++;
128   if (swag->head == NULL) {
129     xbt_assert0(!(swag->tail), "Inconsistent swag.");
130     swag->head = obj;
131     swag->tail = obj;
132     return;
133   }
134
135   xbt_swag_getPrev(obj, swag->offset) = swag->tail;
136   xbt_swag_getNext(xbt_swag_getPrev(obj, swag->offset), swag->offset) = obj;
137
138   swag->tail = obj;
139 }
140
141 /**
142  * \param obj the objet to remove from the swag
143  * \param swag a swag
144  * \return \a obj if it was in the \a swag and NULL otherwise
145  *
146  * removes \a obj from \a swag
147  */
148 XBT_INLINE void *xbt_swag_remove(void *obj, xbt_swag_t swag)
149 {
150   size_t offset = swag->offset;
151
152   if ((!obj) || (!swag))
153     return NULL;
154   if (!xbt_swag_belongs(obj, swag))     /* Trying to remove an object that
155                                            was not in this swag */
156     return NULL;
157
158   if (swag->head == swag->tail) {       /* special case */
159     if (swag->head != obj)      /* Trying to remove an object that was not in this swag */
160       return NULL;
161     swag->head = NULL;
162     swag->tail = NULL;
163     xbt_swag_getNext(obj, offset) = xbt_swag_getPrev(obj, offset) = NULL;
164   } else if (obj == swag->head) {       /* It's the head */
165     swag->head = xbt_swag_getNext(obj, offset);
166     xbt_swag_getPrev(swag->head, offset) = NULL;
167     xbt_swag_getNext(obj, offset) = NULL;
168   } else if (obj == swag->tail) {       /* It's the tail */
169     swag->tail = xbt_swag_getPrev(obj, offset);
170     xbt_swag_getNext(swag->tail, offset) = NULL;
171     xbt_swag_getPrev(obj, offset) = NULL;
172   } else {                      /* It's in the middle */
173     xbt_swag_getNext(xbt_swag_getPrev(obj, offset), offset) = xbt_swag_getNext(obj, offset);
174     xbt_swag_getPrev(xbt_swag_getNext(obj, offset), offset) = xbt_swag_getPrev(obj, offset);
175     xbt_swag_getPrev(obj, offset) = xbt_swag_getNext(obj, offset) = NULL;
176   }
177   (swag->count)--;
178   return obj;
179 }
180
181 /**
182  * \param swag a swag
183  * \return an object from the \a swag
184  */
185 void *xbt_swag_extract(xbt_swag_t swag)
186 {
187   size_t offset = swag->offset;
188   void *obj = NULL;
189
190   if ((!swag) || (!(swag->head)))
191     return NULL;
192
193   obj = swag->head;
194
195   if (swag->head == swag->tail) {       /* special case */
196     swag->head = swag->tail = NULL;
197     xbt_swag_getPrev(obj, offset) = xbt_swag_getNext(obj, offset) = NULL;
198   } else {
199     swag->head = xbt_swag_getNext(obj, offset);
200     xbt_swag_getPrev(swag->head, offset) = NULL;
201     xbt_swag_getNext(obj, offset) = NULL;
202   }
203   (swag->count)--;
204
205   return obj;
206 }
207
208 /**
209  * \param swag a swag
210  * \return the number of objects in \a swag
211  */
212 XBT_INLINE int xbt_swag_size(xbt_swag_t swag)
213 {
214   return (swag->count);
215 }
216
217
218 #ifdef SIMGRID_TEST
219
220 XBT_TEST_SUITE("swag", "Swag data container");
221
222 typedef struct {
223   s_xbt_swag_hookup_t setA;
224   s_xbt_swag_hookup_t setB;
225   const char *name;
226 } shmurtz, s_shmurtz_t, *shmurtz_t;
227
228
229 XBT_TEST_UNIT("basic", test_swag_basic, "Basic usage")
230 {
231   shmurtz_t obj1, obj2, obj;
232   xbt_swag_t setA, setB;
233
234   obj1 = xbt_new0(s_shmurtz_t, 1);
235   obj2 = xbt_new0(s_shmurtz_t, 1);
236
237   obj1->name = "Obj 1";
238   obj2->name = "Obj 2";
239
240   xbt_test_add0("Basic usage");
241   xbt_test_log3("%p %p %ld\n", obj1, &(obj1->setB),
242                 (long) ((char *) &(obj1->setB) - (char *) obj1));
243
244   setA = xbt_swag_new(xbt_swag_offset(*obj1, setA));
245   setB = xbt_swag_new(xbt_swag_offset(*obj1, setB));
246
247   xbt_swag_insert(obj1, setA);
248   xbt_swag_insert(obj1, setB);
249   xbt_swag_insert(obj2, setA);
250   xbt_swag_insert(obj2, setB);
251
252   xbt_swag_remove(obj1, setB);
253   /*  xbt_swag_remove(obj2, setB); */
254
255   xbt_test_add0("Traverse set A");
256   xbt_swag_foreach(obj, setA) {
257     xbt_test_log1("Saw: %s", obj->name);
258   }
259
260   xbt_test_add0("Traverse set B");
261   xbt_swag_foreach(obj, setB) {
262     xbt_test_log1("Saw: %s", obj->name);
263   }
264
265   xbt_test_add0("Ensure set content and length");
266   xbt_test_assert(xbt_swag_belongs(obj1, setA));
267   xbt_test_assert(xbt_swag_belongs(obj2, setA));
268
269   xbt_test_assert(!xbt_swag_belongs(obj1, setB));
270   xbt_test_assert(xbt_swag_belongs(obj2, setB));
271
272   xbt_test_assert(xbt_swag_size(setA) == 2);
273   xbt_test_assert(xbt_swag_size(setB) == 1);
274
275   xbt_swag_free(setA);
276   xbt_swag_free(setB);
277 }
278
279 #endif /* SIMGRID_TEST */