Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
The change Arnaud wanted so much: Big Star Eradication (plus some more, check the...
[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(s_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_assert2(field_type,
221                "Cannot add the field '%s' into struct '%s': its type is NULL. Typo in get_by_name?",
222                name,struct_type->name);
223   GRAS_IN3("(%s %s.%s;)",field_type->name,struct_type->name,name);
224   if (struct_type->category.struct_data.closed) {
225     VERB1("Ignoring request to add field to struct %s (closed. Redefinition?)",
226           struct_type->name);
227     return;
228   }
229
230   gras_assert1(field_type->size != 0,
231                "Cannot add a dynamically sized field in structure %s",
232                struct_type->name);
233     
234   field=gras_new(s_gras_dd_cat_field_t,1);
235   field->name   = (char*)strdup(name);
236
237   DEBUG0("----------------");
238   DEBUG3("PRE s={size=%ld,align=%ld,asize=%ld}",
239          struct_type->size[GRAS_THISARCH], 
240          struct_type->alignment[GRAS_THISARCH], 
241          struct_type->aligned_size[GRAS_THISARCH]);
242      
243      
244   for (arch=0; arch<gras_arch_count; arch ++) {
245     field->offset[arch] = aligned(struct_type->size[arch],
246                                   field_type->alignment[arch]);
247
248     struct_type->size[arch] = field->offset[arch] + field_type->size[arch];
249     struct_type->alignment[arch] = max(struct_type->alignment[arch],
250                                        field_type->alignment[arch]);
251     struct_type->aligned_size[arch] = aligned(struct_type->size[arch],
252                                               struct_type->alignment[arch]);
253   }
254   field->type   = field_type;
255   field->pre    = NULL;
256   field->post   = NULL;
257   
258   gras_dynar_push(struct_type->category.struct_data.fields, &field);
259
260   DEBUG3("Push a %s into %s at offset %ld.",
261          field_type->name, struct_type->name,field->offset[GRAS_THISARCH]);
262   DEBUG3("  f={size=%ld,align=%ld,asize=%ld}",
263          field_type->size[GRAS_THISARCH], 
264          field_type->alignment[GRAS_THISARCH], 
265          field_type->aligned_size[GRAS_THISARCH]);
266   DEBUG3("  s={size=%ld,align=%ld,asize=%ld}",
267          struct_type->size[GRAS_THISARCH], 
268          struct_type->alignment[GRAS_THISARCH], 
269          struct_type->aligned_size[GRAS_THISARCH]);
270   GRAS_OUT;
271 }
272
273 void
274 gras_datadesc_struct_close(gras_datadesc_type_t struct_type) {
275   GRAS_IN;
276   struct_type->category.struct_data.closed = 1;
277 }
278
279 /**
280  * gras_datadesc_cycle_set:
281  * 
282  * Tell GRAS that the pointers of the type described by @ddt may present
283  * some loop, and that the cycle detection mecanism is needed.
284  *
285  * Note that setting this option when not needed have a rather bad effect 
286  * on the performance (several times slower on big data).
287  */
288 void
289 gras_datadesc_cycle_set(gras_datadesc_type_t ddt) {
290   ddt->cycle = 1;
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 mecanism are not needed.
297  * (default)
298  */
299 void
300 gras_datadesc_cycle_unset(gras_datadesc_type_t ddt) {
301   ddt->cycle = 0;
302 }
303
304 /**
305  * gras_datadesc_union:
306  *
307  * Create a new union and give a pointer to it 
308  */
309 gras_datadesc_type_t 
310 gras_datadesc_union(const char                   *name,
311                     gras_datadesc_type_cb_int_t   selector) {
312
313   gras_error_t errcode;
314   gras_datadesc_type_t res;
315   int arch;
316
317   GRAS_IN1("(%s)",name);
318   gras_assert0(selector,
319                "Attempt to creat an union without field_count function");
320
321   res = gras_datadesc_by_name(name);
322   if (res) {
323     /* FIXME: Check that field redefinition matches */
324     gras_assert1(res->category_code == e_gras_datadesc_type_cat_union,
325                  "Redefinition of type %s does not match", name);
326     gras_assert1(res->category.union_data.selector == selector,
327                  "Redefinition of type %s does not match", name);
328     VERB1("Discarding redefinition of %s",name);
329     return res;
330   }
331
332   res = gras_ddt_new(name);
333
334   for (arch=0; arch<gras_arch_count; arch ++) {
335      res->size[arch] = 0;
336      res->alignment[arch] = 0;
337      res->aligned_size[arch] = 0;
338   }
339
340   res->category_code            = e_gras_datadesc_type_cat_union;
341   res->category.union_data.fields =
342      gras_dynar_new(sizeof(gras_dd_cat_field_t*),
343                     &gras_dd_cat_field_free);
344   res->category.union_data.selector = selector;
345
346   return res;
347 }
348
349 /**
350  * gras_datadesc_union_append:
351  *
352  * Append a field to the union
353  */
354 void
355 gras_datadesc_union_append(gras_datadesc_type_t  union_type,
356                            const char           *name,
357                            gras_datadesc_type_t  field_type) {
358
359   gras_dd_cat_field_t field;
360   int arch;
361
362   GRAS_IN3("(%s %s.%s;)",field_type->name,union_type->name,name);
363   gras_assert1(field_type->size != 0,
364                "Cannot add a dynamically sized field in union %s",
365                union_type->name);
366
367   if (union_type->category.union_data.closed) {
368     VERB1("Ignoring request to add field to union %s (closed)",
369            union_type->name);
370     return;
371   }
372     
373   field=gras_new0(s_gras_dd_cat_field_t,1);
374
375   field->name   = (char*)strdup(name);
376   field->type   = field_type;
377   /* All offset are left to 0 in an union */
378   
379   gras_dynar_push(union_type->category.union_data.fields, &field);
380
381   for (arch=0; arch<gras_arch_count; arch ++) {
382     union_type->size[arch] = max(union_type->size[arch],
383                                  field_type->size[arch]);
384     union_type->alignment[arch] = max(union_type->alignment[arch],
385                                       field_type->alignment[arch]);
386     union_type->aligned_size[arch] = aligned(union_type->size[arch],
387                                              union_type->alignment[arch]);
388   }
389 }
390
391 void
392 gras_datadesc_union_close(gras_datadesc_type_t union_type) {
393    union_type->category.union_data.closed = 1;
394 }
395 /**
396  * gras_datadesc_ref:
397  *
398  * Create a new ref to a fixed type and give a pointer to it 
399  */
400 gras_datadesc_type_t 
401   gras_datadesc_ref(const char           *name,
402                     gras_datadesc_type_t  referenced_type) {
403
404   gras_error_t errcode;
405   gras_datadesc_type_t res;
406   gras_datadesc_type_t pointer_type = gras_datadesc_by_name("data pointer");
407   int arch;
408
409   GRAS_IN1("(%s)",name);
410   res = gras_datadesc_by_name(name);
411   if (res) {
412     gras_assert1(res->category_code == e_gras_datadesc_type_cat_ref,
413                  "Redefinition of %s does not match",name);
414     gras_assert1(res->category.ref_data.type == referenced_type,
415                  "Redefinition of %s does not match",name);
416     gras_assert1(res->category.ref_data.selector == NULL,
417                  "Redefinition of %s does not match",name);
418     VERB1("Discarding redefinition of %s",name);
419     return res;
420   }
421
422   res = gras_ddt_new(name);
423
424   gras_assert0(pointer_type, "Cannot get the description of data pointer");
425       
426   for (arch=0; arch<gras_arch_count; arch ++){
427     res->size[arch] = pointer_type->size[arch];
428     res->alignment[arch] = pointer_type->alignment[arch];
429     res->aligned_size[arch] = pointer_type->aligned_size[arch];
430   }
431   
432   res->category_code              = e_gras_datadesc_type_cat_ref;
433   res->category.ref_data.type     = referenced_type;
434   res->category.ref_data.selector = NULL;
435
436   return res;
437 }
438 /**
439  * gras_datadesc_ref_generic:
440  *
441  * Create a new ref to a type given at use time, and give a pointer to it 
442  */
443 gras_datadesc_type_t 
444   gras_datadesc_ref_generic(const char                *name,
445                             gras_datadesc_selector_t   selector) {
446
447   gras_datadesc_type_t res;
448   gras_datadesc_type_t pointer_type = gras_datadesc_by_name("data pointer");
449   int arch;
450
451   GRAS_IN1("(%s)",name);
452   res = gras_datadesc_by_name(name);
453   if (res) {
454     gras_assert1(res->category_code == e_gras_datadesc_type_cat_ref,
455                  "Redefinition of type %s does not match", name);
456     gras_assert1(res->category.ref_data.type == NULL,
457                  "Redefinition of type %s does not match", name);
458     gras_assert1(res->category.ref_data.selector == selector,
459                  "Redefinition of type %s does not match", name);
460     VERB1("Discarding redefinition of %s",name);
461     return res;
462   }
463   res = gras_ddt_new(name);
464
465   gras_assert0(pointer_type, "Cannot get the description of data pointer");
466       
467   for (arch=0; arch<gras_arch_count; arch ++) {
468     res->size[arch] = pointer_type->size[arch];
469     res->alignment[arch] = pointer_type->alignment[arch];
470     res->aligned_size[arch] = pointer_type->aligned_size[arch];
471   }
472
473   res->category_code            = e_gras_datadesc_type_cat_ref;
474
475   res->category.ref_data.type     = NULL;
476   res->category.ref_data.selector = selector;
477
478   return res;
479 }
480
481 /**
482  * gras_datadesc_array_fixed:
483  *
484  * Create a new array and give a pointer to it 
485  */
486 gras_datadesc_type_t 
487   gras_datadesc_array_fixed(const char           *name,
488                             gras_datadesc_type_t  element_type,
489                             long int              fixed_size) {
490
491   gras_datadesc_type_t res;
492   int arch;
493
494   GRAS_IN1("(%s)",name);
495   res = gras_datadesc_by_name(name);
496   if (res) {
497     gras_assert1(res->category_code == e_gras_datadesc_type_cat_array,
498                  "Redefinition of type %s does not match", name);
499     gras_assert1(res->category.array_data.type == element_type,
500                  "Redefinition of type %s does not match", name);
501     gras_assert1(res->category.array_data.fixed_size == fixed_size,
502                  "Redefinition of type %s does not match", name);
503     gras_assert1(res->category.array_data.dynamic_size == NULL,
504                  "Redefinition of type %s does not match", name);
505     VERB1("Discarding redefinition of %s",name);
506
507     return res;
508   }
509   res = gras_ddt_new(name);
510
511   gras_assert1(fixed_size > 0, "'%s' is a array of null fixed size",name);
512   for (arch=0; arch<gras_arch_count; arch ++) {
513     res->size[arch] = fixed_size * element_type->aligned_size[arch];
514     res->alignment[arch] = element_type->alignment[arch];
515     res->aligned_size[arch] = res->size[arch];
516   }  
517
518   res->category_code            = e_gras_datadesc_type_cat_array;
519
520   res->category.array_data.type         = element_type;
521   res->category.array_data.fixed_size   = fixed_size;
522   res->category.array_data.dynamic_size = NULL;
523
524   return res;
525 }
526 /**
527  * gras_datadesc_array_dyn:
528  *
529  * Create a new array and give a pointer to it 
530  */
531 gras_datadesc_type_t 
532   gras_datadesc_array_dyn(const char                  *name,
533                           gras_datadesc_type_t         element_type,
534                           gras_datadesc_type_cb_int_t  dynamic_size) {
535
536   gras_datadesc_type_t res;
537   int arch;
538
539   GRAS_IN1("(%s)",name);
540   gras_assert1(dynamic_size,
541                "'%s' is a dynamic array without size discriminant",
542                name);
543
544   res = gras_datadesc_by_name(name);
545   if (res) {
546     gras_assert1(res->category_code == e_gras_datadesc_type_cat_array,
547                  "Redefinition of type %s does not match", name);
548     gras_assert1(res->category.array_data.type == element_type,
549                  "Redefinition of type %s does not match", name);
550     gras_assert1(res->category.array_data.fixed_size == 0,
551                  "Redefinition of type %s does not match", name);
552     gras_assert1(res->category.array_data.dynamic_size == dynamic_size,
553                  "Redefinition of type %s does not match", name);
554     VERB1("Discarding redefinition of %s",name);
555
556     return res;
557   }
558
559   res = gras_ddt_new(name);
560
561   for (arch=0; arch<gras_arch_count; arch ++) {
562     res->size[arch] = 0; /* make sure it indicates "dynamic" */
563     res->alignment[arch] = element_type->alignment[arch];
564     res->aligned_size[arch] = 0; /*FIXME: That was so in GS, but looks stupid*/
565   }
566
567   res->category_code            = e_gras_datadesc_type_cat_array;
568
569   res->category.array_data.type         = element_type;
570   res->category.array_data.fixed_size   = 0;
571   res->category.array_data.dynamic_size = dynamic_size;
572
573   return res;
574 }
575
576 /**
577  * gras_datadesc_ref_pop_arr:
578  *
579  * Most of the time, you want to include a reference in your structure which
580  * is a pointer to a dynamic array whose size is fixed by another field of 
581  * your structure.
582  *
583  * This case pops up so often that this function was created to take care of
584  * this case. It creates a dynamic array type whose size is poped from the 
585  * current cbps, and then create a reference to it.
586  *
587  * The name of the created datatype will be the name of the element type, with
588  * '[]*' appended to it.
589  *
590  * Then to use it, you just have to make sure that your structure pre-callback
591  * does push the size of the array in the cbps (using #gras_cbps_i_push), and 
592  * you are set. 
593  *
594  * But be remember that this is a stack. If you have two different pop_arr, you
595  * should push the second one first, so that the first one is on the top of the 
596  * list when the first field gets transfered.
597  *
598  */
599 gras_datadesc_type_t 
600   gras_datadesc_ref_pop_arr(gras_datadesc_type_t element_type) {
601
602   gras_datadesc_type_t res;
603   char *name=(char*)gras_malloc(strlen(element_type->name) + 4);
604
605   sprintf(name,"%s[]",element_type->name);
606
607   res = gras_datadesc_array_dyn(name,element_type,
608                                 gras_datadesc_cb_pop);
609
610   sprintf(name,"%s[]*",element_type->name);
611   res = gras_datadesc_ref(name,res);
612
613   gras_free(name);
614
615   return res;
616 }
617 gras_error_t
618 gras_datadesc_import_nws(const char           *name,
619                          const DataDescriptor *desc,
620                          unsigned long         howmany,
621                /* OUT */ gras_datadesc_type_t *dst) {
622   RAISE_UNIMPLEMENTED;
623 }
624
625 /**
626  * gras_datadesc_cb_send:
627  *
628  * Add a pre-send callback to this datadesc.
629  * (useful to push the sizes of the upcoming arrays, for example)
630  */
631 void gras_datadesc_cb_send (gras_datadesc_type_t          type,
632                             gras_datadesc_type_cb_void_t  send) {
633   type->send = send;
634 }
635 /**
636  * gras_datadesc_cb_recv:
637  *
638  * Add a post-receive callback to this datadesc.
639  * (useful to put the function pointers to the rigth value, for example)
640  */
641 void gras_datadesc_cb_recv(gras_datadesc_type_t          type,
642                            gras_datadesc_type_cb_void_t  recv) {
643   type->recv = recv;
644 }
645 /**
646  * gras_dd_find_field:
647  * 
648  * Returns the type descriptor of the given field. Abort on error.
649  */
650 static gras_datadesc_type_t 
651   gras_dd_find_field(gras_datadesc_type_t  type,
652                      const char           *field_name) {
653    gras_datadesc_type_t sub_type=NULL;
654    gras_dynar_t         field_array;
655    
656    gras_dd_cat_field_t  field=NULL;
657    int                  field_num;
658    
659    if (type->category_code == e_gras_datadesc_type_cat_union) {
660       field_array = type->category.union_data.fields;
661    } else if (type->category_code == e_gras_datadesc_type_cat_struct) {
662       field_array = type->category.struct_data.fields;
663    } else {
664       ERROR2("%s (%p) is not a struct nor an union. There is no field.", type->name,(void*)type);
665       gras_abort();
666    }
667    gras_dynar_foreach(field_array,field_num,field) {
668       if (!strcmp(field_name,field->name)) {
669          return field->type;
670       }
671    }
672    ERROR2("No field nammed %s in %s",field_name,type->name);
673    gras_abort();
674
675 }
676                                   
677 /**
678  * gras_datadesc_cb_field_send:
679  *
680  * Add a pre-send callback to the given field of the datadesc (which must be a struct or union).
681  * (useful to push the sizes of the upcoming arrays, for example)
682  */
683 void gras_datadesc_cb_field_send (gras_datadesc_type_t          type,
684                                   const char                   *field_name,
685                                   gras_datadesc_type_cb_void_t  send) {
686    
687    gras_datadesc_type_t sub_type=gras_dd_find_field(type,field_name);   
688    sub_type->send = send;
689 }
690
691 /**
692  * gras_datadesc_cb_field_push:
693  *
694  * Add a pre-send callback to the given field resulting in its value to be pushed to
695  * the stack of sizes. It must be a int, unsigned int, long int or unsigned long int.
696  */
697 void gras_datadesc_cb_field_push (gras_datadesc_type_t  type,
698                                   const char           *field_name) {
699    
700    gras_datadesc_type_t sub_type=gras_dd_find_field(type,field_name);
701    if (!strcmp("int",sub_type->name)) {
702       sub_type->send = gras_datadesc_cb_push_int;
703    } else if (!strcmp("unsigned int",sub_type->name)) {
704       sub_type->send = gras_datadesc_cb_push_uint;
705    } else if (!strcmp("long int",sub_type->name)) {
706       sub_type->send = gras_datadesc_cb_push_lint;
707    } else if (!strcmp("unsigned long int",sub_type->name)) {
708       sub_type->send = gras_datadesc_cb_push_ulint;
709    } else {
710       ERROR1("Field %s is not an int, unsigned int, long int neither unsigned long int",
711              sub_type->name);
712       gras_abort();
713    }
714 }
715 /**
716  * gras_datadesc_cb_field_recv:
717  *
718  * Add a post-receive callback to the given field of the datadesc (which must be a struct or union).
719  * (useful to put the function pointers to the right value, for example)
720  */
721 void gras_datadesc_cb_field_recv(gras_datadesc_type_t          type,
722                                  const char                   *field_name,
723                                  gras_datadesc_type_cb_void_t  recv) {
724    
725    gras_datadesc_type_t sub_type=gras_dd_find_field(type,field_name);   
726    sub_type->recv = recv;
727 }
728
729 /**
730  * gras_datadesc_free:
731  *
732  * Free a datadesc. Should only be called at gras_exit. 
733  */
734 void gras_datadesc_free(gras_datadesc_type_t *type) {
735
736   DEBUG1("Let's free ddt %s",(*type)->name);
737   
738   switch ((*type)->category_code) {
739   case e_gras_datadesc_type_cat_scalar:
740   case e_gras_datadesc_type_cat_ref:
741   case e_gras_datadesc_type_cat_array:
742     /* nothing to free in there */
743     break;
744     
745   case e_gras_datadesc_type_cat_ignored:
746     if ((*type)->category.ignored_data.free_func) {
747       (*type)->category.ignored_data.free_func
748         ((*type)->category.ignored_data.default_value);
749     }
750     break;
751     
752   case e_gras_datadesc_type_cat_struct:
753     gras_dynar_free(&( (*type)->category.struct_data.fields ));
754     break;
755     
756   case e_gras_datadesc_type_cat_union:
757     gras_dynar_free(&( (*type)->category.union_data.fields ));
758     break;
759     
760   default:
761     /* datadesc was invalid. Killing it is like euthanasy, I guess */
762     break;
763   }
764   gras_free((*type)->name);
765   gras_free(*type);
766   type=NULL;
767 }