Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Interface revolution: do not try to survive to malloc failure
[simgrid.git] / src / xbt / dict_cursor.c
1 /* $Id$ */
2
3 /* dict_cursor - iterators over dictionnaries                               */
4
5 /* Authors: Martin Quinson                                                  */
6 /* Copyright (C) 2003,2004 Martin Quinson.                                  */
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 "gras_private.h"
12 #include "dict_private.h"
13
14 #include <string.h> /* strlen() */
15
16 GRAS_LOG_EXTERNAL_CATEGORY(dict);
17 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(dict_cursor,dict,"To traverse dictionaries");
18
19
20 /*####[ Dict cursor functions ]#############################################*/
21 /* To traverse (simple) dicts                                               */
22 /* Don't add or remove entries to the dict while traversing !!!             */
23 /*###########################################################################*/
24 struct gras_dict_cursor_ {
25   /* we store all level encountered until here, to backtrack on next() */
26   gras_dynar_t *keys;
27   gras_dynar_t *key_lens;
28   int           pos;
29   int           pos_len;
30   gras_dictelm_t  *head;
31 };
32
33 static _GRAS_INLINE void
34 _cursor_push_keys(gras_dict_cursor_t *p_cursor,
35                   gras_dictelm_t        *p_elm);
36
37 #undef gras_dict_CURSOR_DEBUG
38 /*#define gras_dict_CURSOR_DEBUG 1*/
39
40 /**
41  * gras_dict_cursor_new:
42  *
43  * @head: the head of the dict
44  * @cursor: the curent position in the dict
45  *
46  * Structure creator
47  */
48 void
49 gras_dict_cursor_new(const gras_dict_t          *p_head,
50                      /*OUT*/gras_dict_cursor_t **pp_cursor) {
51   gras_error_t        errcode  = no_error;
52   gras_dict_cursor_t *p_cursor = NULL;
53
54   p_cursor = gras_new(gras_dict_cursor_t,1);
55
56   gras_dynar_new(&p_cursor->keys,     sizeof(char **), NULL);
57   gras_dynar_new(&p_cursor->key_lens, sizeof(int  *),  NULL);
58
59   p_cursor->pos     = 0;
60   p_cursor->pos_len = 0;
61   p_cursor->head    = p_head ? p_head->head : NULL;
62
63   gras_dict_cursor_rewind(p_cursor);
64
65   *pp_cursor = p_cursor;
66
67 }
68
69 /**
70  * gras_dict_cursor_free:
71  *
72  * @cursor: poor victim
73  *
74  * Structure destructor
75  */
76 void
77 gras_dict_cursor_free(gras_dict_cursor_t *p_cursor) {
78   if (p_cursor) {
79     gras_dynar_free(p_cursor->keys);
80     gras_dynar_free(p_cursor->key_lens);
81     memset(p_cursor, 0, sizeof(gras_dict_cursor_t));
82     gras_free(p_cursor);
83   }
84 }
85
86 /**
87  * __cursor_not_null:
88  *
89  * Sanity check to see if the head contains something
90  */
91 static _GRAS_INLINE
92 gras_error_t
93 __cursor_not_null(gras_dict_cursor_t *p_cursor) {
94
95   gras_assert0(p_cursor, "Null cursor");
96
97   if (!p_cursor->head) {
98     return mismatch_error;
99   }
100
101   return no_error;
102 }
103
104
105 static _GRAS_INLINE
106 void
107 _cursor_push_keys(gras_dict_cursor_t *p_cursor,
108                   gras_dictelm_t        *p_elm) {
109   gras_error_t         errcode = no_error;
110   gras_dictelm_t      *p_child = NULL;
111   int                  i       = 0;
112   static volatile int  count   = 0; /* ??? */
113
114   CDEBUG1(dict_cursor, "Push childs of %p in the cursor", (void*)p_elm);
115
116   if (p_elm->content) {
117     gras_dynar_push(p_cursor->keys,     &p_elm->key    );
118     gras_dynar_push(p_cursor->key_lens, &p_elm->key_len);
119     count++;
120   }
121
122   gras_dynar_foreach(p_elm->sub, i, p_child) {
123     if (p_child)
124       _cursor_push_keys(p_cursor, p_child);
125   }
126
127   CDEBUG1(dict_cursor, "Count = %d", count);
128 }
129
130 /**
131  * gras_dict_cursor_rewind:
132  * @cursor: the cursor
133  * @Returns: gras_error_t
134  *
135  * back to the first element
136  */
137 void
138 gras_dict_cursor_rewind(gras_dict_cursor_t *p_cursor) {
139   gras_error_t errcode = no_error;
140
141   CDEBUG0(dict_cursor, "gras_dict_cursor_rewind");
142   gras_assert(p_cursor);
143
144   gras_dynar_reset(p_cursor->keys);
145   gras_dynar_reset(p_cursor->key_lens);
146
147   if (!p_cursor->head)
148     return ;
149
150   _cursor_push_keys(p_cursor, p_cursor->head);
151
152   gras_dynar_cursor_first(p_cursor->keys,     &p_cursor->pos    );
153   gras_dynar_cursor_first(p_cursor->key_lens, &p_cursor->pos_len);
154
155 }
156
157 /**
158  * gras_dict_cursor_first:
159  * @dict: on what to let the cursor iterate
160  * @cursor: dest address
161  *
162  * Create the cursor if it does not exists. Rewind it in any case.
163  */
164 void         gras_dict_cursor_first    (const gras_dict_t   *dict,
165                                         gras_dict_cursor_t **cursor){
166
167   if (!*cursor) {
168     DEBUG0("Create the cursor on first use");
169     gras_dict_cursor_new(dict,cursor);
170   }
171
172   gras_dict_cursor_rewind(*cursor);
173 }
174
175
176 /**
177  * gras_dict_cursor_step:
178  * @cursor: the cursor
179  *
180  * Move to the next element. 
181  */
182 void
183 gras_dict_cursor_step(gras_dict_cursor_t *p_cursor) {
184   gras_assert(p_cursor);
185
186   gras_dynar_cursor_step(p_cursor->keys,     &p_cursor->pos);
187   gras_dynar_cursor_step(p_cursor->key_lens, &p_cursor->pos_len);
188 }
189
190 /**
191  * gras_dict_cursor_get_or_free:
192  * @cursor: the cursor
193  * @Returns: true if it's ok, false if there is no more data
194  *
195  * Get current data
196  */
197 int
198 gras_dict_cursor_get_or_free(gras_dict_cursor_t **cursor,
199                              char               **key,
200                              void               **data) {
201   gras_error_t  errcode = no_error;
202   int           key_len = 0;
203   
204   if (!cursor || !(*cursor))
205     return FALSE;
206
207   if (gras_dynar_length((*cursor)->keys) <= (*cursor)->pos) {
208     gras_dict_cursor_free(*cursor);
209     *cursor=NULL;
210     return FALSE;
211   }
212     
213   gras_dynar_get((*cursor)->keys,     (*cursor)->pos,     key    );
214   gras_dynar_get((*cursor)->key_lens, (*cursor)->pos_len, &key_len);
215
216   errcode = gras_dictelm_get_ext((*cursor)->head, *key, key_len, data);
217   if (errcode == mismatch_error) {
218     gras_dict_cursor_free(*cursor);
219     *cursor=NULL;
220     return FALSE;
221   }
222
223   gras_assert1(errcode == no_error,
224                "Unexpected problem while retrieving the content of cursor. Got %s",
225                gras_error_name(errcode));
226
227   return TRUE;
228 }
229
230 /**
231  * gras_dict_cursor_get_key:
232  * @cursor: the cursor
233  * @key: the current element
234  * @Returns: gras_error_t
235  *
236  * Get current key
237  */
238 gras_error_t
239 gras_dict_cursor_get_key(gras_dict_cursor_t  *p_cursor,
240                          /*OUT*/char        **key) {
241   gras_error_t errcode = no_error;
242
243   TRY(__cursor_not_null(p_cursor));
244
245   gras_dynar_get(p_cursor->keys, p_cursor->pos - 1, key);
246
247   return errcode;
248 }
249
250 /**
251  * gras_dict_cursor_get_data:
252  * @cursor: the cursor
253  *
254  * Get current data
255  */
256 gras_error_t
257 gras_dict_cursor_get_data(gras_dict_cursor_t  *p_cursor,
258                           /*OUT*/void        **data) {
259   gras_error_t  errcode = no_error;
260   char         *key     = NULL;
261   int           key_len = 0;
262
263   TRY(__cursor_not_null(p_cursor));
264
265   gras_dynar_get(p_cursor->keys,     p_cursor->pos-1,     &key    );
266   gras_dynar_get(p_cursor->key_lens, p_cursor->pos_len-1, &key_len);
267
268   TRY(gras_dictelm_get_ext(p_cursor->head, key, key_len, data));
269
270   return errcode;
271 }
272
273