Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
7cfff636fb6cde83d19ba79978e476549b2d27de
[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 static void gras_datadesc_dynar_cb(gras_datadesc_type_t typedesc,
636                                    gras_cbps_t vars, void *data)
637 {
638   gras_datadesc_type_t subtype;
639   xbt_dynar_t dynar = (xbt_dynar_t) data;
640
641   memcpy(&dynar->free_f, &typedesc->extra, sizeof(dynar->free_f));
642
643   /* search for the elemsize in what we have. If elements are "int", typedesc got is "int[]*" */
644   subtype = gras_dd_find_field(typedesc, "data")->type;
645
646   /* this is now a ref to array of what we're looking for */
647   subtype = subtype->category.ref_data.type;
648   subtype = subtype->category.array_data.type;
649
650   DEBUG1("subtype is %s", subtype->name);
651
652   dynar->elmsize = subtype->size[GRAS_THISARCH];
653   dynar->size = dynar->used;
654   dynar->mutex = NULL;
655 }
656
657 /** \brief Declare a new type being a dynar in which each elements are of the given type
658  *
659  *  The type gets registered under the name "dynar(%s)_s", where %s is the name of the subtype.
660  *  For example, a dynar of doubles will be called "dynar(double)_s" and a dynar of dynar of
661  *  strings will be called "dynar(dynar(string)_s)_s".
662  *
663  *  \param elm_t: the datadesc of the elements
664  *  \param free_func: the function to use to free the elements when the dynar gets freed
665  */
666 gras_datadesc_type_t
667 gras_datadesc_dynar(gras_datadesc_type_t elm_t, void_f_pvoid_t free_func)
668 {
669
670   char *buffname;
671   gras_datadesc_type_t res;
672
673   asprintf(&buffname, "s_xbt_dynar_of_%s", elm_t->name);
674
675   res = gras_datadesc_struct(buffname);
676
677   gras_datadesc_struct_append(res, "size",
678                               gras_datadesc_by_name("unsigned long int"));
679
680   gras_datadesc_struct_append(res, "used",
681                               gras_datadesc_by_name("unsigned long int"));
682
683   gras_datadesc_struct_append(res, "elmsize",
684                               gras_datadesc_by_name("unsigned long int"));
685
686   gras_datadesc_struct_append(res, "data", gras_datadesc_ref_pop_arr(elm_t));
687
688   gras_datadesc_struct_append(res, "free_f",
689                               gras_datadesc_by_name("function pointer"));
690   memcpy(res->extra, &free_func, sizeof(free_func));
691
692   gras_datadesc_struct_append(res, "mutex",
693                               gras_datadesc_by_name("data pointer"));
694
695   gras_datadesc_struct_close(res);
696
697   gras_datadesc_cb_field_push(res, "used");
698   gras_datadesc_cb_recv(res, &gras_datadesc_dynar_cb);
699
700   /* build a ref to it */
701   free(buffname);
702   asprintf(&buffname, "xbt_dynar_of_%s", elm_t->name);
703   res = gras_datadesc_ref(buffname, res);
704   free(buffname);
705   return res;
706 }
707
708 #include "xbt/matrix.h"
709 static void gras_datadesc_matrix_cb(gras_datadesc_type_t typedesc,
710                                     gras_cbps_t vars, void *data)
711 {
712   gras_datadesc_type_t subtype;
713   xbt_matrix_t matrix = (xbt_matrix_t) data;
714
715   memcpy(&matrix->free_f, &typedesc->extra, sizeof(matrix->free_f));
716
717   /* search for the elemsize in what we have. If elements are "int", typedesc got is "int[]*" */
718   subtype = gras_dd_find_field(typedesc, "data")->type;
719
720   /* this is now a ref to array of what we're looking for */
721   subtype = subtype->category.ref_data.type;
722   subtype = subtype->category.array_data.type;
723
724   DEBUG1("subtype is %s", subtype->name);
725
726   matrix->elmsize = subtype->size[GRAS_THISARCH];
727 }
728
729 gras_datadesc_type_t
730 gras_datadesc_matrix(gras_datadesc_type_t elm_t, void_f_pvoid_t const free_f)
731 {
732   char *buffname;
733   gras_datadesc_type_t res;
734
735   asprintf(&buffname, "s_xbt_matrix_t(%s)", elm_t->name);
736   res = gras_datadesc_struct(buffname);
737
738   gras_datadesc_struct_append(res, "lines",
739                               gras_datadesc_by_name("unsigned int"));
740   gras_datadesc_struct_append(res, "rows",
741                               gras_datadesc_by_name("unsigned int"));
742
743   gras_datadesc_struct_append(res, "elmsize",
744                               gras_datadesc_by_name("unsigned long int"));
745
746   gras_datadesc_struct_append(res, "data", gras_datadesc_ref_pop_arr(elm_t));
747   gras_datadesc_struct_append(res, "free_f",
748                               gras_datadesc_by_name("function pointer"));
749   gras_datadesc_struct_close(res);
750
751   gras_datadesc_cb_field_push(res, "lines");
752   gras_datadesc_cb_field_push_multiplier(res, "rows");
753
754   gras_datadesc_cb_recv(res, &gras_datadesc_matrix_cb);
755   memcpy(res->extra, &free_f, sizeof(free_f));
756
757   /* build a ref to it */
758   free(buffname);
759   asprintf(&buffname, "xbt_matrix_t(%s)", elm_t->name);
760   res = gras_datadesc_ref(buffname, res);
761   free(buffname);
762   return res;
763 }
764
765 gras_datadesc_type_t
766 gras_datadesc_import_nws(const char *name,
767                          const DataDescriptor * desc, unsigned long howmany)
768 {
769   THROW_UNIMPLEMENTED;
770 }
771
772 /**
773  * (useful to push the sizes of the upcoming arrays, for example)
774  */
775 void gras_datadesc_cb_send(gras_datadesc_type_t type,
776                            gras_datadesc_type_cb_void_t send)
777 {
778   type->send = send;
779 }
780
781 /**
782  * (useful to put the function pointers to the rigth value, for example)
783  */
784 void gras_datadesc_cb_recv(gras_datadesc_type_t type,
785                            gras_datadesc_type_cb_void_t recv)
786 {
787   type->recv = recv;
788 }
789
790 /*
791  * gras_dd_find_field:
792  *
793  * Returns the type descriptor of the given field. Abort on error.
794  */
795 static gras_dd_cat_field_t
796 gras_dd_find_field(gras_datadesc_type_t type, const char *field_name)
797 {
798   xbt_dynar_t field_array;
799
800   gras_dd_cat_field_t field = NULL;
801   unsigned int field_num;
802
803   if (type->category_code == e_gras_datadesc_type_cat_union) {
804     field_array = type->category.union_data.fields;
805   } else if (type->category_code == e_gras_datadesc_type_cat_struct) {
806     field_array = type->category.struct_data.fields;
807   } else {
808     ERROR2("%s (%p) is not a struct nor an union. There is no field.",
809            type->name, (void *) type);
810     xbt_abort();
811   }
812   xbt_dynar_foreach(field_array, field_num, field) {
813     if (!strcmp(field_name, field->name)) {
814       return field;
815     }
816   }
817   ERROR2("No field named '%s' in '%s'", field_name, type->name);
818   xbt_abort();
819
820 }
821
822 /**
823  * The given datadesc must be a struct or union (abort if not).
824  * (useful to push the sizes of the upcoming arrays, for example)
825  */
826 void gras_datadesc_cb_field_send(gras_datadesc_type_t type,
827                                  const char *field_name,
828                                  gras_datadesc_type_cb_void_t send)
829 {
830
831   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);
832   field->send = send;
833 }
834
835
836 /**
837  * The value, which must be an int, unsigned int, long int or unsigned long int
838  * is pushed to the stacks of sizes and can then be retrieved with
839  * \ref gras_datadesc_ref_pop_arr or directly with \ref gras_cbps_i_pop.
840  */
841 void gras_datadesc_cb_field_push(gras_datadesc_type_t type,
842                                  const char *field_name)
843 {
844
845   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);
846   gras_datadesc_type_t sub_type = field->type;
847
848   DEBUG3("add a PUSHy cb to '%s' field (type '%s') of '%s'",
849          field_name, sub_type->name, type->name);
850   if (!strcmp("int", sub_type->name)) {
851     field->send = gras_datadesc_cb_push_int;
852   } else if (!strcmp("unsigned int", sub_type->name)) {
853     field->send = gras_datadesc_cb_push_uint;
854   } else if (!strcmp("long int", sub_type->name)) {
855     field->send = gras_datadesc_cb_push_lint;
856   } else if (!strcmp("unsigned long int", sub_type->name)) {
857     field->send = gras_datadesc_cb_push_ulint;
858   } else {
859     ERROR1
860       ("Field %s is not an int, unsigned int, long int neither unsigned long int",
861        sub_type->name);
862     xbt_abort();
863   }
864 }
865
866 /**
867  * Any previously pushed value is poped and the field value is multiplied to
868  * it. The result is then pushed back into the stack of sizes. It can then be
869  * retrieved with \ref gras_datadesc_ref_pop_arr or directly with \ref
870  * gras_cbps_i_pop.
871  *
872  * The field must be an int, unsigned int, long int or unsigned long int.
873  */
874 void gras_datadesc_cb_field_push_multiplier(gras_datadesc_type_t type,
875                                             const char *field_name)
876 {
877
878   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);
879   gras_datadesc_type_t sub_type = field->type;
880
881   DEBUG3("add a MPUSHy cb to '%s' field (type '%s') of '%s'",
882          field_name, sub_type->name, type->name);
883   if (!strcmp("int", sub_type->name)) {
884     field->send = gras_datadesc_cb_push_int_mult;
885   } else if (!strcmp("unsigned int", sub_type->name)) {
886     field->send = gras_datadesc_cb_push_uint_mult;
887   } else if (!strcmp("long int", sub_type->name)) {
888     field->send = gras_datadesc_cb_push_lint_mult;
889   } else if (!strcmp("unsigned long int", sub_type->name)) {
890     field->send = gras_datadesc_cb_push_ulint_mult;
891   } else {
892     ERROR1
893       ("Field %s is not an int, unsigned int, long int neither unsigned long int",
894        sub_type->name);
895     xbt_abort();
896   }
897 }
898
899 /**
900  * The given datadesc must be a struct or union (abort if not).
901  * (useful to put the function pointers to the right value, for example)
902  */
903 void gras_datadesc_cb_field_recv(gras_datadesc_type_t type,
904                                  const char *field_name,
905                                  gras_datadesc_type_cb_void_t recv)
906 {
907
908   gras_dd_cat_field_t field = gras_dd_find_field(type, field_name);
909   field->recv = recv;
910 }
911
912 /*
913  * Free a datadesc. Should only be called at xbt_exit.
914  */
915 void gras_datadesc_free(gras_datadesc_type_t * type)
916 {
917
918   DEBUG1("Let's free ddt %s", (*type)->name);
919
920   switch ((*type)->category_code) {
921   case e_gras_datadesc_type_cat_scalar:
922   case e_gras_datadesc_type_cat_ref:
923   case e_gras_datadesc_type_cat_array:
924     /* nothing to free in there */
925     break;
926
927   case e_gras_datadesc_type_cat_struct:
928     xbt_dynar_free(&((*type)->category.struct_data.fields));
929     break;
930
931   case e_gras_datadesc_type_cat_union:
932     xbt_dynar_free(&((*type)->category.union_data.fields));
933     break;
934
935   default:
936     /* datadesc was invalid. Killing it is like euthanasy, I guess */
937     break;
938   }
939   free((*type)->name);
940   free(*type);
941   type = NULL;
942 }
943
944 /**
945  * gras_datadesc_type_cmp:
946  *
947  * Compares two datadesc types with the same semantic than strcmp.
948  *
949  * This comparison does not take the set headers into account (name and ID),
950  * but only the payload (actual type description).
951  */
952 int gras_datadesc_type_cmp(const gras_datadesc_type_t d1,
953                            const gras_datadesc_type_t d2)
954 {
955   int ret;
956   unsigned int cpt;
957   gras_dd_cat_field_t field1, field2;
958   gras_datadesc_type_t field_desc_1, field_desc_2;
959
960   if (d1 == d2)
961     return 0;                   /* easy optimization */
962
963   if (!d1 && d2) {
964     DEBUG0("ddt_cmp: !d1 && d2 => 1");
965     return 1;
966   }
967   if (!d1 && !d2) {
968     DEBUG0("ddt_cmp: !d1 && !d2 => 0");
969     return 0;
970   }
971   if (d1 && !d2) {
972     DEBUG0("ddt_cmp: d1 && !d2 => -1");
973     return -1;
974   }
975
976   for (cpt = 0; cpt < gras_arch_count; cpt++) {
977     if (d1->size[cpt] != d2->size[cpt]) {
978       DEBUG5("ddt_cmp: %s->size=%ld  !=  %s->size=%ld (on %s)",
979              d1->name, d1->size[cpt], d2->name, d2->size[cpt],
980              gras_arches[cpt].name);
981       return d1->size[cpt] > d2->size[cpt] ? 1 : -1;
982     }
983
984     if (d1->alignment[cpt] != d2->alignment[cpt]) {
985       DEBUG5("ddt_cmp: %s->alignment=%ld  !=  %s->alignment=%ld (on %s)",
986              d1->name, d1->alignment[cpt], d2->name, d2->alignment[cpt],
987              gras_arches[cpt].name);
988       return d1->alignment[cpt] > d2->alignment[cpt] ? 1 : -1;
989     }
990
991     if (d1->aligned_size[cpt] != d2->aligned_size[cpt]) {
992       DEBUG5
993         ("ddt_cmp: %s->aligned_size=%ld  !=  %s->aligned_size=%ld (on %s)",
994          d1->name, d1->aligned_size[cpt], d2->name, d2->aligned_size[cpt],
995          gras_arches[cpt].name);
996       return d1->aligned_size[cpt] > d2->aligned_size[cpt] ? 1 : -1;
997     }
998   }
999
1000   if (d1->category_code != d2->category_code) {
1001     DEBUG4("ddt_cmp: %s->cat=%s  !=  %s->cat=%s",
1002            d1->name, gras_datadesc_cat_names[d1->category_code],
1003            d2->name, gras_datadesc_cat_names[d2->category_code]);
1004     return d1->category_code > d2->category_code ? 1 : -1;
1005   }
1006
1007   if (d1->send != d2->send) {
1008     DEBUG4("ddt_cmp: %s->send=%p  !=  %s->send=%p",
1009            d1->name, (void *) d1->send, d2->name, (void *) d2->send);
1010     return 1;                   /* ISO C forbids ordered comparisons of pointers to functions */
1011   }
1012
1013   if (d1->recv != d2->recv) {
1014     DEBUG4("ddt_cmp: %s->recv=%p  !=  %s->recv=%p",
1015            d1->name, (void *) d1->recv, d2->name, (void *) d2->recv);
1016     return 1;                   /* ISO C forbids ordered comparisons of pointers to functions */
1017   }
1018
1019   switch (d1->category_code) {
1020   case e_gras_datadesc_type_cat_scalar:
1021     if (d1->category.scalar_data.encoding !=
1022         d2->category.scalar_data.encoding)
1023       return d1->category.scalar_data.encoding >
1024         d2->category.scalar_data.encoding ? 1 : -1;
1025     break;
1026
1027   case e_gras_datadesc_type_cat_struct:
1028     if (xbt_dynar_length(d1->category.struct_data.fields) !=
1029         xbt_dynar_length(d2->category.struct_data.fields)) {
1030       DEBUG4("ddt_cmp: %s (having %lu fields) !=  %s (having %lu fields)",
1031              d1->name, xbt_dynar_length(d1->category.struct_data.fields),
1032              d2->name, xbt_dynar_length(d2->category.struct_data.fields));
1033
1034       return xbt_dynar_length(d1->category.struct_data.fields) >
1035         xbt_dynar_length(d2->category.struct_data.fields) ? 1 : -1;
1036     }
1037     xbt_dynar_foreach(d1->category.struct_data.fields, cpt, field1) {
1038
1039       field2 =
1040         xbt_dynar_get_as(d2->category.struct_data.fields, cpt,
1041                          gras_dd_cat_field_t);
1042       field_desc_1 = field1->type;
1043       field_desc_2 = field2->type;
1044       ret = gras_datadesc_type_cmp(field_desc_1, field_desc_2);
1045       if (ret) {
1046         DEBUG6("%s->field[%d]=%s != %s->field[%d]=%s",
1047                d1->name, cpt, field1->name, d2->name, cpt, field2->name);
1048         return ret;
1049       }
1050
1051     }
1052     break;
1053
1054   case e_gras_datadesc_type_cat_union:
1055     if (d1->category.union_data.selector != d2->category.union_data.selector)
1056       return 1;                 /* ISO C forbids ordered comparisons of pointers to functions */
1057
1058     if (xbt_dynar_length(d1->category.union_data.fields) !=
1059         xbt_dynar_length(d2->category.union_data.fields))
1060       return xbt_dynar_length(d1->category.union_data.fields) >
1061         xbt_dynar_length(d2->category.union_data.fields) ? 1 : -1;
1062
1063     xbt_dynar_foreach(d1->category.union_data.fields, cpt, field1) {
1064
1065       field2 =
1066         xbt_dynar_get_as(d2->category.union_data.fields, cpt,
1067                          gras_dd_cat_field_t);
1068       field_desc_1 = field1->type;
1069       field_desc_2 = field2->type;
1070       ret = gras_datadesc_type_cmp(field_desc_1, field_desc_2);
1071       if (ret)
1072         return ret;
1073
1074     }
1075     break;
1076
1077
1078   case e_gras_datadesc_type_cat_ref:
1079     if (d1->category.ref_data.selector != d2->category.ref_data.selector)
1080       return 1;                 /* ISO C forbids ordered comparisons of pointers to functions */
1081
1082     if (d1->category.ref_data.type != d2->category.ref_data.type)
1083       return d1->category.ref_data.type > d2->category.ref_data.type ? 1 : -1;
1084     break;
1085
1086   case e_gras_datadesc_type_cat_array:
1087     if (d1->category.array_data.type != d2->category.array_data.type)
1088       return d1->category.array_data.type >
1089         d2->category.array_data.type ? 1 : -1;
1090
1091     if (d1->category.array_data.fixed_size !=
1092         d2->category.array_data.fixed_size)
1093       return d1->category.array_data.fixed_size >
1094         d2->category.array_data.fixed_size ? 1 : -1;
1095
1096     if (d1->category.array_data.dynamic_size !=
1097         d2->category.array_data.dynamic_size)
1098       return 1;                 /* ISO C forbids ordered comparisons of pointers to functions */
1099
1100     break;
1101
1102   default:
1103     /* two stupidly created ddt are equally stupid ;) */
1104     break;
1105   }
1106   return 0;
1107
1108 }