Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
3077ebdb68506c6a910e5913e0540d1bfb3d4427
[simgrid.git] / src / gras / DataDesc / cbps.c
1 /* $Id$ */
2
3 /* cbps - persistant states for callbacks                                   */
4
5 /* Copyright (c) 2003 Olivier Aumage.                                       */
6 /* Copyright (c) 2003, 2004 Martin Quinson.                                 */
7 /* All rights reserved.                                                     */
8
9 /* This program is free software; you can redistribute it and/or modify it
10  * under the terms of the license (GNU LGPL) which comes with this package. */
11
12 #include "xbt/ex.h"
13 #include "gras/DataDesc/datadesc_private.h"
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ddt_cbps,datadesc,"callback persistant state");
15
16 typedef struct {
17   gras_datadesc_type_t  type;
18   void                 *data;
19 } s_gras_cbps_elm_t, *gras_cbps_elm_t;
20
21 typedef struct s_gras_cbps {
22   xbt_dynar_t lints; /* simple stack of long integers (easy interface) */
23
24   xbt_dict_t  space; /* varname x dynar of gras_cbps_elm_t */
25   xbt_dynar_t frames; /* of dynar of names defined within this frame
26                            (and to pop when we leave it) */
27   xbt_dynar_t globals;
28 } s_gras_cbps_t;
29
30 void free_string(void *d);
31
32 void free_string(void *d){
33   free(*(void**)d);
34 }
35
36 gras_cbps_t gras_cbps_new(void) {
37   gras_cbps_t  res;
38
39   res=xbt_new(s_gras_cbps_t,1);
40
41   res->lints = xbt_dynar_new(sizeof(int), NULL);
42   res->space = xbt_dict_new();
43   /* no leak, the content is freed manually on block_end */
44   res->frames = xbt_dynar_new(sizeof(xbt_dynar_t), NULL);
45   res->globals = xbt_dynar_new(sizeof(char*), NULL);
46
47   gras_cbps_block_begin(res);
48
49   return res;
50 }
51
52 void gras_cbps_free(gras_cbps_t *state) {
53
54   xbt_dynar_free( &( (*state)->lints   ) );
55
56   gras_cbps_block_end(*state);
57   xbt_dict_free ( &( (*state)->space   ) );
58   xbt_dynar_free( &( (*state)->frames  ) );
59   xbt_dynar_free( &( (*state)->globals ) );
60
61   free(*state);
62   *state = NULL;
63 }
64
65 /** \brief Declare a new element in the PS, and give it a value.
66  *
67  * If an element of that
68  * name already exists, it is masked by the one given here, and will be 
69  * seeable again only after a pop to remove the value this push adds.
70  */
71 xbt_error_t
72 gras_cbps_v_push(gras_cbps_t          ps,
73                  const char          *name,
74                  void                *data,
75                  gras_datadesc_type_t ddt) {
76
77   xbt_dynar_t     varstack,frame;
78   gras_cbps_elm_t var;
79   char           *varname = (char*)strdup(name);
80   xbt_ex_t        e;
81
82   DEBUG2("push(%s,%p)",name,(void*)data);
83
84   TRY {
85     varstack = xbt_dict_get(ps->space, name);
86   } CATCH(e) {
87     if (e.category == mismatch_error) {
88       DEBUG1("Create a new variable stack for '%s' into the space",name);
89       varstack = xbt_dynar_new(sizeof (gras_cbps_elm_t *), NULL);
90       xbt_dict_set(ps->space, varname, (void **)varstack, NULL);
91       xbt_ex_free(e);
92     /* leaking, you think? only if you do not close all the openned blocks ;)*/
93     } else {
94       RETHROW;
95     }
96   }
97  
98   var       = xbt_new0(s_gras_cbps_elm_t,1);
99   var->type = ddt;
100   var->data = data;
101   
102   xbt_dynar_push(varstack, &var);
103   
104   xbt_dynar_pop(ps->frames, &frame);
105   DEBUG4("Push %s (%p @%p) into frame %p",varname,(void*)varname,(void*)&varname,(void*)frame);
106   xbt_dynar_push(frame, &varname);
107   xbt_dynar_push(ps->frames, &frame); 
108   return no_error;
109 }
110
111 /** \brief Retrieve an element from the PS, and remove it from the PS.
112  *
113  * If it's not
114  * present in the current block, it will fail (with abort) and not search
115  * in upper blocks since this denotes a programmation error.
116  */
117 xbt_error_t
118 gras_cbps_v_pop (gras_cbps_t            ps, 
119                  const char            *name,
120                  gras_datadesc_type_t  *ddt,
121                  void                 **res) {
122   xbt_dynar_t          varstack,frame;
123   gras_cbps_elm_t       var            = NULL;
124   void                 *data           = NULL;
125   xbt_ex_t e;
126
127   DEBUG1("pop(%s)",name);
128   TRY {
129     varstack = xbt_dict_get(ps->space, name);
130   } CATCH(e) {
131     if (e.category == mismatch_error) {
132       xbt_ex_free(e);
133       THROW1(mismatch_error,1,"Asked to pop the non-existant %s",
134              name);
135     }
136     RETHROW;
137   }
138   xbt_dynar_pop(varstack, &var);
139   
140   if (!xbt_dynar_length(varstack)) {
141     DEBUG1("Last incarnation of %s poped. Kill it",name);
142     xbt_dict_remove(ps->space, name);
143     xbt_dynar_free(&varstack);
144   }
145   
146   if (ddt)
147     *ddt = var->type;  
148   data = var->data;
149   
150   free(var);
151   
152   xbt_dynar_pop(ps->frames, &frame);
153   {
154     int l = xbt_dynar_length(frame);
155     
156     while (l--) {
157       char *_name = NULL;
158                                                                                 
159       _name = xbt_dynar_get_as(frame, l, char*);
160       if (!strcmp(name, _name)) {
161         xbt_dynar_remove_at(frame, l, &_name);
162         free(_name);
163         break;
164       }
165     }
166   }
167   xbt_dynar_push(ps->frames, &frame);
168   
169   *res = data;
170   return no_error;
171 }
172
173 /** \brief Change the value of an element in the PS.
174  * 
175  * If it's not present in the current block, look in the upper ones.
176  * If it's not present in any of them, modify in the globals
177  * If not present there neither, the code may segfault (Oli?).
178  *
179  * Once a reference to an element of that name is found somewhere in the PS,
180  *   its value is changed.
181  */
182 void
183 gras_cbps_v_set (gras_cbps_t          ps,
184                  const char          *name,
185                  void                *data,
186                  gras_datadesc_type_t ddt) {
187
188   xbt_dynar_t dynar = NULL;
189   gras_cbps_elm_t elm = NULL;
190   xbt_ex_t e;
191   
192   DEBUG1("set(%s)",name);
193   TRY {
194     dynar = xbt_dict_get(ps->space, name);
195   } CATCH(e) {
196     if (e.category == mismatch_error) {
197       dynar = NULL;
198       xbt_ex_free(e);
199     } else {
200       RETHROW;
201     }
202   }
203
204   if (dynar == NULL) {
205     dynar = xbt_dynar_new(sizeof (gras_cbps_elm_t), NULL);
206     xbt_dict_set(ps->space, name, (void **)dynar, NULL);
207     
208     elm   = xbt_new0(s_gras_cbps_elm_t,1);
209     xbt_dynar_push(ps->globals, &name);
210   } else {
211     xbt_dynar_pop(dynar, &elm);
212   }
213   
214   elm->type   = ddt;
215   elm->data   = data;
216  
217   xbt_dynar_push(dynar, &elm);
218
219 }
220
221 /** \brief Get the value of an element in the PS without modifying it.
222  * 
223  * (note that you get the content of the data struct and not a copy to it)
224  * If it's not present in the current block, look in the upper ones.
225  * If it's not present in any of them, look in the globals
226  * If not present there neither, the code may segfault (Oli?).
227  */
228 void *
229 gras_cbps_v_get (gras_cbps_t           ps, 
230                  const char           *name,
231                  /* OUT */gras_datadesc_type_t *ddt) {
232   
233   xbt_dynar_t    dynar = NULL;
234   gras_cbps_elm_t elm   = NULL;
235   
236   DEBUG1("get(%s)",name);
237   dynar = xbt_dict_get(ps->space, name);
238   xbt_dynar_pop(dynar, &elm);
239   xbt_dynar_push(dynar, &elm);
240   
241   if (ddt) {
242     *ddt = elm->type;
243   }
244   
245   return elm->data;
246
247 }
248
249 /** \brief Begins a new block. 
250  *
251  * Blocks are usefull to remove a whole set of declarations you don't even know
252  *
253  * E.g., they constitute an elegent solution to recursive data structures. 
254  *
255  * push/pop may be used in some cases for that, but if your recursive data 
256  * struct contains other structs needing themselves callbacks, you have to
257  * use block_{begin,end} to do the trick.
258  */
259
260 void
261 gras_cbps_block_begin(gras_cbps_t ps) {
262
263   xbt_dynar_t dynar = NULL;
264
265   DEBUG0(">>> Block begin");
266   dynar = xbt_dynar_new(sizeof (char *), NULL);
267   xbt_dynar_push(ps->frames, &dynar);
268 }
269
270 /** \brief End the current block, and go back to the upper one. */
271 void
272 gras_cbps_block_end(gras_cbps_t ps) {
273
274   xbt_dynar_t  frame        = NULL;
275   int           cursor       =    0;
276   char         *name         = NULL;
277
278   xbt_assert0(xbt_dynar_length(ps->frames),
279                "More block_end than block_begin");
280   xbt_dynar_pop(ps->frames, &frame);
281   
282   xbt_dynar_foreach(frame, cursor, name) {
283
284     xbt_dynar_t    varstack    = NULL;
285     gras_cbps_elm_t var         = NULL;
286  
287     DEBUG2("Get ride of %s (%p)",name,(void*)name);
288     varstack = xbt_dict_get(ps->space, name);
289     xbt_dynar_pop(varstack, &var);
290  
291     if (!xbt_dynar_length(varstack)) {
292       xbt_dict_remove(ps->space, name);
293       xbt_dynar_free_container(&varstack); /*already empty, save a test ;) */
294     }
295     
296     if (var->data) free(var->data);
297     free(var);
298     free(name);
299   }
300   xbt_dynar_free_container(&frame);/* we just emptied it */
301   DEBUG0("<<< Block end");
302 }
303
304
305 /** \brief Push a new integer value into the cbps. */
306 void
307 gras_cbps_i_push(gras_cbps_t ps,
308                  int val) {
309   DEBUG1("push %d as a size",val);
310   xbt_dynar_push_as(ps->lints,int,val);
311 }
312 /** \brief Pop the lastly pushed integer value from the cbps. */
313 int
314 gras_cbps_i_pop(gras_cbps_t ps) {
315   int ret;
316
317   xbt_assert0(xbt_dynar_length(ps->lints) > 0,
318                "gras_cbps_i_pop: no value to pop");
319   ret = xbt_dynar_pop_as(ps->lints,int);
320   DEBUG1("pop %d as a size",ret);
321   return ret;
322 }
323
324 /** \brief Generic cb returning the lastly pushed value
325  * 
326  * Used by \ref gras_datadesc_ref_pop_arr
327  */
328 int gras_datadesc_cb_pop(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
329   return gras_cbps_i_pop(vars);
330 }
331
332 /** \brief Cb to push an integer. Must be attached to the field you want to push */
333 void gras_datadesc_cb_push_int(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
334    int *i = (int*)data;
335    gras_cbps_i_push(vars, (int) *i);
336 }
337
338 /** \brief Cb to push an unsigned integer. Must be attached to the field you want to push */
339 void gras_datadesc_cb_push_uint(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
340    unsigned int *i = (unsigned int*)data;
341    gras_cbps_i_push(vars, (int) *i);
342 }
343
344 /** \brief Cb to push an long integer. Must be attached to the field you want to push
345  */
346 void gras_datadesc_cb_push_lint(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
347    long int *i = (long int*)data;
348    gras_cbps_i_push(vars, (int) *i);
349 }
350 /** \brief Cb to push an long integer. Must be attached to the field you want to push
351  */
352 void gras_datadesc_cb_push_ulint(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
353    unsigned long int *i = (unsigned long int*)data;
354    gras_cbps_i_push(vars, (int) *i);
355 }