From: Mathieu Desnoyers Date: Sat, 26 Feb 2011 20:01:16 +0000 (-0500) Subject: Add type class/type structure management X-Git-Tag: v0.1~182 X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=c054553dac076f91196b372fa19efaf2adc4e4f9 Add type class/type structure management Also add new "variant" type. Signed-off-by: Mathieu Desnoyers --- diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c index c8a37122..580133cc 100644 --- a/formats/ctf/ctf.c +++ b/formats/ctf/ctf.c @@ -3,7 +3,7 @@ * * Format registration. * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,6 +37,8 @@ static struct format ctf_format = { .enum_write = ctf_enum_write, .struct_begin = ctf_struct_begin, .struct_end = ctf_struct_end, + .variant_begin = ctf_variant_begin, + .variant_end = ctf_variant_end, .array_begin = ctf_array_begin, .array_end = ctf_array_end, .sequence_begin = ctf_sequence_begin, diff --git a/formats/ctf/types/enum.c b/formats/ctf/types/enum.c index e0bb545b..62433451 100644 --- a/formats/ctf/types/enum.c +++ b/formats/ctf/types/enum.c @@ -3,7 +3,7 @@ * * Enumeration mapping strings (quarks) from/to integers. * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,6 +20,9 @@ #include #include +/* + * The caller should unref the GArray. + */ GArray *ctf_enum_read(struct stream_pos *pos, const struct type_class_enum *src) { diff --git a/formats/ctf/types/variant.c b/formats/ctf/types/variant.c new file mode 100644 index 00000000..78adca3d --- /dev/null +++ b/formats/ctf/types/variant.c @@ -0,0 +1,29 @@ +/* + * Common Trace Format + * + * Variant format access functions. + * + * Copyright 2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + +#include + +void ctf_variant_begin(struct stream_pos *pos, + const struct type_class_variant *variant_class) +{ +} + +void ctf_variant_end(struct stream_pos *pos, + const struct type_class_variant *variant_class) +{ +} diff --git a/include/babeltrace/ctf/metadata.h b/include/babeltrace/ctf/metadata.h new file mode 100644 index 00000000..622ed7b6 --- /dev/null +++ b/include/babeltrace/ctf/metadata.h @@ -0,0 +1,45 @@ +#ifndef _BABELTRACE_CTF_METADATA_H +#define _BABELTRACE_CTF_METADATA_H + +/* + * BabelTrace + * + * CTF Metadata Header + * + * Copyright 2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + +#include +#include + +struct ctf_trace; +struct ctf_stream; +struct ctf_event; + +struct ctf_trace { + struct declaration_scope *scope; +}; + +struct ctf_stream { + struct declaration_scope *scope; + GArray *events_by_id; /* Array of struct ctf_event indexed by id */ + GHashTable *event_quark_to_id; /* GQuark to numeric id */ +}; + + +struct ctf_event { + struct declaration_scope *scope; + GQuark qname; +}; + +#endif /* _BABELTRACE_CTF_METADATA_H */ diff --git a/include/babeltrace/format.h b/include/babeltrace/format.h index b9c3e9fb..24276fa4 100644 --- a/include/babeltrace/format.h +++ b/include/babeltrace/format.h @@ -6,7 +6,7 @@ * * Trace Format Header * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -67,6 +67,10 @@ struct format { const struct type_class_struct *struct_class); void (*struct_end)(struct stream_pos *pos, const struct type_class_struct *struct_class); + void (*variant_begin)(struct stream_pos *pos, + const struct type_class_variant *variant_class); + void (*variant_end)(struct stream_pos *pos, + const struct type_class_variant *variant_class); void (*array_begin)(struct stream_pos *pos, const struct type_class_array *array_class); void (*array_end)(struct stream_pos *pos, diff --git a/include/babeltrace/types.h b/include/babeltrace/types.h index a315c4c3..242b9057 100644 --- a/include/babeltrace/types.h +++ b/include/babeltrace/types.h @@ -6,7 +6,7 @@ * * Type Header * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -85,19 +85,34 @@ char *get_pos_addr(struct stream_pos *pos) } struct format; +struct type; struct type_class { GQuark name; /* type name */ size_t alignment; /* type alignment, in bits */ - int ref; /* number of references to the type */ + int ref; /* number of references to the type class */ /* - * Type copy function. Knows how to find the child type_class from the - * parent type_class. + * class_free called with type class ref is decremented to 0. + */ + void (*class_free)(struct type_class *type_class); + struct type *(*type_new)(struct type_class *_class, + struct declaration_scope *parent_scope); + /* + * type_free called with type ref is decremented to 0. + */ + void (*type_free)(struct type *type); + /* + * Type copy function. Knows how to find the child type from the parent + * type. */ void (*copy)(struct stream_pos *dest, const struct format *fdest, struct stream_pos *src, const struct format *fsrc, - const struct type_class *type_class); - void (*free)(struct type_class *type_class); + struct type *type); +}; + +struct type { + struct type_class *_class; + int ref; /* number of references to the type instance */ }; /* @@ -112,6 +127,16 @@ struct type_class_integer { int signedness; }; +struct type_integer { + struct type p; + struct type_class_integer *_class; + /* Last values read */ + union { + uint64_t _unsigned; + int64_t _signed; + } value; +}; + struct type_class_float { struct type_class p; struct type_class_integer *sign; @@ -121,6 +146,13 @@ struct type_class_float { /* TODO: we might want to express more info about NaN, +inf and -inf */ }; +struct type_float { + struct type p; + struct type_class_float *_class; + /* Last values read */ + long double value; +}; + /* * enum_val_equal assumes that signed and unsigned memory layout overlap. */ @@ -164,19 +196,58 @@ struct type_class_enum { struct enum_table table; }; +struct type_enum { + struct type p; + struct type_class_enum *_class; + /* Last GQuark values read. Keeping a reference on the GQuark array. */ + GArray *value; +}; + struct type_class_string { struct type_class p; }; -struct field { +struct type_string { + struct type p; + struct type_class_string *_class; + char *value; /* freed at type_string teardown */ +}; + +struct type_class_field { GQuark name; struct type_class *type_class; }; +struct field { + struct type *type; +}; + struct type_class_struct { struct type_class p; GHashTable *fields_by_name; /* Tuples (field name, field index) */ - GArray *fields; /* Array of fields */ + GArray *fields; /* Array of type_class_field */ +}; + +struct type_struct { + struct type p; + struct type_class_struct *_class; + struct declaration_scope *scope; + GArray *fields; /* Array of struct field */ +}; + +struct type_class_variant { + struct type_class p; + GHashTable *fields_by_tag; /* Tuples (field tag, field index) */ + GArray *fields; /* Array of type_class_field */ +}; + +struct type_variant { + struct type p; + struct type_class_variant *_class; + struct declaration_scope *scope; + struct type *tag; + GArray *fields; /* Array of struct field */ + struct field *current_field; /* Last field read */ }; struct type_class_array { @@ -185,35 +256,64 @@ struct type_class_array { struct type_class *elem; }; +struct type_array { + struct type p; + struct type_class_array *_class; + struct declaration_scope *scope; + struct field current_element; /* struct field */ +}; + struct type_class_sequence { struct type_class p; struct type_class_integer *len_class; struct type_class *elem; }; -struct type_class *lookup_type(GQuark qname); -int register_type(struct type_class *type_class); +struct type_sequence { + struct type p; + struct type_class_sequence *_class; + struct declaration_scope *scope; + struct type_integer *len; + struct field current_element; /* struct field */ +}; + +/* Type declaration scope */ +struct declaration_scope { + /* Hash table mapping type name GQuark to struct type_class */ + GHashTable *type_classes; + struct declaration_scope *parent_scope; +}; + +struct type_class *lookup_type_class(GQuark qname, + struct declaration_scope *scope); +int register_type_class(struct type_class *type_class, + struct declaration_scope *scope); + +void type_class_ref(struct type_class *type_class); +void type_class_unref(struct type_class *type_class); + +struct declaration_scope * +new_declaration_scope(struct declaration_scope *parent_scope); +void free_declaration_scope(struct declaration_scope *scope); -void type_ref(struct type_class *type_class); -void type_unref(struct type_class *type_class); +void type_ref(struct type *type); +void type_unref(struct type *type); /* Nameless types can be created by passing a NULL name */ -struct type_class_integer *integer_type_new(const char *name, +struct type_class_integer *integer_type_class_new(const char *name, size_t len, int byte_order, int signedness, size_t alignment); -void integer_type_free(struct type_class_integer *int_class); /* * mantissa_len is the length of the number of bytes represented by the mantissa * (e.g. result of DBL_MANT_DIG). It includes the leading 1. */ -struct type_class_float *float_type_new(const char *name, +struct type_class_float *float_type_class_new(const char *name, size_t mantissa_len, size_t exp_len, int byte_order, size_t alignment); -void float_type_free(struct type_class_float *float_class); /* * A GQuark can be translated to/from strings with g_quark_from_string() and @@ -245,47 +345,72 @@ void enum_signed_insert(struct type_class_enum *enum_class, int64_t start, int64_t end, GQuark q); void enum_unsigned_insert(struct type_class_enum *enum_class, uint64_t start, uint64_t end, GQuark q); +size_t enum_get_nr_enumerators(struct type_class_enum *enum_class); -struct type_class_enum *enum_type_new(const char *name, +struct type_class_enum *enum_type_class_new(const char *name, size_t len, int byte_order, int signedness, size_t alignment); -void enum_type_free(struct type_class_enum *enum_class); -struct type_class_struct *struct_type_new(const char *name); -void struct_type_free(struct type_class_struct *struct_class); -void struct_type_add_field(struct type_class_struct *struct_class, - const char *field_name, - struct type_class *type_class); +struct type_class_struct *struct_type_class_new(const char *name); +void struct_type_class_add_field(struct type_class_struct *struct_class, + const char *field_name, + struct type_class *type_class); /* * Returns the index of a field within a structure. */ unsigned long -struct_type_lookup_field_index(struct type_class_struct *struct_class, - GQuark field_name); +struct_type_class_lookup_field_index(struct type_class_struct *struct_class, + GQuark field_name); /* * field returned only valid as long as the field structure is not appended to. */ +struct type_class_field * +struct_type_class_get_field_from_index(struct type_class_struct *struct_class, + unsigned long index); struct field * -struct_type_get_field_from_index(struct type_class_struct *struct_class, +struct_type_get_field_from_index(struct type_struct *_struct, unsigned long index); +/* + * The tag enumeration is validated to ensure that it contains only mappings + * from numeric values to a single tag. Overlapping tag value ranges are + * therefore forbidden. + */ +struct type_class_variant *variant_type_class_new(const char *name); +void variant_type_class_add_field(struct type_class_variant *variant_class, + const char *tag_name, + struct type_class *type_class); +struct type_class_field * +variant_type_class_get_field_from_tag(struct type_class_variant *variant_class, + GQuark tag); +/* + * Returns 0 on success, -EPERM on error. + */ +int variant_type_set_tag(struct type_variant *variant, + struct type *enum_tag_instance); +/* + * Returns the field selected by the current tag value. + * field returned only valid as long as the variant structure is not appended + * to. + */ +struct field * +variant_type_get_current_field(struct type_variant *variant); + /* * elem_class passed as parameter now belongs to the array. No need to free it - * explicitely. + * explicitly. "len" is the number of elements in the array. */ -struct type_class_array *array_type_new(const char *name, +struct type_class_array *array_type_class_new(const char *name, size_t len, struct type_class *elem_class); -void array_type_free(struct type_class_array *array_class); /* * int_class and elem_class passed as parameter now belongs to the sequence. No - * need to free them explicitely. + * need to free them explicitly. */ -struct type_class_sequence *sequence_type_new(const char *name, +struct type_class_sequence *sequence_type_class_new(const char *name, struct type_class_integer *len_class, struct type_class *elem_class); -void sequence_type_free(struct type_class_sequence *sequence_class); #endif /* _BABELTRACE_TYPES_H */ diff --git a/types/array.c b/types/array.c index 01483b52..6ac4a1a1 100644 --- a/types/array.c +++ b/types/array.c @@ -3,7 +3,7 @@ * * BabelTrace - Array Type Converter * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -19,40 +19,43 @@ #include #include +static +struct type *_array_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void _array_type_free(struct type *type); + void array_copy(struct stream_pos *dest, const struct format *fdest, struct stream_pos *src, const struct format *fsrc, - const struct type_class *type_class) + struct type *type) { - struct type_class_array *array_class = - container_of(type_class, struct type_class_array, p); - unsigned int i; + struct type_sequence *array = container_of(type, struct type_array, p); + struct type_class_array *array_class = array->_class; + uint64_t i; fsrc->array_begin(src, array_class); fdest->array_begin(dest, array_class); for (i = 0; i < array_class->len; i++) { - struct type_class *elem_class = array_class->elem; - elem_class->copy(dest, fdest, src, fsrc, elem_class); + struct type_class *elem_class = array->current_element.type; + elem_type->p._class->copy(dest, fdest, src, fsrc, elem_type); } fsrc->array_end(src, array_class); fdest->array_end(dest, array_class); } -void array_type_free(struct type_class_array *array_class) -{ - type_unref(array_class->elem); - g_free(array_class); -} - -static void _array_type_free(struct type_class *type_class) +static +void _array_type_class_free(struct type_class *type_class) { struct type_class_array *array_class = container_of(type_class, struct type_class_array, p); - array_type_free(array_class); + + type_class_unref(array_class->elem); + g_free(array_class); } -struct type_class_array *array_type_new(const char *name, size_t len, - struct type_class *elem) +struct type_class_array * +array_type_class_new(const char *name, size_t len, struct type_class *elem) { struct type_class_array *array_class; struct type_class *type_class; @@ -60,7 +63,6 @@ struct type_class_array *array_type_new(const char *name, size_t len, array_class = g_new(struct type_class_array, 1); type_class = &array_class->p; - array_class->len = len; type_ref(elem); array_class->elem = elem; @@ -68,7 +70,9 @@ struct type_class_array *array_type_new(const char *name, size_t len, /* No need to align the array, the first element will align itself */ type_class->alignment = 1; type_class->copy = array_copy; - type_class->free = _array_type_free; + type_class->class_free = _array_type_class_free; + type_class->type_new = _array_type_new; + type_class->type_free = _array_type_free; type_class->ref = 1; if (type_class->name) { @@ -79,7 +83,39 @@ struct type_class_array *array_type_new(const char *name, size_t len, return array_class; error_register: - type_unref(array_class->elem); + type_class_unref(array_class->elem); g_free(array_class); return NULL; } + +static +struct type_array *_array_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) +{ + struct type_class_array *array_class = + container_of(type_class, struct type_class_array, p); + struct type_array *array; + + array = g_new(struct type_array, 1); + type_class_ref(&array_class->p); + array->p._class = array_class; + array->p.ref = 1; + array->scope = new_declaration_scope(parent_scope); + array->current_element.type = + array_class->elem.p->type_new(&array_class->elem.p, + parent_scope); + return &array->p; +} + +static +void _array_type_free(struct type *type) +{ + struct type_array *array = + container_of(type, struct type_array, p); + struct type *elem_type = array->current_element.type; + + elem_type->p._class->type_free(elem_type); + free_declaration_scope(array->scope); + type_class_unref(array->p._class); + g_free(array); +} diff --git a/types/enum.c b/types/enum.c index 6ad4d450..109fd281 100644 --- a/types/enum.c +++ b/types/enum.c @@ -3,7 +3,7 @@ * * BabelTrace - Enumeration Type * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,12 @@ #include #include +static +struct type_enum *_enum_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void _enum_type_free(struct type *type); + static void enum_range_set_free(void *ptr) { @@ -336,17 +342,26 @@ void enum_unsigned_insert(struct type_class_enum *enum_class, range->end._unsigned = end; } +size_t enum_get_nr_enumerators(struct type_class_enum *enum_class) +{ + return g_hash_table_size(enum_class->table.quark_to_range_set); +} + void enum_copy(struct stream_pos *dest, const struct format *fdest, struct stream_pos *src, const struct format *fsrc, - const struct type_class *type_class) + struct type *type) { - struct type_class_enum *enum_class = - container_of(type_class, struct type_class_enum, p.p); + struct type_enum *_enum = container_of(type, struct type_enum, p); + struct type_class_enum *enum_class = _enum->_class; GArray *array; GQuark v; array = fsrc->enum_read(src, enum_class); assert(array); + /* unref previous array */ + if (_enum->value) + g_array_unref(_enum->value, TRUE); + _enum->value = array; /* * Arbitrarily choose the first one. * TODO: use direct underlying type read/write intead. Not doing it for @@ -356,8 +371,11 @@ void enum_copy(struct stream_pos *dest, const struct format *fdest, return fdest->enum_write(dest, enum_class, v); } -void enum_type_free(struct type_class_enum *enum_class) +static +void _enum_type_class_free(struct type_class *type_class) { + struct type_class_enum *enum_class = + container_of(type_class, struct enum_type_class, p); struct enum_range_to_quark *iter, *tmp; g_hash_table_destroy(enum_class->table.value_to_quark_set); @@ -369,18 +387,9 @@ void enum_type_free(struct type_class_enum *enum_class) g_free(enum_class); } -static -void _enum_type_free(struct type_class *type_class) -{ - struct type_class_enum *enum_class = - container_of(type_class, struct type_class_enum, p.p); - enum_type_free(enum_class); -} - -struct type_class_enum *enum_type_new(const char *name, - size_t len, int byte_order, - int signedness, - size_t alignment) +struct type_class_enum * +_enum_type_class_new(const char *name, size_t len, int byte_order, + int signedness, size_t alignment) { struct type_class_enum *enum_class; struct type_class_integer *int_class; @@ -399,25 +408,58 @@ struct type_class_enum *enum_type_new(const char *name, int_class->p.name = g_quark_from_string(name); int_class->p.alignment = alignment; int_class->p.copy = enum_copy; - int_class->p.free = _enum_type_free; + int_class->p.class_free = _enum_type_class_free; + int_class->p.type_new = _enum_type_new; + int_class->p.type_free = _enum_type_free; int_class->p.ref = 1; int_class->len = len; int_class->byte_order = byte_order; int_class->signedness = signedness; if (int_class->p.name) { ret = register_type(&int_class->p); - if (ret) { - struct enum_range_to_quark *iter, *tmp; - - g_hash_table_destroy(enum_class->table.value_to_quark_set); - cds_list_for_each_entry_safe(iter, tmp, &enum_class->table.range_to_quark, node) { - cds_list_del(&iter->node); - g_free(iter); - } - g_hash_table_destroy(enum_class->table.quark_to_range_set); - g_free(enum_class); - return NULL; - } + if (ret) + goto register_error; } return enum_class; + +register_error: + { + struct enum_range_to_quark *iter, *tmp; + + cds_list_for_each_entry_safe(iter, tmp, &enum_class->table.range_to_quark, node) { + cds_list_del(&iter->node); + g_free(iter); + } + } + g_hash_table_destroy(enum_class->table.value_to_quark_set); + g_hash_table_destroy(enum_class->table.quark_to_range_set); + g_free(enum_class); + return NULL; +} + +static +struct type_enum *_enum_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) +{ + struct type_class_enum *enum_class = + container_of(type_class, struct type_class_enum, p); + struct type_enum *_enum; + + _enum = g_new(struct type_enum, 1); + type_class_ref(&enum_class->p); + _enum->p._class = enum_class; + _enum->p.ref = 1; + _enum->value = NULL; + return &_enum->p; +} + +static +void _enum_type_free(struct type *type) +{ + struct type_enum *_enum = container_of(type, struct type_enum, p); + + type_class_unref(_enum->p._class); + if (_enum->value) + g_array_unref(_enum->value, TRUE); + g_free(_enum); } diff --git a/types/float.c b/types/float.c index 2ce6b592..c78cf584 100644 --- a/types/float.c +++ b/types/float.c @@ -3,7 +3,7 @@ * * BabelTrace - Float Type Converter * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -19,14 +19,20 @@ #include #include +static +struct type_float *_float_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void _float_type_free(struct type *type); + void float_copy(struct stream_pos *destp, const struct format *fdest, struct stream_pos *srcp, const struct format *fsrc, - const struct type_class *type_class) + struct type *type) { - struct type_class_float *float_class = - container_of(type_class, struct type_class_float, p); + struct type_float *_float = container_of(type, struct type_float, p); + struct type_class_float *float_class = _float->_class; if (fsrc->float_copy == fdest->float_copy) { fsrc->float_copy(destp, srcp, float_class); @@ -38,25 +44,21 @@ void float_copy(struct stream_pos *destp, } } -void float_type_free(struct type_class_float *float_class) -{ - integer_type_free(float_class->exp); - integer_type_free(float_class->mantissa); - integer_type_free(float_class->sign); - g_free(float_class); -} - -static void _float_type_free(struct type_class *type_class) +static +void _float_type_class_free(struct type_class *type_class) { struct type_class_float *float_class = container_of(type_class, struct type_class_float, p); - float_type_free(float_class); + + type_class_unref(&float_class->exp->p); + type_class_unref(&float_class->mantissa->p); + type_class_unref(&float_class->sign->p); + g_free(float_class); } -struct type_class_float *float_type_new(const char *name, - size_t mantissa_len, - size_t exp_len, int byte_order, - size_t alignment) +struct type_class_float * +float_type_class_new(const char *name, size_t mantissa_len, + size_t exp_len, int byte_order, size_t alignment) { struct type_class_float *float_class; struct type_class *type_class; @@ -64,11 +66,12 @@ struct type_class_float *float_type_new(const char *name, float_class = g_new(struct type_class_float, 1); type_class = &float_class->p; - type_class->name = g_quark_from_string(name); type_class->alignment = alignment; type_class->copy = float_copy; - type_class->free = _float_type_free; + type_class->class_free = _float_type_class_free; + type_class->type_new = _float_type_new; + type_class->type_free = _float_type_free; type_class->ref = 1; float_class->byte_order = byte_order; @@ -93,12 +96,37 @@ struct type_class_float *float_type_new(const char *name, return float_class; error_register: - integer_type_free(float_class->exp); + type_class_unref(&float_class->exp->p); error_exp: - integer_type_free(float_class->mantissa); + type_class_unref(&float_class->mantissa->p); error_mantissa: - integer_type_free(float_class->sign); + type_class_unref(&float_class->sign->p); error_sign: g_free(float_class); return NULL; } + +static +struct type_float *_float_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) +{ + struct type_class_float *float_class = + container_of(type_class, struct type_class_float, p); + struct type_float *_float; + + _float = g_new(struct type_float, 1); + type_class_ref(&_float_class->p); + _float->p._class = _float_class; + _float->p.ref = 1; + _float->value = 0.0; + return &_float->p; +} + +static +void _float_type_free(struct type *type) +{ + struct type_float *_float = container_of(type, struct type_float, p); + + type_class_unref(_float->p._class); + g_free(_float); +} diff --git a/types/integer.c b/types/integer.c index 1e926f7b..ea292900 100644 --- a/types/integer.c +++ b/types/integer.c @@ -3,7 +3,7 @@ * * BabelTrace - Integer Type Converter * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,12 +21,19 @@ #include #include +static +struct type *_integer_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void _integer_type_free(struct type *type); + void integer_copy(struct stream_pos *dest, const struct format *fdest, struct stream_pos *src, const struct format *fsrc, - const struct type_class *type_class) + struct type *type) { - struct type_class_integer *int_class = - container_of(type_class, struct type_class_integer, p); + struct type_integer *integer = container_of(type, struct type_integer, + p); + struct type_class_integer *int_class = integer->_class; if (!int_class->signedness) { uint64_t v; @@ -41,22 +48,17 @@ void integer_copy(struct stream_pos *dest, const struct format *fdest, } } -void integer_type_free(struct type_class_integer *int_class) +static +void _integer_type_class_free(struct type_class *type_class) { - g_free(int_class); -} - -static void _integer_type_free(struct type_class *type_class) -{ - struct type_class_integer *int_class = + struct type_class_integer *integer_class = container_of(type_class, struct type_class_integer, p); - integer_type_free(int_class); + g_free(integer_class); } -struct type_class_integer *integer_type_new(const char *name, - size_t len, int byte_order, - int signedness, - size_t alignment) +struct type_class_integer * +integer_type_class_new(const char *name, size_t len, int byte_order, + int signedness, size_t alignment) { struct type_class_integer *int_class; int ret; @@ -65,7 +67,9 @@ struct type_class_integer *integer_type_new(const char *name, int_class->p.name = g_quark_from_string(name); int_class->p.alignment = alignment; int_class->p.copy = integer_copy; - int_class->p.free = _integer_type_free; + int_class->p.class_free = _integer_type_class_free; + int_class->p.type_free = _integer_type_free; + int_class->p.type_new = _integer_type_new; int_class->p.ref = 1; int_class->len = len; int_class->byte_order = byte_order; @@ -79,3 +83,29 @@ struct type_class_integer *integer_type_new(const char *name, } return int_class; } + +static +struct type_integer *_integer_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) +{ + struct type_class_integer *integer_class = + container_of(type_class, struct type_class_integer, p); + struct type_integer *integer; + + integer = g_new(struct type_integer, 1); + type_class_ref(&integer_class->p); + integer->p._class = integer_class; + integer->p.ref = 1; + integer->value._unsigned = 0; + return &integer->p; +} + +static +void _integer_type_free(struct type *type) +{ + struct type_integer *integer = + container_of(type, struct type_integer, p); + + type_class_unref(integer->p._class); + g_free(integer); +} diff --git a/types/sequence.c b/types/sequence.c index 49671828..8f3fed9a 100644 --- a/types/sequence.c +++ b/types/sequence.c @@ -3,7 +3,7 @@ * * BabelTrace - Sequence Type Converter * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,47 +23,49 @@ #define max(a, b) ((a) < (b) ? (b) : (a)) #endif +static +struct type *_sequence_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void _sequence_type_free(struct type *type); + void sequence_copy(struct stream_pos *dest, const struct format *fdest, struct stream_pos *src, const struct format *fsrc, - const struct type_class *type_class) + struct type *type) { - struct type_class_sequence *sequence_class = - container_of(type_class, struct type_class_sequence, p); - unsigned int i; - size_t len; + struct type_sequence *sequence = + container_of(type, struct type_sequence, p); + struct type_class_sequence *sequence_class = sequence->_class; + uint64_t i; - fsrc->sequence_begin(src, sequence_class); - fdest->sequence_begin(dest, sequence_class); + fsrc->sequence_begin(src, sequence); + fdest->sequence_begin(dest, sequence); - len = fsrc->uint_read(src, sequence_class->len_class); - fdest->uint_write(dest, sequence_class->len_class, len); + sequence->len->p._class->copy(dest, fdest, src, fsrc, + &sequence->len->p); - for (i = 0; i < len; i++) { - struct type_class *elem_class = sequence_class->elem; - elem_class->copy(dest, fdest, src, fsrc, elem_class); + for (i = 0; i < sequence->len->value._unsigned; i++) { + struct type *elem_type = sequence->current_element.type; + elem_type->p._class->copy(dest, fdest, src, fsrc, elem_type); } - fsrc->sequence_end(src, sequence_class); - fdest->sequence_end(dest, sequence_class); + fsrc->sequence_end(src, sequence); + fdest->sequence_end(dest, sequence); } -void sequence_type_free(struct type_class_sequence *sequence_class) -{ - sequence_class->elem->free(sequence_class->elem); - type_unref(&sequence_class->len_class->p); - type_unref(sequence_class->elem); - g_free(sequence_class); -} - -static void _sequence_type_free(struct type_class *type_class) +static +void _sequence_type_class_free(struct type_class *type_class) { struct type_class_sequence *sequence_class = container_of(type_class, struct type_class_sequence, p); - sequence_type_free(sequence_class); + + type_class_unref(&sequence_class->len_class->p); + type_class_unref(sequence_class->elem); + g_free(sequence_class); } struct type_class_sequence * -sequence_type_new(const char *name, struct type_class_integer *len_class, - struct type_class *elem) +sequence_type_class_new(const char *name, struct type_class_integer *len_class, + struct type_class *elem) { struct type_class_sequence *sequence_class; struct type_class *type_class; @@ -71,9 +73,7 @@ sequence_type_new(const char *name, struct type_class_integer *len_class, sequence_class = g_new(struct type_class_sequence, 1); type_class = &sequence_class->p; - assert(!len_class->signedness); - type_ref(&len_class->p); sequence_class->len_class = len_class; type_ref(elem); @@ -82,7 +82,9 @@ sequence_type_new(const char *name, struct type_class_integer *len_class, type_class->alignment = max(len_class->p.alignment, elem->alignment); type_class->copy = sequence_copy; - type_class->free = _sequence_type_free; + type_class->class_free = _sequence_type_class_free; + type_class->type_new = _sequence_type_new; + type_class->type_free = _sequence_type_free; type_class->ref = 1; if (type_class->name) { @@ -93,8 +95,45 @@ sequence_type_new(const char *name, struct type_class_integer *len_class, return sequence_class; error_register: - type_unref(&len_class->p); - type_unref(elem); + type_class_unref(&len_class->p); + type_class_unref(elem); g_free(sequence_class); return NULL; } + +static +struct type *_sequence_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) +{ + struct type_class_sequence *sequence_class = + container_of(type_class, struct type_class_sequence, p); + struct type_sequence *sequence; + + sequence = g_new(struct type_sequence, 1); + type_class_ref(&sequence_class->p); + sequence->p._class = sequence_class; + sequence->p.ref = 1; + sequence->scope = new_declaration_scope(parent_scope); + sequence->len.type = + sequence_class->len_class.p->type_new(&sequence_class->len_class.p, + parent_scope); + sequence->current_element.type = + sequence_class->elem.p->type_new(&sequence_class->elem.p, + parent_scope); + return &sequence->p; +} + +static +void _sequence_type_free(struct type *type) +{ + struct type_sequence *sequence = + container_of(type, struct type_sequence, p); + struct type *len_type = sequence->len.type; + struct type *elem_type = sequence->current_element.type; + + len_type->p._class->type_free(len_type); + elem_type->p._class->type_free(elem_type); + free_declaration_scope(sequence->scope); + type_class_unref(sequence->p._class); + g_free(sequence); +} diff --git a/types/string.c b/types/string.c index ab0ec72c..e76ac77a 100644 --- a/types/string.c +++ b/types/string.c @@ -3,7 +3,7 @@ * * BabelTrace - String Type Converter * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,12 +20,18 @@ #include #include +static +struct type_string *_string_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void _string_type_free(struct type *type); + void string_copy(struct stream_pos *dest, const struct format *fdest, struct stream_pos *src, const struct format *fsrc, - const struct type_class *type_class) + struct type *type) { - struct type_class_string *string_class = - container_of(type_class, struct type_class_string, p); + struct type_string *string = container_of(type, struct type_string, p); + struct type_class_string *string_class = string->_class; if (fsrc->string_copy == fdest->string_copy) { fsrc->string_copy(dest, src, string_class); @@ -38,19 +44,16 @@ void string_copy(struct stream_pos *dest, const struct format *fdest, } } -void string_type_free(struct type_class_string *string_class) -{ - g_free(string_class); -} - -static void _string_type_free(struct type_class *type_class) +static +void _string_type_class_free(struct type_class_string *string_class) { struct type_class_string *string_class = container_of(type_class, struct type_class_string, p); - string_type_free(string_class); + g_free(string_class); } -struct type_class_string *string_type_new(const char *name) +struct type_class_string * +string_type_class_new(const char *name) { struct type_class_string *string_class; int ret; @@ -59,7 +62,9 @@ struct type_class_string *string_type_new(const char *name) string_class->p.name = g_quark_from_string(name); string_class->p.alignment = CHAR_BIT; string_class->p.copy = string_copy; - string_class->p.free = _string_type_free; + string_class->p.class_free = _string_type_class_free; + string_class->p.type_new = _string_type_new; + string_class->p.type_free = _string_type_free; string_class->p.ref = 1; if (string_class->p.name) { ret = register_type(&string_class->p); @@ -70,3 +75,30 @@ struct type_class_string *string_type_new(const char *name) } return string_class; } + +static +struct type_string *_string_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) +{ + struct type_class_string *string_class = + container_of(type_class, struct type_class_string, p); + struct type_string *string; + + string = g_new(struct type_string, 1); + type_class_ref(&string_class->p); + string->p._class = string_class; + string->p.ref = 1; + string->value = NULL; + return &string->p; +} + +static +void _string_type_free(struct type *type) +{ + struct type_string *string = + container_of(type, struct type_string, p); + + type_class_unref(string->p._class); + g_free(string->value); + g_free(string); +} diff --git a/types/struct.c b/types/struct.c index d3e9f3c4..1e1b458a 100644 --- a/types/struct.c +++ b/types/struct.c @@ -3,7 +3,7 @@ * * BabelTrace - Structure Type Converter * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,52 +23,56 @@ #define max(a, b) ((a) < (b) ? (b) : (a)) #endif +static +struct type *_struct_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void _struct_type_free(struct type *type); + void struct_copy(struct stream_pos *dest, const struct format *fdest, struct stream_pos *src, const struct format *fsrc, - const struct type_class *type_class) + struct type *type) { - struct type_class_struct *struct_class = - container_of(type_class, struct type_class_struct, p); - unsigned int i; + struct type_struct *_struct = container_of(type, struct type_struct, p); + struct type_class_struct *struct_class = _struct->_class; + unsigned long i; fsrc->struct_begin(src, struct_class); fdest->struct_begin(dest, struct_class); - for (i = 0; i < struct_class->fields->len; i++) { - struct field *field = &g_array_index(struct_class->fields, + for (i = 0; i < _struct->fields->len; i++) { + struct field *field = &g_array_index(_struct->fields, struct field, i); - struct type_class *field_class = field->type_class; + struct type_class *field_class = field->type->p._class; - field_class->copy(dest, fdest, src, fsrc, field_class); + field_class->copy(dest, fdest, src, fsrc, &field->type->p); } fsrc->struct_end(src, struct_class); fdest->struct_end(dest, struct_class); } -void struct_type_free(struct type_class_struct *struct_class) +static +void _struct_type_class_free(struct type_class *type_class) { - unsigned int i; + struct type_class_struct *struct_class = + container_of(type_class, struct type_class_struct, p); + unsigned long i; g_hash_table_destroy(struct_class->fields_by_name); for (i = 0; i < struct_class->fields->len; i++) { - struct field *field = &g_array_index(struct_class->fields, - struct field, i); - type_unref(field->type_class); + struct field *type_class_field = + &g_array_index(struct_class->fields, + struct type_class_field, i); + type_class_unref(field->type_class); } g_array_free(struct_class->fields, true); g_free(struct_class); } -static void _struct_type_free(struct type_class *type_class) -{ - struct type_class_struct *struct_class = - container_of(type_class, struct type_class_struct, p); - struct_type_free(struct_class); -} - -struct type_class_struct *struct_type_new(const char *name) +struct type_class_struct * +struct_type_class_new(const char *name) { struct type_class_struct *struct_class; struct type_class *type_class; @@ -76,16 +80,17 @@ struct type_class_struct *struct_type_new(const char *name) struct_class = g_new(struct type_class_struct, 1); type_class = &struct_class->p; - struct_class->fields_by_name = g_hash_table_new(g_direct_hash, g_direct_equal); - struct_class->fields = g_array_sized_new(false, false, - sizeof(struct field), + struct_class->fields = g_array_sized_new(FALSE, TRUE, + sizeof(struct type_class_field), DEFAULT_NR_STRUCT_FIELDS); type_class->name = g_quark_from_string(name); type_class->alignment = 1; type_class->copy = struct_copy; - type_class->free = _struct_type_free; + type_class->class_free = _struct_type_class_free; + type_class->type_new = _struct_type_new; + type_class->type_free = _struct_type_free; type_class->ref = 1; if (type_class->name) { @@ -96,20 +101,57 @@ struct type_class_struct *struct_type_new(const char *name) return struct_class; error_register: + g_hash_table_destroy(struct_class->fields_by_name); + g_array_free(struct_class->fields, true); g_free(struct_class); return NULL; } -void struct_type_add_field(struct type_class_struct *struct_class, - const char *field_name, - struct type_class *type_class) +static +struct type_struct *_struct_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) { - struct field *field; + struct type_class_struct *_struct_class = + container_of(type_class, struct type_class_struct, p); + struct type_struct *_struct; + + _struct = g_new(struct type_struct, 1); + type_class_ref(&_struct_class->p); + _struct->p._class = _struct_class; + _struct->p.ref = 1; + _struct->scope = new_declaration_scope(parent_scope); + _struct->fields = g_array_sized_new(FALSE, TRUE, + sizeof(struct field), + DEFAULT_NR_STRUCT_FIELDS); + return &_struct->p; +} + +static +void _struct_type_free(struct type *type) +{ + struct type_struct *_struct = container_of(type, struct type_struct, p); + unsigned long i; + + for (i = 0; i < _struct->fields->len; i++) { + struct field *field = &g_array_index(_struct->fields, + struct field, i); + type_unref(field->type); + } + free_declaration_scope(_struct->scope); + type_class_unref(_struct->p._class); + g_free(_struct); +} + +void struct_type_class_add_field(struct type_class_struct *struct_class, + const char *field_name, + struct type_class *type_class) +{ + struct type_class_field *field; unsigned long index; g_array_set_size(struct_class->fields, struct_class->fields->len + 1); index = struct_class->fields->len - 1; /* last field (new) */ - field = &g_array_index(struct_class->fields, struct field, index); + field = &g_array_index(struct_class->fields, struct type_class_field, index); field->name = g_quark_from_string(field_name); type_ref(type_class); field->type_class = type_class; @@ -126,8 +168,8 @@ void struct_type_add_field(struct type_class_struct *struct_class, } unsigned long -struct_type_lookup_field_index(struct type_class_struct *struct_class, - GQuark field_name) +struct_type_class_lookup_field_index(struct type_class_struct *struct_class, + GQuark field_name) { unsigned long index; @@ -136,12 +178,22 @@ struct_type_lookup_field_index(struct type_class_struct *struct_class, return index; } +/* + * field returned only valid as long as the field structure is not appended to. + */ +struct type_class_field * +struct_type_class_get_field_from_index(struct type_class_struct *struct_class, + unsigned long index) +{ + return &g_array_index(struct_class->fields, struct type_class_field, index); +} + /* * field returned only valid as long as the field structure is not appended to. */ struct field * -struct_type_get_field_from_index(struct type_class_struct *struct_class, +struct_type_get_field_from_index(struct type_struct *struct_type, unsigned long index) { - return &g_array_index(struct_class->fields, struct field, index); + return &g_array_index(struct_type->fields, struct field, index); } diff --git a/types/types.c b/types/types.c index 6fb3e598..96133780 100644 --- a/types/types.c +++ b/types/types.c @@ -5,7 +5,7 @@ * * Types registry. * - * Copyright 2010 - Mathieu Desnoyers + * Copyright 2010, 2011 - Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,57 +22,87 @@ #include #include -/* - * Type hash table contains the registered types. Type registration is typically - * performed by a type plugin. - * TODO: support plugin unload (unregistration of types). - */ -GHashTable *type_classes; - -struct type_class *lookup_type(GQuark qname) +static +struct type_class *lookup_type_class_scope(GQuark qname, + struct declaration_scope *scope) { - return g_hash_table_lookup(type_classes, + return g_hash_table_lookup(scope->type_classes, (gconstpointer) (unsigned long) qname); } -static void free_type(struct type_class *type_class) +struct type_class *lookup_type_class(GQuark qname, + struct declaration_scope *scope) +{ + struct type_class *tc; + + while (scope) { + tc = lookup_type_class_scope(qname, scope); + if (tc) + return tc; + scope = scope->parent_scope; + } + return NULL; +} + +static void free_type_class(struct type_class *type_class) +{ + type_class->class_free(type_class); +} + +static void free_type(struct type *type) { - type_class->free(type_class); + type->p.type_free(type); } -int register_type(struct type_class *type_class) +int register_type_class(struct type_class *type_class, + struct declaration_scope *scope) { - if (lookup_type(type_class->name)) + /* Only lookup in local scope */ + if (lookup_type_class_scope(type_class->name, scope)) return -EEXIST; - g_hash_table_insert(type_classes, + g_hash_table_insert(scope->type_classes, (gpointer) (unsigned long) type_class->name, type_class); return 0; } -void type_ref(struct type_class *type_class) +void type_class_ref(struct type_class *type_class) { type_class->ref++; } -void type_unref(struct type_class *type_class) +void type_class_unref(struct type_class *type_class) { if (!--type_class->ref) - free_type(type_class); + free_type_class(type_class); } -int init_types(void) +void type_ref(struct type *type) { - type_classes = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) free_type); - if (!type_classes) - return -ENOMEM; - return 0; + type->ref++; } -int finalize_types(void) +void type_unref(struct type *type) { - g_hash_table_destroy(type_classes); - return 0; + if (!--type->ref) + free_type(type); +} + +struct declaration_scope * +new_declaration_scope(struct declaration_scope *parent_scope) +{ + struct declaration_scope *scope = g_new(struct declaration_scope, 1); + + scope->type_classes = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, + (GDestroyNotify) type_class_unref); + scope->parent_scope = parent_scope; + return scope; +} + +void free_declaration_scope(struct declaration_scope *scope) +{ + g_hash_table_destroy(scope->type_classes); + g_free(scope); } diff --git a/types/variant.c b/types/variant.c new file mode 100644 index 00000000..0cf0ca68 --- /dev/null +++ b/types/variant.c @@ -0,0 +1,247 @@ +/* + * variant.c + * + * BabelTrace - Variant Type Converter + * + * Copyright 2011 - Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + +#include +#include + + +static +struct type *variant_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope); +static +void variant_type_free(struct type *type); + +void variant_copy(struct stream_pos *dest, const struct format *fdest, + struct stream_pos *src, const struct format *fsrc, + struct type *type) +{ + struct type_variant *variant = container_of(type, struct type_variant, + p); + struct type_class_variant *variant_class = variant->_class; + struct field *field; + struct type_class *field_class; + unsigned long i; + + fsrc->variant_begin(src, variant_class); + fdest->variant_begin(dest, variant_class); + + field = variant_type_get_current_field(variant); + field_class = field->type->p._class; + field_class->copy(dest, fdest, src, fsrc, &field->type->p); + + fsrc->variant_end(src, variant_class); + fdest->variant_end(dest, variant_class); +} + +static +void variant_type_class_free(struct type_class *type_class) +{ + struct type_class_variant *variant_class = + container_of(type_class, struct type_class_variant, p); + unsigned long i; + + g_hash_table_destroy(struct_class->fields_by_tag); + + for (i = 0; i < variant_class->fields->len; i++) { + struct field *type_class_field = + &g_array_index(variant_class->fields, + struct type_class_field, i); + type_class_unref(field->type_class); + } + g_array_free(variant_class->fields, true); + g_free(variant_class); +} + +struct type_class_variant * +variant_type_class_new(const char *name) +{ + struct type_class_variant *variant_class; + struct type_class *type_class; + int ret; + + variant_class = g_new(struct type_class_variant, 1); + type_class = &variant_class->p; + variant_class->fields_by_tag = g_hash_table_new(g_direct_hash, + g_direct_equal); + variant_class->fields = g_array_sized_new(FALSE, TRUE, + sizeof(struct type_class_field), + DEFAULT_NR_STRUCT_FIELDS); + type_class->name = g_quark_from_string(name); + type_class->alignment = 1; + type_class->copy = variant_copy; + type_class->class_free = _variant_type_class_free; + type_class->type_new = _variant_type_new; + type_class->type_free = _variant_type_free; + type_class->ref = 1; + + if (type_class->name) { + ret = register_type(type_class); + if (ret) + goto error_register; + } + return struct_class; + +error_register: + g_hash_table_destroy(variant_class->fields_by_tag); + g_array_free(variant_class->fields, true); + g_free(variant_class); + return NULL; +} + +static +struct type_variant *_variant_type_new(struct type_class *type_class, + struct declaration_scope *parent_scope) +{ + struct type_class_variant *variant_class = + container_of(type_class, struct type_class_variant, p); + struct type_struct *variant; + + variant = g_new(struct type_variant, 1); + type_class_ref(&variant_class->p); + variant->p._class = variant_class; + variant->p.ref = 1; + variant->scope = new_declaration_scope(parent_scope); + variant->fields = g_array_sized_new(FALSE, TRUE, + sizeof(struct field), + DEFAULT_NR_STRUCT_FIELDS); + variant->current_field = NULL; + return &variant->p; +} + +static +void variant_type_free(struct type *type) +{ + struct type_variant *variant = container_of(type, struct type_variant, + p); + unsigned long i; + + for (i = 0; i < variant->fields->len; i++) { + struct field *field = &g_array_index(variant->fields, + struct field, i); + type_unref(field->type); + } + free_declaration_scope(variant->scope); + type_class_unref(variant->p._class); + g_free(variant); +} + +void variant_type_class_add_field(struct type_class_variant *variant_class, + const char *tag_name, + struct type_class *type_class) +{ + struct type_class_field *field; + unsigned long index; + + g_array_set_size(variant_class->fields, variant_class->fields->len + 1); + index = variant_class->fields->len - 1; /* last field (new) */ + field = &g_array_index(variant_class->fields, struct type_class_field, index); + field->name = g_quark_from_string(tag_name); + type_ref(type_class); + field->type_class = type_class; + /* Keep index in hash rather than pointer, because array can relocate */ + g_hash_table_insert(variant_class->fields_by_name, + (gpointer) (unsigned long) field->name, + (gpointer) index); + /* + * Alignment of variant is based on the alignment of its currently + * selected choice, so we leave variant alignment as-is (statically + * speaking). + */ +} + +struct type_class_field * +struct_type_class_get_field_from_tag(struct type_class_variant *variant_class, + GQuark tag) +{ + unsigned long index; + + index = (unsigned long) g_hash_table_lookup(variant_class->fields_by_tag, + (gconstpointer) (unsigned long) tag); + return &g_array_index(variant_class->fields, struct type_class_field, index); +} + +/* + * tag_instance is assumed to be an enumeration. + */ +int variant_type_set_tag(struct type_variant *variant, + struct type *enum_tag_instance) +{ + struct type_enum *_enum = + container_of(struct type_enum, variant->enum_tag, p); + struct type_class_enum *enum_class = _enum->_class; + int missing_field = 0; + unsigned long i; + + /* + * Strictly speaking, each enumerator must map to a field of the + * variant. However, we are even stricter here by requiring that each + * variant choice map to an enumerator too. We then validate that the + * number of enumerators equals the number of variant choices. + */ + if (variant->_class->fields->len != enum_get_nr_enumerators(enum_class)) + return -EPERM; + + for (i = 0; i < variant->_class->fields->len; i++) { + struct type_class_field *field_class = + &g_array_index(variant->_class->fields, + struct type_class_field, i); + if (!enum_quark_to_range_set(enum_class, field_class->name)) { + missing_field = 1; + break; + } + } + if (missing_field) + return -EPERM; + + /* + * Check the enumeration: it must map each value to one and only one + * enumerator tag. + * TODO: we should also check that each range map to one and only one + * tag. For the moment, we will simply check this dynamically in + * variant_type_get_current_field(). + */ + + /* Set the enum tag field */ + variant->enum_tag = enum_tag_instance; + return 0; +} + +/* + * field returned only valid as long as the field structure is not appended to. + */ +struct field * +variant_type_get_current_field(struct type_variant *variant) +{ + struct type_enum *_enum = + container_of(struct type_enum, variant->enum_tag, p); + struct variat_type_class *variant_class = variant->_class; + unsigned long index; + GArray *tag_array; + GQuark tag; + + tag_array = _enum->value; + /* + * The 1 to 1 mapping from enumeration to value should have been already + * checked. (see TODO above) + */ + assert(tag_array->len == 1); + tag = g_array_index(tag_array, GQuark, 0); + index = (unsigned long) g_hash_table_lookup(variant_class->fields_by_tag, + (gconstpointer) (unsigned long) tag); + return &g_array_index(variant_class->fields, struct field, index); +}