From 265e809cb65022c2d9f15c0ddc0d607445621b76 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Sat, 30 Jan 2016 01:19:01 -0500 Subject: [PATCH] Add bt_ctf_field_type_compare(): field type deep comparison MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The new bt_ctf_field_type_compare() function compares two field types recursively. The tag field type of variant field types are not compared; only the tag strings are compared. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- formats/ctf/ir/event-types.c | 442 ++++++++++++++++++++++++ include/babeltrace/ctf-ir/event-types.h | 17 + 2 files changed, 459 insertions(+) diff --git a/formats/ctf/ir/event-types.c b/formats/ctf/ir/event-types.c index db144a3f..c750d218 100644 --- a/formats/ctf/ir/event-types.c +++ b/formats/ctf/ir/event-types.c @@ -229,6 +229,44 @@ struct bt_ctf_field_type *(* const type_copy_funcs[])( [CTF_TYPE_STRING] = bt_ctf_field_type_string_copy, }; +static +int bt_ctf_field_type_integer_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_floating_point_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_enumeration_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_string_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_structure_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_variant_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_array_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); +static +int bt_ctf_field_type_sequence_compare(struct bt_ctf_field_type *, + struct bt_ctf_field_type *); + +static +int (* const type_compare_funcs[])(struct bt_ctf_field_type *, + struct bt_ctf_field_type *) = { + [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_compare, + [CTF_TYPE_ENUM] = bt_ctf_field_type_enumeration_compare, + [CTF_TYPE_FLOAT] = bt_ctf_field_type_floating_point_compare, + [CTF_TYPE_STRUCT] = bt_ctf_field_type_structure_compare, + [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_compare, + [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_compare, + [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_compare, + [CTF_TYPE_STRING] = bt_ctf_field_type_string_compare, +}; + static void destroy_enumeration_mapping(struct enumeration_mapping *mapping) { @@ -3417,3 +3455,407 @@ struct bt_ctf_field_type *bt_ctf_field_type_string_copy( end: return copy; } + +static +int bt_ctf_field_type_integer_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_integer *integer_a; + struct bt_ctf_field_type_integer *integer_b; + struct declaration_integer *decl_a; + struct declaration_integer *decl_b; + + integer_a = container_of(type_a, struct bt_ctf_field_type_integer, + parent); + integer_b = container_of(type_b, struct bt_ctf_field_type_integer, + parent); + decl_a = &integer_a->declaration; + decl_b = &integer_b->declaration; + + /* Length */ + if (decl_a->len != decl_b->len) { + goto end; + } + + /* + * Compare user byte orders only, not the cached, + * real byte orders. + */ + if (integer_a->user_byte_order != integer_b->user_byte_order) { + goto end; + } + + /* Signedness */ + if (decl_a->signedness != decl_b->signedness) { + goto end; + } + + /* Base */ + if (decl_a->base != decl_b->base) { + goto end; + } + + /* Encoding */ + if (decl_a->encoding != decl_b->encoding) { + goto end; + } + + /* Mapped clock */ + if (integer_a->mapped_clock != integer_b->mapped_clock) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_floating_point_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_floating_point *float_a; + struct bt_ctf_field_type_floating_point *float_b; + + float_a = container_of(type_a, + struct bt_ctf_field_type_floating_point, parent); + float_b = container_of(type_b, + struct bt_ctf_field_type_floating_point, parent); + + /* Sign length */ + if (float_a->sign.len != float_b->sign.len) { + goto end; + } + + /* Exponent length */ + if (float_a->exp.len != float_b->exp.len) { + goto end; + } + + /* Mantissa length */ + if (float_a->mantissa.len != float_b->mantissa.len) { + goto end; + } + + /* + * Compare user byte orders only, not the cached, + * real byte orders. + */ + if (float_a->user_byte_order != float_b->user_byte_order) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int compare_enumeration_mappings(struct enumeration_mapping *mapping_a, + struct enumeration_mapping *mapping_b) +{ + int ret = 1; + + /* Label */ + if (mapping_a->string != mapping_b->string) { + goto end; + } + + /* Range start */ + if (mapping_a->range_start._unsigned != + mapping_b->range_start._unsigned) { + goto end; + } + + /* Range end */ + if (mapping_a->range_end._unsigned != + mapping_b->range_end._unsigned) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_enumeration_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_enumeration *enum_a; + struct bt_ctf_field_type_enumeration *enum_b; + + enum_a = container_of(type_a, + struct bt_ctf_field_type_enumeration, parent); + enum_b = container_of(type_b, + struct bt_ctf_field_type_enumeration, parent); + + /* Container field type */ + ret = bt_ctf_field_type_compare(enum_a->container, enum_b->container); + if (ret) { + goto end; + } + + ret = 1; + + /* Entries */ + if (enum_a->entries->len != enum_b->entries->len) { + goto end; + } + + for (i = 0; i < enum_a->entries->len; ++i) { + struct enumeration_mapping *mapping_a = + g_ptr_array_index(enum_a->entries, i); + struct enumeration_mapping *mapping_b = + g_ptr_array_index(enum_b->entries, i); + + if (compare_enumeration_mappings(mapping_a, mapping_b)) { + goto end; + } + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_string_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_string *string_a; + struct bt_ctf_field_type_string *string_b; + + string_a = container_of(type_a, + struct bt_ctf_field_type_string, parent); + string_b = container_of(type_b, + struct bt_ctf_field_type_string, parent); + + /* Encoding */ + if (string_a->declaration.encoding != string_b->declaration.encoding) { + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int compare_structure_fields(struct structure_field *field_a, + struct structure_field *field_b) +{ + int ret = 1; + + /* Label */ + if (field_a->name != field_b->name) { + goto end; + } + + /* Type */ + ret = bt_ctf_field_type_compare(field_a->type, field_b->type); + +end: + return ret; +} + +static +int bt_ctf_field_type_structure_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_structure *struct_a; + struct bt_ctf_field_type_structure *struct_b; + + struct_a = container_of(type_a, + struct bt_ctf_field_type_structure, parent); + struct_b = container_of(type_b, + struct bt_ctf_field_type_structure, parent); + + /* Alignment */ + if (bt_ctf_field_type_get_alignment(type_a) != + bt_ctf_field_type_get_alignment(type_b)) { + goto end; + } + + /* Fields */ + if (struct_a->fields->len != struct_b->fields->len) { + goto end; + } + + for (i = 0; i < struct_a->fields->len; ++i) { + struct structure_field *field_a = + g_ptr_array_index(struct_a->fields, i); + struct structure_field *field_b = + g_ptr_array_index(struct_b->fields, i); + + ret = compare_structure_fields(field_a, field_b); + if (ret) { + goto end; + } + + ret = 1; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_variant_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + int i; + struct bt_ctf_field_type_variant *variant_a; + struct bt_ctf_field_type_variant *variant_b; + + variant_a = container_of(type_a, + struct bt_ctf_field_type_variant, parent); + variant_b = container_of(type_b, + struct bt_ctf_field_type_variant, parent); + + /* Tag name */ + if (strcmp(variant_a->tag_name->str, variant_b->tag_name->str)) { + goto end; + } + + /* Tag type */ + ret = bt_ctf_field_type_compare( + (struct bt_ctf_field_type *) variant_a->tag, + (struct bt_ctf_field_type *) variant_b->tag); + if (ret) { + goto end; + } + + ret = 1; + + /* Fields */ + if (variant_a->fields->len != variant_b->fields->len) { + goto end; + } + + for (i = 0; i < variant_a->fields->len; ++i) { + struct structure_field *field_a = + g_ptr_array_index(variant_a->fields, i); + struct structure_field *field_b = + g_ptr_array_index(variant_b->fields, i); + + ret = compare_structure_fields(field_a, field_b); + if (ret) { + goto end; + } + + ret = 1; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +static +int bt_ctf_field_type_array_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + struct bt_ctf_field_type_array *array_a; + struct bt_ctf_field_type_array *array_b; + + array_a = container_of(type_a, + struct bt_ctf_field_type_array, parent); + array_b = container_of(type_b, + struct bt_ctf_field_type_array, parent); + + /* Length */ + if (array_a->length != array_b->length) { + goto end; + } + + /* Element type */ + ret = bt_ctf_field_type_compare(array_a->element_type, + array_b->element_type); + +end: + return ret; +} + +static +int bt_ctf_field_type_sequence_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = -1; + struct bt_ctf_field_type_sequence *sequence_a; + struct bt_ctf_field_type_sequence *sequence_b; + + sequence_a = container_of(type_a, + struct bt_ctf_field_type_sequence, parent); + sequence_b = container_of(type_b, + struct bt_ctf_field_type_sequence, parent); + + /* Length name */ + if (strcmp(sequence_a->length_field_name->str, + sequence_b->length_field_name->str)) { + goto end; + } + + /* Element type */ + ret = bt_ctf_field_type_compare(sequence_a->element_type, + sequence_b->element_type); + +end: + return ret; +} + +int bt_ctf_field_type_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b) +{ + int ret = 1; + + if (type_a == type_b) { + /* Same reference: equal (even if both are NULL) */ + ret = 0; + goto end; + } + + if (!type_a || !type_b) { + ret = -1; + goto end; + } + + if (type_a->declaration->id != type_b->declaration->id) { + /* Different type IDs */ + goto end; + } + + if (type_a->declaration->id == CTF_TYPE_UNKNOWN) { + /* Both have unknown type IDs */ + goto end; + } + + ret = type_compare_funcs[type_a->declaration->id](type_a, type_b); + +end: + return ret; +} diff --git a/include/babeltrace/ctf-ir/event-types.h b/include/babeltrace/ctf-ir/event-types.h index 059a5b84..fbef87c8 100644 --- a/include/babeltrace/ctf-ir/event-types.h +++ b/include/babeltrace/ctf-ir/event-types.h @@ -741,6 +741,23 @@ extern enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order( extern int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, enum bt_ctf_byte_order byte_order); +/* + * bt_ctf_field_type_compare: compare two field types recursively + * + * Compare two field types recursively. + * + * The registered tag field type of a variant field type is ignored: + * only the tag strings are compared. + * + * @param type_a Field type A. + * @param type_b Field type B. + * + * Returns 0 if both field types are semantically equivalent, or a + * negative value when they are not equivalent or on error. + */ +extern int bt_ctf_field_type_compare(struct bt_ctf_field_type *type_a, + struct bt_ctf_field_type *type_b); + /* * bt_ctf_field_type_get_type_id: get a field type's ctf_type_id. * -- 2.34.1