Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Document black magic about aligned_size for scalars. Thanks Oli on IRC
[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(new,DataDesc);
14
15 static gras_error_t
16 gras_ddt_new(const char            *name,
17              gras_datadesc_type_t **dst) {
18
19   gras_datadesc_type_t *res=malloc(sizeof(gras_datadesc_type_t));
20   if (!res) 
21     RAISE_MALLOC;
22
23   memset(res, 0, sizeof(res));
24   res->name = strdup(name);
25   
26   *dst=res;
27   return no_error;
28 }
29
30 /**
31  * gras_ddt_new_scalar:
32  *
33  * Create a new scalar and give a pointer to it 
34  */
35 gras_error_t 
36 gras_ddt_new_scalar(const char                       *name,
37                     long int                         size,
38                     enum e_gras_dd_scalar_encoding   encoding,
39                     gras_datadesc_type_cb_void_t     cb,
40                     gras_datadesc_type_t           **dst) {
41
42   gras_error_t errcode;
43   gras_datadesc_type_t *res;
44
45   TRY(gras_ddt_new(name,dst));
46   res=*dst;
47
48   res->size = size>0 ? size : 0;
49   
50   if (size>0) { 
51     long int sz   = size;
52     long int mask = sz;
53
54     /* just in case you wonder, x>>1 == x/2 on all architecture when x>=0 */
55
56     /* make sure mask have all the bits under the biggest one of size set to 1
57        Example: size=000100101 => mask=0000111111 */
58     while ((sz >>= 1)) {
59       mask |= sz;
60     }
61
62     if (size & (mask >> 1)) { /* if size have bits to one beside its biggest */
63       /* size is not a power of 2 */
64       /* alignment= next power of 2 after size */
65       res->alignment = (size & ~(mask >> 1)) << 1;
66       gras_assert0(res->alignment != 0,
67                    "scalar type too large");
68       
69       res->aligned_size    = aligned(size, res->alignment);
70       gras_assert0 (res->aligned_size >= 0,
71                     "scalar type too large");
72       
73     } else {
74       /* size is a power of 2, life is great */
75       res->alignment       = size;
76       res->aligned_size    = size;
77     }
78     
79   } else {
80     res->alignment    = 0;
81     res->aligned_size = 0;
82   }
83
84   res->category_code                 = e_gras_datadesc_type_cat_scalar;
85   res->category.scalar_data.encoding = encoding;
86
87   res->pre = cb;
88   return no_error;
89 }
90
91
92 /**
93  * gras_dd_cat_field_free:
94  *
95  * Frees one struct or union field
96  */
97 void gras_dd_cat_field_free(void *f) {
98   gras_dd_cat_field_t *field = (gras_dd_cat_field_t *)f;
99   if (field) {
100     if (field->name) 
101       free(field->name);
102     free(field);
103   }
104 }
105
106 /**
107  * gras_ddt_new_struct:
108  *
109  * Create a new struct and give a pointer to it 
110  */
111 gras_error_t 
112 gras_ddt_new_struct(const char                      *name,
113                     gras_datadesc_type_cb_void_t     pre,
114                     gras_datadesc_type_cb_void_t     post,
115                     gras_datadesc_type_t           **dst) {
116
117   gras_error_t errcode;
118   gras_datadesc_type_t *res;
119
120   TRY(gras_ddt_new(name,dst));
121   res=*dst;
122
123   res->size                     = 0;
124   res->alignment                = 0;
125   res->aligned_size             = 0;
126   res->category_code            = e_gras_datadesc_type_cat_struct;
127   TRY(gras_dynar_new(&(res->category.struct_data.fields),
128                      sizeof(gras_dd_cat_field_t*),
129                      &gras_dd_cat_field_free));
130   res->pre                      = pre;
131   res->post                     = post;
132
133   return no_error;
134 }
135
136 /**
137  * gras_ddt_new_struct_append:
138  *
139  * Append a field to the struct
140  */
141 gras_error_t 
142 gras_ddt_new_struct_append(gras_datadesc_type_t            *struct_type,
143                            const char                      *name,
144                            gras_datadesc_type_t            *field_type,
145                            gras_datadesc_type_cb_void_t     pre,
146                            gras_datadesc_type_cb_void_t     post) {
147
148   gras_error_t errcode;
149   gras_dd_cat_field_t *field;
150
151   gras_assert0(field_type->size >= 0,
152                "Cannot add a dynamically sized field in a structure");
153     
154   field=malloc(sizeof(gras_dd_cat_field_t));
155   if (!field)
156     RAISE_MALLOC;
157
158   field->name   = strdup(name);
159   field->offset = aligned(struct_type->size, field_type->alignment);
160   field->code   = field_type->code;
161   field->pre    = pre;
162   field->post   = post;
163   
164   TRY(gras_dynar_push(struct_type->category.struct_data.fields, field));
165
166   struct_type->size             = field->offset + field_type->size;
167   struct_type->alignment        = max(struct_type->alignment, field_type->alignment);
168   struct_type->aligned_size     = aligned(struct_type->size, struct_type->alignment);
169
170   return no_error;
171 }
172
173 /**
174  * gras_ddt_new_union:
175  *
176  * Create a new union and give a pointer to it 
177  */
178 gras_error_t 
179 gras_ddt_new_union(const char                      *name,
180                    gras_datadesc_type_cb_int_t      field_count,
181                    gras_datadesc_type_cb_void_t     post,
182                    gras_datadesc_type_t           **dst) {
183
184   gras_error_t errcode;
185   gras_datadesc_type_t *res;
186
187   gras_assert0(field_count,
188                "Attempt to creat an union without field_count function");
189
190   TRY(gras_ddt_new(name,dst));
191   res=*dst;
192
193   res->size                     = 0;
194   res->alignment                = 0;
195   res->aligned_size             = 0;
196   res->category_code            = e_gras_datadesc_type_cat_union;
197   TRY(gras_dynar_new(&(res->category.union_data.fields),
198                      sizeof(gras_dd_cat_field_t*),
199                      &gras_dd_cat_field_free));
200   res->category.union_data.field_count = field_count;
201   res->pre                      = NULL;
202   res->post                     = post;
203
204   return no_error;
205 }
206
207 /**
208  * gras_ddt_new_union_append:
209  *
210  * Append a field to the union
211  */
212 gras_error_t 
213 gras_ddt_new_union_append(gras_datadesc_type_t            *union_type,
214                           const char                      *name,
215                           gras_datadesc_type_t            *field_type,
216                           gras_datadesc_type_cb_void_t     pre,
217                           gras_datadesc_type_cb_void_t     post) {
218
219   gras_error_t errcode;
220   gras_dd_cat_field_t *field;
221
222   gras_assert0(field_type->size >= 0,
223                "Cannot add a dynamically sized field in an union");
224     
225   field=malloc(sizeof(gras_dd_cat_field_t));
226   if (!field)
227     RAISE_MALLOC;
228
229   field->name   = strdup(name);
230   field->offset = 0; /* that's the purpose of union ;) */
231   field->code   = field_type->code;
232   field->pre    = pre;
233   field->post   = post;
234   
235   TRY(gras_dynar_push(union_type->category.union_data.fields, field));
236
237   union_type->size         = max(union_type->size, field_type->size);
238   union_type->alignment    = max(union_type->alignment, field_type->alignment);
239   union_type->aligned_size = aligned(union_type->size, union_type->alignment);
240
241   return no_error;
242 }
243
244 /**
245  * gras_ddt_new_ref:
246  *
247  * Create a new ref and give a pointer to it 
248  */
249 gras_error_t 
250 gras_ddt_new_ref(const char                      *name,
251                  gras_datadesc_type_t            *referenced_type,
252                  gras_datadesc_type_cb_int_t      discriminant,
253                  gras_datadesc_type_cb_void_t     post,
254                  gras_datadesc_type_t           **dst) {
255
256   gras_error_t errcode;
257   gras_datadesc_type_t *res;
258
259   gras_assert0(discriminant || referenced_type,
260                "Attempt to create a generic reference without discriminant");
261
262   TRY(gras_ddt_new(name,dst));
263   res=*dst;
264
265   /* FIXME: Size from bootstraping */
266   res->size                     = 0;
267   res->alignment                = 0;
268   res->aligned_size             = 0;
269   res->category_code            = e_gras_datadesc_type_cat_ref;
270
271   res->category.ref_data.code         = referenced_type ? referenced_type->code : -1;
272   res->category.ref_data.discriminant = discriminant;
273   res->pre                      = NULL;
274   res->post                     = post;
275
276   return no_error;
277 }
278
279 /**
280  * gras_ddt_new_array:
281  *
282  * Create a new array and give a pointer to it 
283  */
284 gras_error_t 
285 gras_ddt_new_array(const char                      *name,
286                    gras_datadesc_type_t            *element_type,
287                    long int                         fixed_size,
288                    gras_datadesc_type_cb_int_t      dynamic_size,
289                    gras_datadesc_type_cb_void_t     post,
290                    gras_datadesc_type_t           **dst) {
291
292   gras_error_t errcode;
293   gras_datadesc_type_t *res;
294
295   gras_assert0(dynamic_size || fixed_size>0,
296                "Attempt to create a dynamic array without size discriminant");
297
298   TRY(gras_ddt_new(name,dst));
299   res=*dst;
300
301   if (fixed_size <= 0) {
302     res->size = fixed_size;
303   } else {
304     res->size = fixed_size * element_type->aligned_size;
305   }
306   res->alignment                = element_type->alignment;
307   res->aligned_size             = fixed_size; /*FIXME: That was so in GS, but looks stupid*/
308   res->category_code            = e_gras_datadesc_type_cat_array;
309
310   res->category.array_data.code         = element_type->code;
311   res->category.array_data.fixed_size   = fixed_size;
312   res->category.array_data.dynamic_size = dynamic_size;
313
314   res->pre                      = NULL;
315   res->post                     = post;
316
317   return no_error;
318 }
319
320 /**
321  * gras_ddt_new_ignored:
322  *
323  * Create a new ignored field and give a pointer to it. 
324  *
325  * If you give a default value, it will be copied away so that you can free your copy.
326  */
327 gras_error_t 
328 gras_ddt_new_ignored(const char *name,
329                      void *default_value,
330                      void_f_pvoid_t   *free_func,
331                      long int                       size,
332                      long int                       alignment,
333                      gras_datadesc_type_cb_void_t     post,
334                      gras_datadesc_type_t           **dst) {
335   gras_error_t errcode;
336   gras_datadesc_type_t *res;
337
338   TRY(gras_ddt_new(name,dst));
339   res=*dst;
340
341   res->size             = size > 0?size:0;
342   res->alignment        = alignment;
343
344   if (size > 0) {
345     res->aligned_size   = aligned(size, alignment);
346   } else {
347     res->aligned_size   = 0;
348   }
349
350   if (default_value && res->size) {
351     res->category.ignored_data.default_value = malloc((size_t)size);
352     if (! (res->category.ignored_data.default_value) ) 
353       RAISE_MALLOC;
354     memcpy(res->category.ignored_data.default_value,
355            default_value, (size_t)size);
356   }
357
358   res->category_code = e_gras_datadesc_type_cat_ignored;
359   res->category.ignored_data.free_func = free_func;
360
361   res->post = post;
362
363
364   res->size = size;
365
366   return no_error;
367 }
368
369 /**
370  * gras_ddt_free:
371  *
372  * Frees a datadescription.
373  */
374 void gras_ddt_free(gras_datadesc_type_t **type) {
375   gras_datadesc_type_t *t;
376
377   if (type && *type) {
378     t=*type;
379
380     free(t->name);
381     switch (t->category_code) {
382     case e_gras_datadesc_type_cat_scalar:
383     case e_gras_datadesc_type_cat_ref:
384     case e_gras_datadesc_type_cat_array:
385       /* nothing to free in there */
386       break;
387
388     case e_gras_datadesc_type_cat_ignored:
389       if (t->category.ignored_data.free_func) {
390         t->category.ignored_data.free_func(t->category.ignored_data.default_value);
391       }
392       break;
393
394     case e_gras_datadesc_type_cat_struct:
395       gras_dynar_free(t->category.struct_data.fields);
396       break;
397
398     case e_gras_datadesc_type_cat_union:
399       gras_dynar_free(t->category.union_data.fields);
400       break;
401       
402     default:
403       /* datadesc was invalid. Killing it is like euthanasy, I guess */
404       break;
405     }
406   }
407 }