Logo AND Algorithmique Numérique Distribuée

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