Logo AND Algorithmique Numérique Distribuée

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