Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Current state. See changelog, sorry, I'm out of time
[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 "xbt/misc.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 gras_dict_cursor_t *
49 gras_dict_cursor_new(const gras_dict_t          *p_head) {
50   gras_error_t        errcode  = no_error;
51   gras_dict_cursor_t *res = NULL;
52
53   res = gras_new(gras_dict_cursor_t,1);
54   res->keys     = gras_dynar_new(sizeof(char **), NULL);
55   res->key_lens = gras_dynar_new(sizeof(int  *),  NULL);
56   res->pos      = 0;
57   res->pos_len  = 0;
58   res->head     = p_head ? p_head->head : NULL;
59
60   gras_dict_cursor_rewind(res);
61
62   return res;
63 }
64
65 /**
66  * gras_dict_cursor_free:
67  *
68  * @cursor: poor victim
69  *
70  * Structure destructor
71  */
72 void
73 gras_dict_cursor_free(gras_dict_cursor_t *p_cursor) {
74   if (p_cursor) {
75     gras_dynar_free(p_cursor->keys);
76     gras_dynar_free(p_cursor->key_lens);
77     memset(p_cursor, 0, sizeof(gras_dict_cursor_t));
78     gras_free(p_cursor);
79   }
80 }
81
82 /**
83  * __cursor_not_null:
84  *
85  * Sanity check to see if the head contains something
86  */
87 static _GRAS_INLINE
88 gras_error_t
89 __cursor_not_null(gras_dict_cursor_t *p_cursor) {
90
91   gras_assert0(p_cursor, "Null cursor");
92
93   if (!p_cursor->head) {
94     return mismatch_error;
95   }
96
97   return no_error;
98 }
99
100
101 static _GRAS_INLINE
102 void
103 _cursor_push_keys(gras_dict_cursor_t *p_cursor,
104                   gras_dictelm_t        *p_elm) {
105   gras_error_t         errcode = no_error;
106   gras_dictelm_t      *p_child = NULL;
107   int                  i       = 0;
108   static volatile int  count   = 0; /* ??? */
109
110   CDEBUG1(dict_cursor, "Push childs of %p in the cursor", (void*)p_elm);
111
112   if (p_elm->content) {
113     gras_dynar_push(p_cursor->keys,     &p_elm->key    );
114     gras_dynar_push(p_cursor->key_lens, &p_elm->key_len);
115     count++;
116   }
117
118   gras_dynar_foreach(p_elm->sub, i, p_child) {
119     if (p_child)
120       _cursor_push_keys(p_cursor, p_child);
121   }
122
123   CDEBUG1(dict_cursor, "Count = %d", count);
124 }
125
126 /**
127  * gras_dict_cursor_rewind:
128  * @cursor: the cursor
129  * @Returns: gras_error_t
130  *
131  * back to the first element
132  */
133 void
134 gras_dict_cursor_rewind(gras_dict_cursor_t *p_cursor) {
135   gras_error_t errcode = no_error;
136
137   CDEBUG0(dict_cursor, "gras_dict_cursor_rewind");
138   gras_assert(p_cursor);
139
140   gras_dynar_reset(p_cursor->keys);
141   gras_dynar_reset(p_cursor->key_lens);
142
143   if (!p_cursor->head)
144     return ;
145
146   _cursor_push_keys(p_cursor, p_cursor->head);
147
148   gras_dynar_cursor_first(p_cursor->keys,     &p_cursor->pos    );
149   gras_dynar_cursor_first(p_cursor->key_lens, &p_cursor->pos_len);
150
151 }
152
153 /**
154  * gras_dict_cursor_first:
155  * @dict: on what to let the cursor iterate
156  * @cursor: dest address
157  *
158  * Create the cursor if it does not exists. Rewind it in any case.
159  */
160 void gras_dict_cursor_first (const gras_dict_t   *dict,
161                              gras_dict_cursor_t **cursor){
162
163   if (!*cursor) {
164     DEBUG0("Create the cursor on first use");
165     *cursor=gras_dict_cursor_new(dict);
166   }
167
168   gras_dict_cursor_rewind(*cursor);
169 }
170
171
172 /**
173  * gras_dict_cursor_step:
174  * @cursor: the cursor
175  *
176  * Move to the next element. 
177  */
178 void
179 gras_dict_cursor_step(gras_dict_cursor_t *p_cursor) {
180   gras_assert(p_cursor);
181
182   gras_dynar_cursor_step(p_cursor->keys,     &p_cursor->pos);
183   gras_dynar_cursor_step(p_cursor->key_lens, &p_cursor->pos_len);
184 }
185
186 /**
187  * gras_dict_cursor_get_or_free:
188  * @cursor: the cursor
189  * @Returns: true if it's ok, false if there is no more data
190  *
191  * Get current data
192  */
193 int
194 gras_dict_cursor_get_or_free(gras_dict_cursor_t **cursor,
195                              char               **key,
196                              void               **data) {
197   gras_error_t  errcode = no_error;
198   int           key_len = 0;
199   
200   if (!cursor || !(*cursor))
201     return FALSE;
202
203   if (gras_dynar_length((*cursor)->keys) <= (*cursor)->pos) {
204     gras_dict_cursor_free(*cursor);
205     *cursor=NULL;
206     return FALSE;
207   }
208     
209   gras_dynar_get((*cursor)->keys,     (*cursor)->pos,     key    );
210   gras_dynar_get((*cursor)->key_lens, (*cursor)->pos_len, &key_len);
211
212   errcode = gras_dictelm_get_ext((*cursor)->head, *key, key_len, data);
213   if (errcode == mismatch_error) {
214     gras_dict_cursor_free(*cursor);
215     *cursor=NULL;
216     return FALSE;
217   }
218
219   gras_assert1(errcode == no_error,
220                "Unexpected problem while retrieving the content of cursor. Got %s",
221                gras_error_name(errcode));
222
223   return TRUE;
224 }
225
226 /**
227  * gras_dict_cursor_get_key:
228  * @cursor: the cursor
229  * @key: the current element
230  * @Returns: gras_error_t
231  *
232  * Get current key
233  */
234 gras_error_t
235 gras_dict_cursor_get_key(gras_dict_cursor_t  *p_cursor,
236                          /*OUT*/char        **key) {
237   gras_error_t errcode = no_error;
238
239   TRY(__cursor_not_null(p_cursor));
240
241   gras_dynar_get(p_cursor->keys, p_cursor->pos - 1, key);
242
243   return errcode;
244 }
245
246 /**
247  * gras_dict_cursor_get_data:
248  * @cursor: the cursor
249  *
250  * Get current data
251  */
252 gras_error_t
253 gras_dict_cursor_get_data(gras_dict_cursor_t  *p_cursor,
254                           /*OUT*/void        **data) {
255   gras_error_t  errcode = no_error;
256   char         *key     = NULL;
257   int           key_len = 0;
258
259   TRY(__cursor_not_null(p_cursor));
260
261   gras_dynar_get(p_cursor->keys,     p_cursor->pos-1,     &key    );
262   gras_dynar_get(p_cursor->key_lens, p_cursor->pos_len-1, &key_len);
263
264   TRY(gras_dictelm_get_ext(p_cursor->head, key, key_len, data));
265
266   return errcode;
267 }
268
269