Logo AND Algorithmique Numérique Distribuée

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