Logo AND Algorithmique Numérique Distribuée

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