Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Take the gras.h from the current dir, not the installed one
[simgrid.git] / src / gras / DataDesc / cbps.c
1 /* $Id$ */
2
3 /* cbps - persistant states for callbacks                                   */
4
5 /* Authors: Olivier Aumage, Martin Quinson                                  */
6 /* Copyright (C) 2003, 2004 da GRAS posse.                                  */
7
8 /* This program is free software; you can redistribute it and/or modify it
9    under the terms of the license (GNU LGPL) which comes with this package. */
10
11 #include "DataDesc/datadesc_private.h"
12 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(cbps,datadesc);
13
14 typedef struct {
15   gras_datadesc_type_t *type;
16   void                 *data;
17 } gras_dd_cbps_elm_t;
18
19 struct s_gras_dd_cbps {
20   gras_dict_t  *space; /* varname x dynar of gras_dd_cbps_elm_t */
21   gras_dynar_t *frames; /* of dynar of names defined within this frame
22                            (and to pop when we leave it) */
23   gras_dynar_t *globals;
24 };
25
26 static void free_string(void *d);
27
28 static void free_string(void *d){
29   free(*(void**)d);
30 }
31
32 gras_error_t
33 gras_dd_cbps_new(gras_dd_cbps_t **dst) {
34   gras_error_t errcode;
35   gras_dd_cbps_t *res;
36
37   if (!(res=malloc(sizeof(gras_dd_cbps_t))))
38     RAISE_MALLOC;
39
40   TRY(gras_dict_new(&(res->space)));
41   /* no leak, the content is freed manually on block_end */
42   TRY(gras_dynar_new(&(res->frames), sizeof(gras_dynar_t*), NULL));
43   TRY(gras_dynar_new(&(res->globals), sizeof(char*), NULL));
44
45   gras_dd_cbps_block_begin(res);
46   *dst = res;
47   return no_error;
48 }
49
50 void
51 gras_dd_cbps_free(gras_dd_cbps_t **state) {
52
53   gras_dd_cbps_block_end(*state);
54   gras_dict_free ( &( (*state)->space   ) );
55   gras_dynar_free(    (*state)->frames    );
56   gras_dynar_free(    (*state)->globals   );
57
58   free(*state);
59   *state = NULL;
60 }
61
62 /**
63  * gras_dd_cbps_push:
64  *
65  * Declare a new element in the PS, and give it a value. If an element of that
66  * name already exists, it is masked by the one given here, and will be 
67  * seeable again only after a pop to remove the value this push adds.
68  */
69 gras_error_t
70 gras_dd_cbps_push(gras_dd_cbps_t        *ps,
71                   const char            *name,
72                   void                  *data,
73                   gras_datadesc_type_t  *ddt) {
74
75   gras_dynar_t            *varstack,*frame;
76   gras_dd_cbps_elm_t      *p_var;
77   gras_error_t errcode;
78   char *varname = strdup(name);
79
80   DEBUG2("push(%s,%p)",name,data);
81   errcode = gras_dict_get(ps->space, name, (void **)&varstack);
82  
83   if (errcode == mismatch_error) {
84     DEBUG1("Create a new variable stack for '%s' into the space",name);
85     gras_dynar_new(&varstack, sizeof (gras_dd_cbps_elm_t *), NULL);
86     gras_dict_set(ps->space, varname, (void **)varstack, NULL);
87     /* leaking, you think? only if you do not close all the openned blocks ;)*/
88   } else if (errcode != no_error) {
89     return errcode;
90   }
91  
92   p_var       = calloc(1, sizeof(gras_dd_cbps_elm_t));
93   p_var->type = ddt;
94   p_var->data = data;
95   
96   gras_dynar_push(varstack, &p_var);
97   
98   gras_dynar_pop(ps->frames, &frame);
99   DEBUG4("Push %s (%p @%p) into frame %p",varname,varname,&varname,frame);
100   gras_dynar_push(frame, &varname);
101   gras_dynar_push(ps->frames, &frame); 
102   return no_error;
103 }
104
105 /**
106  * gras_dd_cbps_pop:
107  *
108  * Retrieve an element from the PS, and remove it from the PS. 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 gras_error_t
113 gras_dd_cbps_pop (gras_dd_cbps_t        *ps, 
114                   const char            *name,
115                   gras_datadesc_type_t **ddt,
116                   void                 **res) {
117   gras_dynar_t            *varstack,*frame;
118   gras_dd_cbps_elm_t      *var          = NULL;
119   void                    *data           = NULL;
120   gras_error_t errcode;
121
122   DEBUG1("pop(%s)",name);
123   /* FIXME: Error handling */
124   errcode = gras_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   gras_dynar_pop(varstack, &var);
130   
131   if (!gras_dynar_length(varstack)) {
132     DEBUG1("Last incarnation of %s poped. Kill it",name);
133     gras_dict_remove(ps->space, name);
134     gras_dynar_free(varstack);
135   }
136   
137   if (ddt)
138     *ddt = var->type;  
139   data    = var->data;
140   
141   free(var);
142   
143   gras_dynar_pop(ps->frames, &frame);
144   {
145     int l = gras_dynar_length(frame);
146     
147     while (l--) {
148       char *_name = NULL;
149                                                                                 
150       gras_dynar_get(frame, l, &_name);
151       if (!strcmp(name, _name)) {
152         gras_dynar_remove_at(frame, l, &_name);
153         free(_name);
154         break;
155       }
156     }
157   }
158   gras_dynar_push(ps->frames, &frame);
159   
160   *res = data;
161   return no_error;
162 }
163
164 /**
165  * gras_dd_cbps_set:
166  *
167  * Change the value of an element in the PS.  
168  * If it's not present in the current block, look in the upper ones.
169  * If it's not present in any of them, modify in the globals
170  * If not present there neither, the code may segfault (Oli?).
171  *
172  * Once a reference to an element of that name is found somewhere in the PS,
173  *   its value is changed.
174  */
175 void
176 gras_dd_cbps_set (gras_dd_cbps_t        *ps,
177                   const char            *name,
178                   void                  *data,
179                   gras_datadesc_type_t  *ddt) {
180
181   gras_dynar_t            *p_dynar        = NULL;
182   gras_dd_cbps_elm_t      *p_elm          = NULL;
183   gras_error_t errcode;
184   
185   DEBUG1("set(%s)",name);
186   errcode = gras_dict_get(ps->space, name, (void **)&p_dynar);
187   
188   if (errcode == mismatch_error) {
189     gras_dynar_new(&p_dynar, sizeof (gras_dd_cbps_elm_t *), NULL);
190     gras_dict_set(ps->space, name, (void **)p_dynar, NULL);
191     
192     p_elm   = calloc(1, sizeof(gras_dd_cbps_elm_t));
193     gras_dynar_push(ps->globals, &name);
194   } else {
195     gras_dynar_pop(p_dynar, &p_elm);
196   }
197   
198   p_elm->type   = ddt;
199   p_elm->data   = data;
200  
201   gras_dynar_push(p_dynar, &p_elm);
202
203 }
204
205 /**
206  * gras_dd_cbps_get:
207  *
208  * Get the value of an element in the PS without modifying it. 
209  * (note that you get the content of the data struct and not a copy to it)
210  * If it's not present in the current block, look in the upper ones.
211  * If it's not present in any of them, look in the globals
212  * If not present there neither, the code may segfault (Oli?).
213  */
214 void *
215 gras_dd_cbps_get (gras_dd_cbps_t        *ps, 
216                   const char            *name,
217                   gras_datadesc_type_t **ddt) {
218   
219   gras_dynar_t            *p_dynar        = NULL;
220   gras_dd_cbps_elm_t      *p_elm          = NULL;
221   
222   DEBUG1("get(%s)",name);
223   /* FIXME: Error handling */
224   gras_dict_get(ps->space, name, (void **)&p_dynar);
225   gras_dynar_pop(p_dynar, &p_elm);
226   gras_dynar_push(p_dynar, &p_elm);
227   
228   if (ddt) {
229     *ddt = p_elm->type;
230   }
231   
232   return p_elm->data;
233
234 }
235
236 /**
237  * gras_dd_cbps_block_begin:
238  *
239  * Begins a new block. 
240  *
241  * Blocks are usefull to remove a whole set of declarations you don't even know
242  *
243  * E.g., they constitute an elegent solution to recursive data structures. 
244  *
245  * push/pop may be used in some cases for that, but if your recursive data 
246  * struct contains other structs needing themselves callbacks, you have to
247  * use block_{begin,end} to do the trick.
248  */
249
250 void
251 gras_dd_cbps_block_begin(gras_dd_cbps_t *ps) {
252
253   gras_dynar_t            *p_dynar        = NULL;
254
255   DEBUG0(">>> Block begin");
256   gras_dynar_new(&p_dynar, sizeof (char *), NULL);
257   gras_dynar_push(ps->frames, &p_dynar);
258 }
259
260 /**
261  * gras_dd_cbps_block_begin:
262  *
263  * End the current block, and go back to the upper one.
264  */
265 void
266 gras_dd_cbps_block_end(gras_dd_cbps_t *ps) {
267
268   gras_dynar_t            *frame        = NULL;
269   int                      cursor         =    0;
270   char                    *name           = NULL;
271
272   gras_assert0(gras_dynar_length(ps->frames),
273                "More block_end than block_begin");
274   gras_dynar_pop(ps->frames, &frame);
275   
276   gras_dynar_foreach(frame, cursor, name) {
277
278     gras_dynar_t            *varstack    = NULL;
279     gras_dd_cbps_elm_t      *var         = NULL;
280  
281     DEBUG2("Get ride of %s (%p)",name,name);
282     gras_dict_get(ps->space, name, (void **)&varstack);
283     gras_dynar_pop(varstack, &var);
284  
285     if (!gras_dynar_length(varstack)) {
286       gras_dict_remove(ps->space, name);
287       gras_dynar_free_container(varstack); /*already empty, save a test ;) */
288     }
289     
290     if (var->data) free(var->data);
291     free(var);
292     free(name);
293   }
294   gras_dynar_free_container(frame);/* we just emptied it */
295   DEBUG0("<<< Block end");
296 }
297
298
299