Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d7e021d558c3daac0f841562e6c4746a37a5cba0
[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 /* Authors: Olivier Aumage, Martin Quinson                                  */
6 /* Copyright (C) 2003, 2004 the GRAS posse.                                 */
7
8 /* This program is free software; you can redistribute it and/or modify it
9    under the terms of the license (GNU LGPL) which comes with this package. */
10
11 #include "xbt/misc.h" /* min()/max() */
12 #include "gras/DataDesc/datadesc_private.h"
13
14 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(ddt_create,datadesc,"Creating new datadescriptions");
15
16 /**
17  * gras_ddt_freev:
18  *
19  * gime that memory back, dude. I mean it.
20  */
21 void gras_ddt_freev(void *ddt) {
22   gras_datadesc_type_t *type= (gras_datadesc_type_t *)ddt;
23   
24   if (type) {
25     gras_datadesc_free(type);
26   }
27 }
28
29 static gras_datadesc_type_t *gras_ddt_new(const char *name) {
30   gras_error_t errcode;
31   gras_datadesc_type_t *res;
32
33   GRAS_IN1("(%s)",name);
34   res=gras_new0(gras_datadesc_type_t,1);
35
36   res->name = (char*)strdup(name);
37   res->name_len = strlen(name);
38   res->cycle = 0;
39       
40   gras_set_add(gras_datadesc_set_local,
41                (gras_set_elm_t*)res,&gras_ddt_freev);
42   GRAS_OUT;
43   return res;
44 }
45
46 /**
47  * gras_datadesc_by_name:
48  *
49  * Retrieve a type from its name
50  */
51 gras_datadesc_type_t *gras_datadesc_by_name(const char *name) {
52
53   gras_datadesc_type_t *type;
54
55   GRAS_IN1("(%s)",name);
56   if (gras_set_get_by_name(gras_datadesc_set_local,
57                            name,(gras_set_elm_t**)&type) == no_error) {
58     GRAS_OUT;
59     return type;
60   } else { 
61     GRAS_OUT;
62     return NULL;
63   }
64 }
65
66 /**
67  * gras_datadesc_by_id:
68  *
69  * Retrieve a type from its code
70  */
71 gras_error_t gras_datadesc_by_id(long int               code,
72                                  gras_datadesc_type_t **type) {
73   GRAS_IN;
74   return gras_set_get_by_id(gras_datadesc_set_local,
75                             code,(gras_set_elm_t**)type);
76 }
77
78 /**
79  * gras_datadesc_scalar:
80  *
81  * Create a new scalar and give a pointer to it 
82  */
83 gras_datadesc_type_t *
84   gras_datadesc_scalar(const char                      *name,
85                        gras_ddt_scalar_type_t           type,
86                        enum e_gras_dd_scalar_encoding   encoding) {
87
88   gras_datadesc_type_t *res;
89   long int arch;
90
91   GRAS_IN;
92   res = gras_datadesc_by_name(name);
93   if (res) {
94     gras_assert1(res->category_code == e_gras_datadesc_type_cat_scalar,
95                  "Redefinition of type %s does not match", name);
96     gras_assert1(res->category.scalar_data.encoding == encoding,
97                  "Redefinition of type %s does not match", name);
98     gras_assert1(res->category.scalar_data.type == type,
99                  "Redefinition of type %s does not match", name);
100     VERB1("Discarding redefinition of %s",name);
101     return res;
102   }
103   res = gras_ddt_new(name);
104
105   for (arch = 0; arch < gras_arch_count; arch ++) {
106     long int sz;
107     long int mask;
108     res->size[arch]         = gras_arches[arch].sizeofs[type];
109     res->alignment[arch]    = gras_arches[arch].boundaries[type];
110     res->aligned_size[arch] = aligned(res->size[arch], res->alignment[arch]);
111 /* FIXME: kill the following after discution with Oli */
112 #if 0
113     sz = res->size[arch];
114     mask = sz;
115     
116     /* just in case you wonder, x>>1 == x/2 on all architectures when x>=0
117        and a size is always>=0 */
118     
119     /* make sure mask have all the bits under the biggest one of size set to 1
120        Example: size=000100101 => mask=0000111111 */
121     while ((sz >>= 1)) {
122       mask |= sz;
123     } 
124     
125     if (res->size[arch] & (mask >> 1)) { /* if size have bits to one beside its biggest */
126       /* size is not a power of 2 */
127       /* alignment= next power of 2 after size */
128       res->alignment[arch] = (res->size[arch] & ~(mask >> 1)) << 1;
129       gras_assert0(res->alignment[arch] != 0,
130                    "scalar type too large");
131       
132       res->aligned_size[arch] = aligned(res->size[arch], res->alignment[arch]);
133       gras_assert0 (res->aligned_size[arch] >= 0,
134                     "scalar type too large");
135       
136     } else {
137       /* size is a power of 2, life is great */
138       res->alignment[arch]       = res->size[arch];
139       res->aligned_size[arch]    = res->size[arch];
140     }
141 #endif     
142   }
143
144   res->category_code                 = e_gras_datadesc_type_cat_scalar;
145   res->category.scalar_data.encoding = encoding;
146   res->category.scalar_data.type     = type;
147   GRAS_OUT;
148   
149   return res;
150 }
151
152
153 /**
154  * gras_dd_cat_field_free:
155  *
156  * Frees one struct or union field
157  */
158 void gras_dd_cat_field_free(void *f) {
159   gras_dd_cat_field_t *field = *(gras_dd_cat_field_t **)f;
160   GRAS_IN;
161   if (field) {
162     if (field->name) 
163       gras_free(field->name);
164     gras_free(field);
165   }
166   GRAS_OUT;
167 }
168
169 /**
170  * gras_datadesc_struct:
171  *
172  * Create a new struct and give a pointer to it 
173  */
174 gras_datadesc_type_t *
175   gras_datadesc_struct(const char            *name) {
176
177   gras_error_t errcode;
178   gras_datadesc_type_t *res;
179   long int arch;
180   
181   GRAS_IN1("(%s)",name);
182   res = gras_datadesc_by_name(name);
183   if (res) {
184     /* FIXME: Check that field redefinition matches */
185     gras_assert1(res->category_code == e_gras_datadesc_type_cat_struct,
186                  "Redefinition of type %s does not match", name);
187     VERB1("Discarding redefinition of %s",name);
188     return res;
189   }
190   res = gras_ddt_new(name);
191
192   for (arch=0; arch<gras_arch_count; arch ++) {
193     res->size[arch] = 0;
194     res->alignment[arch] = 0;
195     res->aligned_size[arch] = 0;
196   }
197   res->category_code = e_gras_datadesc_type_cat_struct;
198   res->category.struct_data.fields = 
199        gras_dynar_new(sizeof(gras_dd_cat_field_t*),
200                       &gras_dd_cat_field_free);
201
202   GRAS_OUT;
203   return res;
204 }
205
206 /**
207  * gras_datadesc_struct_append:
208  *
209  * Append a field to the struct
210  */
211 void
212 gras_datadesc_struct_append(gras_datadesc_type_t  *struct_type,
213                             const char            *name,
214                             gras_datadesc_type_t  *field_type) {
215
216   gras_error_t errcode;
217   gras_dd_cat_field_t *field;
218   int arch;
219
220   GRAS_IN3("(%s %s.%s;)",field_type->name,struct_type->name,name);
221   if (struct_type->category.struct_data.closed) {
222     VERB1("Ignoring request to add field to struct %s (closed. Redefinition?)",
223           struct_type->name);
224     return;
225   }
226
227   gras_assert1(field_type->size != 0,
228                "Cannot add a dynamically sized field in structure %s",
229                struct_type->name);
230     
231   field=gras_new(gras_dd_cat_field_t,1);
232   field->name   = (char*)strdup(name);
233
234   DEBUG0("----------------");
235   DEBUG3("PRE s={size=%ld,align=%ld,asize=%ld}",
236          struct_type->size[GRAS_THISARCH], 
237          struct_type->alignment[GRAS_THISARCH], 
238          struct_type->aligned_size[GRAS_THISARCH]);
239      
240      
241   for (arch=0; arch<gras_arch_count; arch ++) {
242     field->offset[arch] = aligned(struct_type->size[arch],
243                                   field_type->alignment[arch]);
244
245     struct_type->size[arch] = field->offset[arch] + field_type->size[arch];
246     struct_type->alignment[arch] = max(struct_type->alignment[arch],
247                                        field_type->alignment[arch]);
248     struct_type->aligned_size[arch] = aligned(struct_type->size[arch],
249                                               struct_type->alignment[arch]);
250   }
251   field->type   = field_type;
252   field->pre    = NULL;
253   field->post   = NULL;
254   
255   gras_dynar_push(struct_type->category.struct_data.fields, &field);
256
257   DEBUG3("Push a %s into %s at offset %ld.",
258          field_type->name, struct_type->name,field->offset[GRAS_THISARCH]);
259   DEBUG3("  f={size=%ld,align=%ld,asize=%ld}",
260          field_type->size[GRAS_THISARCH], 
261          field_type->alignment[GRAS_THISARCH], 
262          field_type->aligned_size[GRAS_THISARCH]);
263   DEBUG3("  s={size=%ld,align=%ld,asize=%ld}",
264          struct_type->size[GRAS_THISARCH], 
265          struct_type->alignment[GRAS_THISARCH], 
266          struct_type->aligned_size[GRAS_THISARCH]);
267   GRAS_OUT;
268 }
269
270 void
271 gras_datadesc_struct_close(gras_datadesc_type_t  *struct_type) {
272   GRAS_IN;
273   struct_type->category.struct_data.closed = 1;
274 }
275
276 /**
277  * gras_datadesc_cycle_set:
278  * 
279  * Tell GRAS that the pointers of the type described by @ddt may present
280  * some loop, and that the cycle detection mecanism is needed.
281  *
282  * Note that setting this option when not needed have a rather bad effect 
283  * on the performance (several times slower on big data).
284  */
285 void
286 gras_datadesc_cycle_set(gras_datadesc_type_t  *ddt) {
287   ddt->cycle = 1;
288 }
289 /**
290  * gras_datadesc_cycle_unset:
291  * 
292  * Tell GRAS that the pointers of the type described by @ddt do not present
293  * any loop and that cycle detection mecanism are not needed.
294  * (default)
295  */
296 void
297 gras_datadesc_cycle_unset(gras_datadesc_type_t *ddt) {
298   ddt->cycle = 0;
299 }
300
301 /**
302  * gras_datadesc_union:
303  *
304  * Create a new union and give a pointer to it 
305  */
306 gras_datadesc_type_t *
307 gras_datadesc_union(const char                   *name,
308                     gras_datadesc_type_cb_int_t   selector) {
309
310   gras_error_t errcode;
311   gras_datadesc_type_t *res;
312   int arch;
313
314   GRAS_IN1("(%s)",name);
315   gras_assert0(selector,
316                "Attempt to creat an union without field_count function");
317
318   res = gras_datadesc_by_name(name);
319   if (res) {
320     /* FIXME: Check that field redefinition matches */
321     gras_assert1(res->category_code == e_gras_datadesc_type_cat_union,
322                  "Redefinition of type %s does not match", name);
323     gras_assert1(res->category.union_data.selector == selector,
324                  "Redefinition of type %s does not match", name);
325     VERB1("Discarding redefinition of %s",name);
326     return res;
327   }
328
329   res = gras_ddt_new(name);
330
331   for (arch=0; arch<gras_arch_count; arch ++) {
332      res->size[arch] = 0;
333      res->alignment[arch] = 0;
334      res->aligned_size[arch] = 0;
335   }
336
337   res->category_code            = e_gras_datadesc_type_cat_union;
338   res->category.union_data.fields =
339      gras_dynar_new(sizeof(gras_dd_cat_field_t*),
340                     &gras_dd_cat_field_free);
341   res->category.union_data.selector = selector;
342
343   return res;
344 }
345
346 /**
347  * gras_datadesc_union_append:
348  *
349  * Append a field to the union
350  */
351 void
352 gras_datadesc_union_append(gras_datadesc_type_t  *union_type,
353                            const char            *name,
354                            gras_datadesc_type_t  *field_type) {
355
356   gras_dd_cat_field_t *field;
357   int arch;
358
359   GRAS_IN3("(%s %s.%s;)",field_type->name,union_type->name,name);
360   gras_assert1(field_type->size != 0,
361                "Cannot add a dynamically sized field in union %s",
362                union_type->name);
363
364   if (union_type->category.union_data.closed) {
365     VERB1("Ignoring request to add field to union %s (closed)",
366            union_type->name);
367     return;
368   }
369     
370   field=gras_new0(gras_dd_cat_field_t,1);
371
372   field->name   = (char*)strdup(name);
373   field->type   = field_type;
374   /* All offset are left to 0 in an union */
375   
376   gras_dynar_push(union_type->category.union_data.fields, &field);
377
378   for (arch=0; arch<gras_arch_count; arch ++) {
379     union_type->size[arch] = max(union_type->size[arch],
380                                  field_type->size[arch]);
381     union_type->alignment[arch] = max(union_type->alignment[arch],
382                                       field_type->alignment[arch]);
383     union_type->aligned_size[arch] = aligned(union_type->size[arch],
384                                              union_type->alignment[arch]);
385   }
386 }
387
388 void
389 gras_datadesc_union_close(gras_datadesc_type_t  *union_type) {
390    union_type->category.union_data.closed = 1;
391 }
392 /**
393  * gras_datadesc_ref:
394  *
395  * Create a new ref to a fixed type and give a pointer to it 
396  */
397 gras_datadesc_type_t *
398   gras_datadesc_ref(const char             *name,
399                     gras_datadesc_type_t   *referenced_type) {
400
401   gras_error_t errcode;
402   gras_datadesc_type_t *res;
403   gras_datadesc_type_t *pointer_type = gras_datadesc_by_name("data pointer");
404   int arch;
405
406   GRAS_IN1("(%s)",name);
407   res = gras_datadesc_by_name(name);
408   if (res) {
409     gras_assert1(res->category_code == e_gras_datadesc_type_cat_ref,
410                  "Redefinition of %s does not match",name);
411     gras_assert1(res->category.ref_data.type == referenced_type,
412                  "Redefinition of %s does not match",name);
413     gras_assert1(res->category.ref_data.selector == NULL,
414                  "Redefinition of %s does not match",name);
415     VERB1("Discarding redefinition of %s",name);
416     return res;
417   }
418
419   res = gras_ddt_new(name);
420
421   gras_assert0(pointer_type, "Cannot get the description of data pointer");
422       
423   for (arch=0; arch<gras_arch_count; arch ++){
424     res->size[arch] = pointer_type->size[arch];
425     res->alignment[arch] = pointer_type->alignment[arch];
426     res->aligned_size[arch] = pointer_type->aligned_size[arch];
427   }
428   
429   res->category_code              = e_gras_datadesc_type_cat_ref;
430   res->category.ref_data.type     = referenced_type;
431   res->category.ref_data.selector = NULL;
432
433   return res;
434 }
435 /**
436  * gras_datadesc_ref_generic:
437  *
438  * Create a new ref to a type given at use time, and give a pointer to it 
439  */
440 gras_datadesc_type_t *
441   gras_datadesc_ref_generic(const char                *name,
442                             gras_datadesc_selector_t   selector) {
443
444   gras_datadesc_type_t *res;
445   gras_datadesc_type_t *pointer_type = gras_datadesc_by_name("data pointer");
446   int arch;
447
448   GRAS_IN1("(%s)",name);
449   res = gras_datadesc_by_name(name);
450   if (res) {
451     gras_assert1(res->category_code == e_gras_datadesc_type_cat_ref,
452                  "Redefinition of type %s does not match", name);
453     gras_assert1(res->category.ref_data.type == NULL,
454                  "Redefinition of type %s does not match", name);
455     gras_assert1(res->category.ref_data.selector == selector,
456                  "Redefinition of type %s does not match", name);
457     VERB1("Discarding redefinition of %s",name);
458     return res;
459   }
460   res = gras_ddt_new(name);
461
462   gras_assert0(pointer_type, "Cannot get the description of data pointer");
463       
464   for (arch=0; arch<gras_arch_count; arch ++) {
465     res->size[arch] = pointer_type->size[arch];
466     res->alignment[arch] = pointer_type->alignment[arch];
467     res->aligned_size[arch] = pointer_type->aligned_size[arch];
468   }
469
470   res->category_code            = e_gras_datadesc_type_cat_ref;
471
472   res->category.ref_data.type     = NULL;
473   res->category.ref_data.selector = selector;
474
475   return res;
476 }
477
478 /**
479  * gras_datadesc_array_fixed:
480  *
481  * Create a new array and give a pointer to it 
482  */
483 gras_datadesc_type_t *
484   gras_datadesc_array_fixed(const char              *name,
485                             gras_datadesc_type_t    *element_type,
486                             long int                 fixed_size) {
487
488   gras_datadesc_type_t *res;
489   int arch;
490
491   GRAS_IN1("(%s)",name);
492   res = gras_datadesc_by_name(name);
493   if (res) {
494     gras_assert1(res->category_code == e_gras_datadesc_type_cat_array,
495                  "Redefinition of type %s does not match", name);
496     gras_assert1(res->category.array_data.type == element_type,
497                  "Redefinition of type %s does not match", name);
498     gras_assert1(res->category.array_data.fixed_size == fixed_size,
499                  "Redefinition of type %s does not match", name);
500     gras_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   gras_assert1(fixed_size > 0, "'%s' is a array of null 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  * gras_datadesc_array_dyn:
525  *
526  * Create a new array and give a pointer to it 
527  */
528 gras_datadesc_type_t *
529   gras_datadesc_array_dyn(const char                      *name,
530                           gras_datadesc_type_t            *element_type,
531                           gras_datadesc_type_cb_int_t      dynamic_size) {
532
533   gras_datadesc_type_t *res;
534   int arch;
535
536   GRAS_IN1("(%s)",name);
537   gras_assert1(dynamic_size,
538                "'%s' is a dynamic array without size discriminant",
539                name);
540
541   res = gras_datadesc_by_name(name);
542   if (res) {
543     gras_assert1(res->category_code == e_gras_datadesc_type_cat_array,
544                  "Redefinition of type %s does not match", name);
545     gras_assert1(res->category.array_data.type == element_type,
546                  "Redefinition of type %s does not match", name);
547     gras_assert1(res->category.array_data.fixed_size == 0,
548                  "Redefinition of type %s does not match", name);
549     gras_assert1(res->category.array_data.dynamic_size == dynamic_size,
550                  "Redefinition of type %s does not match", name);
551     VERB1("Discarding redefinition of %s",name);
552
553     return res;
554   }
555
556   res = gras_ddt_new(name);
557
558   for (arch=0; arch<gras_arch_count; arch ++) {
559     res->size[arch] = 0; /* make sure it indicates "dynamic" */
560     res->alignment[arch] = element_type->alignment[arch];
561     res->aligned_size[arch] = 0; /*FIXME: That was so in GS, but looks stupid*/
562   }
563
564   res->category_code            = e_gras_datadesc_type_cat_array;
565
566   res->category.array_data.type         = element_type;
567   res->category.array_data.fixed_size   = 0;
568   res->category.array_data.dynamic_size = dynamic_size;
569
570   return res;
571 }
572
573 /**
574  * gras_datadesc_ref_pop_arr:
575  *
576  * Most of the time, you want to include a reference in your structure which
577  * is a pointer to a dynamic array whose size is fixed by another field of 
578  * your structure.
579  *
580  * This case pops up so often that this function was created to take care of
581  * this case. It creates a dynamic array type whose size is poped from the 
582  * current cbps, and then create a reference to it.
583  *
584  * The name of the created datatype will be the name of the element type, with
585  * '[]*' appended to it.
586  *
587  * Then to use it, you just have to make sure that your structure pre-callback
588  * does push the size of the array in the cbps (using #gras_cbps_i_push), and 
589  * you are set. 
590  *
591  * But be remember that this is a stack. If you have two different pop_arr, you
592  * should push the second one first, so that the first one is on the top of the 
593  * list when the first field gets transfered.
594  *
595  */
596 gras_datadesc_type_t *
597   gras_datadesc_ref_pop_arr(gras_datadesc_type_t  *element_type) {
598
599   gras_datadesc_type_t *res;
600   char *name=(char*)gras_malloc(strlen(element_type->name) + 4);
601
602   sprintf(name,"%s[]",element_type->name);
603
604   res = gras_datadesc_array_dyn(name,element_type,
605                                 gras_datadesc_cb_pop);
606
607   sprintf(name,"%s[]*",element_type->name);
608   res = gras_datadesc_ref(name,res);
609
610   gras_free(name);
611
612   return res;
613 }
614 gras_error_t
615 gras_datadesc_import_nws(const char           *name,
616                          const DataDescriptor *desc,
617                          size_t                howmany,
618                          gras_datadesc_type_t **dst) {
619   RAISE_UNIMPLEMENTED;
620 }
621
622 /**
623  * gras_datadesc_cb_send:
624  *
625  * Add a pre-send callback to this datadesc.
626  * (useful to push the sizes of the upcoming arrays, for example)
627  */
628 void gras_datadesc_cb_send (gras_datadesc_type_t         *type,
629                             gras_datadesc_type_cb_void_t  send) {
630   type->send = send;
631 }
632 /**
633  * gras_datadesc_cb_recv:
634  *
635  * Add a post-receive callback to this datadesc.
636  * (useful to put the function pointers to the rigth value, for example)
637  */
638 void gras_datadesc_cb_recv(gras_datadesc_type_t         *type,
639                            gras_datadesc_type_cb_void_t  recv) {
640   type->recv = recv;
641 }
642 /**
643  * gras_dd_find_field:
644  * 
645  * Returns the type descriptor of the given field. Abort on error.
646  */
647 static gras_datadesc_type_t *
648   gras_dd_find_field(gras_datadesc_type_t         *type,
649                      const char                   *field_name) {
650    gras_datadesc_type_t *sub_type=NULL;
651    gras_dynar_t         *field_array;
652    
653    gras_dd_cat_field_t  *field=NULL;
654    int                   field_num;
655    
656    if (type->category_code == e_gras_datadesc_type_cat_union) {
657       field_array = type->category.union_data.fields;
658    } else if (type->category_code == e_gras_datadesc_type_cat_struct) {
659       field_array = type->category.struct_data.fields;
660    } else {
661       ERROR2("%s (%p) is not a struct nor an union. There is no field.", type->name,(void*)type);
662       gras_abort();
663    }
664    gras_dynar_foreach(field_array,field_num,field) {
665       if (!strcmp(field_name,field->name)) {
666          return field->type;
667       }
668    }
669    ERROR2("No field nammed %s in %s",field_name,type->name);
670    gras_abort();
671
672 }
673                                   
674 /**
675  * gras_datadesc_cb_field_send:
676  *
677  * Add a pre-send callback to the given field of the datadesc (which must be a struct or union).
678  * (useful to push the sizes of the upcoming arrays, for example)
679  */
680 void gras_datadesc_cb_field_send (gras_datadesc_type_t         *type,
681                                   const char                   *field_name,
682                                   gras_datadesc_type_cb_void_t  send) {
683    
684    gras_datadesc_type_t *sub_type=gras_dd_find_field(type,field_name);   
685    sub_type->send = send;
686 }
687
688 /**
689  * gras_datadesc_cb_field_push:
690  *
691  * Add a pre-send callback to the given field resulting in its value to be pushed to
692  * the stack of sizes. It must be a int, unsigned int, long int or unsigned long int.
693  */
694 void gras_datadesc_cb_field_push (gras_datadesc_type_t         *type,
695                                   const char                   *field_name) {
696    
697    gras_datadesc_type_t *sub_type=gras_dd_find_field(type,field_name);
698    if (!strcmp("int",sub_type->name)) {
699       sub_type->send = gras_datadesc_cb_push_int;
700    } else if (!strcmp("unsigned int",sub_type->name)) {
701       sub_type->send = gras_datadesc_cb_push_uint;
702    } else if (!strcmp("long int",sub_type->name)) {
703       sub_type->send = gras_datadesc_cb_push_lint;
704    } else if (!strcmp("unsigned long int",sub_type->name)) {
705       sub_type->send = gras_datadesc_cb_push_ulint;
706    } else {
707       ERROR1("Field %s is not an int, unsigned int, long int neither unsigned long int",
708              sub_type->name);
709       gras_abort();
710    }
711 }
712 /**
713  * gras_datadesc_cb_field_recv:
714  *
715  * Add a post-receive callback to the given field of the datadesc (which must be a struct or union).
716  * (useful to put the function pointers to the right value, for example)
717  */
718 void gras_datadesc_cb_field_recv(gras_datadesc_type_t         *type,
719                                  const char                   *field_name,
720                                  gras_datadesc_type_cb_void_t  recv) {
721    
722    gras_datadesc_type_t *sub_type=gras_dd_find_field(type,field_name);   
723    sub_type->recv = recv;
724 }
725
726 /**
727  * gras_datadesc_free:
728  *
729  * Free a datadesc. Should only be called at gras_exit. 
730  */
731 void gras_datadesc_free(gras_datadesc_type_t *type) {
732
733   DEBUG1("Let's free ddt %s",type->name);
734   
735   switch (type->category_code) {
736   case e_gras_datadesc_type_cat_scalar:
737   case e_gras_datadesc_type_cat_ref:
738   case e_gras_datadesc_type_cat_array:
739     /* nothing to free in there */
740     break;
741     
742   case e_gras_datadesc_type_cat_ignored:
743     if (type->category.ignored_data.free_func) {
744       type->category.ignored_data.free_func
745         (type->category.ignored_data.default_value);
746     }
747     break;
748     
749   case e_gras_datadesc_type_cat_struct:
750     gras_dynar_free(type->category.struct_data.fields);
751     break;
752     
753   case e_gras_datadesc_type_cat_union:
754     gras_dynar_free(type->category.union_data.fields);
755     break;
756     
757   default:
758     /* datadesc was invalid. Killing it is like euthanasy, I guess */
759     break;
760   }
761   gras_free(type->name);
762   gras_free(type);
763 }