Logo AND Algorithmique Numérique Distribuée

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