Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
a947f07ffb89828833e6fbce0b37f280fc6b5b64
[simgrid.git] / src / gras / DataDesc / ddt_create.c
1 /* ddt_new - creation/deletion of datatypes structs (private to this module)*/\r
2 \r
3 /* Copyright (c) 2004, 2005, 2006, 2007, 2009, 2010. The SimGrid Team.\r
4  * All rights reserved.                                                     */\r
5 \r
6 /* This program is free software; you can redistribute it and/or modify it\r
7  * under the terms of the license (GNU LGPL) which comes with this package. */\r
8 \r
9 #include "xbt/misc.h"           /* min()/max() */\r
10 #include "xbt/ex.h"\r
11 #include "gras/DataDesc/datadesc_private.h"\r
12 \r
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(gras_ddt_create, gras_ddt,\r
14                                 "Creating new datadescriptions");\r
15 \r
16 /*** prototypes ***/\r
17 static gras_dd_cat_field_t\r
18 gras_dd_find_field(gras_datadesc_type_t type, const char *field_name);\r
19 /**\r
20  * gras_ddt_freev:\r
21  *\r
22  * gime that memory back, dude. I mean it.\r
23  */\r
24 void gras_ddt_freev(void *ddt)\r
25 {\r
26   gras_datadesc_type_t type = (gras_datadesc_type_t) ddt;\r
27 \r
28   if (type) {\r
29     gras_datadesc_free(&type);\r
30   }\r
31 }\r
32 \r
33 static gras_datadesc_type_t gras_ddt_new(const char *name)\r
34 {\r
35   gras_datadesc_type_t res;\r
36 \r
37   XBT_IN1("(%s)", name);\r
38   res = xbt_new0(s_gras_datadesc_type_t, 1);\r
39 \r
40   res->name = (char *) strdup(name);\r
41   res->name_len = strlen(name);\r
42   res->cycle = 0;\r
43 \r
44   xbt_set_add(gras_datadesc_set_local, (xbt_set_elm_t) res, gras_ddt_freev);\r
45   XBT_OUT;\r
46   return res;\r
47 }\r
48 \r
49 /** @brief retrieve an existing message type from its name (or NULL if it does not exist). */\r
50 gras_datadesc_type_t gras_datadesc_by_name_or_null(const char *name)\r
51 {\r
52   xbt_ex_t e;\r
53   gras_datadesc_type_t res = NULL;\r
54 \r
55   TRY {\r
56     res = gras_datadesc_by_name(name);\r
57   } CATCH(e) {\r
58     res = NULL;\r
59     xbt_ex_free(e);\r
60   }\r
61   return res;\r
62 }\r
63 \r
64 /**\r
65  * Search the given datadesc (or raises an exception if it can't be found)\r
66  */\r
67 gras_datadesc_type_t gras_datadesc_by_name(const char *name)\r
68 {\r
69   xbt_ex_t e;\r
70   gras_datadesc_type_t res = NULL;\r
71   volatile int found = 0;\r
72   TRY {\r
73     res =\r
74       (gras_datadesc_type_t) xbt_set_get_by_name(gras_datadesc_set_local,\r
75                                                  name);\r
76     found = 1;\r
77   } CATCH(e) {\r
78     if (e.category != not_found_error)\r
79       RETHROW;\r
80     xbt_ex_free(e);\r
81   }\r
82   if (!found)\r
83     THROW1(not_found_error, 0, "No registred datatype of that name: %s",\r
84            name);\r
85 \r
86   return res;\r
87 }\r
88 \r
89 /**\r
90  * Retrieve a type from its code (or NULL if not found)\r
91  */\r
92 gras_datadesc_type_t gras_datadesc_by_id(long int code)\r
93 {\r
94   xbt_ex_t e;\r
95   gras_datadesc_type_t res = NULL;\r
96   TRY {\r
97     res =\r
98       (gras_datadesc_type_t) xbt_set_get_by_id(gras_datadesc_set_local, code);\r
99   } CATCH(e) {\r
100     if (e.category != not_found_error)\r
101       RETHROW;\r
102     xbt_ex_free(e);\r
103     res = NULL;\r
104   }\r
105   return res;\r
106 }\r
107 \r
108 /**\r
109  * Create a new scalar and give a pointer to it\r
110  */\r
111 gras_datadesc_type_t\r
112 gras_datadesc_scalar(const char *name,\r
113                      gras_ddt_scalar_type_t type,\r
114                      enum e_gras_dd_scalar_encoding encoding)\r
115 {\r
116 \r
117   gras_datadesc_type_t res;\r
118   long int arch;\r
119 \r
120   XBT_IN;\r
121   res = gras_datadesc_by_name_or_null(name);\r
122   if (res) {\r
123     xbt_assert1(res->category_code == e_gras_datadesc_type_cat_scalar,\r
124                 "Redefinition of type %s does not match", name);\r
125     xbt_assert1(res->category.scalar_data.encoding == encoding,\r
126                 "Redefinition of type %s does not match", name);\r
127     xbt_assert1(res->category.scalar_data.type == type,\r
128                 "Redefinition of type %s does not match", name);\r
129     VERB1("Discarding redefinition of %s", name);\r
130     return res;\r
131   }\r
132   res = gras_ddt_new(name);\r
133 \r
134   for (arch = 0; arch < gras_arch_count; arch++) {\r
135     res->size[arch] = gras_arches[arch].sizeofs[type];\r
136     res->alignment[arch] = gras_arches[arch].boundaries[type];\r
137     res->aligned_size[arch] =\r
138       ddt_aligned(res->size[arch], res->alignment[arch]);\r
139   }\r
140 \r
141   res->category_code = e_gras_datadesc_type_cat_scalar;\r
142   res->category.scalar_data.encoding = encoding;\r
143   res->category.scalar_data.type = type;\r
144   XBT_OUT;\r
145 \r
146   return res;\r
147 }\r
148 \r
149 \r
150 /** Frees one struct or union field */\r
151 void gras_dd_cat_field_free(void *f)\r
152 {\r
153   gras_dd_cat_field_t field = *(gras_dd_cat_field_t *) f;\r
154   XBT_IN;\r
155   if (field) {\r
156     if (field->name)\r
157       free(field->name);\r
158     free(field);\r
159   }\r
160   XBT_OUT;\r
161 }\r
162 \r
163 /** \brief Declare a new structure description */\r
164 gras_datadesc_type_t gras_datadesc_struct(const char *name)\r
165 {\r
166 \r
167   gras_datadesc_type_t res;\r
168   long int arch;\r
169 \r
170   XBT_IN1("(%s)", name);\r
171   res = gras_datadesc_by_name_or_null(name);\r
172   if (res) {\r
173     /* FIXME: Check that field redefinition matches */\r
174     xbt_assert1(res->category_code == e_gras_datadesc_type_cat_struct,\r
175                 "Redefinition of type %s does not match", name);\r
176     VERB1("Discarding redefinition of %s", name);\r
177     return res;\r
178   }\r
179   res = gras_ddt_new(name);\r
180 \r
181   for (arch = 0; arch < gras_arch_count; arch++) {\r
182     res->size[arch] = 0;\r
183     res->alignment[arch] = 0;\r
184     res->aligned_size[arch] = 0;\r
185   }\r
186   res->category_code = e_gras_datadesc_type_cat_struct;\r
187   res->category.struct_data.fields =\r
188     xbt_dynar_new(sizeof(gras_dd_cat_field_t), gras_dd_cat_field_free);\r
189 \r
190   XBT_OUT;\r
191   return res;\r
192 }\r
193 \r
194 /** \brief Append a new field to a structure description */\r
195 void\r
196 gras_datadesc_struct_append(gras_datadesc_type_t struct_type,\r
197                             const char *name, gras_datadesc_type_t field_type)\r
198 {\r
199 \r
200   gras_dd_cat_field_t field;\r
201   int arch;\r
202 \r
203   xbt_assert2(field_type,\r
204               "Cannot add the field '%s' into struct '%s': its type is NULL",\r
205               name, struct_type->name);\r
206   XBT_IN3("(%s %s.%s;)", field_type->name, struct_type->name, name);\r
207   if (struct_type->category.struct_data.closed) {\r
208     VERB1\r
209       ("Ignoring request to add field to struct %s (closed. Redefinition?)",\r
210        struct_type->name);\r
211     return;\r
212   }\r
213 \r
214   xbt_assert1(field_type->size[GRAS_THISARCH] >= 0,\r
215               "Cannot add a dynamically sized field in structure %s",\r
216               struct_type->name);\r
217 \r
218   field = xbt_new(s_gras_dd_cat_field_t, 1);\r
219   field->name = (char *) strdup(name);\r
220 \r
221   DEBUG0("----------------");\r
222   DEBUG3("PRE s={size=%ld,align=%ld,asize=%ld}",\r
223          struct_type->size[GRAS_THISARCH],\r
224          struct_type->alignment[GRAS_THISARCH],\r
225          struct_type->aligned_size[GRAS_THISARCH]);\r
226 \r
227 \r
228   for (arch = 0; arch < gras_arch_count; arch++) {\r
229     field->offset[arch] = ddt_aligned(struct_type->size[arch],\r
230                                       field_type->alignment[arch]);\r
231 \r
232     struct_type->size[arch] = field->offset[arch] + field_type->size[arch];\r
233     struct_type->alignment[arch] = max(struct_type->alignment[arch],\r
234                                        field_type->alignment[arch]);\r
235     struct_type->aligned_size[arch] = ddt_aligned(struct_type->size[arch],\r
236                                                   struct_type->alignment\r
237                                                   [arch]);\r
238   }\r
239   field->type = field_type;\r
240   field->send = NULL;\r
241   field->recv = NULL;\r
242 \r
243   xbt_dynar_push(struct_type->category.struct_data.fields, &field);\r
244 \r
245   DEBUG3("Push a %s into %s at offset %ld.",\r
246          field_type->name, struct_type->name, field->offset[GRAS_THISARCH]);\r
247   DEBUG3("  f={size=%ld,align=%ld,asize=%ld}",\r
248          field_type->size[GRAS_THISARCH],\r
249          field_type->alignment[GRAS_THISARCH],\r
250          field_type->aligned_size[GRAS_THISARCH]);\r
251   DEBUG3("  s={size=%ld,align=%ld,asize=%ld}",\r
252          struct_type->size[GRAS_THISARCH],\r
253          struct_type->alignment[GRAS_THISARCH],\r
254          struct_type->aligned_size[GRAS_THISARCH]);\r
255   XBT_OUT;\r
256 }\r
257 \r
258 /** \brief Close a structure description\r
259  *\r
260  * No new field can be added afterward, and it is mandatory to close the structure before using it.\r
261  */\r
262 void gras_datadesc_struct_close(gras_datadesc_type_t struct_type)\r
263 {\r
264   int arch;\r
265   XBT_IN;\r
266   struct_type->category.struct_data.closed = 1;\r
267   for (arch = 0; arch < gras_arch_count; arch++) {\r
268     struct_type->size[arch] = struct_type->aligned_size[arch];\r
269   }\r
270   DEBUG4("structure %s closed. size=%ld,align=%ld,asize=%ld",\r
271          struct_type->name,\r
272          struct_type->size[GRAS_THISARCH],\r
273          struct_type->alignment[GRAS_THISARCH],\r
274          struct_type->aligned_size[GRAS_THISARCH]);\r
275 }\r
276 \r
277 /**\r
278  * gras_datadesc_cycle_set:\r
279  *\r
280  * Tell GRAS that the pointers of the type described by ddt may present\r
281  * some loop, and that the cycle detection mechanism is needed.\r
282  *\r
283  * Note that setting this option when not needed have a rather bad effect\r
284  * on the performance (several times slower on big data).\r
285  */\r
286 void gras_datadesc_cycle_set(gras_datadesc_type_t ddt)\r
287 {\r
288   ddt->cycle = 1;\r
289 }\r
290 \r
291 /**\r
292  * gras_datadesc_cycle_unset:\r
293  *\r
294  * Tell GRAS that the pointers of the type described by ddt do not present\r
295  * any loop and that cycle detection mechanism are not needed.\r
296  * (default)\r
297  */\r
298 void gras_datadesc_cycle_unset(gras_datadesc_type_t ddt)\r
299 {\r
300   ddt->cycle = 0;\r
301 }\r
302 \r
303 /** \brief Declare a new union description */\r
304 gras_datadesc_type_t\r
305 gras_datadesc_union(const char *name, gras_datadesc_type_cb_int_t selector)\r
306 {\r
307 \r
308   gras_datadesc_type_t res;\r
309   int arch;\r
310 \r
311   XBT_IN1("(%s)", name);\r
312   xbt_assert0(selector,\r
313               "Attempt to creat an union without field_count function");\r
314 \r
315   res = gras_datadesc_by_name_or_null(name);\r
316   if (res) {\r
317     /* FIXME: Check that field redefinition matches */\r
318     xbt_assert1(res->category_code == e_gras_datadesc_type_cat_union,\r
319                 "Redefinition of type %s does not match", name);\r
320     xbt_assert1(res->category.union_data.selector == selector,\r
321                 "Redefinition of type %s does not match", name);\r
322     VERB1("Discarding redefinition of %s", name);\r
323     return res;\r
324   }\r
325 \r
326   res = gras_ddt_new(name);\r
327 \r
328   for (arch = 0; arch < gras_arch_count; arch++) {\r
329     res->size[arch] = 0;\r
330     res->alignment[arch] = 0;\r
331     res->aligned_size[arch] = 0;\r
332   }\r
333 \r
334   res->category_code = e_gras_datadesc_type_cat_union;\r
335   res->category.union_data.fields =\r
336     xbt_dynar_new(sizeof(gras_dd_cat_field_t *), gras_dd_cat_field_free);\r
337   res->category.union_data.selector = selector;\r
338 \r
339   return res;\r
340 }\r
341 \r
342 /** \brief Append a new field to an union description */\r
343 void gras_datadesc_union_append(gras_datadesc_type_t union_type,\r
344                                 const char *name,\r
345                                 gras_datadesc_type_t field_type)\r
346 {\r
347 \r
348   gras_dd_cat_field_t field;\r
349   int arch;\r
350 \r
351   XBT_IN3("(%s %s.%s;)", field_type->name, union_type->name, name);\r
352   xbt_assert1(field_type->size[GRAS_THISARCH] >= 0,\r
353               "Cannot add a dynamically sized field in union %s",\r
354               union_type->name);\r
355 \r
356   if (union_type->category.union_data.closed) {\r
357     VERB1("Ignoring request to add field to union %s (closed)",\r
358           union_type->name);\r
359     return;\r
360   }\r
361 \r
362   field = xbt_new0(s_gras_dd_cat_field_t, 1);\r
363 \r
364   field->name = (char *) strdup(name);\r
365   field->type = field_type;\r
366   /* All offset are left to 0 in an union */\r
367 \r
368   xbt_dynar_push(union_type->category.union_data.fields, &field);\r
369 \r
370   for (arch = 0; arch < gras_arch_count; arch++) {\r
371     union_type->size[arch] = max(union_type->size[arch],\r
372                                  field_type->size[arch]);\r
373     union_type->alignment[arch] = max(union_type->alignment[arch],\r
374                                       field_type->alignment[arch]);\r
375     union_type->aligned_size[arch] = ddt_aligned(union_type->size[arch],\r
376                                                  union_type->alignment[arch]);\r
377   }\r
378 }\r
379 \r
380 \r
381 /** \brief Close an union description\r
382  *\r
383  * No new field can be added afterward, and it is mandatory to close the union before using it.\r
384  */\r
385 void gras_datadesc_union_close(gras_datadesc_type_t union_type)\r
386 {\r
387   union_type->category.union_data.closed = 1;\r
388 }\r
389 \r
390 /** \brief Copy a type under another name\r
391  *\r
392  * This may reveal useful to circumvent parsing macro limitations\r
393  */\r
394 gras_datadesc_type_t\r
395 gras_datadesc_copy(const char *name, gras_datadesc_type_t copied)\r
396 {\r
397 \r
398   gras_datadesc_type_t res = gras_ddt_new(name);\r
399   char *name_cpy = res->name;\r
400 \r
401   memcpy(res, copied, sizeof(s_gras_datadesc_type_t));\r
402   res->name = name_cpy;\r
403   return res;\r
404 }\r
405 \r
406 /** \brief Declare a new type being a reference to the one passed in arg */\r
407 gras_datadesc_type_t\r
408 gras_datadesc_ref(const char *name, gras_datadesc_type_t referenced_type)\r
409 {\r
410 \r
411   gras_datadesc_type_t res;\r
412   gras_datadesc_type_t pointer_type = gras_datadesc_by_name("data pointer");\r
413   int arch;\r
414 \r
415   XBT_IN1("(%s)", name);\r
416   res = gras_datadesc_by_name_or_null(name);\r
417   if (res) {\r
418     xbt_assert1(res->category_code == e_gras_datadesc_type_cat_ref,\r
419                 "Redefinition of %s does not match", name);\r
420     xbt_assert1(res->category.ref_data.type == referenced_type,\r
421                 "Redefinition of %s does not match", name);\r
422     xbt_assert1(res->category.ref_data.selector == NULL,\r
423                 "Redefinition of %s does not match", name);\r
424     VERB1("Discarding redefinition of %s", name);\r
425     return res;\r
426   }\r
427 \r
428   res = gras_ddt_new(name);\r
429 \r
430   xbt_assert0(pointer_type, "Cannot get the description of data pointer");\r
431 \r
432   for (arch = 0; arch < gras_arch_count; arch++) {\r
433     res->size[arch] = pointer_type->size[arch];\r
434     res->alignment[arch] = pointer_type->alignment[arch];\r
435     res->aligned_size[arch] = pointer_type->aligned_size[arch];\r
436   }\r
437 \r
438   res->category_code = e_gras_datadesc_type_cat_ref;\r
439   res->category.ref_data.type = referenced_type;\r
440   res->category.ref_data.selector = NULL;\r
441 \r
442   return res;\r
443 }\r
444 \r
445 /** \brief Declare a new type being a generic reference.\r
446  *\r
447  * The callback passed in argument is to be used to select which type is currently used.\r
448  * So, when GRAS wants to send a generic reference, it passes the current data to the selector\r
449  * callback and expects it to return the type description to use.\r
450  */\r
451 gras_datadesc_type_t\r
452 gras_datadesc_ref_generic(const char *name, gras_datadesc_selector_t selector)\r
453 {\r
454 \r
455   gras_datadesc_type_t res;\r
456   gras_datadesc_type_t pointer_type = gras_datadesc_by_name("data pointer");\r
457   int arch;\r
458 \r
459   XBT_IN1("(%s)", name);\r
460   res = gras_datadesc_by_name_or_null(name);\r
461 \r
462   if (res) {\r
463     xbt_assert1(res->category_code == e_gras_datadesc_type_cat_ref,\r
464                 "Redefinition of type %s does not match", name);\r
465     xbt_assert1(res->category.ref_data.type == NULL,\r
466                 "Redefinition of type %s does not match", name);\r
467     xbt_assert1(res->category.ref_data.selector == selector,\r
468                 "Redefinition of type %s does not match", name);\r
469     VERB1("Discarding redefinition of %s", name);\r
470     return res;\r
471   }\r
472   res = gras_ddt_new(name);\r
473 \r
474   xbt_assert0(pointer_type, "Cannot get the description of data pointer");\r
475 \r
476   for (arch = 0; arch < gras_arch_count; arch++) {\r
477     res->size[arch] = pointer_type->size[arch];\r
478     res->alignment[arch] = pointer_type->alignment[arch];\r
479     res->aligned_size[arch] = pointer_type->aligned_size[arch];\r
480   }\r
481 \r
482   res->category_code = e_gras_datadesc_type_cat_ref;\r
483 \r
484   res->category.ref_data.type = NULL;\r
485   res->category.ref_data.selector = selector;\r
486 \r
487   return res;\r
488 }\r
489 \r
490 /** \brief Declare a new type being an array of fixed size and content */\r
491 gras_datadesc_type_t\r
492 gras_datadesc_array_fixed(const char *name,\r
493                           gras_datadesc_type_t element_type,\r
494                           long int fixed_size)\r
495 {\r
496 \r
497   gras_datadesc_type_t res;\r
498   int arch;\r
499 \r
500   XBT_IN1("(%s)", name);\r
501   res = gras_datadesc_by_name_or_null(name);\r
502   if (res) {\r
503     xbt_assert1(res->category_code == e_gras_datadesc_type_cat_array,\r
504                 "Redefinition of type %s does not match", name);\r
505 \r
506     if (res->category.array_data.type != element_type) {\r
507       ERROR1("Redefinition of type %s does not match: array elements differ",\r
508              name);\r
509       gras_datadesc_type_dump(res->category.array_data.type);\r
510       gras_datadesc_type_dump(element_type);\r
511     }\r
512 \r
513     xbt_assert1(res->category.array_data.fixed_size == fixed_size,\r
514                 "Redefinition of type %s does not match", name);\r
515     xbt_assert1(res->category.array_data.dynamic_size == NULL,\r
516                 "Redefinition of type %s does not match", name);\r
517     VERB1("Discarding redefinition of %s", name);\r
518 \r
519     return res;\r
520   }\r
521   res = gras_ddt_new(name);\r
522 \r
523   xbt_assert1(fixed_size >= 0, "'%s' is a array of negative fixed size",\r
524               name);\r
525   for (arch = 0; arch < gras_arch_count; arch++) {\r
526     res->size[arch] = fixed_size * element_type->aligned_size[arch];\r
527     res->alignment[arch] = element_type->alignment[arch];\r
528     res->aligned_size[arch] = res->size[arch];\r
529   }\r
530 \r
531   res->category_code = e_gras_datadesc_type_cat_array;\r
532 \r
533   res->category.array_data.type = element_type;\r
534   res->category.array_data.fixed_size = fixed_size;\r
535   res->category.array_data.dynamic_size = NULL;\r
536 \r
537   return res;\r
538 }\r
539 \r
540 /** \brief Declare a new type being an array of fixed size, but accepting several content types. */\r
541 gras_datadesc_type_t gras_datadesc_array_dyn(const char *name,\r
542                                              gras_datadesc_type_t\r
543                                              element_type,\r
544                                              gras_datadesc_type_cb_int_t\r
545                                              dynamic_size)\r
546 {\r
547 \r
548   gras_datadesc_type_t res;\r
549   int arch;\r
550 \r
551   XBT_IN1("(%s)", name);\r
552   xbt_assert1(dynamic_size,\r
553               "'%s' is a dynamic array without size discriminant", name);\r
554 \r
555   res = gras_datadesc_by_name_or_null(name);\r
556   if (res) {\r
557     xbt_assert1(res->category_code == e_gras_datadesc_type_cat_array,\r
558                 "Redefinition of type %s does not match", name);\r
559     xbt_assert1(res->category.array_data.type == element_type,\r
560                 "Redefinition of type %s does not match", name);\r
561     xbt_assert1(res->category.array_data.fixed_size == -1,\r
562                 "Redefinition of type %s does not match", name);\r
563     xbt_assert1(res->category.array_data.dynamic_size == dynamic_size,\r
564                 "Redefinition of type %s does not match", name);\r
565     VERB1("Discarding redefinition of %s", name);\r
566 \r
567     return res;\r
568   }\r
569 \r
570   res = gras_ddt_new(name);\r
571 \r
572   for (arch = 0; arch < gras_arch_count; arch++) {\r
573     res->size[arch] = 0;        /* make sure it indicates "dynamic" */\r
574     res->alignment[arch] = element_type->alignment[arch];\r
575     res->aligned_size[arch] = 0;        /*FIXME: That was so in GS, but looks stupid */\r
576   }\r
577 \r
578   res->category_code = e_gras_datadesc_type_cat_array;\r
579 \r
580   res->category.array_data.type = element_type;\r
581   res->category.array_data.fixed_size = -1;\r
582   res->category.array_data.dynamic_size = dynamic_size;\r
583 \r
584   return res;\r
585 }\r
586 \r
587 /** \brief Declare a new type being an array which size can be found with \ref gras_cbps_i_pop\r
588  *\r
589  * Most of the time, you want to include a reference in your structure which\r
590  * is a pointer to a dynamic array whose size is fixed by another field of\r
591  * your structure.\r
592  *\r
593  * This case pops up so often that this function was created to take care of\r
594  * this case. It creates a dynamic array type whose size is poped from the\r
595  * current cbps, and then create a reference to it.\r
596  *\r
597  * The name of the created datatype will be the name of the element type, with\r
598  * '[]*' appended to it.\r
599  *\r
600  * Then to use it, you just have to make sure that your structure pre-callback\r
601  * does push the size of the array in the cbps (using #gras_cbps_i_push), and\r
602  * you are set.\r
603  *\r
604  * But be remember that this is a stack. If you have two different pop_arr, you\r
605  * should push the second one first, so that the first one is on the top of the\r
606  * list when the first field gets transfered.\r
607  *\r
608  */\r
609 gras_datadesc_type_t\r
610 gras_datadesc_ref_pop_arr(gras_datadesc_type_t element_type)\r
611 {\r
612   int cpt=0;\r
613   gras_datadesc_type_t res,ddt2;\r
614   char *name = (char *) xbt_malloc(strlen(element_type->name) + 4);\r
615 \r
616   sprintf(name, "%s[]", element_type->name);\r
617   /* Make sure we are not trying to redefine a ddt with the same name */\r
618   ddt2 = gras_datadesc_by_name_or_null(name);\r
619 \r
620   while (ddt2) {\r
621     free(name);\r
622     name=bprintf("%s[]_%d",element_type->name,cpt++);\r
623     ddt2=gras_datadesc_by_name_or_null(name);\r
624   }\r
625 \r
626   res = gras_datadesc_array_dyn(name, element_type, gras_datadesc_cb_pop);\r
627 \r
628   sprintf(name, "%s[]*", element_type->name);\r
629   cpt=0;\r
630   ddt2 = gras_datadesc_by_name_or_null(name);\r
631   while (ddt2) {\r
632     free(name);\r
633     name=bprintf("%s[]*_%d",element_type->name,cpt++);\r
634     ddt2=gras_datadesc_by_name_or_null(name);\r
635   }\r
636 \r
637   res = gras_datadesc_ref(name, res);\r
638 \r
639   free(name);\r
640 \r
641   return res;\r
642 }\r
643 \r
644 /*\r
645  *##\r
646  *## Constructor of container datatypes\r
647  *##\r
648  */\r
649 \r
650 static void gras_datadesc_dynar_cb(gras_datadesc_type_t typedesc,\r
651                                    gras_cbps_t vars, void *data)\r
652 {\r
653   gras_datadesc_type_t subtype;\r
654   xbt_dynar_t dynar = (xbt_dynar_t) data;\r
655 \r
656   memcpy(&dynar->free_f, &typedesc->extra, sizeof(dynar->free_f));\r
657 \r
658   /* search for the elemsize in what we have. If elements are "int", typedesc got is "int[]*" */\r
659   subtype = gras_dd_find_field(typedesc, "data")->type;\r
660 \r
661   /* this is now a ref to array of what we're looking for */\r
662   subtype = subtype->category.ref_data.type;\r
663   subtype = subtype->category.array_data.type;\r
664 \r
665   DEBUG1("subtype is %s", subtype->name);\r
666 \r
667   dynar->elmsize = subtype->size[GRAS_THISARCH];\r
668   dynar->size = dynar->used;\r
669   dynar->mutex = NULL;\r
670 }\r
671 \r
672 /** \brief Declare a new type being a dynar in which each elements are of the given type\r
673  *\r
674  *  The type gets registered under the name "dynar(%s)_s", where %s is the name of the subtype.\r
675  *  For example, a dynar of doubles will be called "dynar(double)_s" and a dynar of dynar of\r
676  *  strings will be called "dynar(dynar(string)_s)_s".\r
677  *\r
678  *  \param elm_t: the datadesc of the elements\r
679  *  \param free_func: the function to use to free the elements when the dynar gets freed\r
680  */\r
681 gras_datadesc_type_t\r
682 gras_datadesc_dynar(gras_datadesc_type_t elm_t, void_f_pvoid_t free_func)\r
683 {\r
684 \r
685   char *buffname;\r
686   gras_datadesc_type_t res;\r
687 \r
688   asprintf(&buffname, "s_xbt_dynar_of_%s", elm_t->name);\r
689 \r
690   res = gras_datadesc_struct(buffname);\r
691 \r
692   gras_datadesc_struct_append(res, "size",\r
693                               gras_datadesc_by_name("unsigned long int"));\r
694 \r
695   gras_datadesc_struct_append(res, "used",\r
696                               gras_datadesc_by_name("unsigned long int"));\r
697 \r
698   gras_datadesc_struct_append(res, "elmsize",\r
699                               gras_datadesc_by_name("unsigned long int"));\r
700 \r
701   gras_datadesc_struct_append(res, "data", gras_datadesc_ref_pop_arr(elm_t));\r
702 \r
703   gras_datadesc_struct_append(res, "free_f",\r
704                               gras_datadesc_by_name("function pointer"));\r
705   memcpy(res->extra, &free_func, sizeof(free_func));\r
706 \r
707   gras_datadesc_struct_append(res, "mutex",\r
708                               gras_datadesc_by_name("data pointer"));\r
709 \r
710   gras_datadesc_struct_close(res);\r
711 \r
712   gras_datadesc_cb_field_push(res, "used");\r
713   gras_datadesc_cb_recv(res, &gras_datadesc_dynar_cb);\r
714 \r
715   /* build a ref to it */\r
716   free(buffname);\r
717   asprintf(&buffname, "xbt_dynar_of_%s", elm_t->name);\r
718   res = gras_datadesc_ref(buffname, res);\r
719   free(buffname);\r
720   return res;\r
721 }\r
722 \r
723 #include "xbt/matrix.h"\r
724 static void gras_datadesc_matrix_cb(gras_datadesc_type_t typedesc,\r
725                                     gras_cbps_t vars, void *data)\r
726 {\r
727   gras_datadesc_type_t subtype;\r
728   xbt_matrix_t matrix = (xbt_matrix_t) data;\r
729 \r
730   memcpy(&matrix->free_f, &typedesc->extra, sizeof(matrix->free_f));\r
731 \r
732   /* search for the elemsize in what we have. If elements are "int", typedesc got is "int[]*" */\r
733   subtype = gras_dd_find_field(typedesc, "data")->type;\r
734 \r
735   /* this is now a ref to array of what we're looking for */\r
736   subtype = subtype->category.ref_data.type;\r
737   subtype = subtype->category.array_data.type;\r
738 \r
739   DEBUG1("subtype is %s", subtype->name);\r
740 \r
741   matrix->elmsize = subtype->size[GRAS_THISARCH];\r
742 }\r
743 \r
744 gras_datadesc_type_t\r
745 gras_datadesc_matrix(gras_datadesc_type_t elm_t, void_f_pvoid_t const free_f)\r
746 {\r
747   char *buffname;\r
748   gras_datadesc_type_t res;\r
749 \r
750   asprintf(&buffname, "s_xbt_matrix_t(%s)", elm_t->name);\r
751   res = gras_datadesc_struct(buffname);\r
752 \r
753   gras_datadesc_struct_append(res, "lines",\r
754                               gras_datadesc_by_name("unsigned int"));\r
755   gras_datadesc_struct_append(res, "rows",\r
756                               gras_datadesc_by_name("unsigned int"));\r
757 \r
758   gras_datadesc_struct_append(res, "elmsize",\r
759                               gras_datadesc_by_name("unsigned long int"));\r
760 \r
761   gras_datadesc_struct_append(res, "data", gras_datadesc_ref_pop_arr(elm_t));\r
762   gras_datadesc_struct_append(res, "free_f",\r
763                               gras_datadesc_by_name("function pointer"));\r
764   gras_datadesc_struct_close(res);\r
765 \r
766   gras_datadesc_cb_field_push(res, "lines");\r
767   gras_datadesc_cb_field_push_multiplier(res, "rows");\r
768 \r
769   gras_datadesc_cb_recv(res, &gras_datadesc_matrix_cb);\r
770   memcpy(res->extra, &free_f, sizeof(free_f));\r
771 \r
772   /* build a ref to it */\r
773   free(buffname);\r
774   asprintf(&buffname, "xbt_matrix_t(%s)", elm_t->name);\r
775   res = gras_datadesc_ref(buffname, res);\r
776   free(buffname);\r
777   return res;\r
778 }\r
779 \r
780 gras_datadesc_type_t\r
781 gras_datadesc_import_nws(const char *name,\r
782                          const DataDescriptor * desc, unsigned long howmany)\r
783 {\r
784   THROW_UNIMPLEMENTED;\r
785 }\r
786 \r
787 /**\r
788  * (useful to push the sizes of the upcoming arrays, for example)\r
789  */\r
790 void gras_datadesc_cb_send(gras_datadesc_type_t type,\r
791                            gras_datadesc_type_cb_void_t send)\r
792 {\r
793   type->send = send;\r
794 }\r
795 \r
796 /**\r
797  * (useful to put the function pointers to the rigth value, for example)\r
798  */\r
799 void gras_datadesc_cb_recv(gras_datadesc_type_t type,\r
800                            gras_datadesc_type_cb_void_t recv)\r
801 {\r
802   type->recv = recv;\r
803 }\r
804 \r
805 /*\r
806  * gras_dd_find_field:\r
807  *\r
808  * Returns the type descriptor of the given field. Abort on error.\r
809  */\r
810 static gras_dd_cat_field_t\r
811 gras_dd_find_field(gras_datadesc_type_t type, const char *field_name)\r
812 {\r
813   xbt_dynar_t field_array;\r
814 \r
815   gras_dd_cat_field_t field = NULL;\r
816   unsigned int field_num;\r
817 \r
818   if (type->category_code == e_gras_datadesc_type_cat_union) {\r
819     field_array = type->category.union_data.fields;\r
820   } else if (type->category_code == e_gras_datadesc_type_cat_struct) {\r
821     field_array = type->category.struct_data.fields;\r
822   } else {\r
823     ERROR2("%s (%p) is not a struct nor an union. There is no field.",\r
824            type->name, (void *) type);\r
825     xbt_abort();\r
826   }\r
827   xbt_dynar_foreach(field_array, field_num, field) {\r
828     if (!strcmp(field_name, field->name)) {\r
829       return field;\r
830     }\r
831   }\r
832   ERROR2("No field named '%s' in '%s'", field_name, type->name);\r
833   xbt_abort();\r
834 \r
835 }\r
836 \r
837 /**\r
838  * The given datadesc must be a struct or union (abort if not).\r
839  * (useful to push the sizes of the upcoming arrays, for example)\r
840  */\r
841 void gras_datadesc_cb_field_send(gras_datadesc_type_t type,\r
842                                  const char *field_name,\r
843                                  gras_datadesc_type_cb_void_t send)\r
844 {\r
845 \r
846   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);\r
847   field->send = send;\r
848 }\r
849 \r
850 \r
851 /**\r
852  * The value, which must be an int, unsigned int, long int or unsigned long int\r
853  * is pushed to the stacks of sizes and can then be retrieved with\r
854  * \ref gras_datadesc_ref_pop_arr or directly with \ref gras_cbps_i_pop.\r
855  */\r
856 void gras_datadesc_cb_field_push(gras_datadesc_type_t type,\r
857                                  const char *field_name)\r
858 {\r
859 \r
860   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);\r
861   gras_datadesc_type_t sub_type = field->type;\r
862 \r
863   DEBUG3("add a PUSHy cb to '%s' field (type '%s') of '%s'",\r
864          field_name, sub_type->name, type->name);\r
865   if (!strcmp("int", sub_type->name)) {\r
866     field->send = gras_datadesc_cb_push_int;\r
867   } else if (!strcmp("unsigned int", sub_type->name)) {\r
868     field->send = gras_datadesc_cb_push_uint;\r
869   } else if (!strcmp("long int", sub_type->name)) {\r
870     field->send = gras_datadesc_cb_push_lint;\r
871   } else if (!strcmp("unsigned long int", sub_type->name)) {\r
872     field->send = gras_datadesc_cb_push_ulint;\r
873   } else {\r
874     ERROR1\r
875       ("Field %s is not an int, unsigned int, long int neither unsigned long int",\r
876        sub_type->name);\r
877     xbt_abort();\r
878   }\r
879 }\r
880 \r
881 /**\r
882  * Any previously pushed value is poped and the field value is multiplied to\r
883  * it. The result is then pushed back into the stack of sizes. It can then be\r
884  * retrieved with \ref gras_datadesc_ref_pop_arr or directly with \ref\r
885  * gras_cbps_i_pop.\r
886  *\r
887  * The field must be an int, unsigned int, long int or unsigned long int.\r
888  */\r
889 void gras_datadesc_cb_field_push_multiplier(gras_datadesc_type_t type,\r
890                                             const char *field_name)\r
891 {\r
892 \r
893   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);\r
894   gras_datadesc_type_t sub_type = field->type;\r
895 \r
896   DEBUG3("add a MPUSHy cb to '%s' field (type '%s') of '%s'",\r
897          field_name, sub_type->name, type->name);\r
898   if (!strcmp("int", sub_type->name)) {\r
899     field->send = gras_datadesc_cb_push_int_mult;\r
900   } else if (!strcmp("unsigned int", sub_type->name)) {\r
901     field->send = gras_datadesc_cb_push_uint_mult;\r
902   } else if (!strcmp("long int", sub_type->name)) {\r
903     field->send = gras_datadesc_cb_push_lint_mult;\r
904   } else if (!strcmp("unsigned long int", sub_type->name)) {\r
905     field->send = gras_datadesc_cb_push_ulint_mult;\r
906   } else {\r
907     ERROR1\r
908       ("Field %s is not an int, unsigned int, long int neither unsigned long int",\r
909        sub_type->name);\r
910     xbt_abort();\r
911   }\r
912 }\r
913 \r
914 /**\r
915  * The given datadesc must be a struct or union (abort if not).\r
916  * (useful to put the function pointers to the right value, for example)\r
917  */\r
918 void gras_datadesc_cb_field_recv(gras_datadesc_type_t type,\r
919                                  const char *field_name,\r
920                                  gras_datadesc_type_cb_void_t recv)\r
921 {\r
922 \r
923   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);\r
924   field->recv = recv;\r
925 }\r
926 \r
927 /*\r
928  * Free a datadesc. Should only be called at xbt_exit.\r
929  */\r
930 void gras_datadesc_free(gras_datadesc_type_t * type)\r
931 {\r
932 \r
933   DEBUG1("Let's free ddt %s", (*type)->name);\r
934 \r
935   switch ((*type)->category_code) {\r
936   case e_gras_datadesc_type_cat_scalar:\r
937   case e_gras_datadesc_type_cat_ref:\r
938   case e_gras_datadesc_type_cat_array:\r
939     /* nothing to free in there */\r
940     break;\r
941 \r
942   case e_gras_datadesc_type_cat_struct:\r
943     xbt_dynar_free(&((*type)->category.struct_data.fields));\r
944     break;\r
945 \r
946   case e_gras_datadesc_type_cat_union:\r
947     xbt_dynar_free(&((*type)->category.union_data.fields));\r
948     break;\r
949 \r
950   default:\r
951     /* datadesc was invalid. Killing it is like euthanasy, I guess */\r
952     break;\r
953   }\r
954   free((*type)->name);\r
955   free(*type);\r
956   type = NULL;\r
957 }\r
958 \r
959 /**\r
960  * gras_datadesc_type_cmp:\r
961  *\r
962  * Compares two datadesc types with the same semantic than strcmp.\r
963  *\r
964  * This comparison does not take the set headers into account (name and ID),\r
965  * but only the payload (actual type description).\r
966  */\r
967 int gras_datadesc_type_cmp(const gras_datadesc_type_t d1,\r
968                            const gras_datadesc_type_t d2)\r
969 {\r
970   int ret;\r
971   unsigned int cpt;\r
972   gras_dd_cat_field_t field1, field2;\r
973   gras_datadesc_type_t field_desc_1, field_desc_2;\r
974 \r
975   if (d1 == d2)\r
976     return 0;                   /* easy optimization */\r
977 \r
978   if (!d1 && d2) {\r
979     DEBUG0("ddt_cmp: !d1 && d2 => 1");\r
980     return 1;\r
981   }\r
982   if (!d1 && !d2) {\r
983     DEBUG0("ddt_cmp: !d1 && !d2 => 0");\r
984     return 0;\r
985   }\r
986   if (d1 && !d2) {\r
987     DEBUG0("ddt_cmp: d1 && !d2 => -1");\r
988     return -1;\r
989   }\r
990 \r
991   for (cpt = 0; cpt < gras_arch_count; cpt++) {\r
992     if (d1->size[cpt] != d2->size[cpt]) {\r
993       DEBUG5("ddt_cmp: %s->size=%ld  !=  %s->size=%ld (on %s)",\r
994              d1->name, d1->size[cpt], d2->name, d2->size[cpt],\r
995              gras_arches[cpt].name);\r
996       return d1->size[cpt] > d2->size[cpt] ? 1 : -1;\r
997     }\r
998 \r
999     if (d1->alignment[cpt] != d2->alignment[cpt]) {\r
1000       DEBUG5("ddt_cmp: %s->alignment=%ld  !=  %s->alignment=%ld (on %s)",\r
1001              d1->name, d1->alignment[cpt], d2->name, d2->alignment[cpt],\r
1002              gras_arches[cpt].name);\r
1003       return d1->alignment[cpt] > d2->alignment[cpt] ? 1 : -1;\r
1004     }\r
1005 \r
1006     if (d1->aligned_size[cpt] != d2->aligned_size[cpt]) {\r
1007       DEBUG5\r
1008         ("ddt_cmp: %s->aligned_size=%ld  !=  %s->aligned_size=%ld (on %s)",\r
1009          d1->name, d1->aligned_size[cpt], d2->name, d2->aligned_size[cpt],\r
1010          gras_arches[cpt].name);\r
1011       return d1->aligned_size[cpt] > d2->aligned_size[cpt] ? 1 : -1;\r
1012     }\r
1013   }\r
1014 \r
1015   if (d1->category_code != d2->category_code) {\r
1016     DEBUG4("ddt_cmp: %s->cat=%s  !=  %s->cat=%s",\r
1017            d1->name, gras_datadesc_cat_names[d1->category_code],\r
1018            d2->name, gras_datadesc_cat_names[d2->category_code]);\r
1019     return d1->category_code > d2->category_code ? 1 : -1;\r
1020   }\r
1021 \r
1022   if (d1->send != d2->send) {\r
1023     DEBUG4("ddt_cmp: %s->send=%p  !=  %s->send=%p",\r
1024            d1->name, (void *) d1->send, d2->name, (void *) d2->send);\r
1025     return 1;                   /* ISO C forbids ordered comparisons of pointers to functions */\r
1026   }\r
1027 \r
1028   if (d1->recv != d2->recv) {\r
1029     DEBUG4("ddt_cmp: %s->recv=%p  !=  %s->recv=%p",\r
1030            d1->name, (void *) d1->recv, d2->name, (void *) d2->recv);\r
1031     return 1;                   /* ISO C forbids ordered comparisons of pointers to functions */\r
1032   }\r
1033 \r
1034   switch (d1->category_code) {\r
1035   case e_gras_datadesc_type_cat_scalar:\r
1036     if (d1->category.scalar_data.encoding !=\r
1037         d2->category.scalar_data.encoding)\r
1038       return d1->category.scalar_data.encoding >\r
1039         d2->category.scalar_data.encoding ? 1 : -1;\r
1040     break;\r
1041 \r
1042   case e_gras_datadesc_type_cat_struct:\r
1043     if (xbt_dynar_length(d1->category.struct_data.fields) !=\r
1044         xbt_dynar_length(d2->category.struct_data.fields)) {\r
1045       DEBUG4("ddt_cmp: %s (having %lu fields) !=  %s (having %lu fields)",\r
1046              d1->name, xbt_dynar_length(d1->category.struct_data.fields),\r
1047              d2->name, xbt_dynar_length(d2->category.struct_data.fields));\r
1048 \r
1049       return xbt_dynar_length(d1->category.struct_data.fields) >\r
1050         xbt_dynar_length(d2->category.struct_data.fields) ? 1 : -1;\r
1051     }\r
1052     xbt_dynar_foreach(d1->category.struct_data.fields, cpt, field1) {\r
1053 \r
1054       field2 =\r
1055         xbt_dynar_get_as(d2->category.struct_data.fields, cpt,\r
1056                          gras_dd_cat_field_t);\r
1057       field_desc_1 = field1->type;\r
1058       field_desc_2 = field2->type;\r
1059       ret = gras_datadesc_type_cmp(field_desc_1, field_desc_2);\r
1060       if (ret) {\r
1061         DEBUG6("%s->field[%d]=%s != %s->field[%d]=%s",\r
1062                d1->name, cpt, field1->name, d2->name, cpt, field2->name);\r
1063         return ret;\r
1064       }\r
1065 \r
1066     }\r
1067     break;\r
1068 \r
1069   case e_gras_datadesc_type_cat_union:\r
1070     if (d1->category.union_data.selector != d2->category.union_data.selector)\r
1071       return 1;                 /* ISO C forbids ordered comparisons of pointers to functions */\r
1072 \r
1073     if (xbt_dynar_length(d1->category.union_data.fields) !=\r
1074         xbt_dynar_length(d2->category.union_data.fields))\r
1075       return xbt_dynar_length(d1->category.union_data.fields) >\r
1076         xbt_dynar_length(d2->category.union_data.fields) ? 1 : -1;\r
1077 \r
1078     xbt_dynar_foreach(d1->category.union_data.fields, cpt, field1) {\r
1079 \r
1080       field2 =\r
1081         xbt_dynar_get_as(d2->category.union_data.fields, cpt,\r
1082                          gras_dd_cat_field_t);\r
1083       field_desc_1 = field1->type;\r
1084       field_desc_2 = field2->type;\r
1085       ret = gras_datadesc_type_cmp(field_desc_1, field_desc_2);\r
1086       if (ret)\r
1087         return ret;\r
1088 \r
1089     }\r
1090     break;\r
1091 \r
1092 \r
1093   case e_gras_datadesc_type_cat_ref:\r
1094     if (d1->category.ref_data.selector != d2->category.ref_data.selector)\r
1095       return 1;                 /* ISO C forbids ordered comparisons of pointers to functions */\r
1096 \r
1097     if (d1->category.ref_data.type != d2->category.ref_data.type)\r
1098       return d1->category.ref_data.type > d2->category.ref_data.type ? 1 : -1;\r
1099     break;\r
1100 \r
1101   case e_gras_datadesc_type_cat_array:\r
1102     if (d1->category.array_data.type != d2->category.array_data.type)\r
1103       return d1->category.array_data.type >\r
1104         d2->category.array_data.type ? 1 : -1;\r
1105 \r
1106     if (d1->category.array_data.fixed_size !=\r
1107         d2->category.array_data.fixed_size)\r
1108       return d1->category.array_data.fixed_size >\r
1109         d2->category.array_data.fixed_size ? 1 : -1;\r
1110 \r
1111     if (d1->category.array_data.dynamic_size !=\r
1112         d2->category.array_data.dynamic_size)\r
1113       return 1;                 /* ISO C forbids ordered comparisons of pointers to functions */\r
1114 \r
1115     break;\r
1116 \r
1117   default:\r
1118     /* two stupidly created ddt are equally stupid ;) */\r
1119     break;\r
1120   }\r
1121   return 0;\r
1122 \r
1123 }\r