Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add the possibility to remove an item in the middle of the list.
[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 XBT_LOG_EXTERNAL_CATEGORY(dict);
17 XBT_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 xbt_dict_cursor_ {
25   /* we store all level encountered until here, to backtrack on next() */
26   xbt_dynar_t   keys;
27   xbt_dynar_t   key_lens;
28   int            pos;
29   int            pos_len;
30   xbt_dictelm_t head;
31 };
32
33 static _XBT_INLINE void
34 _cursor_push_keys(xbt_dict_cursor_t p_cursor,
35                   xbt_dictelm_t     p_elm);
36
37 #undef xbt_dict_CURSOR_DEBUG
38 /*#define xbt_dict_CURSOR_DEBUG 1*/
39
40 /**
41  * xbt_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 xbt_dict_cursor_t 
49 xbt_dict_cursor_new(const xbt_dict_t head) {
50   xbt_error_t        errcode  = no_error;
51   xbt_dict_cursor_t res = NULL;
52
53   res = xbt_new(s_xbt_dict_cursor_t,1);
54   res->keys     = xbt_dynar_new(sizeof(char **), NULL);
55   res->key_lens = xbt_dynar_new(sizeof(int  *),  NULL);
56   res->pos      = 0;
57   res->pos_len  = 0;
58   res->head     = head ? head->head : NULL;
59
60   xbt_dict_cursor_rewind(res);
61
62   return res;
63 }
64
65 /**
66  * xbt_dict_cursor_free:
67  *
68  * @cursor: poor victim
69  *
70  * Structure destructor
71  */
72 void
73 xbt_dict_cursor_free(xbt_dict_cursor_t *cursor) {
74   if (*cursor) {
75     xbt_dynar_free(&((*cursor)->keys));
76     xbt_dynar_free(&((*cursor)->key_lens));
77     xbt_free(*cursor);
78     *cursor = NULL;
79   }
80 }
81
82 /**
83  * __cursor_not_null:
84  *
85  * Sanity check to see if the head contains something
86  */
87 static _XBT_INLINE
88 xbt_error_t
89 __cursor_not_null(xbt_dict_cursor_t cursor) {
90
91   xbt_assert0(cursor, "Null cursor");
92
93   if (!cursor->head) {
94     return mismatch_error;
95   }
96
97   return no_error;
98 }
99
100
101 static _XBT_INLINE
102 void
103 _cursor_push_keys(xbt_dict_cursor_t cursor,
104                   xbt_dictelm_t     elm) {
105   xbt_error_t         errcode = no_error;
106   xbt_dictelm_t       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*)elm);
111
112   if (elm->content) {
113     xbt_dynar_push(cursor->keys,     &elm->key    );
114     xbt_dynar_push(cursor->key_lens, &elm->key_len);
115     count++;
116   }
117
118   xbt_dynar_foreach(elm->sub, i, child) {
119     if (child)
120       _cursor_push_keys(cursor, child);
121   }
122
123   CDEBUG1(dict_cursor, "Count = %d", count);
124 }
125
126 /**
127  * xbt_dict_cursor_rewind:
128  * @cursor: the cursor
129  * @Returns: xbt_error_t
130  *
131  * back to the first element
132  */
133 void
134 xbt_dict_cursor_rewind(xbt_dict_cursor_t cursor) {
135   xbt_error_t errcode = no_error;
136
137   CDEBUG0(dict_cursor, "xbt_dict_cursor_rewind");
138   xbt_assert(cursor);
139
140   xbt_dynar_reset(cursor->keys);
141   xbt_dynar_reset(cursor->key_lens);
142
143   if (!cursor->head)
144     return ;
145
146   _cursor_push_keys(cursor, cursor->head);
147
148   xbt_dynar_cursor_first(cursor->keys,     &cursor->pos    );
149   xbt_dynar_cursor_first(cursor->key_lens, &cursor->pos_len);
150
151 }
152
153 /**
154  * xbt_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 xbt_dict_cursor_first (const xbt_dict_t   dict,
161                              xbt_dict_cursor_t *cursor){
162
163   if (!*cursor) {
164     DEBUG0("Create the cursor on first use");
165     *cursor=xbt_dict_cursor_new(dict);
166   }
167
168   xbt_dict_cursor_rewind(*cursor);
169 }
170
171
172 /**
173  * xbt_dict_cursor_step:
174  * @cursor: the cursor
175  *
176  * Move to the next element. 
177  */
178 void
179 xbt_dict_cursor_step(xbt_dict_cursor_t cursor) {
180   xbt_assert(cursor);
181
182   xbt_dynar_cursor_step(cursor->keys,     &cursor->pos);
183   xbt_dynar_cursor_step(cursor->key_lens, &cursor->pos_len);
184 }
185
186 /**
187  * xbt_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 xbt_dict_cursor_get_or_free(xbt_dict_cursor_t  *cursor,
195                              char               **key,
196                              void               **data) {
197   xbt_error_t  errcode = no_error;
198   int           key_len = 0;
199   
200   if (!cursor || !(*cursor))
201     return FALSE;
202
203   if (xbt_dynar_length((*cursor)->keys) <= (*cursor)->pos) {
204     xbt_dict_cursor_free(cursor);
205     return FALSE;
206   }
207     
208   *key    = xbt_dynar_get_as((*cursor)->keys,     (*cursor)->pos,     char*);
209   key_len = xbt_dynar_get_as((*cursor)->key_lens, (*cursor)->pos_len, int);
210
211   errcode = xbt_dictelm_get_ext((*cursor)->head, *key, key_len, data);
212   if (errcode == mismatch_error) {
213     xbt_dict_cursor_free(cursor);
214     return FALSE;
215   }
216
217   xbt_assert1(errcode == no_error,
218                "Unexpected problem while retrieving the content of cursor. Got %s",
219                xbt_error_name(errcode));
220
221   return TRUE;
222 }
223
224 /**
225  * xbt_dict_cursor_get_key:
226  * @cursor: the cursor
227  * @key: the current element
228  * @Returns: xbt_error_t
229  *
230  * Get current key
231  */
232 xbt_error_t
233 xbt_dict_cursor_get_key(xbt_dict_cursor_t   cursor,
234                          /*OUT*/char        **key) {
235   xbt_error_t errcode = no_error;
236
237   TRY(__cursor_not_null(cursor));
238
239   *key = xbt_dynar_get_as(cursor->keys, cursor->pos - 1, char*);
240
241   return errcode;
242 }
243
244 /**
245  * xbt_dict_cursor_get_data:
246  * @cursor: the cursor
247  *
248  * Get current data
249  */
250 xbt_error_t
251 xbt_dict_cursor_get_data(xbt_dict_cursor_t   cursor,
252                           /*OUT*/void        **data) {
253   xbt_error_t  errcode = no_error;
254   char         *key     = NULL;
255   int           key_len = 0;
256
257   TRY(__cursor_not_null(cursor));
258
259   key     = xbt_dynar_get_as(cursor->keys,     cursor->pos-1,  char *);
260   key_len = xbt_dynar_get_as(cursor->key_lens, cursor->pos_len-1, int);
261
262   TRY(xbt_dictelm_get_ext(cursor->head, key, key_len, data));
263
264   return errcode;
265 }
266
267