Also add new "variant" type.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Format registration.
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
.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,
*
* Enumeration mapping strings (quarks) from/to integers.
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#include <stdint.h>
#include <glib.h>
+/*
+ * The caller should unref the GArray.
+ */
GArray *ctf_enum_read(struct stream_pos *pos,
const struct type_class_enum *src)
{
--- /dev/null
+/*
+ * Common Trace Format
+ *
+ * Variant format access functions.
+ *
+ * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <babeltrace/ctf/types.h>
+
+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)
+{
+}
--- /dev/null
+#ifndef _BABELTRACE_CTF_METADATA_H
+#define _BABELTRACE_CTF_METADATA_H
+
+/*
+ * BabelTrace
+ *
+ * CTF Metadata Header
+ *
+ * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <babeltrace/types.h>
+#include <glib.h>
+
+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 */
*
* Trace Format Header
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
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,
*
* Type Header
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
}
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 */
};
/*
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;
/* 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.
*/
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 {
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
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 */
*
* BabelTrace - Array Type Converter
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#include <babeltrace/compiler.h>
#include <babeltrace/format.h>
+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;
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;
/* 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) {
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);
+}
*
* BabelTrace - Enumeration Type
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#include <stdint.h>
#include <glib.h>
+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)
{
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
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);
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;
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);
}
*
* BabelTrace - Float Type Converter
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#include <babeltrace/compiler.h>
#include <babeltrace/format.h>
+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);
}
}
-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;
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;
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);
+}
*
* BabelTrace - Integer Type Converter
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#include <babeltrace/format.h>
#include <stdint.h>
+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;
}
}
-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;
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;
}
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);
+}
*
* BabelTrace - Sequence Type Converter
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#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;
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);
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) {
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);
+}
*
* BabelTrace - String Type Converter
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#include <babeltrace/align.h>
#include <babeltrace/format.h>
+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);
}
}
-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;
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);
}
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);
+}
*
* BabelTrace - Structure Type Converter
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#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;
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) {
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;
}
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;
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);
}
*
* Types registry.
*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
#include <glib.h>
#include <errno.h>
-/*
- * 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);
}
--- /dev/null
+/*
+ * variant.c
+ *
+ * BabelTrace - Variant Type Converter
+ *
+ * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <babeltrace/compiler.h>
+#include <babeltrace/format.h>
+
+
+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);
+}