Logo AND Algorithmique Numérique Distribuée

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