Logo AND Algorithmique Numérique Distribuée

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