Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Current state. See changelog, sorry, I'm out of time
[simgrid.git] / src / xbt / set.c
1 /* $Id$ */
2
3 /* set - data container consisting in dict+dynar                            */
4
5 /* Authors: Martin Quinson                                                  */
6 /* Copyright (C) 2004 the 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 "xbt/misc.h"
12 #include "xbt/sysdep.h"
13 #include "xbt/log.h"
14 #include "xbt/error.h"
15 #include "xbt/dynar.h"
16 #include "xbt/dict.h"
17
18 #include "xbt/set.h"
19
20 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(set,xbt,"data container consisting in dict+dynar");
21
22 /*####[ Type definition ]####################################################*/
23 struct gras_set_ {
24   gras_dict_t  *dict;  /* data stored by name */
25   gras_dynar_t *dynar; /* data stored by ID   */
26 };
27
28 /*####[ Memory  ]############################################################*/
29 /**
30  * gras_set_new:
31  * @dst: where to
32  *
33  * Creates a new set.
34  */
35 gras_set_t *gras_set_new (void) {
36   gras_set_t *res=gras_new(gras_set_t,1);
37   gras_error_t errcode;
38
39   res->dict=gras_dict_new ();
40   res->dynar=gras_dynar_new(sizeof(void*),NULL);
41
42   return res;
43 }
44
45 /**
46  * gras_set_free:
47  * @set:
48  *
49  * Frees a set.
50  */
51 void         gras_set_free(gras_set_t **set) {
52   if (*set) {
53     gras_dict_free ( &( (*set)->dict  ) );
54     gras_dynar_free(    (*set)->dynar  );
55     gras_free(*set);
56     *set=NULL;
57   }
58 }
59
60 /**
61  * gras_set_add:
62  * @set: set to populate
63  * @elm: element to add. 
64  * @free_ctn: How to add the data 
65  *
66  * Add an element to a set. 
67  *
68  * elm->name must be set;
69  * elm->name_len is used as is unless it's <= 0 (in which case it's recomputed);
70  * elm->ID is attributed automatically.
71  */
72 void gras_set_add    (gras_set_t     *set,
73                       gras_set_elm_t *elm,
74                       void_f_pvoid_t *free_func) {
75
76   gras_error_t    errcode;
77   gras_set_elm_t *found_in_dict;
78
79   if (elm->name_len <= 0) {
80     elm->name_len = strlen(elm->name);
81   }
82
83   errcode = gras_dict_get_ext (set->dict, 
84                                     elm->name, elm->name_len,
85                                     (void**)&found_in_dict);
86   if (errcode == no_error) {
87     if (elm == found_in_dict) {
88       DEBUG2("Ignoring request to insert the same element twice (key %s ; id %d)",
89              elm->name, elm->ID);
90       return;
91     } else {
92       elm->ID=found_in_dict->ID;
93       DEBUG2("Reinsertion of key %s (id %d)", elm->name, elm->ID);
94       gras_dict_set_ext(set->dict, elm->name, elm->name_len, elm, free_func);
95       gras_dynar_set(set->dynar, elm->ID, &elm);
96       return;
97     }
98   } else {
99     gras_assert_error(mismatch_error);
100   }
101
102   elm->ID = gras_dynar_length( set->dynar );
103   gras_dict_set_ext(set->dict, elm->name, elm->name_len, elm, free_func);
104   gras_dynar_set(set->dynar, elm->ID, &elm);
105   DEBUG2("Insertion of key '%s' (id %d)", elm->name, elm->ID);
106
107 }
108
109 /**
110  * gras_set_get_by_name:
111  * @set:
112  * @name: Name of the searched cell
113  * @dst: where to put the found data into
114  *
115  * get a data stored in the cell by providing its name.
116  */
117 gras_error_t gras_set_get_by_name    (gras_set_t     *set,
118                                       const char     *name,
119                                       /* OUT */gras_set_elm_t **dst) {
120   gras_error_t errcode;
121   errcode = gras_dict_get_ext(set->dict, name, strlen(name), (void**) dst);
122   DEBUG2("Lookup key %s: %s",name,gras_error_name(errcode));
123   return errcode;
124 }
125 /**
126  * gras_set_get_by_name_ext:
127  * @set:
128  * @name: Name of the searched cell
129  * @name_len: length of the name, when strlen cannot be trusted
130  * @dst: where to put the found data into
131  *
132  * get a data stored in the cell by providing its name (and the length
133  * of the name, when strlen cannot be trusted because you don't use a char*
134  * as name, you weird guy).
135  */
136 gras_error_t gras_set_get_by_name_ext(gras_set_t     *set,
137                                       const char     *name,
138                                       int             name_len,
139                                       /* OUT */gras_set_elm_t **dst) {
140
141   return gras_dict_get_ext (set->dict, name, name_len, (void**)dst);
142 }
143
144 /**
145  * gras_set_get_by_code:
146  * @set:
147  * @id: what you're looking for
148  * @dst: where to put the found data into
149  *
150  * get a data stored in the cell by providing its id. 
151  * @warning, if the ID does not exists, you're getting into trouble
152  */
153 gras_error_t gras_set_get_by_id      (gras_set_t     *set,
154                                       int             id,
155                                       /* OUT */gras_set_elm_t **dst) {
156
157   /* Don't bother checking the bounds, the dynar does so */
158
159   gras_dynar_get(set->dynar,id,dst);
160   DEBUG3("Lookup type of id %d (of %lu): %s", 
161          id, gras_dynar_length(set->dynar), (*dst)->name);
162   
163   return no_error;
164 }
165
166 /***
167  *** Cursors
168  ***/
169 struct gras_set_cursor_ {
170   gras_set_t *set;
171   int val;
172 };
173
174 /**
175  * gras_set_cursor_first:
176  * @set: on what to let the cursor iterate
177  * @cursor: dest address
178  *
179  * Create the cursor if it does not exists. Rewind it in any case.
180  */
181 void         gras_set_cursor_first       (gras_set_t   *set,
182                                           gras_set_cursor_t **cursor) {
183
184   if (set != NULL) {
185     if (!*cursor) {
186       DEBUG0("Create the cursor on first use");
187       *cursor = gras_new(gras_set_cursor_t,1);
188       gras_assert0(*cursor,
189                    "Malloc error during the creation of the cursor");
190     }
191     (*cursor)->set = set;
192     gras_dynar_cursor_first(set->dynar, &( (*cursor)->val) );
193   } else {
194     *cursor = NULL;
195   }
196 }
197
198 /**
199  * gras_set_cursor_step:
200  * @cursor: the cursor
201  *
202  * Move to the next element. 
203  */
204 void         gras_set_cursor_step        (gras_set_cursor_t  *cursor) {
205   gras_dynar_cursor_step(cursor->set->dynar, &( cursor->val ) );
206 }
207
208 /**
209  * gras_set_cursor_get_or_free:
210  * @cursor: the cursor
211  * @Returns: true if it's ok, false if there is no more data
212  *
213  * Get current data
214  */
215 int          gras_set_cursor_get_or_free (gras_set_cursor_t **curs,
216                                           gras_set_elm_t    **elm) {
217   gras_set_cursor_t *cursor;
218
219   if (!curs || !(*curs))
220     return FALSE;
221
222   cursor=*curs;
223
224   if (! gras_dynar_cursor_get( cursor->set->dynar,&(cursor->val),elm) ) {
225     gras_free(cursor);
226     *curs=NULL;
227     return FALSE;    
228   } 
229   return TRUE;
230 }