Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d69fe8f937da3e4c2a742165f4e4de471e32c067
[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 "DataDesc/datadesc_private.h"
12
13 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(create,datadesc);
14
15 /**
16  * gras_ddt_freev:
17  *
18  * gime that memory back, dude. I mean it.
19  */
20 void gras_ddt_freev(void *ddt) {
21   gras_datadesc_type_t *type= (gras_datadesc_type_t *)ddt;
22   
23   if (type) {
24     gras_datadesc_unref(type);
25   }
26 }
27
28 static gras_error_t
29 gras_ddt_new(const char            *name,
30              gras_datadesc_type_t **dst) {
31
32   gras_error_t errcode;
33   gras_datadesc_type_t *res;
34
35   res=malloc(sizeof(gras_datadesc_type_t));
36   if (!res) 
37     RAISE_MALLOC;
38
39   memset(res, 0, sizeof(gras_datadesc_type_t));
40   res->name = strdup(name);
41   res->name_len = strlen(name);
42   res->refcounter = 1;
43   
44   TRY(gras_set_add(gras_datadesc_set_local,
45                    (gras_set_elm_t*)res,&gras_ddt_freev));
46     
47   *dst=res;
48   return no_error;
49 }
50
51 /**
52  * gras_datadesc_by_name:
53  *
54  * Retrieve a type from its name
55  */
56 gras_datadesc_type_t *gras_datadesc_by_name(const char *name) {
57
58   gras_datadesc_type_t *type;
59
60   if (gras_set_get_by_name(gras_datadesc_set_local,
61                            name,(gras_set_elm_t**)&type) == no_error) {
62     return type;
63   } else { 
64     return NULL;
65   }
66 }
67
68 /**
69  * gras_datadesc_by_id:
70  *
71  * Retrieve a type from its code
72  */
73 gras_error_t gras_datadesc_by_id(long int               code,
74                                  gras_datadesc_type_t **type) {
75   return gras_set_get_by_id(gras_datadesc_set_local,
76                             code,(gras_set_elm_t**)type);
77 }
78
79 /**
80  * gras_datadesc_scalar:
81  *
82  * Create a new scalar and give a pointer to it 
83  */
84 gras_error_t 
85 gras_datadesc_scalar(const char                      *name,
86                      gras_ddt_scalar_type_t           type,
87                      enum e_gras_dd_scalar_encoding   encoding,
88                      gras_datadesc_type_t           **dst) {
89
90   gras_error_t errcode;
91   gras_datadesc_type_t *res;
92   long int arch;
93
94   TRY(gras_ddt_new(name,dst));
95   res=*dst;
96
97   for (arch = 0; arch < gras_arch_count; arch ++) {
98     long int sz;
99     long int mask;
100     res->size[arch] = gras_arches[arch].sizeof_scalars[type];
101
102     sz = res->size[arch];
103     mask = sz;
104     
105     /* just in case you wonder, x>>1 == x/2 on all architectures when x>=0
106        and a size is always>=0 */
107     
108     /* make sure mask have all the bits under the biggest one of size set to 1
109        Example: size=000100101 => mask=0000111111 */
110     while ((sz >>= 1)) {
111       mask |= sz;
112     } 
113     
114     if (res->size[arch] & (mask >> 1)) { /* if size have bits to one beside its biggest */
115       /* size is not a power of 2 */
116       /* alignment= next power of 2 after size */
117       res->alignment[arch] = (res->size[arch] & ~(mask >> 1)) << 1;
118       gras_assert0(res->alignment[arch] != 0,
119                    "scalar type too large");
120       
121       res->aligned_size[arch] = aligned(res->size[arch], res->alignment[arch]);
122       gras_assert0 (res->aligned_size[arch] >= 0,
123                     "scalar type too large");
124       
125     } else {
126       /* size is a power of 2, life is great */
127       res->alignment[arch]       = res->size[arch];
128       res->aligned_size[arch]    = res->size[arch];
129     }
130   }
131
132   res->category_code                 = e_gras_datadesc_type_cat_scalar;
133   res->category.scalar_data.encoding = encoding;
134
135   return no_error;
136 }
137
138
139 /**
140  * gras_dd_cat_field_free:
141  *
142  * Frees one struct or union field
143  */
144 void gras_dd_cat_field_free(void *f) {
145   gras_dd_cat_field_t *field = *(gras_dd_cat_field_t **)f;
146   if (field) {
147     if (field->name) 
148       free(field->name);
149     free(field);
150   }
151 }
152
153 /**
154  * gras_datadesc_struct:
155  *
156  * Create a new struct and give a pointer to it 
157  */
158 gras_error_t 
159 gras_datadesc_struct(const char            *name,
160                      gras_datadesc_type_t **dst) {
161
162   gras_error_t errcode;
163   gras_datadesc_type_t *res;
164   long int arch;
165
166   TRY(gras_ddt_new(name,dst));
167   res=*dst;
168
169   for (arch=0; arch<gras_arch_count; arch ++) {
170     res->size[arch] = 0;
171     res->alignment[arch] = 0;
172     res->aligned_size[arch] = 0;
173   }
174   res->category_code = e_gras_datadesc_type_cat_struct;
175   TRY(gras_dynar_new(&(res->category.struct_data.fields),
176                      sizeof(gras_dd_cat_field_t*),
177                      &gras_dd_cat_field_free));
178
179   return no_error;
180 }
181
182 /**
183  * gras_datadesc_struct_append:
184  *
185  * Append a field to the struct
186  */
187 gras_error_t 
188 gras_datadesc_struct_append(gras_datadesc_type_t  *struct_type,
189                             const char            *name,
190                             gras_datadesc_type_t  *field_type) {
191
192   gras_error_t errcode;
193   gras_dd_cat_field_t *field;
194   int arch;
195  
196   gras_assert1(!struct_type->category.struct_data.closed,
197                "Cannot add anything to the already closed struct %s",
198                struct_type->name);
199   gras_assert1(field_type->size >= 0,
200                "Cannot add a dynamically sized field in structure %s",
201                struct_type->name);
202     
203   field=malloc(sizeof(gras_dd_cat_field_t));
204   if (!field)
205     RAISE_MALLOC;
206
207   field->name   = strdup(name);
208
209   DEBUG0("----------------");
210   DEBUG4("PRE s={size=%ld,align=%ld,asize=%ld} struct_boundary=%d",
211          struct_type->size[GRAS_THISARCH], 
212          struct_type->alignment[GRAS_THISARCH], 
213          struct_type->aligned_size[GRAS_THISARCH],
214          gras_arches[GRAS_THISARCH].struct_boundary);
215      
216      
217   for (arch=0; arch<gras_arch_count; arch ++) {
218     field->offset[arch] = aligned(struct_type->size[arch],
219                                   min(field_type->alignment[arch],
220                                       gras_arches[arch].struct_boundary));
221
222     struct_type->size[arch] = field->offset[arch] + field_type->size[arch];
223     struct_type->alignment[arch] = max(struct_type->alignment[arch],
224                                        field_type->alignment[arch]);
225     struct_type->aligned_size[arch] = aligned(struct_type->size[arch],
226                                               struct_type->alignment[arch]);
227   }
228   field->code   = field_type->code;
229   field->pre    = NULL;
230   field->post   = NULL;
231   
232   TRY(gras_dynar_push(struct_type->category.struct_data.fields, &field));
233
234   DEBUG3("Push a %s into %s at offset %ld.",
235          field_type->name, struct_type->name,field->offset[GRAS_THISARCH]);
236   DEBUG3("  f={size=%ld,align=%ld,asize=%ld}",
237          field_type->size[GRAS_THISARCH], 
238          field_type->alignment[GRAS_THISARCH], 
239          field_type->aligned_size[GRAS_THISARCH]);
240   DEBUG3("  s={size=%ld,align=%ld,asize=%ld}",
241          struct_type->size[GRAS_THISARCH], 
242          struct_type->alignment[GRAS_THISARCH], 
243          struct_type->aligned_size[GRAS_THISARCH]);
244   return no_error;
245 }
246 void
247 gras_datadesc_struct_close(gras_datadesc_type_t  *struct_type) {
248    struct_type->category.struct_data.closed = 1;
249    //   INFO0("FIXME: Do something in gras_datadesc_struct_close");
250 }
251
252 /**
253  * gras_datadesc_union:
254  *
255  * Create a new union and give a pointer to it 
256  */
257 gras_error_t 
258 gras_datadesc_union(const char                   *name,
259                     gras_datadesc_type_cb_int_t   selector,
260                     gras_datadesc_type_t        **dst) {
261
262   gras_error_t errcode;
263   gras_datadesc_type_t *res;
264   int arch;
265
266   gras_assert0(selector,
267                "Attempt to creat an union without field_count function");
268
269   TRY(gras_ddt_new(name,dst));
270   res=*dst;
271
272   for (arch=0; arch<gras_arch_count; arch ++) {
273      res->size[arch] = 0;
274      res->alignment[arch] = 0;
275      res->aligned_size[arch] = 0;
276   }
277
278   res->category_code            = e_gras_datadesc_type_cat_union;
279   TRY(gras_dynar_new(&(res->category.union_data.fields),
280                      sizeof(gras_dd_cat_field_t*),
281                      &gras_dd_cat_field_free));
282   res->category.union_data.selector = selector;
283
284   return no_error;
285 }
286
287 /**
288  * gras_datadesc_union_append:
289  *
290  * Append a field to the union
291  */
292 gras_error_t 
293 gras_datadesc_union_append(gras_datadesc_type_t  *union_type,
294                            const char            *name,
295                            gras_datadesc_type_t  *field_type) {
296
297   gras_error_t errcode;
298   gras_dd_cat_field_t *field;
299   int arch;
300
301   gras_assert1(!union_type->category.union_data.closed,
302                "Cannot add anything to the already closed union %s",
303                union_type->name);
304   gras_assert1(field_type->size >= 0,
305                "Cannot add a dynamically sized field in union %s",
306                union_type->name);
307     
308   field=malloc(sizeof(gras_dd_cat_field_t));
309   if (!field)
310     RAISE_MALLOC;
311
312   field->name   = strdup(name);
313   for (arch=0; arch<gras_arch_count; arch ++) {
314     field->offset[arch] = 0; /* that's the purpose of union ;) */
315   }
316   field->code   = field_type->code;
317   field->pre    = NULL;
318   field->post   = NULL;
319   
320   TRY(gras_dynar_push(union_type->category.union_data.fields, &field));
321
322   for (arch=0; arch<gras_arch_count; arch ++) {
323     union_type->size[arch] = max(union_type->size[arch],
324                                  field_type->size[arch]);
325     union_type->alignment[arch] = max(union_type->alignment[arch],
326                                       field_type->alignment[arch]);
327     union_type->aligned_size[arch] = aligned(union_type->size[arch],
328                                              union_type->alignment[arch]);
329   }
330   return no_error;
331 }
332
333 void
334 gras_datadesc_union_close(gras_datadesc_type_t  *union_type) {
335    union_type->category.union_data.closed = 1;
336    //   INFO0("FIXME: Do something in gras_datadesc_union_close");
337 }
338 /**
339  * gras_datadesc_ref:
340  *
341  * Create a new ref to a fixed type and give a pointer to it 
342  */
343 gras_error_t 
344 gras_datadesc_ref(const char             *name,
345                   gras_datadesc_type_t   *referenced_type,
346                   gras_datadesc_type_t  **dst) {
347
348   gras_error_t errcode;
349   gras_datadesc_type_t *res;
350   gras_datadesc_type_t *pointer_type = gras_datadesc_by_name("data pointer");
351   int arch;
352
353   TRY(gras_ddt_new(name,dst));
354   res=*dst;
355
356   gras_assert0(pointer_type, "Cannot get the description of data pointer");
357       
358   for (arch=0; arch<gras_arch_count; arch ++){
359     res->size[arch] = pointer_type->size[arch];
360     res->alignment[arch] = pointer_type->alignment[arch];
361     res->aligned_size[arch] = pointer_type->aligned_size[arch];
362   }
363
364   res->category_code            = e_gras_datadesc_type_cat_ref;
365
366   res->category.ref_data.code     = referenced_type->code;
367   res->category.ref_data.selector = NULL;
368
369   return no_error;
370 }
371 /**
372  * gras_datadesc_ref_generic:
373  *
374  * Create a new ref to a type given at use time, and give a pointer to it 
375  */
376 gras_error_t 
377 gras_datadesc_ref_generic(const char                      *name,
378                           gras_datadesc_type_cb_int_t      selector,
379                           gras_datadesc_type_t           **dst) {
380
381   gras_error_t errcode;
382   gras_datadesc_type_t *res;
383   gras_datadesc_type_t *pointer_type = gras_datadesc_by_name("data pointer");
384   int arch;
385
386   TRY(gras_ddt_new(name,dst));
387   res=*dst;
388
389   gras_assert0(pointer_type, "Cannot get the description of data pointer");
390       
391   for (arch=0; arch<gras_arch_count; arch ++) {
392     res->size[arch] = pointer_type->size[arch];
393     res->alignment[arch] = pointer_type->alignment[arch];
394     res->aligned_size[arch] = pointer_type->aligned_size[arch];
395   }
396
397   res->category_code            = e_gras_datadesc_type_cat_ref;
398
399   res->category.ref_data.code     = -1;
400   res->category.ref_data.selector = selector;
401
402   return no_error;
403 }
404
405 /**
406  * gras_datadesc_array_fixed:
407  *
408  * Create a new array and give a pointer to it 
409  */
410 gras_error_t 
411 gras_datadesc_array_fixed(const char              *name,
412                           gras_datadesc_type_t    *element_type,
413                           long int                 fixed_size,
414                           gras_datadesc_type_t   **dst) {
415
416   gras_error_t errcode;
417   gras_datadesc_type_t *res;
418   int arch;
419
420   TRY(gras_ddt_new(name,dst));
421   res=*dst;
422
423   gras_assert1(fixed_size > 0, "'%s' is a array of negative fixed size",name);
424   for (arch=0; arch<gras_arch_count; arch ++) {
425     res->size[arch] = fixed_size * element_type->aligned_size[arch];
426     res->alignment[arch] = element_type->alignment[arch];
427     res->aligned_size[arch] = res->size[arch];
428   }  
429
430   res->category_code            = e_gras_datadesc_type_cat_array;
431
432   res->category.array_data.code         = element_type->code;
433   res->category.array_data.fixed_size   = fixed_size;
434   res->category.array_data.dynamic_size = NULL;
435
436   return no_error;
437 }
438 /**
439  * gras_datadesc_array_dyn:
440  *
441  * Create a new array and give a pointer to it 
442  */
443 gras_error_t 
444 gras_datadesc_array_dyn(const char                      *name,
445                         gras_datadesc_type_t            *element_type,
446                         gras_datadesc_type_cb_int_t      dynamic_size,
447                         gras_datadesc_type_t           **dst) {
448
449   gras_error_t errcode;
450   gras_datadesc_type_t *res;
451   int arch;
452
453   gras_assert1(dynamic_size,
454                "'%s' is a dynamic array without size discriminant",
455                name);
456
457   TRY(gras_ddt_new(name,dst));
458   res=*dst;
459
460   for (arch=0; arch<gras_arch_count; arch ++) {
461     res->size[arch] = -1; /* make sure it indicates "dynamic" */
462     res->alignment[arch] = element_type->alignment[arch];
463     res->aligned_size[arch] = -1; /*FIXME: That was so in GS, but looks stupid*/
464   }
465
466   res->category_code            = e_gras_datadesc_type_cat_array;
467
468   res->category.array_data.code         = element_type->code;
469   res->category.array_data.fixed_size   = -1;
470   res->category.array_data.dynamic_size = dynamic_size;
471
472   return no_error;
473 }
474
475 /**
476  * gras_datadesc_ref_pop_arr:
477  *
478  * Most of the time, you want to include a reference in your structure which
479  * is a pointer to a dynamic array whose size is fixed by another field of 
480  * your structure.
481  *
482  * This case pops up so often that this function was created to take care of
483  * this case. It creates a dynamic array type whose size is poped from the 
484  * current cbps, and then create a reference to it.
485  *
486  * The name of the created datatype will be the name of the element type, with
487  * '[]*' appended to it.
488  *
489  * Then to use it, you just have to make sure that your structure pre-callback
490  * does push the size of the array in the cbps (using #gras_cbps_i_push), and 
491  * you are set. 
492  *
493  * But be remember that this is a stack. If you have two different pop_arr, you
494  * should push the second one first, so that the first one is on the top of the 
495  * list when the first field gets transfered.
496  *
497  */
498 gras_error_t 
499 gras_datadesc_ref_pop_arr(gras_datadesc_type_t  *element_type,
500                           gras_datadesc_type_t **dst) {
501   gras_error_t errcode;
502   char *name=malloc(strlen(element_type->name) + 4);
503
504   sprintf(name,"%s[]",element_type->name);
505
506   TRY(gras_datadesc_array_dyn(name,element_type,
507                                       gras_datadesc_cb_pop, dst));
508
509   sprintf(name,"%s[]*",element_type->name);
510   TRY(gras_datadesc_ref(name,*dst,dst));
511
512   free(name);
513
514   return no_error;
515 }
516 gras_error_t
517 gras_datadesc_import_nws(const char           *name,
518                          const DataDescriptor *desc,
519                          size_t                howmany,
520                          gras_datadesc_type_t **dst) {
521   RAISE_UNIMPLEMENTED;
522 }
523
524 /**
525  * gras_datadesc_cb_send:
526  *
527  * Add a pre-send callback to this datadexc.
528  * (useful to push the sizes of the upcoming arrays, for example)
529  */
530 void gras_datadesc_cb_send (gras_datadesc_type_t         *type,
531                             gras_datadesc_type_cb_void_t  send) {
532   type->send = send;
533 }
534 /**
535  * gras_datadesc_cb_recv:
536  *
537  * Add a post-receive callback to this datadesc.
538  * (useful to put the function pointers to the rigth value, for example)
539  */
540 void gras_datadesc_cb_recv(gras_datadesc_type_t         *type,
541                            gras_datadesc_type_cb_void_t  recv) {
542   type->recv = recv;
543 }
544
545 /**
546  * gras_datadesc_addref:
547  *
548  * Adds a reference to the datastruct. 
549  * ddt will be freed only when the refcount becomes 0.
550  */
551 void gras_datadesc_addref(gras_datadesc_type_t *type) {
552   type->refcounter ++;
553 }
554
555 /**
556  * gras_datadesc_unref:
557  *
558  * Removes a reference to the datastruct. 
559  * ddt will be freed only when the refcount becomes 0.
560  */
561 void gras_datadesc_unref(gras_datadesc_type_t *type) {
562   type->refcounter--;
563   if (!type->refcounter) {
564     /* even the set of ddt released that type. Let's free it */
565     DEBUG1("Let's free ddt %s",type->name);
566
567     free(type->name);
568     switch (type->category_code) {
569     case e_gras_datadesc_type_cat_scalar:
570     case e_gras_datadesc_type_cat_ref:
571     case e_gras_datadesc_type_cat_array:
572       /* nothing to free in there */
573       break;
574
575     case e_gras_datadesc_type_cat_ignored:
576       if (type->category.ignored_data.free_func) {
577         type->category.ignored_data.free_func
578           (type->category.ignored_data.default_value);
579       }
580       break;
581
582     case e_gras_datadesc_type_cat_struct:
583       gras_dynar_free(type->category.struct_data.fields);
584       break;
585
586     case e_gras_datadesc_type_cat_union:
587       gras_dynar_free(type->category.union_data.fields);
588       break;
589       
590     default:
591       /* datadesc was invalid. Killing it is like euthanasy, I guess */
592       break;
593     }
594     free(type);
595   }
596 }