Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
redo the instruction for the error case (please mail the results to...)
[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
13 typedef struct {
14   gras_datadesc_type_t *type;
15   void                 *data;
16 } gras_dd_cbps_elm_t;
17
18 struct s_gras_dd_cbps {
19   gras_dict_t  *space;
20   gras_dynar_t *stack;
21   gras_dynar_t *globals;
22 };
23
24 gras_error_t
25 gras_dd_cbps_new(gras_dd_cbps_t **dst) {
26   gras_error_t errcode;
27   gras_dd_cbps_t *res;
28
29   if (!(res=malloc(sizeof(gras_dd_cbps_t))))
30     RAISE_MALLOC;
31
32   TRY(gras_dict_new(&(res->space)));
33   /* FIXME:leaking on content of dynars*/
34   TRY(gras_dynar_new(&(res->stack), sizeof(gras_dynar_t*), NULL));
35   TRY(gras_dynar_new(&(res->globals), sizeof(char*), NULL));
36
37   *dst = res;
38   return no_error;
39 }
40
41 void
42 gras_dd_cbps_free(gras_dd_cbps_t **state) {
43
44   gras_dict_free ( &( (*state)->space   ) );
45   gras_dynar_free(    (*state)->stack     );
46   gras_dynar_free(    (*state)->globals   );
47
48   free(*state);
49   *state = NULL;
50 }
51
52 /**
53  * gras_dd_cbps_push:
54  *
55  * Declare a new element in the PS, and give it a value. If an element of that
56  * name already exists, it is masked by the one given here, and will be 
57  * seeable again only after a pop to remove the value this push adds.
58  */
59 void
60 gras_dd_cbps_push(gras_dd_cbps_t        *ps,
61                   const char            *name,
62                   void                  *data,
63                   gras_datadesc_type_t  *ddt) {
64
65   gras_dynar_t            *p_dynar        = NULL;
66   gras_dd_cbps_elm_t      *p_var          = NULL;
67  
68   gras_dict_retrieve(ps->space, name, (void **)&p_dynar);
69  
70   if (!p_dynar) {
71     gras_dynar_new(&p_dynar, sizeof (gras_dd_cbps_elm_t *), NULL);
72     gras_dict_insert(ps->space, name, (void **)p_dynar, NULL);
73     /* FIXME: leaking on dynar. Insert in dict with a way to free it */
74   }
75  
76   p_var       = calloc(1, sizeof(gras_dd_cbps_elm_t));
77   p_var->type = ddt;
78   p_var->data = data;
79   
80   gras_dynar_push(p_dynar, &p_var);
81   
82   gras_dynar_pop(ps->stack, &p_dynar);
83   gras_dynar_push(p_dynar, &name);
84   gras_dynar_push(ps->stack, &p_dynar); 
85 }
86
87 /**
88  * gras_dd_cbps_pop:
89  *
90  * Retrieve an element from the PS, and remove it from the PS. If it's not
91  * present in the current block, it will fail (with abort) and not search
92  * in upper blocks since this denotes a programmation error.
93  */
94 void *
95 gras_dd_cbps_pop (gras_dd_cbps_t        *ps, 
96                   const char            *name,
97                   gras_datadesc_type_t **ddt) {
98   gras_dynar_t            *p_dynar        = NULL;
99   gras_dd_cbps_elm_t      *p_elm          = NULL;
100   void                    *data           = NULL;
101
102   /* FIXME: Error handling */
103   gras_dict_retrieve(ps->space, name, (void **)&p_dynar);
104   gras_dynar_pop(p_dynar, &p_elm);
105   
106   if (!gras_dynar_length(p_dynar)) {
107     gras_dict_remove(ps->space, name);
108                 gras_dynar_free_container(p_dynar);
109   }
110   
111   if (ddt) {
112     *ddt = p_elm->type;
113   }
114   
115   data    = p_elm->data;
116   
117   free(p_elm);
118   
119   gras_dynar_pop(ps->stack, &p_dynar);
120   {
121     int l = gras_dynar_length(p_dynar);
122     
123     while (l--) {
124       char *_name = NULL;
125                                                                                 
126       gras_dynar_get(p_dynar, l, &_name);
127       if (!strcmp(name, _name)) {
128         gras_dynar_remove_at(p_dynar, l, &_name);
129         free(_name);
130         break;
131       }
132     }
133   }
134   gras_dynar_push(ps->stack, &p_dynar);
135   
136   
137   return data;
138 }
139
140 /**
141  * gras_dd_cbps_set:
142  *
143  * Change the value of an element in the PS.  
144  * If it's not present in the current block, look in the upper ones.
145  * If it's not present in any of them, look in the globals
146  *   (FIXME: which no function of this API allows to set). 
147  * If not present there neither, the code may segfault (Oli?).
148  *
149  * Once a reference to an element of that name is found somewhere in the PS,
150  *   its value is changed.
151  */
152 void
153 gras_dd_cbps_set (gras_dd_cbps_t        *ps,
154                   const char            *name,
155                   void                  *data,
156                   gras_datadesc_type_t  *ddt) {
157
158   gras_dynar_t            *p_dynar        = NULL;
159   gras_dd_cbps_elm_t      *p_elm          = NULL;
160   
161   gras_dict_retrieve(ps->space, name, (void **)&p_dynar);
162   
163   if (!p_dynar) {
164     gras_dynar_new(&p_dynar, sizeof (gras_dd_cbps_elm_t *), NULL);
165     gras_dict_insert(ps->space, name, (void **)p_dynar, NULL);
166     
167     p_elm   = calloc(1, sizeof(gras_dd_cbps_elm_t));
168     gras_dynar_push(ps->globals, &name);
169   } else {
170     gras_dynar_pop(p_dynar, &p_elm);
171   }
172   
173   p_elm->type   = ddt;
174   p_elm->data   = data;
175  
176   gras_dynar_push(p_dynar, &p_elm);
177
178 }
179
180 /**
181  * gras_dd_cbps_get:
182  *
183  * Get the value of an element in the PS without modifying it. 
184  * (note that you get the content of the data struct and not a copy to it)
185  * If it's not present in the current block, look in the upper ones.
186  * If it's not present in any of them, look in the globals
187  *   (FIXME: which no function of this API allows to set). 
188  * If not present there neither, the code may segfault (Oli?).
189  */
190 void *
191 gras_dd_cbps_get (gras_dd_cbps_t        *ps, 
192                   const char            *name,
193                   gras_datadesc_type_t **ddt) {
194   
195   gras_dynar_t            *p_dynar        = NULL;
196   gras_dd_cbps_elm_t      *p_elm          = NULL;
197   
198   /* FIXME: Error handling */
199   gras_dict_retrieve(ps->space, name, (void **)&p_dynar);
200   gras_dynar_pop(p_dynar, &p_elm);
201   gras_dynar_push(p_dynar, &p_elm);
202   
203   if (ddt) {
204     *ddt = p_elm->type;
205   }
206   
207   return p_elm->data;
208
209 }
210
211 /**
212  * gras_dd_cbps_block_begin:
213  *
214  * Begins a new block. 
215  *
216  * Blocks are usefull to remove a whole set of declarations you don't even know
217  *
218  * E.g., they constitute an elegent solution to recursive data structures. 
219  *
220  * push/pop may be used in some cases for that, but if your recursive data 
221  * struct contains other structs needing themselves callbacks, you have to
222  * use block_{begin,end} to do the trick.
223  */
224
225 void
226 gras_dd_cbps_block_begin(gras_dd_cbps_t *ps) {
227
228   gras_dynar_t            *p_dynar        = NULL;
229   
230   gras_dynar_new(&p_dynar, sizeof (char *), NULL);
231   gras_dynar_push(ps->stack, &p_dynar);
232 }
233
234 /**
235  * gras_dd_cbps_block_begin:
236  *
237  * End the current block, and go back to the upper one.
238  */
239 void
240 gras_dd_cbps_block_end(gras_dd_cbps_t *ps) {
241
242   gras_dynar_t            *p_dynar        = NULL;
243   int                      cursor         =    0;
244   char                    *name           = NULL;
245   
246   gras_dynar_pop(ps->stack, &p_dynar);
247   
248   gras_dynar_foreach(p_dynar, cursor, name) {
249
250     gras_dynar_t            *p_dynar_elm    = NULL;
251     gras_dd_cbps_elm_t      *p_elm          = NULL;
252  
253     gras_dict_retrieve(ps->space, name, (void **)&p_dynar_elm);
254     gras_dynar_pop(p_dynar_elm, &p_elm);
255  
256     if (!gras_dynar_length(p_dynar_elm)) {
257       gras_dict_remove(ps->space, name);
258       gras_dynar_free_container(p_dynar_elm);
259     }
260     
261     free(p_elm);
262     free(name);
263   }
264   
265   gras_dynar_free_container(p_dynar);
266 }
267
268
269