Logo AND Algorithmique Numérique Distribuée

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