From 45c51519900e100d9acda4acb9516ef69bc2d045 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 12 Jul 2019 15:03:40 -0400 Subject: [PATCH] lib: decouple variant FC option names from selector FC mapping names This patch makes the options of a variant field class (FC) which has a selector have their own range set, decoupled from any mapping of the selector FC. Motivation and solution ======================= In CTF 1.8, structure FC member and variant FC option names which start with `_` in the metadata stream must be "unescaped" by removing the `_` prefix. For example: struct { string _salut; string meow; }; `_salut` becomes `salut` in trace IR, while `meow` stays `meow`. CTF 1.8.2 specifies: > Fields starting with an underscore should have their leading > underscore removed by the CTF trace readers. Here, we interpret "should" as "must" because Babeltrace 1, Trace Compass, and other CTF consumers honor this recommandation. It is not specified, however, that this strategy applies to enumeration FC mapping labels. For example: enum { _SALUT, MEOW, }; In Babeltrace 1 (`text` output format and API), `_SALUT` and `MEOW` remain as is, so Babeltrace 2 should do the same. There's an issue however when an enumeration FC is used as a tag, or selector, for a variant FC: enum { _salut, _meow, } tag; variant { string _salut; int _meow; }; This is valid TSDL 1.8, but once in trace IR, the enumeration FC mapping labels need to stay as is, while the variant FC option names need to be unescaped. Once in trace IR, the equivalent would be: enum { _salut, _meow, } tag; variant { string salut; int meow; }; Before this patch, this is not valid because, when a variant FC has a selector FC, the option and mapping names must match exactly: we don't want to bring this CTF-specific escaping logic into the CTF-agnostic API. The current hack to avoid this, performed by `src.ctf.fs`, is to also unescape the mapping names, so as to get: enum { salut, meow, } tag; variant { string salut; int meow; }; However, this makes Babeltrace 2 not behave like Babeltrace 1 because the enumeration FC mapping names are different. For example, the `sink.text.pretty` outputs differ for the same CTF trace. The solution brought by this patch to fix this issue is to make the options of a variant FC have their own range set. Using the example above, the layout in trace IR becomes: enum { _salut, _meow, } tag; variant { string salut {0}; int meow {1}; }; where `{0}` and `{1}` are the range sets associated to the option. Here's another example: enum { _salut, _meow = 12, coucou = 17 ... 45, _meow = 1 ... 5, } tag; variant { string salut {0}; int meow {1 ... 5, 12}; int coucou[5] {17 ... 45}; }; This change allows `src.ctf.fs` to keep the enumeration FC mapping names as is while properly escaping the variant FC option names. Library changes =============== The simple variant field class type is replaced with three new variant field class types: Variant without a selector: You can create a variant FC without a selector FC, just like before, with bt_field_class_variant_create(), passing `NULL` as the `selector_field_class` parameter. The field class's type is `BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR`. You can use bt_field_class_variant_without_selector_append_option() to append an option (name and FC) to a variant FC without a selector. You can use bt_field_class_variant_borrow_option_by_index_const() and bt_field_class_variant_borrow_option_by_name_const() to borrow a variant FC (base) option from a variant FC without a selector. Variant with a selector: You can create a variant FC with a specific selector FC with bt_field_class_variant_create(). The selector FC must be an _integer_ FC. This is less strict than before: because each option has its own range set, the selector FC does not need to be an enumeration FC. It can be an enumeration FC, but there's no association between its mapping names and the variant FC option names. The field class types are `BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR` and `BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR`. There's an unsigned and a signed type to make the API typing more strict: a variant FC with an unsigned selector has specific option objects from which you can borrow unsigned integer range sets. You can use bt_field_class_variant_with_unsigned_selector_append_option() and bt_field_class_variant_with_signed_selector_append_option() to append an option (name, FC, and range set) to a variant FC with a selector. You can use bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const(), bt_field_class_variant_with_unsigned_selector_borrow_option_by_name_const(), bt_field_class_variant_with_signed_selector_borrow_option_by_index_const(), or bt_field_class_variant_with_signed_selector_borrow_option_by_name_const() to borrow a variant FC with a selector option from a variant FC with a selector. The option object's type is either `bt_field_class_variant_with_unsigned_selector_option` or `bt_field_class_variant_with_signed_selector_option`. You can convert it to a base option (to get its name and borrow its field class) with bt_field_class_variant_with_unsigned_selector_option_as_option_const() or bt_field_class_variant_with_signed_selector_option_as_option_const(). You can borrow the ranges of a variant FC with a selector option with bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const() or bt_field_class_variant_with_signed_selector_option_borrow_ranges_const(). You can use bt_field_class_variant_with_selector_borrow_selector_field_path_const() to borrow the selector field path from a variant FC with a selector. I also added the following functions for convenience: * bt_field_variant_borrow_selected_class_option_const() * bt_field_variant_with_unsigned_selector_borrow_selected_class_option_const() * bt_field_variant_with_signed_selector_borrow_selected_class_option_const() For consistency, bt_field_variant_select_option_field() is renamed to bt_field_variant_select_option_field_by_index(). This patch also makes an enumeration FC mapping contain an integer range set object. This was planned anyway, and not doing it here would have meant to duplicate and adapt code for the variant FC option ranges, for example in `sink.text.details` to sort the ranges of a range set. This means that bt_field_class_unsigned_enumeration_map_range() and bt_field_class_signed_enumeration_map_range() are replaced with bt_field_class_unsigned_enumeration_add_mapping() and bt_field_class_signed_enumeration_add_mapping() which accept resp. unsigned and signed integer range sets. This also means that bt_field_class_enumeration_mapping_get_range_count(), bt_field_class_unsigned_enumeration_mapping_get_range_by_index(), and bt_field_class_signed_enumeration_mapping_get_range_by_index() are replaced with bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const() and bt_field_class_signed_enumeration_mapping_borrow_ranges_const(). Because I needed it when adapting the project's plugins, I also added the following functions for convenience: * bt_field_class_unsigned_enumeration_borrow_mapping_by_label_const() * bt_field_class_signed_enumeration_borrow_mapping_by_label_const() Noteworthy plugin changes ========================= `src.ctf.fs`: * Enumeration FC mapping names are not unescaped anymore: they are kept as is. * A CTF IR named FC contains the original name and the escaped name. The original name is used to find the ranges of a variant FC option in the selector FC as the mapping names are not escaped anymore, so they potentially do not match the variant FC option names. * When translating a CTF IR variant FC to a trace IR variant FC, the trace IR selector (enumeration) FC's integer range set references are reused directly to append the corresponding variant FC options. `sink.ctf.fs`: * Enumeration FC mapping names are not escaped anymore: they are kept as is. * If a variant FC has a selector, then for each option, the component finds the corresponding mapping in the selector FC _by range set_ to know whether or not to escape the option name. This is because this must work (from `src.ctf.fs`): enum { salut, _meow, } tag; variant { string salut; int _meow; }; Once in trace IR, the `_meow` option becomes `meow`, but the `_meow` mapping keeps its original name. However, we know that, for `src.ctf.fs`, the range sets match exactly. For the `meow` option, the corresponding mapping is `_meow` because they both have the range set with the single range [1, 1]. In that case, when going back to TSDL, `sink.ctf.fs` writes `_meow` for the option name, while `salut` remains `salut`. I added new `sink.ctf.fs` tests, with new succeeding CTF traces, to verify that the component works as expected with those specific cases. If there's any issue when doing this, `sink.ctf.fs` falls back to creating a dedicated selector FC for the variant FC. For example, in trace IR, this is totally valid: enum { a = 2, b = 5, d = 8, } tag; variant { string a {2}; int b {11}; int c[22] {15 ... 19}; }; because there's no association between mapping names and option names. This too: int tag; variant { string a {2}; int b {11}; int c[22] {15 ... 19}; }; Those specimens cannot be translated to TSDL 1.8 however. * Because of changes in the way TSDL identifers are protected and validated, clock class names are not systematically escaped if it's not needed. Therefore the clock class name `default` remains `default`; it does not become `_default` like before. `sink.text.details`: * Variant FC option ranges are written next to the option's name: var: Variant (unsigned selector) (3 options, Selector field path [Event payload: 0]): COSSETTE: [0]: String _PELCHAT: [1]: String VOISINE: [2] [5, 19]: String * Enumeration FC mapping ranges are written next to the option's name instead of having one per line. I find this is more compact and easier to read as mappings typically do not contain a lot of ranges: tag: Unsigned enumeration (8-bit, Base 10, 3 mappings): COSSETTE: [0] VOISINE: [2] [5, 19] __PELCHAT: [1] Python bindings changes ======================= Essentially, the `bt2` Python package is updated to match the library's API changes: * `_EnumerationFieldClassMapping` is not a set anymore: it has a `ranges` property (which is a set). * _EnumerationFieldClass.map_range() is replaced with _EnumerationFieldClass.add_mapping() to which you pass an integer range set. * _EnumerationFieldClass.labels_for_value() is replaced with _EnumerationFieldClass.mappings_for_value() to get mappings instead of simple labels. * _EnumerationFieldClass.__getitem__() now uses bt_field_class_unsigned_enumeration_borrow_mapping_by_label_const() or bt_field_class_signed_enumeration_borrow_mapping_by_label_const(). * The new `_VariantFieldClassWithSelectorOption` object inherits `_VariantFieldClassOption`, adding a `ranges` property. * With a `_VariantFieldClass`, you can borrow base options (`_VariantFieldClassOption`) to get their names and field classes. * The new types `_VariantFieldClassWithoutSelector`, `_VariantFieldClassWithUnsignedSelector`, and `_VariantFieldClassWithSignedSelector` are analogous to the new types in the library's API. You can create them with _TraceClass.create_variant_field_class_without_selector() and _TraceClass.create_variant_field_class_with_selector(). The selector FC object must be an instance of `_IntegerFieldClass`. Signed-off-by: Philippe Proulx Change-Id: I084b03ea816ff8bee03ef5315c24fa24cfe74d80 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1717 Tested-by: jenkins --- .../babeltrace2/trace-ir/field-class-const.h | 77 +- include/babeltrace2/trace-ir/field-class.h | 70 +- include/babeltrace2/trace-ir/field-const.h | 12 + include/babeltrace2/trace-ir/field.h | 8 +- include/babeltrace2/types.h | 8 +- src/bindings/python/bt2/bt2/field.py | 6 +- src/bindings/python/bt2/bt2/field_class.py | 381 +++++--- .../python/bt2/bt2/native_bt_field_class.i | 42 - src/bindings/python/bt2/bt2/trace_class.py | 12 +- src/common/common.h | 8 +- src/lib/lib-logging.c | 32 +- src/lib/trace-ir/field-class.c | 872 ++++++++++++------ src/lib/trace-ir/field-class.h | 138 ++- src/lib/trace-ir/field.c | 105 ++- src/lib/trace-ir/field.h | 8 +- src/lib/trace-ir/resolve-field-path.c | 39 +- .../ctf/common/metadata/ctf-meta-resolve.c | 6 +- .../ctf/common/metadata/ctf-meta-translate.c | 147 ++- src/plugins/ctf/common/metadata/ctf-meta.h | 177 +++- .../ctf/common/metadata/visitor-generate-ir.c | 100 +- src/plugins/ctf/common/msg-iter/msg-iter.c | 6 +- src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h | 91 +- .../ctf/fs-sink/translate-ctf-ir-to-tsdl.c | 62 +- .../fs-sink/translate-trace-ir-to-ctf-ir.c | 648 ++++++++++++- .../debug-info/trace-ir-data-copy.c | 8 +- .../trace-ir-metadata-field-class-copy.c | 196 ++-- src/plugins/text/details/write.c | 341 ++++--- src/plugins/text/pretty/print.c | 4 +- tests/Makefile.am | 2 + tests/bindings/python/bt2/test_event.py | 16 +- tests/bindings/python/bt2/test_field.py | 20 +- tests/bindings/python/bt2/test_field_class.py | 498 ++++++---- tests/bindings/python/bt2/test_graph.py | 4 +- tests/bindings/python/bt2/test_message.py | 4 +- .../python/bt2/test_message_iterator.py | 4 +- tests/bindings/python/bt2/test_packet.py | 16 +- .../meta-variant-no-underscore/metadata | 24 + .../succeed/meta-variant-no-underscore/stream | Bin 0 -> 15 bytes .../meta-variant-one-underscore/metadata | 24 + .../meta-variant-one-underscore/stream | Bin 0 -> 15 bytes .../meta-variant-reserved-keywords/metadata | 74 ++ .../meta-variant-reserved-keywords/stream | Bin 0 -> 15 bytes .../metadata | 24 + .../meta-variant-same-with-underscore/stream | Bin 0 -> 15 bytes .../meta-variant-two-underscores/metadata | 24 + .../meta-variant-two-underscores/stream | Bin 0 -> 15 bytes .../sink.ctf.fs/succeed/trace-double.expect | 2 +- .../sink.ctf.fs/succeed/trace-float.expect | 2 +- .../trace-meta-variant-no-underscore.expect | 38 + .../trace-meta-variant-one-underscore.expect | 38 + ...race-meta-variant-reserved-keywords.expect | 88 ++ ...e-meta-variant-same-with-underscore.expect | 38 + .../trace-meta-variant-two-underscores.expect | 38 + .../plugins/sink.ctf.fs/succeed/test_succeed | 55 +- 54 files changed, 3248 insertions(+), 1389 deletions(-) create mode 100644 tests/data/ctf-traces/succeed/meta-variant-no-underscore/metadata create mode 100644 tests/data/ctf-traces/succeed/meta-variant-no-underscore/stream create mode 100644 tests/data/ctf-traces/succeed/meta-variant-one-underscore/metadata create mode 100644 tests/data/ctf-traces/succeed/meta-variant-one-underscore/stream create mode 100644 tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/metadata create mode 100644 tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/stream create mode 100644 tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/metadata create mode 100644 tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/stream create mode 100644 tests/data/ctf-traces/succeed/meta-variant-two-underscores/metadata create mode 100644 tests/data/ctf-traces/succeed/meta-variant-two-underscores/stream create mode 100644 tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-no-underscore.expect create mode 100644 tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-one-underscore.expect create mode 100644 tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-reserved-keywords.expect create mode 100644 tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-same-with-underscore.expect create mode 100644 tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-two-underscores.expect diff --git a/include/babeltrace2/trace-ir/field-class-const.h b/include/babeltrace2/trace-ir/field-class-const.h index 0f8536b1..844c9e32 100644 --- a/include/babeltrace2/trace-ir/field-class-const.h +++ b/include/babeltrace2/trace-ir/field-class-const.h @@ -46,7 +46,9 @@ typedef enum bt_field_class_type { BT_FIELD_CLASS_TYPE_STRUCTURE, BT_FIELD_CLASS_TYPE_STATIC_ARRAY, BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, - BT_FIELD_CLASS_TYPE_VARIANT, + BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR, } bt_field_class_type; typedef enum bt_field_class_integer_preferred_display_base { @@ -76,10 +78,18 @@ extern const bt_field_class_unsigned_enumeration_mapping * bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( const bt_field_class *field_class, uint64_t index); +extern const bt_field_class_unsigned_enumeration_mapping * +bt_field_class_unsigned_enumeration_borrow_mapping_by_label_const( + const bt_field_class *field_class, const char *label); + extern const bt_field_class_signed_enumeration_mapping * bt_field_class_signed_enumeration_borrow_mapping_by_index_const( const bt_field_class *field_class, uint64_t index); +extern const bt_field_class_signed_enumeration_mapping * +bt_field_class_signed_enumeration_borrow_mapping_by_label_const( + const bt_field_class *field_class, const char *label); + static inline const bt_field_class_enumeration_mapping * bt_field_class_unsigned_enumeration_mapping_as_mapping_const( @@ -99,18 +109,13 @@ bt_field_class_signed_enumeration_mapping_as_mapping_const( extern const char *bt_field_class_enumeration_mapping_get_label( const bt_field_class_enumeration_mapping *mapping); -extern uint64_t bt_field_class_enumeration_mapping_get_range_count( - const bt_field_class_enumeration_mapping *mapping); - -extern void -bt_field_class_unsigned_enumeration_mapping_get_range_by_index( - const bt_field_class_unsigned_enumeration_mapping *mapping, - uint64_t index, uint64_t *lower, uint64_t *upper); +extern const bt_integer_range_set_unsigned * +bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + const bt_field_class_unsigned_enumeration_mapping *mapping); -extern void -bt_field_class_signed_enumeration_mapping_get_range_by_index( - const bt_field_class_signed_enumeration_mapping *mapping, - uint64_t index, int64_t *lower, int64_t *upper); +extern const bt_integer_range_set_signed * +bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + const bt_field_class_signed_enumeration_mapping *mapping); typedef enum bt_field_class_enumeration_get_mapping_labels_for_value_status { BT_FIELD_CLASS_ENUMERATION_GET_MAPPING_LABELS_BY_VALUE_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, @@ -158,10 +163,6 @@ extern const bt_field_path * bt_field_class_dynamic_array_borrow_length_field_path_const( const bt_field_class *field_class); -extern const bt_field_path * -bt_field_class_variant_borrow_selector_field_path_const( - const bt_field_class *field_class); - extern uint64_t bt_field_class_variant_get_option_count( const bt_field_class *field_class); @@ -173,6 +174,22 @@ extern const bt_field_class_variant_option * bt_field_class_variant_borrow_option_by_name_const( const bt_field_class *field_class, const char *name); +extern const bt_field_class_variant_with_unsigned_selector_option * +bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const( + const bt_field_class *field_class, uint64_t index); + +extern const bt_field_class_variant_with_unsigned_selector_option * +bt_field_class_variant_with_unsigned_selector_borrow_option_by_name_const( + const bt_field_class *field_class, const char *name); + +extern const bt_field_class_variant_with_signed_selector_option * +bt_field_class_variant_with_signed_selector_borrow_option_by_index_const( + const bt_field_class *field_class, uint64_t index); + +extern const bt_field_class_variant_with_signed_selector_option * +bt_field_class_variant_with_signed_selector_borrow_option_by_name_const( + const bt_field_class *field_class, const char *name); + extern const char *bt_field_class_variant_option_get_name( const bt_field_class_variant_option *option); @@ -180,6 +197,34 @@ extern const bt_field_class * bt_field_class_variant_option_borrow_field_class_const( const bt_field_class_variant_option *option); +extern const bt_field_path * +bt_field_class_variant_with_selector_borrow_selector_field_path_const( + const bt_field_class *field_class); + +extern const bt_integer_range_set_unsigned * +bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const( + const bt_field_class_variant_with_unsigned_selector_option *option); + +static inline +const bt_field_class_variant_option * +bt_field_class_variant_with_unsigned_selector_option_as_option_const( + const bt_field_class_variant_with_unsigned_selector_option *option) +{ + return __BT_UPCAST_CONST(bt_field_class_variant_option, option); +} + +extern const bt_integer_range_set_signed * +bt_field_class_variant_with_signed_selector_option_borrow_ranges_const( + const bt_field_class_variant_with_signed_selector_option *option); + +static inline +const bt_field_class_variant_option * +bt_field_class_variant_with_signed_selector_option_as_option_const( + const bt_field_class_variant_with_signed_selector_option *option) +{ + return __BT_UPCAST_CONST(bt_field_class_variant_option, option); +} + extern void bt_field_class_get_ref(const bt_field_class *field_class); extern void bt_field_class_put_ref(const bt_field_class *field_class); diff --git a/include/babeltrace2/trace-ir/field-class.h b/include/babeltrace2/trace-ir/field-class.h index 31c81229..a8c3feaf 100644 --- a/include/babeltrace2/trace-ir/field-class.h +++ b/include/babeltrace2/trace-ir/field-class.h @@ -62,20 +62,20 @@ extern bt_field_class *bt_field_class_unsigned_enumeration_create( extern bt_field_class *bt_field_class_signed_enumeration_create( bt_trace_class *trace_class); -typedef enum bt_field_class_enumeration_map_range_status { - BT_FIELD_CLASS_ENUMERATION_MAP_RANGE_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, - BT_FIELD_CLASS_ENUMERATION_MAP_RANGE_STATUS_OK = __BT_FUNC_STATUS_OK, -} bt_field_class_enumeration_map_range_status; +typedef enum bt_field_class_enumeration_add_mapping_status { + BT_FIELD_CLASS_ENUMERATION_ADD_MAPPING_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, + BT_FIELD_CLASS_ENUMERATION_ADD_MAPPING_STATUS_OK = __BT_FUNC_STATUS_OK, +} bt_field_class_enumeration_add_mapping_status; -extern bt_field_class_enumeration_map_range_status -bt_field_class_unsigned_enumeration_map_range( +extern bt_field_class_enumeration_add_mapping_status +bt_field_class_unsigned_enumeration_add_mapping( bt_field_class *field_class, const char *label, - uint64_t range_lower, uint64_t range_upper); + const bt_integer_range_set_unsigned *range_set); -extern bt_field_class_enumeration_map_range_status -bt_field_class_signed_enumeration_map_range( +extern bt_field_class_enumeration_add_mapping_status +bt_field_class_signed_enumeration_add_mapping( bt_field_class *field_class, const char *label, - int64_t range_lower, int64_t range_upper); + const bt_integer_range_set_signed *range_set); extern bt_field_class *bt_field_class_string_create( bt_trace_class *trace_class); @@ -114,7 +114,7 @@ extern bt_field_class *bt_field_class_array_borrow_element_field_class( typedef enum bt_field_class_dynamic_array_set_length_field_class_status { BT_FIELD_CLASS_DYNAMIC_ARRAY_SET_LENGTH_FIELD_CLASS_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, - BT_FIELD_CLASS_DYNAMIC_ARRAY_SET_LENGTH_FIELD_CLASS_STATUS_OK = __BT_FUNC_STATUS_OK, + BT_FIELD_CLASS_DYNAMIC_ARRAY_SET_LENGTH_FIELD_CLASS_STATUS_OK = __BT_FUNC_STATUS_OK, } bt_field_class_dynamic_array_set_length_field_class_status; extern bt_field_class_dynamic_array_set_length_field_class_status @@ -123,37 +123,35 @@ bt_field_class_dynamic_array_set_length_field_class( bt_field_class *length_field_class); extern bt_field_class *bt_field_class_variant_create( - bt_trace_class *trace_class); - -typedef enum bt_field_class_variant_set_selector_field_class_status { - BT_FIELD_CLASS_VARIANT_SET_SELECTOR_FIELD_CLASS_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, - BT_FIELD_CLASS_VARIANT_SET_SELECTOR_FIELD_CLASS_STATUS_OK = __BT_FUNC_STATUS_OK, -} bt_field_class_variant_set_selector_field_class_status; - -extern bt_field_class_variant_set_selector_field_class_status -bt_field_class_variant_set_selector_field_class(bt_field_class *field_class, + bt_trace_class *trace_class, bt_field_class *selector_field_class); -typedef enum bt_field_class_variant_append_option_status { - BT_FIELD_CLASS_VARIANT_APPEND_OPTION_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, - BT_FIELD_CLASS_VARIANT_APPEND_OPTION_STATUS_OK = __BT_FUNC_STATUS_OK, -} bt_field_class_variant_append_option_status; +typedef enum bt_field_class_variant_without_selector_append_option_status { + BT_FIELD_CLASS_VARIANT_WITHOUT_SELECTOR_APPEND_OPTION_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, + BT_FIELD_CLASS_VARIANT_WITHOUT_SELECTOR_APPEND_OPTION_STATUS_OK = __BT_FUNC_STATUS_OK, +} bt_field_class_variant_without_selector_append_option_status; -extern bt_field_class_variant_append_option_status -bt_field_class_variant_append_option( - bt_field_class *var_field_class, - const char *name, bt_field_class *field_class); +extern bt_field_class_variant_without_selector_append_option_status +bt_field_class_variant_without_selector_append_option( + bt_field_class *var_field_class, const char *name, + bt_field_class *field_class); -extern bt_field_class_variant_option * -bt_field_class_variant_borrow_option_by_index( - bt_field_class *field_class, uint64_t index); +typedef enum bt_field_class_variant_with_selector_append_option_status { + BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_APPEND_OPTION_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, + BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_APPEND_OPTION_STATUS_OK = __BT_FUNC_STATUS_OK, +} bt_field_class_variant_with_selector_append_option_status; -extern bt_field_class_variant_option * -bt_field_class_variant_borrow_option_by_name( - bt_field_class *field_class, const char *name); +extern bt_field_class_variant_with_selector_append_option_status +bt_field_class_variant_with_unsigned_selector_append_option( + bt_field_class *var_field_class, const char *name, + bt_field_class *field_class, + const bt_integer_range_set_unsigned *range_set); -extern bt_field_class *bt_field_class_variant_option_borrow_field_class( - bt_field_class_variant_option *option); +extern bt_field_class_variant_with_selector_append_option_status +bt_field_class_variant_with_signed_selector_append_option( + bt_field_class *var_field_class, const char *name, + bt_field_class *field_class, + const bt_integer_range_set_signed *range_set); #ifdef __cplusplus } diff --git a/include/babeltrace2/trace-ir/field-const.h b/include/babeltrace2/trace-ir/field-const.h index 6509dcb8..e9190f47 100644 --- a/include/babeltrace2/trace-ir/field-const.h +++ b/include/babeltrace2/trace-ir/field-const.h @@ -89,6 +89,18 @@ extern const bt_field * bt_field_variant_borrow_selected_option_field_const( const bt_field *field); +extern const bt_field_class_variant_option * +bt_field_variant_borrow_selected_class_option_const( + const bt_field *field); + +extern const bt_field_class_variant_with_unsigned_selector_option * +bt_field_variant_with_unsigned_selector_borrow_selected_class_option_const( + const bt_field *field); + +extern const bt_field_class_variant_with_signed_selector_option * +bt_field_variant_with_signed_selector_borrow_selected_class_option_const( + const bt_field *field); + #ifdef __cplusplus } #endif diff --git a/include/babeltrace2/trace-ir/field.h b/include/babeltrace2/trace-ir/field.h index 27fd1539..c3b92151 100644 --- a/include/babeltrace2/trace-ir/field.h +++ b/include/babeltrace2/trace-ir/field.h @@ -82,12 +82,12 @@ extern bt_field_dynamic_array_set_length_status bt_field_dynamic_array_set_length( bt_field *field, uint64_t length); -typedef enum bt_field_variant_select_option_field_status { +typedef enum bt_field_variant_select_option_field_by_index_status { BT_FIELD_VARIANT_SELECT_OPTION_FIELD_STATUS_OK = __BT_FUNC_STATUS_OK, -} bt_field_variant_select_option_field_status; +} bt_field_variant_select_option_field_by_index_status; -extern bt_field_variant_select_option_field_status -bt_field_variant_select_option_field( +extern bt_field_variant_select_option_field_by_index_status +bt_field_variant_select_option_field_by_index( bt_field *field, uint64_t index); extern bt_field *bt_field_variant_borrow_selected_option_field( diff --git a/include/babeltrace2/types.h b/include/babeltrace2/types.h index a3992ba0..43357d8f 100644 --- a/include/babeltrace2/types.h +++ b/include/babeltrace2/types.h @@ -91,18 +91,20 @@ typedef struct bt_component_filter bt_component_filter; typedef struct bt_component_sink bt_component_sink; typedef struct bt_component_source bt_component_source; typedef struct bt_connection bt_connection; +typedef struct bt_error bt_error; +typedef struct bt_error_cause bt_error_cause; typedef struct bt_event bt_event; typedef struct bt_event_class bt_event_class; typedef struct bt_event_header_field bt_event_header_field; -typedef struct bt_error bt_error; -typedef struct bt_error_cause bt_error_cause; typedef struct bt_field bt_field; typedef struct bt_field_class bt_field_class; typedef struct bt_field_class_enumeration_mapping bt_field_class_enumeration_mapping; typedef struct bt_field_class_signed_enumeration_mapping bt_field_class_signed_enumeration_mapping; -typedef struct bt_field_class_unsigned_enumeration_mapping bt_field_class_unsigned_enumeration_mapping; typedef struct bt_field_class_structure_member bt_field_class_structure_member; +typedef struct bt_field_class_unsigned_enumeration_mapping bt_field_class_unsigned_enumeration_mapping; typedef struct bt_field_class_variant_option bt_field_class_variant_option; +typedef struct bt_field_class_variant_with_signed_selector_option bt_field_class_variant_with_signed_selector_option; +typedef struct bt_field_class_variant_with_unsigned_selector_option bt_field_class_variant_with_unsigned_selector_option; typedef struct bt_field_path bt_field_path; typedef struct bt_field_path_item bt_field_path_item; typedef struct bt_graph bt_graph; diff --git a/src/bindings/python/bt2/bt2/field.py b/src/bindings/python/bt2/bt2/field.py index 0f3e5e7e..a1c2bf32 100644 --- a/src/bindings/python/bt2/bt2/field.py +++ b/src/bindings/python/bt2/bt2/field.py @@ -446,7 +446,7 @@ class _VariantField(_ContainerField, _Field): @selected_option_index.setter def selected_option_index(self, index): - native_bt.field_variant_select_option_field(self._ptr, index) + native_bt.field_variant_select_option_field_by_index(self._ptr, index) @property def selected_option(self): @@ -580,5 +580,7 @@ _TYPE_ID_TO_OBJ = { native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureField, native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayField, native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayField, - native_bt.FIELD_CLASS_TYPE_VARIANT: _VariantField, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: _VariantField, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: _VariantField, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: _VariantField, } diff --git a/src/bindings/python/bt2/bt2/field_class.py b/src/bindings/python/bt2/bt2/field_class.py index 16d46922..0ccea041 100644 --- a/src/bindings/python/bt2/bt2/field_class.py +++ b/src/bindings/python/bt2/bt2/field_class.py @@ -24,6 +24,7 @@ from bt2 import native_bt, object, utils import collections.abc import bt2.field import bt2.field_path +import bt2.integer_range_set import bt2 @@ -107,105 +108,85 @@ class _RealFieldClass(_FieldClass): _is_single_precision = property(fset=_is_single_precision) -class _EnumerationFieldClassMappingRange: - def __init__(self, lower, upper): - self._lower = lower - self._upper = upper - - @property - def lower(self): - return self._lower - - @property - def upper(self): - return self._upper - - def __eq__(self, other): - return self.lower == other.lower and self.upper == other.upper - - -class _EnumerationFieldClassMapping(collections.abc.Set): +# an enumeration field class mapping does not have a reference count, so +# we copy the properties here to avoid eventual memory access errors. +class _EnumerationFieldClassMapping: def __init__(self, mapping_ptr): - self._mapping_ptr = mapping_ptr + base_mapping_ptr = self._as_enumeration_field_class_mapping_ptr(mapping_ptr) + self._label = native_bt.field_class_enumeration_mapping_get_label(base_mapping_ptr) + assert self._label is not None + ranges_ptr = self._mapping_borrow_ranges_ptr(mapping_ptr) + assert ranges_ptr is not None + self._ranges = self._ranges_type._create_from_ptr_and_get_ref(ranges_ptr) @property def label(self): - mapping_ptr = self._as_enumeration_field_class_mapping_ptr(self._mapping_ptr) - label = native_bt.field_class_enumeration_mapping_get_label(mapping_ptr) - assert label is not None - return label + return self._label - def __len__(self): - mapping_ptr = self._as_enumeration_field_class_mapping_ptr(self._mapping_ptr) - return native_bt.field_class_enumeration_mapping_get_range_count(mapping_ptr) - - def __contains__(self, other_range): - for curr_range in self: - if curr_range == other_range: - return True - return False - - def __iter__(self): - for idx in range(len(self)): - lower, upper = self._get_range_by_index(self._mapping_ptr, idx) - yield _EnumerationFieldClassMappingRange(lower, upper) + @property + def ranges(self): + return self._ranges class _UnsignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping): + _ranges_type = bt2.integer_range_set.UnsignedIntegerRangeSet _as_enumeration_field_class_mapping_ptr = staticmethod(native_bt.field_class_unsigned_enumeration_mapping_as_mapping_const) - _get_range_by_index = staticmethod(native_bt.field_class_unsigned_enumeration_mapping_get_range_by_index) + _mapping_borrow_ranges_ptr = staticmethod(native_bt.field_class_unsigned_enumeration_mapping_borrow_ranges_const) class _SignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping): + _ranges_type = bt2.integer_range_set.SignedIntegerRangeSet _as_enumeration_field_class_mapping_ptr = staticmethod(native_bt.field_class_signed_enumeration_mapping_as_mapping_const) - _get_range_by_index = staticmethod(native_bt.field_class_signed_enumeration_mapping_get_range_by_index) + _mapping_borrow_ranges_ptr = staticmethod(native_bt.field_class_signed_enumeration_mapping_borrow_ranges_const) class _EnumerationFieldClass(_IntegerFieldClass, collections.abc.Mapping): def __len__(self): count = native_bt.field_class_enumeration_get_mapping_count(self._ptr) - assert(count >= 0) + assert count >= 0 return count - def map_range(self, label, lower, upper=None): + def add_mapping(self, label, ranges): utils._check_str(label) + utils._check_type(ranges, self._range_set_type) - if upper is None: - upper = lower + if label in self: + raise bt2.Error("duplicate mapping label '{}'".format(label)) - status = self._map_range(self._ptr, label, lower, upper) + status = self._add_mapping(self._ptr, label, ranges._ptr) utils._handle_func_status(status, - "cannot add mapping to enumeration field class object") + 'cannot add mapping to enumeration field class object') - def labels_for_value(self, value): + def mappings_for_value(self, value): status, labels = self._get_mapping_labels_for_value(self._ptr, value) - utils._handle_func_status(status, "cannot get mapping labels") - return labels + utils._handle_func_status(status, 'cannot get mapping labels for value {}'.format(value)) + return [self[label] for label in labels] def __iter__(self): for idx in range(len(self)): mapping = self._get_mapping_by_index(self._ptr, idx) yield mapping.label - def __getitem__(self, key): - utils._check_str(key) - for idx in range(len(self)): - mapping = self._get_mapping_by_index(self._ptr, idx) - if mapping.label == key: - return mapping + def __getitem__(self, label): + utils._check_str(label) + mapping = self._get_mapping_by_label(self._ptr, label) - raise KeyError(key) + if mapping is None: + raise KeyError(label) + + return mapping def __iadd__(self, mappings): - for mapping in mappings.values(): - for range in mapping: - self.map_range(mapping.label, range.lower, range.upper) + for label, ranges in mappings: + self.add_mapping(label, ranges) return self class _UnsignedEnumerationFieldClass(_EnumerationFieldClass, _UnsignedIntegerFieldClass): _NAME = 'Unsigned enumeration' + _range_set_type = bt2.integer_range_set.UnsignedIntegerRangeSet + _add_mapping = staticmethod(native_bt.field_class_unsigned_enumeration_add_mapping) @staticmethod def _get_mapping_by_index(enum_ptr, index): @@ -214,10 +195,13 @@ class _UnsignedEnumerationFieldClass(_EnumerationFieldClass, _UnsignedIntegerFie return _UnsignedEnumerationFieldClassMapping(mapping_ptr) @staticmethod - def _map_range(enum_ptr, label, lower, upper): - utils._check_uint64(lower) - utils._check_uint64(upper) - return native_bt.field_class_unsigned_enumeration_map_range(enum_ptr, label, lower, upper) + def _get_mapping_by_label(enum_ptr, label): + mapping_ptr = native_bt.field_class_unsigned_enumeration_borrow_mapping_by_label_const(enum_ptr, label) + + if mapping_ptr is None: + return + + return _UnsignedEnumerationFieldClassMapping(mapping_ptr) @staticmethod def _get_mapping_labels_for_value(enum_ptr, value): @@ -227,6 +211,8 @@ class _UnsignedEnumerationFieldClass(_EnumerationFieldClass, _UnsignedIntegerFie class _SignedEnumerationFieldClass(_EnumerationFieldClass, _SignedIntegerFieldClass): _NAME = 'Signed enumeration' + _range_set_type = bt2.integer_range_set.SignedIntegerRangeSet + _add_mapping = staticmethod(native_bt.field_class_signed_enumeration_add_mapping) @staticmethod def _get_mapping_by_index(enum_ptr, index): @@ -235,10 +221,13 @@ class _SignedEnumerationFieldClass(_EnumerationFieldClass, _SignedIntegerFieldCl return _SignedEnumerationFieldClassMapping(mapping_ptr) @staticmethod - def _map_range(enum_ptr, label, lower, upper): - utils._check_int64(lower) - utils._check_int64(upper) - return native_bt.field_class_signed_enumeration_map_range(enum_ptr, label, lower, upper) + def _get_mapping_by_label(enum_ptr, label): + mapping_ptr = native_bt.field_class_signed_enumeration_borrow_mapping_by_label_const(enum_ptr, label) + + if mapping_ptr is None: + return + + return _SignedEnumerationFieldClassMapping(mapping_ptr) @staticmethod def _get_mapping_labels_for_value(enum_ptr, value): @@ -250,110 +239,244 @@ class _StringFieldClass(_FieldClass): _NAME = 'String' -class _FieldContainer(collections.abc.Mapping): +class _StructureFieldClassMember: + def __init__(self, name, field_class): + self._name = name + self._field_class = field_class + + @property + def name(self): + return self._name + + @property + def field_class(self): + return self._field_class + + +class _StructureFieldClass(_FieldClass, collections.abc.Mapping): + _NAME = 'Structure' + + def append_member(self, name, field_class): + utils._check_str(name) + utils._check_type(field_class, _FieldClass) + + if name in self: + raise bt2.Error("duplicate member name '{}'".format(name)) + + status = native_bt.field_class_structure_append_member(self._ptr, name, field_class._ptr) + utils._handle_func_status(status, + 'cannot append member to structure field class object') + def __len__(self): - count = self._get_element_count(self._ptr) + count = native_bt.field_class_structure_get_member_count(self._ptr) assert count >= 0 return count + @staticmethod + def _create_member_from_ptr(member_ptr): + name = native_bt.field_class_structure_member_get_name(member_ptr) + assert name is not None + fc_ptr = native_bt.field_class_structure_member_borrow_field_class_const(member_ptr) + assert fc_ptr is not None + fc = _create_field_class_from_ptr_and_get_ref(fc_ptr) + return _StructureFieldClassMember(name, fc) + def __getitem__(self, key): if not isinstance(key, str): - raise TypeError("key should be a 'str' object, got {}".format(key.__class__.__name__)) + raise TypeError("key must be a 'str' object, got '{}'".format(key.__class__.__name__)) - ptr = self._borrow_field_class_ptr_by_name(key) + member_ptr = native_bt.field_class_structure_borrow_member_by_name_const(self._ptr, key) - if ptr is None: + if member_ptr is None: raise KeyError(key) - return _create_field_class_from_ptr_and_get_ref(ptr) - - def _borrow_field_class_ptr_by_name(self, key): - element_ptr = self._borrow_element_by_name(self._ptr, key) - if element_ptr is None: - return - - return self._element_borrow_field_class(element_ptr) + return self._create_member_from_ptr(member_ptr) def __iter__(self): for idx in range(len(self)): - element_ptr = self._borrow_element_by_index(self._ptr, idx) - assert element_ptr is not None + member_ptr = native_bt.field_class_structure_borrow_member_by_index_const(self._ptr, idx) + assert member_ptr is not None + yield native_bt.field_class_structure_member_get_name(member_ptr) - yield self._element_get_name(element_ptr) - - def _append_element_common(self, name, field_class): - utils._check_str(name) - utils._check_type(field_class, _FieldClass) - status = self._append_element(self._ptr, name, field_class._ptr) - utils._handle_func_status(status, - "cannot add field to {} field class object".format(self._NAME.lower())) - - def __iadd__(self, fields): - for name, field_class in fields.items(): - self._append_element_common(name, field_class) + def __iadd__(self, members): + for name, field_class in members: + self.append_member(name, field_class) return self - def _at_index(self, index): + def member_at_index(self, index): utils._check_uint64(index) - if index < 0 or index >= len(self): + if index >= len(self): raise IndexError - element_ptr = self._borrow_element_by_index(self._ptr, index) - assert element_ptr is not None + member_ptr = native_bt.field_class_structure_borrow_member_by_index_const(self._ptr, index) + assert member_ptr is not None + return self._create_member_from_ptr(member_ptr) + - field_class_ptr = self._element_borrow_field_class(element_ptr) +class _VariantFieldClassOption: + def __init__(self, name, field_class): + self._name = name + self._field_class = field_class - return _create_field_class_from_ptr_and_get_ref(field_class_ptr) + @property + def name(self): + return self._name + @property + def field_class(self): + return self._field_class -class _StructureFieldClass(_FieldClass, _FieldContainer): - _NAME = 'Structure' - _borrow_element_by_index = staticmethod(native_bt.field_class_structure_borrow_member_by_index_const) - _borrow_element_by_name = staticmethod(native_bt.field_class_structure_borrow_member_by_name_const) - _element_get_name = staticmethod(native_bt.field_class_structure_member_get_name) - _element_borrow_field_class = staticmethod(native_bt.field_class_structure_member_borrow_field_class_const) - _get_element_count = staticmethod(native_bt.field_class_structure_get_member_count) - _append_element = staticmethod(native_bt.field_class_structure_append_member) - def append_member(self, name, field_class): - return self._append_element_common(name, field_class) +class _VariantFieldClassWithSelectorOption(_VariantFieldClassOption): + def __init__(self, name, field_class, ranges): + super().__init__(name, field_class) + self._ranges = ranges - def member_at_index(self, index): - return self._at_index(index) + @property + def ranges(self): + return self._ranges -class _VariantFieldClass(_FieldClass, _FieldContainer): +class _VariantFieldClass(_FieldClass, collections.abc.Mapping): _NAME = 'Variant' - _borrow_element_by_index = staticmethod(native_bt.field_class_variant_borrow_option_by_index_const) - _borrow_element_by_name = staticmethod(native_bt.field_class_variant_borrow_option_by_name_const) - _element_get_name = staticmethod(native_bt.field_class_variant_option_get_name) - _element_borrow_field_class = staticmethod(native_bt.field_class_variant_option_borrow_field_class_const) - _get_element_count = staticmethod(native_bt.field_class_variant_get_option_count) - _append_element = staticmethod(native_bt.field_class_variant_append_option) + _borrow_option_by_name_ptr = staticmethod(native_bt.field_class_variant_borrow_option_by_name_const) + _borrow_member_by_index_ptr = staticmethod(native_bt.field_class_variant_borrow_option_by_index_const) - def append_option(self, name, field_class): - return self._append_element_common(name, field_class) + @staticmethod + def _as_option_ptr(opt_ptr): + return opt_ptr + + def _create_option_from_ptr(self, opt_ptr): + name = native_bt.field_class_variant_option_get_name(opt_ptr) + assert name is not None + fc_ptr = native_bt.field_class_variant_option_borrow_field_class_const(opt_ptr) + assert fc_ptr is not None + fc = _create_field_class_from_ptr_and_get_ref(fc_ptr) + return _VariantFieldClassOption(name, fc) + + def __len__(self): + count = native_bt.field_class_variant_get_option_count(self._ptr) + assert count >= 0 + return count + + def __getitem__(self, key): + if not isinstance(key, str): + raise TypeError("key must be a 'str' object, got '{}'".format(key.__class__.__name__)) + + opt_ptr = self._borrow_option_by_name_ptr(self._ptr, key) + + if opt_ptr is None: + raise KeyError(key) + + return self._create_option_from_ptr(opt_ptr) + + def __iter__(self): + for idx in range(len(self)): + opt_ptr = self._borrow_member_by_index_ptr(self._ptr, idx) + assert opt_ptr is not None + base_opt_ptr = self._as_option_ptr(opt_ptr) + yield native_bt.field_class_variant_option_get_name(base_opt_ptr) def option_at_index(self, index): - return self._at_index(index) + utils._check_uint64(index) + + if index >= len(self): + raise IndexError + + opt_ptr = self._borrow_member_by_index_ptr(self._ptr, index) + assert opt_ptr is not None + return self._create_option_from_ptr(opt_ptr) + + +class _VariantFieldClassWithoutSelector(_VariantFieldClass): + _NAME = 'Variant (without selector)' + + def append_option(self, name, field_class): + utils._check_str(name) + utils._check_type(field_class, _FieldClass) + + if name in self: + raise bt2.Error("duplicate option name '{}'".format(name)) + + status = native_bt.field_class_variant_without_selector_append_option(self._ptr, name, field_class._ptr) + utils._handle_func_status(status, + 'cannot append option to variant field class object') + + def __iadd__(self, options): + for name, field_class in options: + self.append_option(name, field_class) + + return self + + +class _VariantFieldClassWithSelector(_VariantFieldClass): + _NAME = 'Variant (with selector)' + + def _create_option_from_ptr(self, opt_ptr): + base_opt_ptr = self._as_option_ptr(opt_ptr) + name = native_bt.field_class_variant_option_get_name(base_opt_ptr) + assert name is not None + fc_ptr = native_bt.field_class_variant_option_borrow_field_class_const(base_opt_ptr) + assert fc_ptr is not None + fc = _create_field_class_from_ptr_and_get_ref(fc_ptr) + range_set_ptr = self._option_borrow_ranges_ptr(opt_ptr) + assert range_set_ptr is not None + range_set = self._range_set_type._create_from_ptr_and_get_ref(range_set_ptr) + return _VariantFieldClassWithSelectorOption(name, fc, range_set) @property def selector_field_path(self): - ptr = native_bt.field_class_variant_borrow_selector_field_path_const(self._ptr) + ptr = native_bt.field_class_variant_with_selector_borrow_selector_field_path_const(self._ptr) + if ptr is None: return return bt2.field_path._FieldPath._create_from_ptr_and_get_ref(ptr) - def _set_selector_field_class(self, selector_fc): - utils._check_type(selector_fc, bt2.field_class._EnumerationFieldClass) - status = native_bt.field_class_variant_set_selector_field_class(self._ptr, selector_fc._ptr) + def append_option(self, name, field_class, ranges): + utils._check_str(name) + utils._check_type(field_class, _FieldClass) + utils._check_type(ranges, self._range_set_type) + + if name in self: + raise bt2.Error("duplicate option name '{}'".format(name)) + + if len(ranges) == 0: + raise ValueError('range set is empty') + + # TODO: check overlaps (precondition of self._append_option()) + + status = self._append_option(self._ptr, name, field_class._ptr, ranges._ptr) utils._handle_func_status(status, - "cannot set variant selector field type") + 'cannot append option to variant field class object') + + def __iadd__(self, options): + for name, field_class, ranges in options: + self.append_option(name, field_class, ranges) + + return self + + +class _VariantFieldClassWithUnsignedSelector(_VariantFieldClassWithSelector): + _NAME = 'Variant (with unsigned selector)' + _borrow_option_by_name_ptr = staticmethod(native_bt.field_class_variant_with_unsigned_selector_borrow_option_by_name_const) + _borrow_member_by_index_ptr = staticmethod(native_bt.field_class_variant_with_unsigned_selector_borrow_option_by_index_const) + _as_option_ptr = staticmethod(native_bt.field_class_variant_with_unsigned_selector_option_as_option_const) + _append_option = staticmethod(native_bt.field_class_variant_with_unsigned_selector_append_option) + _option_borrow_ranges_ptr = staticmethod(native_bt.field_class_variant_with_unsigned_selector_option_borrow_ranges_const) + _range_set_type = bt2.integer_range_set.UnsignedIntegerRangeSet + - _selector_field_class = property(fset=_set_selector_field_class) +class _VariantFieldClassWithSignedSelector(_VariantFieldClassWithSelector): + _NAME = 'Variant (with signed selector)' + _borrow_option_by_name_ptr = staticmethod(native_bt.field_class_variant_with_signed_selector_borrow_option_by_name_const) + _borrow_member_by_index_ptr = staticmethod(native_bt.field_class_variant_with_signed_selector_borrow_option_by_index_const) + _as_option_ptr = staticmethod(native_bt.field_class_variant_with_signed_selector_option_as_option_const) + _append_option = staticmethod(native_bt.field_class_variant_with_signed_selector_append_option) + _option_borrow_ranges_ptr = staticmethod(native_bt.field_class_variant_with_signed_selector_option_borrow_ranges_const) + _range_set_type = bt2.integer_range_set.SignedIntegerRangeSet class _ArrayFieldClass(_FieldClass): @@ -397,5 +520,7 @@ _FIELD_CLASS_TYPE_TO_OBJ = { native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureFieldClass, native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayFieldClass, native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayFieldClass, - native_bt.FIELD_CLASS_TYPE_VARIANT: _VariantFieldClass, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: _VariantFieldClassWithoutSelector, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: _VariantFieldClassWithUnsignedSelector, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: _VariantFieldClassWithSignedSelector, } diff --git a/src/bindings/python/bt2/bt2/native_bt_field_class.i b/src/bindings/python/bt2/bt2/native_bt_field_class.i index e5ed2a89..674d6938 100644 --- a/src/bindings/python/bt2/bt2/native_bt_field_class.i +++ b/src/bindings/python/bt2/bt2/native_bt_field_class.i @@ -45,47 +45,5 @@ } } -/* Output argument typemap for value output (always appends) */ -%typemap(in, numinputs=0) - (const bt_field_class_signed_enumeration_mapping_ranges **) - (bt_field_class_signed_enumeration_mapping_ranges *temp_value = NULL) { - $1 = &temp_value; -} - -%typemap(argout) - (const bt_field_class_signed_enumeration_mapping_ranges **) { - if (*$1) { - /* SWIG_Python_AppendOutput() steals the created object */ - $result = SWIG_Python_AppendOutput($result, - SWIG_NewPointerObj(SWIG_as_voidptr(*$1), - SWIGTYPE_p_bt_field_class_signed_enumeration_mapping_ranges, 0)); - } else { - /* SWIG_Python_AppendOutput() steals Py_None */ - Py_INCREF(Py_None); - $result = SWIG_Python_AppendOutput($result, Py_None); - } -} - -/* Output argument typemap for value output (always appends) */ -%typemap(in, numinputs=0) - (const bt_field_class_unsigned_enumeration_mapping_ranges **) - (bt_field_class_unsigned_enumeration_mapping_ranges *temp_value = NULL) { - $1 = &temp_value; -} - -%typemap(argout) - (const bt_field_class_unsigned_enumeration_mapping_ranges **) { - if (*$1) { - /* SWIG_Python_AppendOutput() steals the created object */ - $result = SWIG_Python_AppendOutput($result, - SWIG_NewPointerObj(SWIG_as_voidptr(*$1), - SWIGTYPE_p_bt_field_class_unsigned_enumeration_mapping_ranges, 0)); - } else { - /* SWIG_Python_AppendOutput() steals Py_None */ - Py_INCREF(Py_None); - $result = SWIG_Python_AppendOutput($result, Py_None); - } -} - %include %include diff --git a/src/bindings/python/bt2/bt2/trace_class.py b/src/bindings/python/bt2/bt2/trace_class.py index 9c825842..d5f63712 100644 --- a/src/bindings/python/bt2/bt2/trace_class.py +++ b/src/bindings/python/bt2/bt2/trace_class.py @@ -27,6 +27,7 @@ __all__ = ['_TraceClass'] import bt2 from bt2 import native_bt, utils, object import bt2.stream_class +import bt2.field_class import collections.abc import functools @@ -261,14 +262,15 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping): return obj def create_variant_field_class(self, selector_fc=None): - ptr = native_bt.field_class_variant_create(self._ptr) - self._check_create_status(ptr, 'variant') - obj = bt2.field_class._VariantFieldClass._create_from_ptr(ptr) + selector_fc_ptr = None if selector_fc is not None: - obj._selector_field_class = selector_fc + utils._check_type(selector_fc, bt2.field_class._IntegerFieldClass) + selector_fc_ptr = selector_fc._ptr - return obj + ptr = native_bt.field_class_variant_create(self._ptr, selector_fc_ptr) + self._check_create_status(ptr, 'variant') + return bt2.field_class._create_field_class_from_ptr_and_get_ref(ptr) # Add a listener to be called when the trace class is destroyed. diff --git a/src/common/common.h b/src/common/common.h index 0fdad32f..b7245275 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -424,8 +424,12 @@ const char *bt_common_field_class_type_string(enum bt_field_class_type class_typ return "BT_FIELD_CLASS_TYPE_STATIC_ARRAY"; case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: return "BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY"; - case BT_FIELD_CLASS_TYPE_VARIANT: - return "BT_FIELD_CLASS_TYPE_VARIANT"; + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + return "BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR"; + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + return "BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR"; + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: + return "BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR"; default: return "(unknown)"; } diff --git a/src/lib/lib-logging.c b/src/lib/lib-logging.c index 836ee9ad..fe72253d 100644 --- a/src/lib/lib-logging.c +++ b/src/lib/lib-logging.c @@ -259,7 +259,9 @@ static inline void format_field_class(char **buf_ch, bool extended, break; } - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { const struct bt_field_class_variant *var_fc = (const void *) field_class; @@ -269,16 +271,22 @@ static inline void format_field_class(char **buf_ch, bool extended, PRFIELD(var_fc->common.named_fcs->len)); } - if (var_fc->selector_fc) { - SET_TMP_PREFIX("selector-fc-"); - format_field_class(buf_ch, extended, tmp_prefix, - var_fc->selector_fc); - } + if (field_class->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || + field_class->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { + const struct bt_field_class_variant_with_selector *var_with_sel_fc = + (const void *) var_fc; - if (var_fc->selector_field_path) { - SET_TMP_PREFIX("selector-field-path-"); - format_field_path(buf_ch, extended, tmp_prefix, - var_fc->selector_field_path); + if (var_with_sel_fc->selector_fc) { + SET_TMP_PREFIX("selector-fc-"); + format_field_class(buf_ch, extended, tmp_prefix, + var_with_sel_fc->selector_fc); + } + + if (var_with_sel_fc->selector_field_path) { + SET_TMP_PREFIX("selector-field-path-"); + format_field_path(buf_ch, extended, tmp_prefix, + var_with_sel_fc->selector_field_path); + } } break; @@ -384,7 +392,9 @@ static inline void format_field(char **buf_ch, bool extended, break; } - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { const struct bt_field_variant *var_field = (const void *) field; diff --git a/src/lib/trace-ir/field-class.c b/src/lib/trace-ir/field-class.c index 30f85dbf..fb2e99ec 100644 --- a/src/lib/trace-ir/field-class.c +++ b/src/lib/trace-ir/field-class.c @@ -45,6 +45,7 @@ #include "field-path.h" #include "utils.h" #include "lib/func-status.h" +#include "lib/integer-range-set.h" enum bt_field_class_type bt_field_class_get_type( const struct bt_field_class *fc) @@ -58,7 +59,6 @@ void init_field_class(struct bt_field_class *fc, enum bt_field_class_type type, bt_object_release_func release_func) { BT_ASSERT(fc); - BT_ASSERT(bt_field_class_has_known_type(fc)); BT_ASSERT(release_func); bt_object_init_shared(&fc->base, release_func); fc->type = type; @@ -195,11 +195,10 @@ void finalize_enumeration_field_class_mapping( if (mapping->label) { g_string_free(mapping->label, TRUE); + mapping->label = NULL; } - if (mapping->ranges) { - g_array_free(mapping->ranges, TRUE); - } + BT_OBJECT_PUT_REF_AND_RESET(mapping->range_set); } static @@ -321,51 +320,80 @@ bt_field_class_signed_enumeration_borrow_mapping_by_index_const( return (const void *) BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, index); } -const char *bt_field_class_enumeration_mapping_get_label( - const struct bt_field_class_enumeration_mapping *mapping) +static +const struct bt_field_class_enumeration_mapping * +borrow_enumeration_field_class_mapping_by_label( + const struct bt_field_class_enumeration *fc, const char *label) { - BT_ASSERT_PRE_DEV_NON_NULL(mapping, "Enumeration field class mapping"); - return mapping->label->str; + struct bt_field_class_enumeration_mapping *mapping = NULL; + uint64_t i; + + BT_ASSERT(fc); + BT_ASSERT_PRE_DEV_NON_NULL(label, "Label"); + + for (i = 0; i < fc->mappings->len; i++) { + struct bt_field_class_enumeration_mapping *this_mapping = + BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, i); + + if (strcmp(this_mapping->label->str, label) == 0) { + mapping = this_mapping; + goto end; + } + } + +end: + return mapping; } -uint64_t bt_field_class_enumeration_mapping_get_range_count( - const struct bt_field_class_enumeration_mapping *mapping) +const struct bt_field_class_signed_enumeration_mapping * +bt_field_class_signed_enumeration_borrow_mapping_by_label_const( + const struct bt_field_class *fc, const char *label) { - BT_ASSERT_PRE_DEV_NON_NULL(mapping, "Enumeration field class mapping"); - return (uint64_t) mapping->ranges->len; + BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); + BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, + "Field class"); + return (const void *) borrow_enumeration_field_class_mapping_by_label( + (const void *) fc, label); } -static inline -void get_enumeration_field_class_mapping_range_at_index( - const struct bt_field_class_enumeration_mapping *mapping, - uint64_t index, uint64_t *lower, uint64_t *upper) +const struct bt_field_class_unsigned_enumeration_mapping * +bt_field_class_unsigned_enumeration_borrow_mapping_by_label_const( + const struct bt_field_class *fc, const char *label) { - const struct bt_field_class_enumeration_mapping_range *range; + BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); + BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, + BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, "Field class"); + return (const void *) borrow_enumeration_field_class_mapping_by_label( + (const void *) fc, label); +} - BT_ASSERT_PRE_DEV_NON_NULL(mapping, "Ranges"); - BT_ASSERT_PRE_DEV_NON_NULL(lower, "Range's lower (output)"); - BT_ASSERT_PRE_DEV_NON_NULL(upper, "Range's upper (output)"); - BT_ASSERT_PRE_DEV_VALID_INDEX(index, mapping->ranges->len); - range = BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(mapping, index); - *lower = range->lower.u; - *upper = range->upper.u; +const char *bt_field_class_enumeration_mapping_get_label( + const struct bt_field_class_enumeration_mapping *mapping) +{ + BT_ASSERT_PRE_DEV_NON_NULL(mapping, "Enumeration field class mapping"); + return mapping->label->str; } -void bt_field_class_unsigned_enumeration_mapping_get_range_by_index( - const struct bt_field_class_unsigned_enumeration_mapping *ranges, - uint64_t index, uint64_t *lower, uint64_t *upper) +const struct bt_integer_range_set_unsigned * +bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + const struct bt_field_class_unsigned_enumeration_mapping *u_mapping) { - get_enumeration_field_class_mapping_range_at_index( - (const void *) ranges, index, lower, upper); + const struct bt_field_class_enumeration_mapping *mapping = + (const void *) u_mapping; + + BT_ASSERT_PRE_DEV_NON_NULL(mapping, "Enumeration field class mapping"); + return (const void *) mapping->range_set; } -void bt_field_class_signed_enumeration_mapping_get_range_by_index( - const struct bt_field_class_signed_enumeration_mapping *ranges, - uint64_t index, int64_t *lower, int64_t *upper) +const struct bt_integer_range_set_signed * +bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + const struct bt_field_class_signed_enumeration_mapping *s_mapping) { - get_enumeration_field_class_mapping_range_at_index( - (const void *) ranges, index, - (uint64_t *) lower, (uint64_t *) upper); + const struct bt_field_class_enumeration_mapping *mapping = + (const void *) s_mapping; + + BT_ASSERT_PRE_DEV_NON_NULL(mapping, "Enumeration field class mapping"); + return (const void *) mapping->range_set; } enum bt_field_class_enumeration_get_mapping_labels_for_value_status @@ -389,10 +417,10 @@ bt_field_class_unsigned_enumeration_get_mapping_labels_for_value( const struct bt_field_class_enumeration_mapping *mapping = BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i); - for (j = 0; j < mapping->ranges->len; j++) { - const struct bt_field_class_enumeration_mapping_range *range = - BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX( - mapping, j); + for (j = 0; j < mapping->range_set->ranges->len; j++) { + const struct bt_integer_range *range = (const void *) + BT_INTEGER_RANGE_SET_RANGE_AT_INDEX( + mapping->range_set, j); if (value >= range->lower.u && value <= range->upper.u) { @@ -429,10 +457,10 @@ bt_field_class_signed_enumeration_get_mapping_labels_for_value( const struct bt_field_class_enumeration_mapping *mapping = BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i); - for (j = 0; j < mapping->ranges->len; j++) { - const struct bt_field_class_enumeration_mapping_range *range = - BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX( - mapping, j); + for (j = 0; j < mapping->range_set->ranges->len; j++) { + const struct bt_integer_range *range = (const void *) + BT_INTEGER_RANGE_SET_RANGE_AT_INDEX( + mapping->range_set, j); if (value >= range->lower.i && value <= range->upper.i) { @@ -448,122 +476,87 @@ bt_field_class_signed_enumeration_get_mapping_labels_for_value( return BT_FUNC_STATUS_OK; } -static inline -enum bt_field_class_enumeration_map_range_status -add_mapping_to_enumeration_field_class( - struct bt_field_class *fc, - const char *label, uint64_t lower, uint64_t upper) +static +bool enumeration_field_class_has_mapping_with_label( + const struct bt_field_class_enumeration *enum_fc, + const char *label) { - int ret = BT_FUNC_STATUS_OK; uint64_t i; - struct bt_field_class_enumeration *enum_fc = (void *) fc; - struct bt_field_class_enumeration_mapping *mapping = NULL; - struct bt_field_class_enumeration_mapping_range *range; + bool exists = false; - BT_ASSERT(fc); - BT_ASSERT_PRE_NON_NULL(label, "Label"); + BT_ASSERT(enum_fc); + BT_ASSERT(label); - /* Find existing mapping identified by this label */ for (i = 0; i < enum_fc->mappings->len; i++) { struct bt_field_class_enumeration_mapping *mapping_candidate = BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i); if (strcmp(mapping_candidate->label->str, label) == 0) { - mapping = mapping_candidate; - break; + exists = true; + goto end; } } - if (!mapping) { - /* Create new mapping for this label */ - g_array_set_size(enum_fc->mappings, enum_fc->mappings->len + 1); - mapping = BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, - enum_fc->mappings->len - 1); - mapping->ranges = g_array_new(FALSE, TRUE, - sizeof(struct bt_field_class_enumeration_mapping_range)); - if (!mapping->ranges) { - finalize_enumeration_field_class_mapping(mapping); - g_array_set_size(enum_fc->mappings, - enum_fc->mappings->len - 1); - ret = BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } +end: + return exists; +} - mapping->label = g_string_new(label); - if (!mapping->label) { - finalize_enumeration_field_class_mapping(mapping); - g_array_set_size(enum_fc->mappings, - enum_fc->mappings->len - 1); - ret = BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } +static inline +enum bt_field_class_enumeration_add_mapping_status +add_mapping_to_enumeration_field_class(struct bt_field_class *fc, + const char *label, const struct bt_integer_range_set *range_set) +{ + enum bt_field_class_enumeration_add_mapping_status status = + BT_FUNC_STATUS_OK; + struct bt_field_class_enumeration *enum_fc = (void *) fc; + struct bt_field_class_enumeration_mapping mapping = { 0 }; + + BT_ASSERT(fc); + BT_ASSERT_PRE_NON_NULL(label, "Label"); + BT_ASSERT_PRE_NON_NULL(range_set, "Range set"); + BT_ASSERT_PRE(!enumeration_field_class_has_mapping_with_label( + enum_fc, label), + "Duplicate mapping name in enumeration field class: " + "%![enum-fc-]+F, label=\"%s\"", fc, label); + mapping.range_set = range_set; + bt_object_get_ref(mapping.range_set); + mapping.label = g_string_new(label); + if (!mapping.label) { + finalize_enumeration_field_class_mapping(&mapping); + status = BT_FUNC_STATUS_MEMORY_ERROR; + goto end; } - /* Add range */ - BT_ASSERT(mapping); - g_array_set_size(mapping->ranges, mapping->ranges->len + 1); - range = BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(mapping, - mapping->ranges->len - 1); - range->lower.u = lower; - range->upper.u = upper; + g_array_append_val(enum_fc->mappings, mapping); BT_LIB_LOGD("Added mapping to enumeration field class: " - "%![fc-]+F, label=\"%s\", lower-unsigned=%" PRIu64 ", " - "upper-unsigned=%" PRIu64, fc, label, lower, upper); + "%![fc-]+F, label=\"%s\"", fc, label); end: - return ret; + return status; } -enum bt_field_class_enumeration_map_range_status -bt_field_class_unsigned_enumeration_map_range( +enum bt_field_class_enumeration_add_mapping_status +bt_field_class_unsigned_enumeration_add_mapping( struct bt_field_class *fc, const char *label, - uint64_t range_lower, uint64_t range_upper) + const struct bt_integer_range_set_unsigned *range_set) { - struct bt_field_class_enumeration *enum_fc = (void *) fc; - BT_ASSERT_PRE_NON_NULL(fc, "Field class"); BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, "Field class"); - BT_ASSERT_PRE(range_lower <= range_upper, - "Range's upper bound is less than lower bound: " - "upper=%" PRIu64 ", lower=%" PRIu64, - range_lower, range_upper); - BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(enum_fc->common.range, - range_lower), - "Range's lower bound is outside the enumeration field class's value range: " - "%![fc-]+F, lower=%" PRIu64, fc, range_lower); - BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(enum_fc->common.range, - range_upper), - "Range's upper bound is outside the enumeration field class's value range: " - "%![fc-]+F, upper=%" PRIu64, fc, range_upper); - return add_mapping_to_enumeration_field_class(fc, label, range_lower, - range_upper); -} - -enum bt_field_class_enumeration_map_range_status -bt_field_class_signed_enumeration_map_range( + return add_mapping_to_enumeration_field_class(fc, label, + (const void *) range_set); +} + +enum bt_field_class_enumeration_add_mapping_status +bt_field_class_signed_enumeration_add_mapping( struct bt_field_class *fc, const char *label, - int64_t range_lower, int64_t range_upper) + const struct bt_integer_range_set_signed *range_set) { - struct bt_field_class_enumeration *enum_fc = (void *) fc; - BT_ASSERT_PRE_NON_NULL(fc, "Field class"); BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, "Field class"); - BT_ASSERT_PRE(range_lower <= range_upper, - "Range's upper bound is less than lower bound: " - "upper=%" PRId64 ", lower=%" PRId64, - range_lower, range_upper); - BT_ASSERT_PRE(bt_util_value_is_in_range_signed(enum_fc->common.range, - range_lower), - "Range's lower bound is outside the enumeration field class's value range: " - "%![fc-]+F, lower=%" PRId64, fc, range_lower); - BT_ASSERT_PRE(bt_util_value_is_in_range_signed(enum_fc->common.range, - range_upper), - "Range's upper bound is outside the enumeration field class's value range: " - "%![fc-]+F, upper=%" PRId64, fc, range_upper); - return add_mapping_to_enumeration_field_class(fc, label, range_lower, - range_upper); + return add_mapping_to_enumeration_field_class(fc, label, + (const void *) range_set); } static @@ -624,15 +617,15 @@ static int init_named_field_classes_container( struct bt_field_class_named_field_class_container *fc, enum bt_field_class_type type, - bt_object_release_func release_func) + bt_object_release_func fc_release_func, + GDestroyNotify named_fc_destroy_func) { int ret = 0; - init_field_class((void *) fc, type, release_func); - fc->named_fcs = g_array_new(FALSE, TRUE, - sizeof(struct bt_named_field_class)); + init_field_class((void *) fc, type, fc_release_func); + fc->named_fcs = g_ptr_array_new_with_free_func(named_fc_destroy_func); if (!fc->named_fcs) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GArray."); + BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray."); ret = -1; goto end; } @@ -659,32 +652,49 @@ void finalize_named_field_class(struct bt_named_field_class *named_fc) if (named_fc->name) { g_string_free(named_fc->name, TRUE); + named_fc->name = NULL; } BT_LOGD_STR("Putting named field class's field class."); BT_OBJECT_PUT_REF_AND_RESET(named_fc->fc); } +static +void destroy_named_field_class(gpointer ptr) +{ + if (ptr) { + finalize_named_field_class(ptr); + g_free(ptr); + } +} + +static +void destroy_variant_with_selector_option(gpointer ptr) +{ + struct bt_field_class_variant_with_selector_option *opt = ptr; + + if (ptr) { + finalize_named_field_class(&opt->common); + BT_OBJECT_PUT_REF_AND_RESET(opt->range_set); + g_free(ptr); + } +} + static void finalize_named_field_classes_container( struct bt_field_class_named_field_class_container *fc) { - uint64_t i; - BT_ASSERT(fc); if (fc->named_fcs) { - for (i = 0; i < fc->named_fcs->len; i++) { - finalize_named_field_class( - &g_array_index(fc->named_fcs, - struct bt_named_field_class, i)); - } + g_ptr_array_free(fc->named_fcs, TRUE); + fc->named_fcs = NULL; - g_array_free(fc->named_fcs, TRUE); } if (fc->name_to_index) { g_hash_table_destroy(fc->name_to_index); + fc->name_to_index = NULL; } } @@ -713,8 +723,10 @@ struct bt_field_class *bt_field_class_structure_create( } ret = init_named_field_classes_container((void *) struct_fc, - BT_FIELD_CLASS_TYPE_STRUCTURE, destroy_structure_field_class); + BT_FIELD_CLASS_TYPE_STRUCTURE, destroy_structure_field_class, + destroy_named_field_class); if (ret) { + /* init_named_field_classes_container() logs errors */ goto error; } @@ -729,48 +741,108 @@ end: } static -int append_named_field_class_to_container_field_class( - struct bt_field_class_named_field_class_container *container_fc, +int init_named_field_class(struct bt_named_field_class *named_fc, const char *name, struct bt_field_class *fc) { - int ret = BT_FUNC_STATUS_OK; - struct bt_named_field_class *named_fc; - GString *name_str; + int status = BT_FUNC_STATUS_OK; - BT_ASSERT(container_fc); - BT_ASSERT_PRE_DEV_FC_HOT(container_fc, "Field class"); - BT_ASSERT_PRE_NON_NULL(name, "Name"); - BT_ASSERT_PRE_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE(!bt_g_hash_table_contains(container_fc->name_to_index, - name), - "Duplicate member/option name in structure/variant field class: " - "%![container-fc-]+F, name=\"%s\"", container_fc, name); - name_str = g_string_new(name); - if (!name_str) { + BT_ASSERT(named_fc); + BT_ASSERT(name); + BT_ASSERT(fc); + named_fc->name = g_string_new(name); + if (!named_fc->name) { BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - ret = BT_FUNC_STATUS_MEMORY_ERROR; + status = BT_FUNC_STATUS_MEMORY_ERROR; goto end; } - g_array_set_size(container_fc->named_fcs, - container_fc->named_fcs->len + 1); - named_fc = &g_array_index(container_fc->named_fcs, - struct bt_named_field_class, container_fc->named_fcs->len - 1); - named_fc->name = name_str; named_fc->fc = fc; - bt_object_get_no_null_check(fc); - g_hash_table_insert(container_fc->name_to_index, named_fc->name->str, - GUINT_TO_POINTER(container_fc->named_fcs->len - 1)); + bt_object_get_no_null_check(named_fc->fc); + bt_named_field_class_freeze(named_fc); - /* - * Freeze the field class, but not the named field class (the - * user can still modify it, if possible, until the container - * itself is frozen). - */ - bt_field_class_freeze(fc); +end: + return status; +} + +static +struct bt_named_field_class *create_named_field_class(const char *name, + struct bt_field_class *fc) +{ + struct bt_named_field_class *named_fc = g_new0( + struct bt_named_field_class, 1); + + if (!named_fc) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate a named field class."); + goto error; + } + + if (init_named_field_class(named_fc, name, fc)) { + /* init_named_field_class() logs errors */ + goto error; + } + + goto end; + +error: + destroy_named_field_class(named_fc); + named_fc = NULL; end: - return ret; + return named_fc; +} + +static +struct bt_field_class_variant_with_selector_option * +create_variant_with_selector_option( + const char *name, struct bt_field_class *fc, + const struct bt_integer_range_set *range_set) +{ + struct bt_field_class_variant_with_selector_option *opt = g_new0( + struct bt_field_class_variant_with_selector_option, 1); + + BT_ASSERT(range_set); + + if (!opt) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate a named field class."); + goto error; + } + + if (init_named_field_class(&opt->common, name, fc)) { + goto error; + } + + opt->range_set = range_set; + bt_object_get_no_null_check(opt->range_set); + bt_integer_range_set_freeze(range_set); + goto end; + +error: + destroy_variant_with_selector_option(opt); + opt = NULL; + +end: + return opt; +} + +static +int append_named_field_class_to_container_field_class( + struct bt_field_class_named_field_class_container *container_fc, + struct bt_named_field_class *named_fc) +{ + BT_ASSERT(container_fc); + BT_ASSERT(named_fc); + BT_ASSERT_PRE_DEV_FC_HOT(container_fc, "Field class"); + BT_ASSERT_PRE(!bt_g_hash_table_contains(container_fc->name_to_index, + named_fc->name->str), + "Duplicate member/option name in structure/variant field class: " + "%![container-fc-]+F, name=\"%s\"", container_fc, + named_fc->name->str); + g_ptr_array_add(container_fc->named_fcs, named_fc); + g_hash_table_insert(container_fc->name_to_index, named_fc->name->str, + GUINT_TO_POINTER(container_fc->named_fcs->len - 1)); + return BT_FUNC_STATUS_OK; } enum bt_field_class_structure_append_member_status @@ -778,12 +850,28 @@ bt_field_class_structure_append_member( struct bt_field_class *fc, const char *name, struct bt_field_class *member_fc) { + enum bt_field_class_structure_append_member_status status; + struct bt_named_field_class *named_fc = NULL; BT_ASSERT_PRE_NON_NULL(fc, "Field class"); BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE, "Field class"); - return append_named_field_class_to_container_field_class((void *) fc, - name, member_fc); + named_fc = create_named_field_class(name, member_fc); + if (!named_fc) { + /* create_named_field_class() logs errors */ + status = BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + status = append_named_field_class_to_container_field_class((void *) fc, + named_fc); + if (status == BT_FUNC_STATUS_OK) { + /* Moved to the container */ + named_fc = NULL; + } + +end: + return status; } uint64_t bt_field_class_structure_get_member_count( @@ -805,7 +893,7 @@ borrow_named_field_class_from_container_field_class_at_index( { BT_ASSERT(fc); BT_ASSERT_PRE_DEV_VALID_INDEX(index, fc->named_fcs->len); - return BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc, index); + return fc->named_fcs->pdata[index]; } const struct bt_field_class_structure_member * @@ -849,8 +937,7 @@ borrow_named_field_class_from_container_field_class_by_name( goto end; } - named_fc = BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc, - GPOINTER_TO_UINT(value)); + named_fc = fc->named_fcs->pdata[GPOINTER_TO_UINT(value)]; end: return named_fc; @@ -899,14 +986,12 @@ bt_field_class_structure_member_borrow_field_class_const( return named_fc->fc; } -struct bt_field_class * -bt_field_class_structure_member_borrow_field_class( - struct bt_field_class_structure_member *member) +static +void finalize_variant_field_class(struct bt_field_class_variant *var_fc) { - struct bt_named_field_class *named_fc = (void *) member; - - BT_ASSERT_PRE_DEV_NON_NULL(member, "Structure field class member"); - return named_fc->fc; + BT_ASSERT(var_fc); + BT_LIB_LOGD("Finalizing variant field class object: %!+F", var_fc); + finalize_named_field_classes_container((void *) var_fc); } static @@ -915,8 +1000,17 @@ void destroy_variant_field_class(struct bt_object *obj) struct bt_field_class_variant *fc = (void *) obj; BT_ASSERT(fc); - BT_LIB_LOGD("Destroying variant field class object: %!+F", fc); - finalize_named_field_classes_container((void *) fc); + finalize_variant_field_class(fc); + g_free(fc); +} + +static +void destroy_variant_with_selector_field_class(struct bt_object *obj) +{ + struct bt_field_class_variant_with_selector *fc = (void *) obj; + + BT_ASSERT(fc); + finalize_variant_field_class(&fc->common); BT_LOGD_STR("Putting selector field path."); BT_OBJECT_PUT_REF_AND_RESET(fc->selector_field_path); BT_LOGD_STR("Putting selector field class."); @@ -925,27 +1019,71 @@ void destroy_variant_field_class(struct bt_object *obj) } struct bt_field_class *bt_field_class_variant_create( - bt_trace_class *trace_class) + bt_trace_class *trace_class, bt_field_class *selector_fc) { int ret; struct bt_field_class_variant *var_fc = NULL; + struct bt_field_class_variant_with_selector *var_with_sel_fc = NULL; + enum bt_field_class_type fc_type; BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class"); - BT_LOGD_STR("Creating default variant field class object."); - var_fc = g_new0(struct bt_field_class_variant, 1); - if (!var_fc) { - BT_LIB_LOGE_APPEND_CAUSE( - "Failed to allocate one variant field class."); - goto error; + + if (selector_fc) { + BT_ASSERT_PRE_FC_IS_INT(selector_fc, "Selector field class"); } - ret = init_named_field_classes_container((void *) var_fc, - BT_FIELD_CLASS_TYPE_VARIANT, destroy_variant_field_class); - if (ret) { - goto error; + BT_LIB_LOGD("Creating default variant field class: %![sel-fc-]+F", + selector_fc); + + if (selector_fc) { + var_with_sel_fc = g_new0( + struct bt_field_class_variant_with_selector, 1); + if (!var_with_sel_fc) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate one variant field class with selector."); + goto error; + } + + if (selector_fc->type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || + selector_fc->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) { + fc_type = BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR; + } else { + fc_type = BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR; + } + + ret = init_named_field_classes_container( + (void *) var_with_sel_fc, fc_type, + destroy_variant_with_selector_field_class, + destroy_variant_with_selector_option); + if (ret) { + /* init_named_field_classes_container() logs errors */ + goto error; + } + + var_with_sel_fc->selector_fc = selector_fc; + bt_object_get_no_null_check(var_with_sel_fc->selector_fc); + bt_field_class_freeze(selector_fc); + var_fc = (void *) var_with_sel_fc; + } else { + var_fc = g_new0(struct bt_field_class_variant, 1); + if (!var_fc) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate one variant field class without selector."); + goto error; + } + + ret = init_named_field_classes_container((void *) var_fc, + BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR, + destroy_variant_field_class, destroy_named_field_class); + if (ret) { + /* init_named_field_classes_container() logs errors */ + goto error; + } } - BT_LIB_LOGD("Created variant field class object: %!+F", var_fc); + BT_ASSERT(var_fc); + BT_LIB_LOGD("Created default variant field class with selector object: " + "%![var-fc-]+F, %![sel-fc-]+F", var_fc, selector_fc); goto end; error: @@ -955,34 +1093,206 @@ end: return (void *) var_fc; } -enum bt_field_class_variant_set_selector_field_class_status -bt_field_class_variant_set_selector_field_class( - struct bt_field_class *fc, - struct bt_field_class *selector_fc) -{ - struct bt_field_class_variant *var_fc = (void *) fc; - - BT_ASSERT_PRE_NON_NULL(fc, "Variant field class"); - BT_ASSERT_PRE_NON_NULL(selector_fc, "Selector field class"); - BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class"); - BT_ASSERT_PRE_FC_IS_ENUM(selector_fc, "Selector field class"); - BT_ASSERT_PRE_DEV_FC_HOT(fc, "Variant field class"); - var_fc->selector_fc = selector_fc; - bt_object_get_no_null_check(selector_fc); - bt_field_class_freeze(selector_fc); - return BT_FUNC_STATUS_OK; +enum bt_field_class_variant_without_selector_append_option_status +bt_field_class_variant_without_selector_append_option(struct bt_field_class *fc, + const char *name, struct bt_field_class *option_fc) +{ + enum bt_field_class_variant_without_selector_append_option_status status; + struct bt_named_field_class *named_fc = NULL; + + BT_ASSERT_PRE_NON_NULL(fc, "Field class"); + BT_ASSERT_PRE_NON_NULL(name, "Name"); + BT_ASSERT_PRE_NON_NULL(option_fc, "Option field class"); + BT_ASSERT_PRE_FC_HAS_ID(fc, + BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR, "Field class"); + named_fc = create_named_field_class(name, option_fc); + if (!named_fc) { + /* create_named_field_class() logs errors */ + status = BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + status = append_named_field_class_to_container_field_class((void *) fc, + named_fc); + if (status == BT_FUNC_STATUS_OK) { + /* Moved to the container */ + named_fc = NULL; + } + +end: + if (named_fc) { + destroy_named_field_class(named_fc); + } + + return status; } -enum bt_field_class_variant_append_option_status -bt_field_class_variant_append_option( - struct bt_field_class *fc, - const char *name, struct bt_field_class *option_fc) +static +int ranges_overlap(GPtrArray *var_fc_opts, const struct bt_integer_range_set *range_set, + bool is_signed, bool *has_overlap) +{ + int status = BT_FUNC_STATUS_OK; + struct bt_integer_range_set *full_range_set; + uint64_t i; + + *has_overlap = false; + + /* + * Build a single range set with all the ranges and test for + * overlaps. + */ + if (is_signed) { + full_range_set = (void *) bt_integer_range_set_signed_create(); + } else { + full_range_set = (void *) bt_integer_range_set_unsigned_create(); + } + + if (!full_range_set) { + BT_LOGE_STR("Failed to create a range set."); + status = BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + /* Add existing option ranges */ + for (i = 0; i < var_fc_opts->len; i++) { + struct bt_field_class_variant_with_selector_option *opt = + var_fc_opts->pdata[i]; + uint64_t j; + + for (j = 0; j < opt->range_set->ranges->len; j++) { + struct bt_integer_range *range = BT_INTEGER_RANGE_SET_RANGE_AT_INDEX( + opt->range_set, j); + + if (is_signed) { + status = bt_integer_range_set_signed_add_range( + (void *) full_range_set, range->lower.i, + range->upper.i); + } else { + status = bt_integer_range_set_unsigned_add_range( + (void *) full_range_set, range->lower.u, + range->upper.u); + } + + if (status) { + goto end; + } + } + } + + /* Add new ranges */ + for (i = 0; i < range_set->ranges->len; i++) { + struct bt_integer_range *range = BT_INTEGER_RANGE_SET_RANGE_AT_INDEX( + range_set, i); + + if (is_signed) { + status = bt_integer_range_set_signed_add_range( + (void *) full_range_set, range->lower.i, + range->upper.i); + } else { + status = bt_integer_range_set_unsigned_add_range( + (void *) full_range_set, range->lower.u, + range->upper.u); + } + + if (status) { + goto end; + } + } + + /* Check overlaps */ + if (is_signed) { + *has_overlap = bt_integer_range_set_signed_has_overlaps(full_range_set); + } else { + *has_overlap = bt_integer_range_set_unsigned_has_overlaps( + full_range_set); + } + +end: + bt_object_put_ref(full_range_set); + return status; +} + +static +int append_option_to_variant_with_selector_field_class( + struct bt_field_class *fc, const char *name, + struct bt_field_class *option_fc, + const struct bt_integer_range_set *range_set, + enum bt_field_class_type expected_type) { + int status; + struct bt_field_class_variant_with_selector *var_fc = (void *) fc; + struct bt_field_class_variant_with_selector_option *opt = NULL; + bool has_overlap; BT_ASSERT_PRE_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class"); - return append_named_field_class_to_container_field_class((void *) fc, - name, option_fc); + BT_ASSERT_PRE_NON_NULL(name, "Name"); + BT_ASSERT_PRE_NON_NULL(option_fc, "Option field class"); + BT_ASSERT_PRE_NON_NULL(range_set, "Range set"); + BT_ASSERT_PRE_FC_HAS_ID(fc, expected_type, "Field class"); + BT_ASSERT_PRE(range_set->ranges->len > 0, + "Range set is empty: addr=%p", range_set); + status = ranges_overlap(var_fc->common.common.named_fcs, range_set, + expected_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR, + &has_overlap); + if (status) { + /* ranges_overlap() logs errors */ + goto end; + } + + BT_ASSERT_PRE(!has_overlap, + "Range set's ranges and existing ranges have an overlap: " + "addr=%p", range_set); + opt = create_variant_with_selector_option(name, option_fc, range_set); + if (!opt) { + /* create_variant_with_selector_option() logs errors */ + status = BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + status = append_named_field_class_to_container_field_class((void *) fc, + &opt->common); + if (status == BT_FUNC_STATUS_OK) { + /* Moved to the container */ + opt = NULL; + } + +end: + if (opt) { + destroy_variant_with_selector_option(opt); + } + + return status; +} + +enum bt_field_class_variant_with_selector_append_option_status +bt_field_class_variant_with_unsigned_selector_append_option( + struct bt_field_class *fc, const char *name, + struct bt_field_class *option_fc, + const struct bt_integer_range_set_unsigned *range_set) +{ + return append_option_to_variant_with_selector_field_class(fc, + name, option_fc, (const void *) range_set, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR); +} + +enum bt_field_class_variant_with_selector_append_option_status +bt_field_class_variant_with_signed_selector_append_option( + struct bt_field_class *fc, const char *name, + struct bt_field_class *option_fc, + const struct bt_integer_range_set_signed *range_set) +{ + return append_option_to_variant_with_selector_field_class(fc, + name, option_fc, (const void *) range_set, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR); +} + +uint64_t bt_field_class_variant_get_option_count(const struct bt_field_class *fc) +{ + const struct bt_field_class_variant *var_fc = (const void *) fc; + + BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); + BT_ASSERT_PRE_DEV_FC_IS_VARIANT(fc, "Field class"); + return (uint64_t) var_fc->common.named_fcs->len; } const struct bt_field_class_variant_option * @@ -990,51 +1300,71 @@ bt_field_class_variant_borrow_option_by_name_const( const struct bt_field_class *fc, const char *name) { BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, - "Field class"); + BT_ASSERT_PRE_DEV_FC_IS_VARIANT(fc, "Field class"); return (const void *) borrow_named_field_class_from_container_field_class_by_name( (void *) fc, name); } -struct bt_field_class_variant_option * -bt_field_class_variant_borrow_option_by_name( - struct bt_field_class *fc, const char *name) +const struct bt_field_class_variant_option * +bt_field_class_variant_borrow_option_by_index_const( + const struct bt_field_class *fc, uint64_t index) { BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class"); - return (void *) - borrow_named_field_class_from_container_field_class_by_name( - (void *) fc, name); + BT_ASSERT_PRE_DEV_FC_IS_VARIANT(fc, "Field class"); + return (const void *) + borrow_named_field_class_from_container_field_class_at_index( + (void *) fc, index); } -uint64_t bt_field_class_variant_get_option_count(const struct bt_field_class *fc) +const struct bt_field_class_variant_with_unsigned_selector_option * +bt_field_class_variant_with_unsigned_selector_borrow_option_by_name_const( + const struct bt_field_class *fc, const char *name) { - const struct bt_field_class_variant *var_fc = (const void *) fc; - BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class"); - return (uint64_t) var_fc->common.named_fcs->len; + BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR, + "Field class"); + return (const void *) + borrow_named_field_class_from_container_field_class_by_name( + (void *) fc, name); } -const struct bt_field_class_variant_option * -bt_field_class_variant_borrow_option_by_index_const( +const struct bt_field_class_variant_with_unsigned_selector_option * +bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const( const struct bt_field_class *fc, uint64_t index) { BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class"); + BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR, + "Field class"); return (const void *) borrow_named_field_class_from_container_field_class_at_index( (void *) fc, index); } -struct bt_field_class_variant_option * -bt_field_class_variant_borrow_option_by_index( - struct bt_field_class *fc, uint64_t index) +const struct bt_field_class_variant_with_signed_selector_option * +bt_field_class_variant_with_signed_selector_borrow_option_by_name_const( + const struct bt_field_class *fc, const char *name) { BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class"); - return (void *) + BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR, + "Field class"); + return (const void *) + borrow_named_field_class_from_container_field_class_by_name( + (void *) fc, name); +} + +const struct bt_field_class_variant_with_signed_selector_option * +bt_field_class_variant_with_signed_selector_borrow_option_by_index_const( + const struct bt_field_class *fc, uint64_t index) +{ + BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); + BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR, + "Field class"); + return (const void *) borrow_named_field_class_from_container_field_class_at_index( (void *) fc, index); } @@ -1058,25 +1388,37 @@ bt_field_class_variant_option_borrow_field_class_const( return named_fc->fc; } -struct bt_field_class * -bt_field_class_variant_option_borrow_field_class( - struct bt_field_class_variant_option *option) +const struct bt_integer_range_set_unsigned * +bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const( + const struct bt_field_class_variant_with_unsigned_selector_option *option) { - struct bt_named_field_class *named_fc = (void *) option; + const struct bt_field_class_variant_with_selector_option *opt = + (const void *) option; BT_ASSERT_PRE_DEV_NON_NULL(option, "Variant field class option"); - return named_fc->fc; + return (const void *) opt->range_set; +} + +const struct bt_integer_range_set_signed * +bt_field_class_variant_with_signed_selector_option_borrow_ranges_const( + const struct bt_field_class_variant_with_signed_selector_option *option) +{ + const struct bt_field_class_variant_with_selector_option *opt = + (const void *) option; + + BT_ASSERT_PRE_DEV_NON_NULL(option, "Variant field class option"); + return (const void *) opt->range_set; } const struct bt_field_path * -bt_field_class_variant_borrow_selector_field_path_const( +bt_field_class_variant_with_selector_borrow_selector_field_path_const( const struct bt_field_class *fc) { - const struct bt_field_class_variant *var_fc = (const void *) fc; + const struct bt_field_class_variant_with_selector *var_fc = + (const void *) fc; BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); - BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, - "Field class"); + BT_ASSERT_PRE_DEV_FC_IS_VARIANT_WITH_SEL(fc, "Field class"); return var_fc->selector_field_path; } @@ -1088,7 +1430,7 @@ void init_array_field_class(struct bt_field_class_array *fc, BT_ASSERT(element_fc); init_field_class((void *) fc, type, release_func); fc->element_fc = element_fc; - bt_object_get_no_null_check(element_fc); + bt_object_get_no_null_check(fc->element_fc); bt_field_class_freeze(element_fc); } @@ -1227,7 +1569,7 @@ bt_field_class_dynamic_array_set_length_field_class( BT_ASSERT_PRE_FC_IS_UNSIGNED_INT(length_fc, "Length field class"); BT_ASSERT_PRE_DEV_FC_HOT(fc, "Dynamic array field class"); array_fc->length_fc = length_fc; - bt_object_get_no_null_check(length_fc); + bt_object_get_no_null_check(array_fc->length_fc); bt_field_class_freeze(length_fc); return BT_FUNC_STATUS_OK; } @@ -1291,18 +1633,17 @@ void _bt_field_class_freeze(const struct bt_field_class *c_fc) switch (fc->type) { case BT_FIELD_CLASS_TYPE_STRUCTURE: - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { struct bt_field_class_named_field_class_container *container_fc = (void *) fc; uint64_t i; for (i = 0; i < container_fc->named_fcs->len; i++) { - struct bt_named_field_class *named_fc = - BT_FIELD_CLASS_NAMED_FC_AT_INDEX( - container_fc, i); - - bt_named_field_class_freeze(named_fc); + bt_named_field_class_freeze( + container_fc->named_fcs->pdata[i]); } break; @@ -1332,7 +1673,9 @@ void bt_field_class_make_part_of_trace_class(const struct bt_field_class *c_fc) switch (fc->type) { case BT_FIELD_CLASS_TYPE_STRUCTURE: - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { struct bt_field_class_named_field_class_container *container_fc = (void *) fc; @@ -1340,8 +1683,7 @@ void bt_field_class_make_part_of_trace_class(const struct bt_field_class *c_fc) for (i = 0; i < container_fc->named_fcs->len; i++) { struct bt_named_field_class *named_fc = - BT_FIELD_CLASS_NAMED_FC_AT_INDEX( - container_fc, i); + container_fc->named_fcs->pdata[i]; bt_field_class_make_part_of_trace_class(named_fc->fc); } diff --git a/src/lib/trace-ir/field-class.h b/src/lib/trace-ir/field-class.h index 447eaab3..476b86dc 100644 --- a/src/lib/trace-ir/field-class.h +++ b/src/lib/trace-ir/field-class.h @@ -28,6 +28,7 @@ #include #include #include "common/macros.h" +#include "common/common.h" #include "lib/object.h" #include #include @@ -49,6 +50,14 @@ #define _BT_ASSERT_PRE_FC_IS_UNSIGNED_INT_FMT(_name) \ _name " is not an unsigned integer field class: %![fc-]+F" + +#define _BT_ASSERT_PRE_FC_IS_SIGNED_INT_COND(_fc) \ + (((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER || \ + ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) + +#define _BT_ASSERT_PRE_FC_IS_SIGNED_INT_FMT(_name) \ + _name " is not a signed integer field class: %![fc-]+F" + #define _BT_ASSERT_PRE_FC_IS_ENUM_COND(_fc) \ (((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION || \ ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) @@ -63,6 +72,21 @@ #define _BT_ASSERT_PRE_FC_IS_ARRAY_FMT(_name) \ _name " is not an array field class: %![fc-]+F" +#define _BT_ASSERT_PRE_FC_IS_VARIANT_COND(_fc) \ + (((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR || \ + ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || \ + ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) + +#define _BT_ASSERT_PRE_FC_IS_VARIANT_FMT(_name) \ + _name " is not a variant field class: %![fc-]+F" + +#define _BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_COND(_fc) \ + (((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || \ + ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) + +#define _BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_FMT(_name) \ + _name " is not a variant field class with a selector: %![fc-]+F" + #define _BT_ASSERT_PRE_FC_HAS_ID_COND(_fc, _type) \ (((const struct bt_field_class *) (_fc))->type == (_type)) @@ -71,54 +95,74 @@ #define BT_ASSERT_PRE_FC_IS_INT(_fc, _name) \ BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_IS_INT_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_INT_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_INT_FMT(_name), (_fc)) #define BT_ASSERT_PRE_FC_IS_UNSIGNED_INT(_fc, _name) \ BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_IS_UNSIGNED_INT_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_UNSIGNED_INT_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_UNSIGNED_INT_FMT(_name), (_fc)) + +#define BT_ASSERT_PRE_FC_IS_SIGNED_INT(_fc, _name) \ + BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_IS_SIGNED_INT_COND(_fc), \ + _BT_ASSERT_PRE_FC_IS_SIGNED_INT_FMT(_name), (_fc)) #define BT_ASSERT_PRE_FC_IS_ENUM(_fc, _name) \ BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_IS_ENUM_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_ENUM_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_ENUM_FMT(_name), (_fc)) #define BT_ASSERT_PRE_FC_IS_ARRAY(_fc, _name) \ BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_IS_ARRAY_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_ARRAY_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_ARRAY_FMT(_name), (_fc)) + +#define BT_ASSERT_PRE_FC_IS_VARIANT(_fc, _name) \ + BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_IS_VARIANT_COND(_fc), \ + _BT_ASSERT_PRE_FC_IS_VARIANT_FMT(_name), (_fc)) + +#define BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL(_fc, _name) \ + BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_COND(_fc), \ + _BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_FMT(_name), (_fc)) #define BT_ASSERT_PRE_FC_HAS_ID(_fc, _type, _name) \ BT_ASSERT_PRE(_BT_ASSERT_PRE_FC_HAS_ID_COND((_fc), (_type)), \ - _BT_ASSERT_PRE_FC_HAS_ID_FMT(_name), \ - bt_common_field_class_type_string(_type), (_fc)) + _BT_ASSERT_PRE_FC_HAS_ID_FMT(_name), \ + bt_common_field_class_type_string(_type), (_fc)) #define BT_ASSERT_PRE_DEV_FC_IS_INT(_fc, _name) \ BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_IS_INT_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_INT_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_INT_FMT(_name), (_fc)) #define BT_ASSERT_PRE_DEV_FC_IS_UNSIGNED_INT(_fc, _name) \ BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_IS_UNSIGNED_INT_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_UNSIGNED_INT_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_UNSIGNED_INT_FMT(_name), (_fc)) + +#define BT_ASSERT_PRE_DEV_FC_IS_SIGNED_INT(_fc, _name) \ + BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_IS_SIGNED_INT_COND(_fc), \ + _BT_ASSERT_PRE_FC_IS_SIGNED_INT_FMT(_name), (_fc)) #define BT_ASSERT_PRE_DEV_FC_IS_ENUM(_fc, _name) \ BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_IS_ENUM_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_ENUM_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_ENUM_FMT(_name), (_fc)) #define BT_ASSERT_PRE_DEV_FC_IS_ARRAY(_fc, _name) \ BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_IS_ARRAY_COND(_fc), \ - _BT_ASSERT_PRE_FC_IS_ARRAY_FMT(_name), (_fc)) + _BT_ASSERT_PRE_FC_IS_ARRAY_FMT(_name), (_fc)) + +#define BT_ASSERT_PRE_DEV_FC_IS_VARIANT(_fc, _name) \ + BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_IS_VARIANT_COND(_fc), \ + _BT_ASSERT_PRE_FC_IS_VARIANT_FMT(_name), (_fc)) + +#define BT_ASSERT_PRE_DEV_FC_IS_VARIANT_WITH_SEL(_fc, _name) \ + BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_COND(_fc), \ + _BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_FMT(_name), (_fc)) #define BT_ASSERT_PRE_DEV_FC_HAS_ID(_fc, _type, _name) \ BT_ASSERT_PRE_DEV(_BT_ASSERT_PRE_FC_HAS_ID_COND((_fc), (_type)), \ - _BT_ASSERT_PRE_FC_HAS_ID_FMT(_name), \ - bt_common_field_class_type_string(_type), (_fc)) + _BT_ASSERT_PRE_FC_HAS_ID_FMT(_name), \ + bt_common_field_class_type_string(_type), (_fc)) #define BT_ASSERT_PRE_DEV_FC_HOT(_fc, _name) \ BT_ASSERT_PRE_DEV_HOT((const struct bt_field_class *) (_fc), \ (_name), ": %!+F", (_fc)) -#define BT_FIELD_CLASS_NAMED_FC_AT_INDEX(_fc, _index) \ - (&g_array_index(((struct bt_field_class_named_field_class_container *) (_fc))->named_fcs, \ - struct bt_named_field_class, (_index))) - #define BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(_fc, _index) \ (&g_array_index(((struct bt_field_class_enumeration *) (_fc))->mappings, \ struct bt_field_class_enumeration_mapping, (_index))) @@ -158,23 +202,11 @@ struct bt_field_class_integer { enum bt_field_class_integer_preferred_display_base base; }; -struct bt_field_class_enumeration_mapping_range { - union { - uint64_t u; - int64_t i; - } lower; - - union { - uint64_t u; - int64_t i; - } upper; -}; - struct bt_field_class_enumeration_mapping { GString *label; - /* Array of `struct bt_field_class_enumeration_mapping_range` */ - GArray *ranges; + /* Owner by this */ + const struct bt_integer_range_set *range_set; }; struct bt_field_class_unsigned_enumeration_mapping; @@ -219,22 +251,20 @@ struct bt_named_field_class { struct bt_field_class_structure_member; struct bt_field_class_variant_option; +struct bt_field_class_variant_with_unsigned_selector_option; +struct bt_field_class_variant_with_signed_selector_option; -/* - * This is the base field class for a container of named field classes. - * Structure and variant field classes inherit this. - */ struct bt_field_class_named_field_class_container { struct bt_field_class common; /* * Key: `const char *`, not owned by this (owned by named field - * type objects contained in `named_fcs` below). + * class objects contained in `named_fcs` below). */ GHashTable *name_to_index; - /* Array of `struct bt_named_field_class` */ - GArray *named_fcs; + /* Array of `struct bt_named_field_class *` */ + GPtrArray *named_fcs; }; struct bt_field_class_structure { @@ -263,23 +293,39 @@ struct bt_field_class_dynamic_array { struct bt_field_path *length_field_path; }; +/* Variant FC (with selector) option: named field class + range set */ +struct bt_field_class_variant_with_selector_option { + struct bt_named_field_class common; + + /* Owned by this */ + const struct bt_integer_range_set *range_set; +}; + struct bt_field_class_variant { + /* + * Depending on the variant field class type, the contained + * named field classes are of type + * `struct bt_named_field_class *` if the variant field class + * doesn't have a selector, or + * `struct bt_field_class_variant_with_selector_option *` + * if it has. + */ struct bt_field_class_named_field_class_container common; +}; - /* Weak: never dereferenced, only use to find it elsewhere */ - struct bt_field_class *selector_fc; +struct bt_field_class_variant_with_selector { + struct bt_field_class_variant common; + + /* + * Owned by this, but never dereferenced: only use to find it + * elsewhere. + */ + const struct bt_field_class *selector_fc; /* Owned by this */ struct bt_field_path *selector_field_path; }; -static inline -bool bt_field_class_has_known_type(const struct bt_field_class *fc) -{ - return fc->type >= BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER && - fc->type <= BT_FIELD_CLASS_TYPE_VARIANT; -} - BT_HIDDEN void _bt_field_class_freeze(const struct bt_field_class *field_class); diff --git a/src/lib/trace-ir/field.c b/src/lib/trace-ir/field.c index 26def356..b0a5b532 100644 --- a/src/lib/trace-ir/field.c +++ b/src/lib/trace-ir/field.c @@ -139,16 +139,18 @@ struct bt_field *create_variant_field(struct bt_field_class *); static struct bt_field *(* const field_create_funcs[])(struct bt_field_class *) = { - [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER] = create_integer_field, - [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER] = create_integer_field, - [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = create_integer_field, - [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION] = create_integer_field, - [BT_FIELD_CLASS_TYPE_REAL] = create_real_field, - [BT_FIELD_CLASS_TYPE_STRING] = create_string_field, - [BT_FIELD_CLASS_TYPE_STRUCTURE] = create_structure_field, - [BT_FIELD_CLASS_TYPE_STATIC_ARRAY] = create_static_array_field, - [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY] = create_dynamic_array_field, - [BT_FIELD_CLASS_TYPE_VARIANT] = create_variant_field, + [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER] = create_integer_field, + [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER] = create_integer_field, + [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = create_integer_field, + [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION] = create_integer_field, + [BT_FIELD_CLASS_TYPE_REAL] = create_real_field, + [BT_FIELD_CLASS_TYPE_STRING] = create_string_field, + [BT_FIELD_CLASS_TYPE_STRUCTURE] = create_structure_field, + [BT_FIELD_CLASS_TYPE_STATIC_ARRAY] = create_static_array_field, + [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY] = create_dynamic_array_field, + [BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR] = create_variant_field, + [BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR] = create_variant_field, + [BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR] = create_variant_field, }; static @@ -171,16 +173,18 @@ void destroy_variant_field(struct bt_field *field); static void (* const field_destroy_funcs[])(struct bt_field *) = { - [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER] = destroy_integer_field, - [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER] = destroy_integer_field, - [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = destroy_integer_field, - [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION] = destroy_integer_field, - [BT_FIELD_CLASS_TYPE_REAL] = destroy_real_field, - [BT_FIELD_CLASS_TYPE_STRING] = destroy_string_field, - [BT_FIELD_CLASS_TYPE_STRUCTURE] = destroy_structure_field, - [BT_FIELD_CLASS_TYPE_STATIC_ARRAY] = destroy_array_field, - [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY] = destroy_array_field, - [BT_FIELD_CLASS_TYPE_VARIANT] = destroy_variant_field, + [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER] = destroy_integer_field, + [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER] = destroy_integer_field, + [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = destroy_integer_field, + [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION] = destroy_integer_field, + [BT_FIELD_CLASS_TYPE_REAL] = destroy_real_field, + [BT_FIELD_CLASS_TYPE_STRING] = destroy_string_field, + [BT_FIELD_CLASS_TYPE_STRUCTURE] = destroy_structure_field, + [BT_FIELD_CLASS_TYPE_STATIC_ARRAY] = destroy_array_field, + [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY] = destroy_array_field, + [BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR] = destroy_variant_field, + [BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR] = destroy_variant_field, + [BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR] = destroy_variant_field, }; struct bt_field_class *bt_field_borrow_class(const struct bt_field *field) @@ -208,7 +212,6 @@ struct bt_field *bt_field_create(struct bt_field_class *fc) struct bt_field *field = NULL; BT_ASSERT(fc); - BT_ASSERT(bt_field_class_has_known_type(fc)); field = field_create_funcs[fc->type](fc); if (!field) { BT_LIB_LOGE_APPEND_CAUSE("Cannot create field object from field class: " @@ -320,8 +323,7 @@ int create_fields_from_named_field_classes( for (i = 0; i < fc->named_fcs->len; i++) { struct bt_field *field; - struct bt_named_field_class *named_fc = - BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc, i); + struct bt_named_field_class *named_fc = fc->named_fcs->pdata[i]; field = bt_field_create(named_fc->fc); if (!field) { @@ -854,8 +856,7 @@ struct bt_field *borrow_variant_field_selected_option_field( struct bt_field_variant *var_field = (void *) field; BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); - BT_ASSERT_PRE_DEV_FIELD_HAS_CLASS_TYPE(field, - BT_FIELD_CLASS_TYPE_VARIANT, "Field"); + BT_ASSERT_PRE_DEV_FIELD_IS_VARIANT(field, "Field"); BT_ASSERT_PRE_DEV(var_field->selected_field, "Variant field has no selected field: %!+f", field); return var_field->selected_field; @@ -873,15 +874,57 @@ const struct bt_field *bt_field_variant_borrow_selected_option_field_const( return borrow_variant_field_selected_option_field((void *) field); } -enum bt_field_variant_select_option_field_status -bt_field_variant_select_option_field( +static +const struct bt_field_class_variant_option * +borrow_variant_field_selected_class_option(const struct bt_field *field) +{ + const struct bt_field_class_named_field_class_container *container_fc; + const struct bt_field_variant *var_field = (const void *) field; + + BT_ASSERT(field); + BT_ASSERT_PRE_DEV(var_field->selected_field, + "Variant field has no selected field: %!+f", field); + container_fc = (const void *) field->class; + return container_fc->named_fcs->pdata[var_field->selected_index]; +} + +const struct bt_field_class_variant_option * +bt_field_variant_borrow_selected_class_option_const( + const struct bt_field *field) +{ + BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_IS_VARIANT(field, "Field"); + return borrow_variant_field_selected_class_option(field); +} + +const struct bt_field_class_variant_with_unsigned_selector_option * +bt_field_variant_with_unsigned_selector_borrow_selected_class_option_const( + const struct bt_field *field) +{ + BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_HAS_CLASS_TYPE(field, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR, "Field"); + return (const void *) borrow_variant_field_selected_class_option(field); +} + +const struct bt_field_class_variant_with_signed_selector_option * +bt_field_variant_with_signed_selector_borrow_selected_class_option_const( + const struct bt_field *field) +{ + BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_HAS_CLASS_TYPE(field, + BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR, "Field"); + return (const void *) borrow_variant_field_selected_class_option(field); +} + +enum bt_field_variant_select_option_field_by_index_status +bt_field_variant_select_option_field_by_index( struct bt_field *field, uint64_t index) { struct bt_field_variant *var_field = (void *) field; BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); - BT_ASSERT_PRE_DEV_FIELD_HAS_CLASS_TYPE(field, - BT_FIELD_CLASS_TYPE_VARIANT, "Field"); + BT_ASSERT_PRE_DEV_FIELD_IS_VARIANT(field, "Field"); BT_ASSERT_PRE_DEV_FIELD_HOT(field, "Field"); BT_ASSERT_PRE_DEV_VALID_INDEX(index, var_field->fields->len); var_field->selected_field = var_field->fields->pdata[index]; @@ -895,8 +938,7 @@ uint64_t bt_field_variant_get_selected_option_field_index( const struct bt_field_variant *var_field = (const void *) field; BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); - BT_ASSERT_PRE_DEV_FIELD_HAS_CLASS_TYPE(field, - BT_FIELD_CLASS_TYPE_VARIANT, "Field"); + BT_ASSERT_PRE_DEV_FIELD_IS_VARIANT(field, "Field"); BT_ASSERT_PRE_DEV(var_field->selected_field, "Variant field has no selected field: %!+f", field); return var_field->selected_index; @@ -1000,7 +1042,6 @@ BT_HIDDEN void bt_field_destroy(struct bt_field *field) { BT_ASSERT(field); - BT_ASSERT(bt_field_class_has_known_type(field->class)); field_destroy_funcs[field->class->type](field); } diff --git a/src/lib/trace-ir/field.h b/src/lib/trace-ir/field.h index f20378fc..ce595f97 100644 --- a/src/lib/trace-ir/field.h +++ b/src/lib/trace-ir/field.h @@ -64,6 +64,13 @@ ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, \ _name " is not an array field: %![field-]+f", (_field)) +#define BT_ASSERT_PRE_DEV_FIELD_IS_VARIANT(_field, _name) \ + BT_ASSERT_PRE_DEV( \ + ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR || \ + ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || \ + ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR, \ + _name " is not a variant field: %![field-]+f", (_field)) + #define BT_ASSERT_PRE_DEV_FIELD_IS_SET(_field, _name) \ BT_ASSERT_PRE_DEV(bt_field_is_set(_field), \ _name " is not set: %!+f", (_field)) @@ -187,7 +194,6 @@ bt_bool _bt_field_is_set(const struct bt_field *field) goto end; } - BT_ASSERT(bt_field_class_has_known_type(field->class)); BT_ASSERT(field->methods->is_set); is_set = field->methods->is_set(field); diff --git a/src/lib/trace-ir/resolve-field-path.c b/src/lib/trace-ir/resolve-field-path.c index 59fc0164..610e9cc0 100644 --- a/src/lib/trace-ir/resolve-field-path.c +++ b/src/lib/trace-ir/resolve-field-path.c @@ -48,7 +48,9 @@ bool find_field_class_recursive(struct bt_field_class *fc, switch (fc->type) { case BT_FIELD_CLASS_TYPE_STRUCTURE: - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { struct bt_field_class_named_field_class_container *container_fc = (void *) fc; @@ -56,8 +58,7 @@ bool find_field_class_recursive(struct bt_field_class *fc, for (i = 0; i < container_fc->named_fcs->len; i++) { struct bt_named_field_class *named_fc = - BT_FIELD_CLASS_NAMED_FC_AT_INDEX( - container_fc, i); + container_fc->named_fcs->pdata[i]; struct bt_field_path_item item = { .type = BT_FIELD_PATH_ITEM_TYPE_INDEX, .index = i, @@ -241,13 +242,16 @@ struct bt_field_class *borrow_child_field_class( switch (parent_fc->type) { case BT_FIELD_CLASS_TYPE_STRUCTURE: - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { + struct bt_field_class_named_field_class_container *container_fc = + (void *) parent_fc; struct bt_named_field_class *named_fc; BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX); - named_fc = BT_FIELD_CLASS_NAMED_FC_AT_INDEX(parent_fc, - fp_item->index); + named_fc = container_fc->named_fcs->pdata[fp_item->index]; child_fc = named_fc->fc; break; } @@ -292,7 +296,9 @@ bool target_field_path_in_different_scope_has_struct_fc_only( if (fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY || - fc->type == BT_FIELD_CLASS_TYPE_VARIANT) { + fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR || + fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || + fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { is_valid = false; goto end; } @@ -409,7 +415,9 @@ bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path, if (tgt_fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || tgt_fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY || - tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT) { + tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR || + tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || + tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { is_valid = false; goto end; } @@ -535,15 +543,17 @@ int bt_resolve_field_paths(struct bt_field_class *fc, break; } - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { - struct bt_field_class_variant *var_fc = (void *) fc; + struct bt_field_class_variant_with_selector *var_fc = + (void *) fc; if (var_fc->selector_fc) { BT_ASSERT(!var_fc->selector_field_path); var_fc->selector_field_path = resolve_field_path(fc, - var_fc->selector_fc, ctx); + (void *) var_fc->selector_fc, ctx); if (!var_fc->selector_field_path) { ret = -1; goto end; @@ -557,7 +567,9 @@ int bt_resolve_field_paths(struct bt_field_class *fc, /* Recursive part */ switch (fc->type) { case BT_FIELD_CLASS_TYPE_STRUCTURE: - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { struct bt_field_class_named_field_class_container *container_fc = (void *) fc; @@ -565,8 +577,7 @@ int bt_resolve_field_paths(struct bt_field_class *fc, for (i = 0; i < container_fc->named_fcs->len; i++) { struct bt_named_field_class *named_fc = - BT_FIELD_CLASS_NAMED_FC_AT_INDEX( - container_fc, i); + container_fc->named_fcs->pdata[i]; ret = bt_resolve_field_paths(named_fc->fc, ctx); if (ret) { diff --git a/src/plugins/ctf/common/metadata/ctf-meta-resolve.c b/src/plugins/ctf/common/metadata/ctf-meta-resolve.c index 05b67e93..6666d9eb 100644 --- a/src/plugins/ctf/common/metadata/ctf-meta-resolve.c +++ b/src/plugins/ctf/common/metadata/ctf-meta-resolve.c @@ -379,8 +379,8 @@ error: /* * Converts a path token list to a field path object. The path token * list is relative from `fc`. The index of the source looking for its - * target within `fc` is indicated by `src_index`. This can be `INT64_MAX` - * if the source is contained in `fc`. + * target within `fc` is indicated by `src_index`. This can be + * `INT64_MAX` if the source is contained in `fc`. * * `field_path` is an output parameter owned by the caller that must be * filled here. @@ -408,7 +408,7 @@ int ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path, child_index = -1; } else { child_index = - ctf_field_class_compound_get_field_class_index_from_name( + ctf_field_class_compound_get_field_class_index_from_orig_name( fc, ft_name); if (child_index < 0) { /* diff --git a/src/plugins/ctf/common/metadata/ctf-meta-translate.c b/src/plugins/ctf/common/metadata/ctf-meta-translate.c index af788824..b8372f24 100644 --- a/src/plugins/ctf/common/metadata/ctf-meta-translate.c +++ b/src/plugins/ctf/common/metadata/ctf-meta-translate.c @@ -83,15 +83,43 @@ bt_field_class *ctf_field_class_enum_to_ir(struct ctx *ctx, for (i = 0; i < fc->mappings->len; i++) { struct ctf_field_class_enum_mapping *mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, i); + void *range_set; + uint64_t range_i; if (fc->base.is_signed) { - ret = bt_field_class_signed_enumeration_map_range( - ir_fc, mapping->label->str, - mapping->range.lower.i, mapping->range.upper.i); + range_set = bt_integer_range_set_signed_create(); } else { - ret = bt_field_class_unsigned_enumeration_map_range( - ir_fc, mapping->label->str, - mapping->range.lower.u, mapping->range.upper.u); + range_set = bt_integer_range_set_unsigned_create(); + } + + BT_ASSERT(range_set); + + for (range_i = 0; range_i < mapping->ranges->len; range_i++) { + struct ctf_range *range = + ctf_field_class_enum_mapping_borrow_range_by_index( + mapping, range_i); + + if (fc->base.is_signed) { + ret = bt_integer_range_set_signed_add_range( + range_set, range->lower.i, + range->upper.i); + } else { + ret = bt_integer_range_set_unsigned_add_range( + range_set, range->lower.u, + range->upper.u); + } + + BT_ASSERT(ret == 0); + } + + if (fc->base.is_signed) { + ret = bt_field_class_signed_enumeration_add_mapping( + ir_fc, mapping->label->str, range_set); + BT_RANGE_SET_SIGNED_PUT_REF_AND_RESET(range_set); + } else { + ret = bt_field_class_unsigned_enumeration_add_mapping( + ir_fc, mapping->label->str, range_set); + BT_RANGE_SET_UNSIGNED_PUT_REF_AND_RESET(range_set); } BT_ASSERT(ret == 0); @@ -183,24 +211,65 @@ bt_field_class *borrow_ir_fc_from_field_path(struct ctx *ctx, return ir_fc; } +static inline +const void *find_ir_enum_field_class_mapping_by_label(const bt_field_class *fc, + const char *label, bool is_signed) +{ + const void *mapping = NULL; + uint64_t i; + + for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) { + const bt_field_class_enumeration_mapping *this_mapping; + const void *spec_this_mapping; + + if (is_signed) { + spec_this_mapping = + bt_field_class_signed_enumeration_borrow_mapping_by_index_const( + fc, i); + this_mapping = + bt_field_class_signed_enumeration_mapping_as_mapping_const( + spec_this_mapping); + } else { + spec_this_mapping = + bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( + fc, i); + this_mapping = + bt_field_class_unsigned_enumeration_mapping_as_mapping_const( + spec_this_mapping); + } + + BT_ASSERT(this_mapping); + BT_ASSERT(spec_this_mapping); + + if (strcmp(bt_field_class_enumeration_mapping_get_label( + this_mapping), label) == 0) { + mapping = spec_this_mapping; + goto end; + } + } + +end: + return mapping; +} + static inline bt_field_class *ctf_field_class_variant_to_ir(struct ctx *ctx, struct ctf_field_class_variant *fc) { int ret; - bt_field_class *ir_fc = bt_field_class_variant_create(ctx->ir_tc); + bt_field_class *ir_fc; uint64_t i; - - BT_ASSERT(ir_fc); + bt_field_class *ir_tag_fc = NULL; if (fc->tag_path.root != CTF_SCOPE_PACKET_HEADER && fc->tag_path.root != CTF_SCOPE_EVENT_HEADER) { - ret = bt_field_class_variant_set_selector_field_class( - ir_fc, borrow_ir_fc_from_field_path(ctx, - &fc->tag_path)); - BT_ASSERT(ret == 0); + ir_tag_fc = borrow_ir_fc_from_field_path(ctx, &fc->tag_path); + BT_ASSERT(ir_tag_fc); } + ir_fc = bt_field_class_variant_create(ctx->ir_tc, ir_tag_fc); + BT_ASSERT(ir_fc); + for (i = 0; i < fc->options->len; i++) { struct ctf_named_field_class *named_fc = ctf_field_class_variant_borrow_option_by_index(fc, i); @@ -209,8 +278,56 @@ bt_field_class *ctf_field_class_variant_to_ir(struct ctx *ctx, BT_ASSERT(named_fc->fc->in_ir); option_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc); BT_ASSERT(option_ir_fc); - ret = bt_field_class_variant_append_option( - ir_fc, named_fc->name->str, option_ir_fc); + + if (ir_tag_fc) { + /* + * At this point the trace IR selector + * (enumeration) field class already exists if + * the variant is tagged (`ir_tag_fc`). This one + * already contains range sets for its mappings, + * so we just reuse the same, finding them by + * matching a variant field class's option's + * _original_ name (with a leading underscore, + * possibly) with a selector field class's + * mapping name. + */ + if (fc->tag_fc->base.is_signed) { + const bt_field_class_signed_enumeration_mapping *mapping = + find_ir_enum_field_class_mapping_by_label( + ir_tag_fc, + named_fc->orig_name->str, true); + const bt_integer_range_set_signed *range_set; + + BT_ASSERT(mapping); + range_set = + bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + mapping); + BT_ASSERT(range_set); + ret = bt_field_class_variant_with_signed_selector_append_option( + ir_fc, named_fc->name->str, + option_ir_fc, range_set); + } else { + const bt_field_class_unsigned_enumeration_mapping *mapping = + find_ir_enum_field_class_mapping_by_label( + ir_tag_fc, + named_fc->orig_name->str, + false); + const bt_integer_range_set_unsigned *range_set; + + BT_ASSERT(mapping); + range_set = + bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + mapping); + BT_ASSERT(range_set); + ret = bt_field_class_variant_with_unsigned_selector_append_option( + ir_fc, named_fc->name->str, + option_ir_fc, range_set); + } + } else { + ret = bt_field_class_variant_without_selector_append_option( + ir_fc, named_fc->name->str, option_ir_fc); + } + BT_ASSERT(ret == 0); bt_field_class_put_ref(option_ir_fc); } diff --git a/src/plugins/ctf/common/metadata/ctf-meta.h b/src/plugins/ctf/common/metadata/ctf-meta.h index e62b40ad..45d49d16 100644 --- a/src/plugins/ctf/common/metadata/ctf-meta.h +++ b/src/plugins/ctf/common/metadata/ctf-meta.h @@ -126,7 +126,9 @@ struct ctf_range { struct ctf_field_class_enum_mapping { GString *label; - struct ctf_range range; + + /* Array of `struct ctf_range` */ + GArray *ranges; }; struct ctf_field_class_enum { @@ -146,6 +148,10 @@ struct ctf_field_class_string { }; struct ctf_named_field_class { + /* Original name which can include a leading `_` */ + GString *orig_name; + + /* Name as translated to trace IR (leading `_` removed) */ GString *name; /* Owned by this */ @@ -356,6 +362,8 @@ void _ctf_named_field_class_init(struct ctf_named_field_class *named_fc) BT_ASSERT(named_fc); named_fc->name = g_string_new(NULL); BT_ASSERT(named_fc->name); + named_fc->orig_name = g_string_new(NULL); + BT_ASSERT(named_fc->orig_name); } static inline @@ -367,6 +375,10 @@ void _ctf_named_field_class_fini(struct ctf_named_field_class *named_fc) g_string_free(named_fc->name, TRUE); } + if (named_fc->orig_name) { + g_string_free(named_fc->orig_name, TRUE); + } + ctf_field_class_destroy(named_fc->fc); } @@ -377,6 +389,8 @@ void _ctf_field_class_enum_mapping_init( BT_ASSERT(mapping); mapping->label = g_string_new(NULL); BT_ASSERT(mapping->label); + mapping->ranges = g_array_new(FALSE, TRUE, sizeof(struct ctf_range)); + BT_ASSERT(mapping->ranges); } static inline @@ -388,6 +402,10 @@ void _ctf_field_class_enum_mapping_fini( if (mapping->label) { g_string_free(mapping->label, TRUE); } + + if (mapping->ranges) { + g_array_free(mapping->ranges, TRUE); + } } static inline @@ -661,21 +679,12 @@ void ctf_field_class_destroy(struct ctf_field_class *fc) } static inline -void ctf_field_class_enum_append_mapping(struct ctf_field_class_enum *fc, - const char *label, uint64_t u_lower, uint64_t u_upper) +struct ctf_range *ctf_field_class_enum_mapping_borrow_range_by_index( + struct ctf_field_class_enum_mapping *mapping, uint64_t index) { - struct ctf_field_class_enum_mapping *mapping; - - BT_ASSERT(fc); - BT_ASSERT(label); - g_array_set_size(fc->mappings, fc->mappings->len + 1); - - mapping = &g_array_index(fc->mappings, - struct ctf_field_class_enum_mapping, fc->mappings->len - 1); - _ctf_field_class_enum_mapping_init(mapping); - g_string_assign(mapping->label, label); - mapping->range.lower.u = u_lower; - mapping->range.upper.u = u_upper; + BT_ASSERT(mapping); + BT_ASSERT(index < mapping->ranges->len); + return &g_array_index(mapping->ranges, struct ctf_range, index); } static inline @@ -688,6 +697,68 @@ struct ctf_field_class_enum_mapping *ctf_field_class_enum_borrow_mapping_by_inde index); } +static inline +struct ctf_field_class_enum_mapping *ctf_field_class_enum_borrow_mapping_by_label( + struct ctf_field_class_enum *fc, const char *label) +{ + struct ctf_field_class_enum_mapping *ret_mapping = NULL; + uint64_t i; + + BT_ASSERT(fc); + BT_ASSERT(label); + + for (i = 0; i < fc->mappings->len; i++) { + struct ctf_field_class_enum_mapping *mapping = + ctf_field_class_enum_borrow_mapping_by_index(fc, i); + + if (strcmp(mapping->label->str, label) == 0) { + ret_mapping = mapping; + goto end; + } + } + +end: + return ret_mapping; +} + +static inline +void ctf_field_class_enum_map_range(struct ctf_field_class_enum *fc, + const char *label, uint64_t u_lower, uint64_t u_upper) +{ + struct ctf_field_class_enum_mapping *mapping = NULL; + struct ctf_range range = { + .lower.u = u_lower, + .upper.u = u_upper, + }; + uint64_t i; + + BT_ASSERT(fc); + BT_ASSERT(label); + + for (i = 0; i < fc->mappings->len; i++) { + mapping = ctf_field_class_enum_borrow_mapping_by_index( + fc, i); + + if (strcmp(mapping->label->str, label) == 0) { + break; + } + } + + if (i == fc->mappings->len) { + mapping = NULL; + } + + if (!mapping) { + g_array_set_size(fc->mappings, fc->mappings->len + 1); + mapping = ctf_field_class_enum_borrow_mapping_by_index( + fc, fc->mappings->len - 1); + _ctf_field_class_enum_mapping_init(mapping); + g_string_assign(mapping->label, label); + } + + g_array_append_val(mapping->ranges, range); +} + static inline struct ctf_named_field_class *ctf_field_class_struct_borrow_member_by_index( struct ctf_field_class_struct *fc, uint64_t index) @@ -768,21 +839,34 @@ end: return int_fc; } +static inline +void _ctf_named_field_class_unescape_orig_name( + struct ctf_named_field_class *named_fc) +{ + const char *name = named_fc->orig_name->str; + + if (name[0] == '_') { + name++; + } + + g_string_assign(named_fc->name, name); +} static inline void ctf_field_class_struct_append_member(struct ctf_field_class_struct *fc, - const char *name, struct ctf_field_class *member_fc) + const char *orig_name, struct ctf_field_class *member_fc) { struct ctf_named_field_class *named_fc; BT_ASSERT(fc); - BT_ASSERT(name); + BT_ASSERT(orig_name); g_array_set_size(fc->members, fc->members->len + 1); named_fc = &g_array_index(fc->members, struct ctf_named_field_class, fc->members->len - 1); _ctf_named_field_class_init(named_fc); - g_string_assign(named_fc->name, name); + g_string_assign(named_fc->orig_name, orig_name); + _ctf_named_field_class_unescape_orig_name(named_fc); named_fc->fc = member_fc; if (member_fc->alignment > fc->base.alignment) { @@ -837,18 +921,19 @@ ctf_field_class_variant_borrow_range_by_index( static inline void ctf_field_class_variant_append_option(struct ctf_field_class_variant *fc, - const char *name, struct ctf_field_class *option_fc) + const char *orig_name, struct ctf_field_class *option_fc) { struct ctf_named_field_class *named_fc; BT_ASSERT(fc); - BT_ASSERT(name); + BT_ASSERT(orig_name); g_array_set_size(fc->options, fc->options->len + 1); named_fc = &g_array_index(fc->options, struct ctf_named_field_class, fc->options->len - 1); _ctf_named_field_class_init(named_fc); - g_string_assign(named_fc->name, name); + g_string_assign(named_fc->orig_name, orig_name); + _ctf_named_field_class_unescape_orig_name(named_fc); named_fc->fc = option_fc; } @@ -864,25 +949,28 @@ void ctf_field_class_variant_set_tag_field_class( fc->tag_fc = tag_fc; for (option_i = 0; option_i < fc->options->len; option_i++) { - uint64_t mapping_i; + uint64_t range_i; struct ctf_named_field_class *named_fc = ctf_field_class_variant_borrow_option_by_index( fc, option_i); + struct ctf_field_class_enum_mapping *mapping; - for (mapping_i = 0; mapping_i < tag_fc->mappings->len; - mapping_i++) { - struct ctf_field_class_enum_mapping *mapping = - ctf_field_class_enum_borrow_mapping_by_index( - tag_fc, mapping_i); + mapping = ctf_field_class_enum_borrow_mapping_by_label( + tag_fc, named_fc->orig_name->str); + if (!mapping) { + continue; + } - if (strcmp(named_fc->name->str, - mapping->label->str) == 0) { - struct ctf_field_class_variant_range range; + for (range_i = 0; range_i < mapping->ranges->len; + range_i++) { + struct ctf_range *range = + ctf_field_class_enum_mapping_borrow_range_by_index( + mapping, range_i); + struct ctf_field_class_variant_range var_range; - range.range = mapping->range; - range.option_index = option_i; - g_array_append_val(fc->ranges, range); - } + var_range.range = *range; + var_range.option_index = option_i; + g_array_append_val(fc->ranges, var_range); } } } @@ -965,8 +1053,8 @@ uint64_t ctf_field_class_compound_get_field_class_count(struct ctf_field_class * } static inline -int64_t ctf_field_class_compound_get_field_class_index_from_name( - struct ctf_field_class *fc, const char *name) +int64_t ctf_field_class_compound_get_field_class_index_from_orig_name( + struct ctf_field_class *fc, const char *orig_name) { int64_t ret_index = -1; uint64_t i; @@ -981,7 +1069,7 @@ int64_t ctf_field_class_compound_get_field_class_index_from_name( ctf_field_class_struct_borrow_member_by_index( struct_fc, i); - if (strcmp(name, named_fc->name->str) == 0) { + if (strcmp(orig_name, named_fc->orig_name->str) == 0) { ret_index = (int64_t) i; goto end; } @@ -998,7 +1086,7 @@ int64_t ctf_field_class_compound_get_field_class_index_from_name( ctf_field_class_variant_borrow_option_by_index( var_fc, i); - if (strcmp(name, named_fc->name->str) == 0) { + if (strcmp(orig_name, named_fc->orig_name->str) == 0) { ret_index = (int64_t) i; goto end; } @@ -1182,12 +1270,21 @@ struct ctf_field_class_enum *_ctf_field_class_enum_copy( ctf_field_class_int_copy_content((void *) copy_fc, (void *) fc); for (i = 0; i < fc->mappings->len; i++) { + uint64_t range_i; + struct ctf_field_class_enum_mapping *mapping = &g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, i); - ctf_field_class_enum_append_mapping(copy_fc, mapping->label->str, - mapping->range.lower.u, mapping->range.upper.u); + for (range_i = 0; range_i < mapping->ranges->len; range_i++) { + struct ctf_range *range = + &g_array_index(mapping->ranges, + struct ctf_range, range_i); + + ctf_field_class_enum_map_range(copy_fc, + mapping->label->str, range->lower.u, + range->upper.u); + } } return copy_fc; diff --git a/src/plugins/ctf/common/metadata/visitor-generate-ir.c b/src/plugins/ctf/common/metadata/visitor-generate-ir.c index 5b64ad28..3413ac17 100644 --- a/src/plugins/ctf/common/metadata/visitor-generate-ir.c +++ b/src/plugins/ctf/common/metadata/visitor-generate-ir.c @@ -679,61 +679,6 @@ static int visit_field_class_specifier_list(struct ctx *ctx, struct ctf_node *ts_list, struct ctf_field_class **decl); -static -char *remove_underscores_from_field_ref(struct ctx *ctx, const char *field_ref) -{ - const char *in_ch; - char *out_ch; - char *ret; - enum { - UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE, - UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE, - } state = UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE; - - BT_ASSERT(field_ref); - ret = calloc(strlen(field_ref) + 1, 1); - if (!ret) { - BT_COMP_LOGE("Failed to allocate a string: size=%zu", - strlen(field_ref) + 1); - goto end; - } - - in_ch = field_ref; - out_ch = ret; - - while (*in_ch != '\0') { - switch (*in_ch) { - case ' ': - case '\t': - /* Remove whitespace */ - in_ch++; - continue; - case '_': - if (state == UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE) { - in_ch++; - state = UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE; - continue; - } - - goto copy; - case '.': - state = UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE; - goto copy; - default: - state = UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE; - goto copy; - } - -copy: - *out_ch = *in_ch; - in_ch++; - out_ch++; - } - -end: - return ret; -} - static int is_unary_string(struct bt_list_head *head) { @@ -1385,10 +1330,6 @@ int visit_field_class_declarator(struct ctx *ctx, const char *id = node_field_class_declarator->u.field_class_declarator.u.id; - if (id[0] == '_') { - id++; - } - *field_name = g_quark_from_string(id); } else { *field_name = 0; @@ -1493,24 +1434,12 @@ int visit_field_class_declarator(struct ctx *ctx, nested_decl = NULL; decl = (void *) array_decl; } else { - char *length_name_no_underscore = - remove_underscores_from_field_ref(ctx, - length_name); - if (!length_name_no_underscore) { - /* - * remove_underscores_from_field_ref() - * logs errors - */ - ret = -EINVAL; - goto error; - } seq_decl = ctf_field_class_sequence_create(); BT_ASSERT(seq_decl); seq_decl->base.elem_fc = nested_decl; nested_decl = NULL; g_string_assign(seq_decl->length_ref, - length_name_no_underscore); - free(length_name_no_underscore); + length_name); decl = (void *) seq_decl; } @@ -2067,17 +1996,7 @@ int visit_variant_decl(struct ctx *ctx, const char *name, * At this point, we have a fresh untagged variant; nobody * else owns it. Set its tag now. */ - char *tag_no_underscore = - remove_underscores_from_field_ref(ctx, tag); - - if (!tag_no_underscore) { - /* remove_underscores_from_field_ref() logs errors */ - goto error; - } - - g_string_assign(untagged_variant_decl->tag_ref, - tag_no_underscore); - free(tag_no_underscore); + g_string_assign(untagged_variant_decl->tag_ref, tag); *variant_decl = untagged_variant_decl; untagged_variant_decl = NULL; } @@ -2118,7 +2037,6 @@ int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator, .value.u = 0, }; const char *label = enumerator->u.enumerator.id; - const char *effective_label = label; struct bt_list_head *values = &enumerator->u.enumerator.values; bt_list_for_each_entry(iter, values, siblings) { @@ -2185,19 +2103,7 @@ int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator, last->value.u = end.value.u + 1; } - if (label[0] == '_') { - /* - * Strip the first underscore of any enumeration field - * class's label in case this enumeration FC is used as - * a variant FC tag later. The variant FC choice names - * could also start with `_`, in which case the prefix - * is removed, and it the resulting choice name needs to - * match tag labels. - */ - effective_label = &label[1]; - } - - ctf_field_class_enum_append_mapping(enum_decl, effective_label, + ctf_field_class_enum_map_range(enum_decl, label, start.value.u, end.value.u); return 0; diff --git a/src/plugins/ctf/common/msg-iter/msg-iter.c b/src/plugins/ctf/common/msg-iter/msg-iter.c index 27d51779..12fc7885 100644 --- a/src/plugins/ctf/common/msg-iter/msg-iter.c +++ b/src/plugins/ctf/common/msg-iter/msg-iter.c @@ -1835,7 +1835,9 @@ bt_field *borrow_next_field(struct bt_msg_iter *notit) next_field = bt_field_array_borrow_element_field_by_index( base_field, index); break; - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: BT_ASSERT(index == 0); next_field = bt_field_variant_borrow_selected_option_field( base_field); @@ -2385,7 +2387,7 @@ struct ctf_field_class *bfcr_borrow_variant_selected_field_class_cb( if (selected_option->fc->in_ir) { bt_field *var_field = stack_top(notit->stack)->base; - ret = bt_field_variant_select_option_field( + ret = bt_field_variant_select_option_field_by_index( var_field, option_index); if (ret) { BT_COMP_LOGW("Cannot select variant field's option field: " diff --git a/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h b/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h index 72d47d4a..19912afb 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h +++ b/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h @@ -311,8 +311,8 @@ struct fs_sink_ctf_field_class_variant *fs_sink_ctf_field_class_variant_create_e fc->tag_ref = g_string_new(NULL); BT_ASSERT(fc->tag_ref); fc->tag_is_before = - bt_field_class_variant_borrow_selector_field_path_const(ir_fc) == - NULL; + bt_field_class_get_type(fc->base.ir_fc) == + BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR; return fc; } @@ -836,91 +836,4 @@ struct fs_sink_ctf_trace *fs_sink_ctf_trace_create(const bt_trace *ir_trace) return trace; } -static inline -bool fs_sink_ctf_ist_valid_identifier(const char *name) -{ - const char *at; - uint64_t i; - bool ist_valid = true; - static const char *reserved_keywords[] = { - "align", - "callsite", - "const", - "char", - "clock", - "double", - "enum", - "env", - "event", - "floating_point", - "float", - "integer", - "int", - "long", - "short", - "signed", - "stream", - "string", - "struct", - "trace", - "typealias", - "typedef", - "unsigned", - "variant", - "void", - "_Bool", - "_Complex", - "_Imaginary", - }; - - /* Make sure the name is not a reserved keyword */ - for (i = 0; i < sizeof(reserved_keywords) / sizeof(*reserved_keywords); - i++) { - if (strcmp(name, reserved_keywords[i]) == 0) { - ist_valid = false; - goto end; - } - } - - /* Make sure the name is not an empty string */ - if (strlen(name) == 0) { - ist_valid = false; - goto end; - } - - /* Make sure the name starts with a letter or `_` */ - if (!isalpha(name[0]) && name[0] != '_') { - ist_valid = false; - goto end; - } - - /* Make sure the name only contains letters, digits, and `_` */ - for (at = name; *at != '\0'; at++) { - if (!isalnum(*at) && *at != '_') { - ist_valid = false; - goto end; - } - } - -end: - return ist_valid; -} - -static inline -int fs_sink_ctf_protect_name(GString *name) -{ - int ret = 0; - - if (!fs_sink_ctf_ist_valid_identifier(name->str)) { - ret = -1; - goto end; - } - - /* Prepend `_` to protect it */ - g_string_prepend_c(name, '_'); - -end: - return ret; -} - #endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_CTF_META_H */ diff --git a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c index 99739e2f..f867edbf 100644 --- a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c +++ b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c @@ -211,58 +211,54 @@ void append_integer_field_class(struct ctx *ctx, const char *label; const bt_field_class_enumeration_mapping *mapping; const bt_field_class_unsigned_enumeration_mapping *u_mapping; - const bt_field_class_signed_enumeration_mapping *i_mapping; + const bt_field_class_signed_enumeration_mapping *s_mapping; + const bt_integer_range_set *ranges; + const bt_integer_range_set_unsigned *u_ranges; + const bt_integer_range_set_signed *s_ranges; uint64_t range_count; uint64_t range_i; if (is_signed) { - i_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const( + s_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const( ir_fc, i); mapping = bt_field_class_signed_enumeration_mapping_as_mapping_const( - i_mapping); + s_mapping); + s_ranges = bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + s_mapping); + ranges = bt_integer_range_set_signed_as_range_set_const( + s_ranges); } else { u_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( ir_fc, i); mapping = bt_field_class_unsigned_enumeration_mapping_as_mapping_const( u_mapping); + u_ranges = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + u_mapping); + ranges = bt_integer_range_set_unsigned_as_range_set_const( + u_ranges); } label = bt_field_class_enumeration_mapping_get_label( mapping); - range_count = - bt_field_class_enumeration_mapping_get_range_count( - mapping); + range_count = bt_integer_range_set_get_range_count( + ranges); for (range_i = 0; range_i < range_count; range_i++) { append_indent(ctx); - - /* - * Systematically prepend `_` to the - * mapping's label as this could be used - * as the tag of a subsequent variant - * field class and variant FC option - * names are systematically protected - * with a leading `_`. - * - * FIXME: This is temporary as the - * library's API should change to - * decouple variant FC option names from - * selector FC labels. The current - * drawback is that an original label - * `HELLO` becomes `_HELLO` in the - * generated metadata, therefore tools - * expecting `HELLO` could fail. - */ - g_string_append(ctx->tsdl, "\"_"); + g_string_append(ctx->tsdl, "\""); append_quoted_string_content(ctx, label); g_string_append(ctx->tsdl, "\" = "); if (is_signed) { + const bt_integer_range_signed *range; int64_t lower, upper; - bt_field_class_signed_enumeration_mapping_get_range_by_index( - i_mapping, range_i, - &lower, &upper); + range = bt_integer_range_set_signed_borrow_range_by_index_const( + s_ranges, range_i); + lower = bt_integer_range_signed_get_lower( + range); + upper = bt_integer_range_signed_get_upper( + range); if (lower == upper) { g_string_append_printf( @@ -274,11 +270,15 @@ void append_integer_field_class(struct ctx *ctx, lower, upper); } } else { + const bt_integer_range_unsigned *range; uint64_t lower, upper; - bt_field_class_unsigned_enumeration_mapping_get_range_by_index( - u_mapping, range_i, - &lower, &upper); + range = bt_integer_range_set_unsigned_borrow_range_by_index_const( + u_ranges, range_i); + lower = bt_integer_range_unsigned_get_lower( + range); + upper = bt_integer_range_unsigned_get_upper( + range); if (lower == upper) { g_string_append_printf( diff --git a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c index 1534c96c..c7be897e 100644 --- a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c +++ b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c @@ -98,10 +98,106 @@ end: return is_reserved; } +static const char *reserved_tsdl_keywords[] = { + "align", + "callsite", + "const", + "char", + "clock", + "double", + "enum", + "env", + "event", + "floating_point", + "float", + "integer", + "int", + "long", + "short", + "signed", + "stream", + "string", + "struct", + "trace", + "typealias", + "typedef", + "unsigned", + "variant", + "void", + "_Bool", + "_Complex", + "_Imaginary", +}; + +static inline +bool ist_valid_identifier(const char *name) +{ + const char *at; + uint64_t i; + bool ist_valid = true; + + /* Make sure the name is not a reserved keyword */ + for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords); + i++) { + if (strcmp(name, reserved_tsdl_keywords[i]) == 0) { + ist_valid = false; + goto end; + } + } + + /* Make sure the name is not an empty string */ + if (strlen(name) == 0) { + ist_valid = false; + goto end; + } + + /* Make sure the name starts with a letter or `_` */ + if (!isalpha(name[0]) && name[0] != '_') { + ist_valid = false; + goto end; + } + + /* Make sure the name only contains letters, digits, and `_` */ + for (at = name; *at != '\0'; at++) { + if (!isalnum(*at) && *at != '_') { + ist_valid = false; + goto end; + } + } + +end: + return ist_valid; +} + +static inline +bool must_protect_identifier(const char *name) +{ + uint64_t i; + bool must_protect = false; + + /* Protect a reserved keyword */ + for (i = 0; i < sizeof(reserved_tsdl_keywords) / sizeof(*reserved_tsdl_keywords); + i++) { + if (strcmp(name, reserved_tsdl_keywords[i]) == 0) { + must_protect = true; + goto end; + } + } + + /* Protect an identifier which already starts with `_` */ + if (name[0] == '_') { + must_protect = true; + goto end; + } + +end: + return must_protect; +} + static inline int cur_path_stack_push(struct ctx *ctx, - uint64_t index_in_parent, const char *ir_name, - const bt_field_class *ir_fc, + uint64_t index_in_parent, const char *name, + bool force_protect_name, const bt_field_class *ir_fc, struct fs_sink_ctf_field_class *parent_fc) { int ret = 0; @@ -110,29 +206,35 @@ int cur_path_stack_push(struct ctx *ctx, g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1); field_path_elem = cur_path_stack_top(ctx); field_path_elem->index_in_parent = index_in_parent; - field_path_elem->name = g_string_new(ir_name); + field_path_elem->name = g_string_new(NULL); + + if (name) { + if (force_protect_name) { + g_string_assign(field_path_elem->name, "_"); + } + + g_string_append(field_path_elem->name, name); - if (ir_name) { if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) { - if (is_reserved_member_name(ir_name, "packet_size") || - is_reserved_member_name(ir_name, "content_size") || - is_reserved_member_name(ir_name, "timestamp_begin") || - is_reserved_member_name(ir_name, "timestamp_end") || - is_reserved_member_name(ir_name, "events_discarded") || - is_reserved_member_name(ir_name, "packet_seq_num")) { + if (is_reserved_member_name(name, "packet_size") || + is_reserved_member_name(name, "content_size") || + is_reserved_member_name(name, "timestamp_begin") || + is_reserved_member_name(name, "timestamp_end") || + is_reserved_member_name(name, "events_discarded") || + is_reserved_member_name(name, "packet_seq_num")) { BT_COMP_LOGE("Unsupported reserved TSDL structure field class member " "or variant field class option name: name=\"%s\"", - ir_name); + name); ret = -1; goto end; } } - ret = fs_sink_ctf_protect_name(field_path_elem->name); - if (ret) { + if (!ist_valid_identifier(field_path_elem->name->str)) { + ret = -1; BT_COMP_LOGE("Unsupported non-TSDL structure field class member " "or variant field class option name: name=\"%s\"", - ir_name); + field_path_elem->name->str); goto end; } } @@ -174,7 +276,8 @@ void cur_path_stack_pop(struct ctx *ctx) */ static int create_relative_field_ref(struct ctx *ctx, - const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref) + const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref, + struct fs_sink_ctf_field_class **user_tgt_fc) { int ret = 0; struct fs_sink_ctf_field_class *tgt_fc = NULL; @@ -307,6 +410,10 @@ int create_relative_field_ref(struct ctx *ctx, if (named_fc->fc == tgt_fc) { g_string_assign(tgt_field_ref, tgt_fc_name); + + if (user_tgt_fc) { + *user_tgt_fc = tgt_fc; + } } else { /* * Using only the target field @@ -334,7 +441,8 @@ end: */ static int create_absolute_field_ref(struct ctx *ctx, - const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref) + const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref, + struct fs_sink_ctf_field_class **user_tgt_fc) { int ret = 0; struct fs_sink_ctf_field_class *fc = NULL; @@ -405,6 +513,10 @@ int create_absolute_field_ref(struct ctx *ctx, fc = named_fc->fc; } + if (user_tgt_fc) { + *user_tgt_fc = fc; + } + end: return ret; } @@ -419,7 +531,8 @@ end: static void resolve_field_class(struct ctx *ctx, const bt_field_path *tgt_ir_field_path, - GString *tgt_field_ref, bool *create_before) + GString *tgt_field_ref, bool *create_before, + struct fs_sink_ctf_field_class **user_tgt_fc) { int ret; bt_scope tgt_scope; @@ -449,10 +562,10 @@ void resolve_field_class(struct ctx *ctx, * requesting field class (fallback). */ ret = create_relative_field_ref(ctx, tgt_ir_field_path, - tgt_field_ref); + tgt_field_ref, user_tgt_fc); if (ret) { ret = create_absolute_field_ref(ctx, tgt_ir_field_path, - tgt_field_ref); + tgt_field_ref, user_tgt_fc); if (ret) { *create_before = true; ret = 0; @@ -461,7 +574,7 @@ void resolve_field_class(struct ctx *ctx, } } else { ret = create_absolute_field_ref(ctx, tgt_ir_field_path, - tgt_field_ref); + tgt_field_ref, user_tgt_fc); /* It must always work in previous scopes */ BT_ASSERT(ret == 0); @@ -551,7 +664,7 @@ int translate_structure_field_class_members(struct ctx *ctx, name = bt_field_class_structure_member_get_name(member); memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const( member); - ret = cur_path_stack_push(ctx, i, name, memb_ir_fc, + ret = cur_path_stack_push(ctx, i, name, true, memb_ir_fc, (void *) struct_fc); if (ret) { BT_COMP_LOGE("Cannot translate structure field class member: " @@ -595,6 +708,328 @@ end: return ret; } +/* + * This function returns whether or not a given field class `tag_fc` + * is valid as the tag field class of the variant field class `fc`. + * + * CTF 1.8 requires that the tag field class be an enumeration field + * class and that, for each variant field class option's range set, the + * tag field class contains a mapping which has the option's name and an + * equal range set. + */ +static inline +bool _is_variant_field_class_tag_valid( + struct fs_sink_ctf_field_class_variant *fc, + struct fs_sink_ctf_field_class *tag_fc) +{ + bool is_valid = true; + bt_field_class_type ir_tag_fc_type = bt_field_class_get_type( + tag_fc->ir_fc); + uint64_t i; + GString *escaped_opt_name = g_string_new(NULL); + + BT_ASSERT(escaped_opt_name); + + if (ir_tag_fc_type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION && + ir_tag_fc_type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) { + is_valid = false; + goto end; + } + + for (i = 0; i < bt_field_class_variant_get_option_count( + fc->base.ir_fc); i++) { + const bt_field_class_variant_option *var_opt_base = + bt_field_class_variant_borrow_option_by_index_const( + fc->base.ir_fc, i); + const char *opt_name = bt_field_class_variant_option_get_name( + var_opt_base); + + /* + * If the option is named `name` in trace IR, then it + * was _possibly_ named `_name` originally if it comes + * from `src.ctf.fs`. This means the corresponding + * enumeration field class mapping was also named + * `_name`, but this one didn't change, as enumeration + * FC mapping names are not escaped; they are literal + * strings. + * + * The `sink.ctf.fs` component escapes all the variant + * FC option names with `_`. Therefore the + * _escaped name_ must match the original enumeration + * FC mapping name. + */ + g_string_assign(escaped_opt_name, "_"); + g_string_append(escaped_opt_name, opt_name); + + if (ir_tag_fc_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) { + const bt_field_class_variant_with_unsigned_selector_option *var_opt = + bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const( + fc->base.ir_fc, i); + const bt_field_class_unsigned_enumeration_mapping *mapping; + const bt_integer_range_set_unsigned *opt_ranges; + const bt_integer_range_set_unsigned *mapping_ranges; + + mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_label_const( + tag_fc->ir_fc, escaped_opt_name->str); + if (!mapping) { + is_valid = false; + goto end; + } + + opt_ranges = bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const( + var_opt); + mapping_ranges = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + mapping); + if (!bt_integer_range_set_unsigned_compare(opt_ranges, + mapping_ranges)) { + is_valid = false; + goto end; + } + } else { + const bt_field_class_variant_with_signed_selector_option *var_opt = + bt_field_class_variant_with_signed_selector_borrow_option_by_index_const( + fc->base.ir_fc, i); + const bt_field_class_signed_enumeration_mapping *mapping; + const bt_integer_range_set_signed *opt_ranges; + const bt_integer_range_set_signed *mapping_ranges; + + mapping = bt_field_class_signed_enumeration_borrow_mapping_by_label_const( + tag_fc->ir_fc, escaped_opt_name->str); + if (!mapping) { + is_valid = false; + goto end; + } + + opt_ranges = bt_field_class_variant_with_signed_selector_option_borrow_ranges_const( + var_opt); + mapping_ranges = bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + mapping); + if (!bt_integer_range_set_signed_compare(opt_ranges, + mapping_ranges)) { + is_valid = false; + goto end; + } + } + } + +end: + return is_valid; +} + +/* + * This function indicates whether or not a given variant FC option name + * must be protected (with the `_` prefix). + * + * One of the goals of `sink.ctf.fs` is to write a CTF trace which is as + * close as possible to an original CTF trace as decoded by + * `src.ctf.fs`. + * + * This scenario is valid in CTF 1.8: + * + * enum { + * HELLO, + * MEOW + * } tag; + * + * variant { + * int HELLO; + * string MEOW; + * }; + * + * Once in trace IR, the enumeration FC mapping names and variant FC + * option names are kept as is. For this reason, we don't want to + * protect the variant FC option names here (by prepending `_`): this + * would make the variant FC option name and the enumeration FC mapping + * name not match. + * + * This scenario is also valid in CTF 1.8: + * + * enum { + * _HELLO, + * MEOW + * } tag; + * + * variant { + * int _HELLO; + * string MEOW; + * }; + * + * Once in trace IR, the enumeration FC mapping names are kept as is, + * but the `_HELLO` variant FC option name becomes `HELLO` (unprotected + * for presentation, as recommended by CTF 1.8). When going back to + * TSDL, we need to protect `HELLO` so that it becomes `_HELLO` to match + * the corresponding enumeration FC mapping name. + * + * This scenario is also valid in CTF 1.8: + * + * enum { + * __HELLO, + * MEOW + * } tag; + * + * variant { + * int __HELLO; + * string MEOW; + * }; + * + * Once in trace IR, the enumeration FC mapping names are kept as is, + * but the `__HELLO` variant FC option name becomes `_HELLO` + * (unprotected). When going back to TSDL, we need to protect `_HELLO` + * so that it becomes `__HELLO` to match the corresponding enumeration + * FC mapping name. + * + * `src.ctf.fs` always uses the _same_ integer range sets for a selector + * FC mapping and a corresponding variant FC option. We can use that + * fact to find the original variant FC option names by matching variant + * FC options and enumeration FC mappings by range set. + */ +static +int must_protect_variant_option_name(const bt_field_class *ir_var_fc, + const bt_field_class *ir_tag_fc, uint64_t opt_i, + GString *name_buf, bool *must_protect) +{ + int ret = 0; + uint64_t i; + bt_field_class_type ir_var_fc_type; + const void *opt_ranges = NULL; + const char *mapping_label = NULL; + const char *ir_opt_name; + const bt_field_class_variant_option *base_var_opt; + bool force_protect = false; + + *must_protect = false; + ir_var_fc_type = bt_field_class_get_type(ir_var_fc); + base_var_opt = bt_field_class_variant_borrow_option_by_index_const( + ir_var_fc, opt_i); + BT_ASSERT(base_var_opt); + ir_opt_name = bt_field_class_variant_option_get_name(base_var_opt); + BT_ASSERT(ir_opt_name); + + /* + * Check if the variant FC option name is required to be + * protected (reserved TSDL keyword or starts with `_`). In that + * case, the name of the selector FC mapping we find must match + * exactly the protected name. + */ + force_protect = must_protect_identifier(ir_opt_name); + if (force_protect) { + *must_protect = true; + g_string_assign(name_buf, "_"); + g_string_append(name_buf, ir_opt_name); + } else { + g_string_assign(name_buf, ir_opt_name); + } + + /* Borrow option's ranges */ + if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR) { + /* No ranges: we're done */ + goto end; + } if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) { + const bt_field_class_variant_with_unsigned_selector_option *var_opt = + bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const( + ir_var_fc, opt_i); + opt_ranges = + bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const( + var_opt); + } else { + const bt_field_class_variant_with_signed_selector_option *var_opt = + bt_field_class_variant_with_signed_selector_borrow_option_by_index_const( + ir_var_fc, opt_i); + opt_ranges = + bt_field_class_variant_with_signed_selector_option_borrow_ranges_const( + var_opt); + } + + /* Find corresponding mapping by range set in selector FC */ + for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_tag_fc); + i++) { + if (ir_var_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) { + const bt_field_class_enumeration_mapping *mapping_base; + const bt_field_class_unsigned_enumeration_mapping *mapping; + const bt_integer_range_set_unsigned *mapping_ranges; + + mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( + ir_tag_fc, i); + mapping_ranges = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + mapping); + + if (bt_integer_range_set_unsigned_compare(opt_ranges, + mapping_ranges)) { + /* We have a winner */ + mapping_base = + bt_field_class_unsigned_enumeration_mapping_as_mapping_const( + mapping); + mapping_label = + bt_field_class_enumeration_mapping_get_label( + mapping_base); + break; + } + } else { + const bt_field_class_enumeration_mapping *mapping_base; + const bt_field_class_signed_enumeration_mapping *mapping; + const bt_integer_range_set_signed *mapping_ranges; + + mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const( + ir_tag_fc, i); + mapping_ranges = bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + mapping); + + if (bt_integer_range_set_signed_compare(opt_ranges, + mapping_ranges)) { + /* We have a winner */ + mapping_base = + bt_field_class_signed_enumeration_mapping_as_mapping_const( + mapping); + mapping_label = + bt_field_class_enumeration_mapping_get_label( + mapping_base); + break; + } + } + } + + if (!mapping_label) { + /* Range set not found: invalid selector for CTF 1.8 */ + ret = -1; + goto end; + } + + /* + * If the enumeration FC mapping name is not the same as the + * variant FC option name and we didn't protect already, try + * protecting the option name and check again. + */ + if (strcmp(mapping_label, name_buf->str) != 0) { + if (force_protect) { + ret = -1; + goto end; + } + + if (mapping_label[0] == '\0') { + ret = -1; + goto end; + } + + g_string_assign(name_buf, "_"); + g_string_append(name_buf, ir_opt_name); + + if (strcmp(mapping_label, name_buf->str) != 0) { + ret = -1; + goto end; + } + + /* + * If this comes from a `src.ctf.fs` source, it looks + * like the variant FC option name was initially + * protected: protect it again when going back to TSDL. + */ + *must_protect = true; + } + +end: + return ret; +} + static inline int translate_variant_field_class(struct ctx *ctx) { @@ -604,38 +1039,156 @@ int translate_variant_field_class(struct ctx *ctx) fs_sink_ctf_field_class_variant_create_empty( cur_path_stack_top(ctx)->ir_fc, cur_path_stack_top(ctx)->index_in_parent); + bt_field_class_type ir_fc_type; + const bt_field_path *ir_selector_field_path = NULL; + struct fs_sink_ctf_field_class *tgt_fc = NULL; + GString *name_buf = g_string_new(NULL); + bt_value *prot_opt_names = bt_value_array_create(); + uint64_t opt_count; BT_ASSERT(fc); + BT_ASSERT(name_buf); + BT_ASSERT(prot_opt_names); + ir_fc_type = bt_field_class_get_type(fc->base.ir_fc); + opt_count = bt_field_class_variant_get_option_count(fc->base.ir_fc); + + if (ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || + ir_fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { + ir_selector_field_path = bt_field_class_variant_with_selector_borrow_selector_field_path_const( + fc->base.ir_fc); + BT_ASSERT(ir_selector_field_path); + } /* Resolve tag field class before appending to parent */ - resolve_field_class(ctx, - bt_field_class_variant_borrow_selector_field_path_const( - fc->base.ir_fc), fc->tag_ref, &fc->tag_is_before); + resolve_field_class(ctx, ir_selector_field_path, fc->tag_ref, + &fc->tag_is_before, &tgt_fc); + + if (ir_selector_field_path && tgt_fc) { + uint64_t mapping_count; + uint64_t option_count; + + /* CTF 1.8: selector FC must be an enumeration FC */ + bt_field_class_type type = bt_field_class_get_type( + tgt_fc->ir_fc); + + if (type != BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION && + type != BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) { + fc->tag_is_before = true; + goto validate_opts; + } + + /* + * Call must_protect_variant_option_name() for each + * option below. In that case we also want selector FC + * to contain as many mappings as the variant FC has + * options. + */ + mapping_count = bt_field_class_enumeration_get_mapping_count( + tgt_fc->ir_fc); + option_count = bt_field_class_variant_get_option_count( + fc->base.ir_fc); + + if (mapping_count != option_count) { + fc->tag_is_before = true; + goto validate_opts; + } + } else { + /* + * No compatible selector field class for CTF 1.8: + * create the appropriate selector field class. + */ + fc->tag_is_before = true; + } + +validate_opts: + /* + * First pass: detect any option name clash with option name + * protection. In that case, we don't fail: just create the + * selector field class before the variant field class. + * + * After this, `prot_opt_names` contains the final option names, + * potentially protected if needed. They can still be invalid + * TSDL identifiers however; this will be checked by + * cur_path_stack_push(). + */ + for (i = 0; i < opt_count; i++) { + bool must_protect = false; + + ret = must_protect_variant_option_name(fc->base.ir_fc, + tgt_fc->ir_fc, i, name_buf, &must_protect); + if (ret) { + fc->tag_is_before = true; + } + + ret = bt_value_array_append_string_element(prot_opt_names, + name_buf->str); + if (ret) { + goto end; + } + } + + for (i = 0; i < opt_count; i++) { + uint64_t j; + const bt_value *opt_name_a = + bt_value_array_borrow_element_by_index_const( + prot_opt_names, i); + + for (j = 0; j < opt_count; j++) { + const bt_value *opt_name_b; + + if (i == j) { + continue; + } + opt_name_b = + bt_value_array_borrow_element_by_index_const( + prot_opt_names, j); + if (bt_value_compare(opt_name_a, opt_name_b)) { + /* + * Variant FC option names are not + * unique when protected. + */ + fc->tag_is_before = true; + goto append_to_parent; + } + } + } + +append_to_parent: append_to_parent_field_class(ctx, (void *) fc); - for (i = 0; i < bt_field_class_variant_get_option_count(fc->base.ir_fc); - i++) { + for (i = 0; i < opt_count; i++) { const bt_field_class_variant_option *opt; - const char *name; const bt_field_class *opt_ir_fc; + const bt_value *prot_opt_name_val = + bt_value_array_borrow_element_by_index_const( + prot_opt_names, i); + const char *prot_opt_name = bt_value_string_get( + prot_opt_name_val); + BT_ASSERT(prot_opt_name); opt = bt_field_class_variant_borrow_option_by_index_const( fc->base.ir_fc, i); - name = bt_field_class_variant_option_get_name(opt); opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const( opt); - ret = cur_path_stack_push(ctx, i, name, opt_ir_fc, (void *) fc); + + /* + * We don't ask cur_path_stack_push() to protect the + * option name because it's already protected at this + * point. + */ + ret = cur_path_stack_push(ctx, i, prot_opt_name, false, + opt_ir_fc, (void *) fc); if (ret) { BT_COMP_LOGE("Cannot translate variant field class option: " - "name=\"%s\"", name); + "name=\"%s\"", prot_opt_name); goto end; } ret = translate_field_class(ctx); if (ret) { BT_COMP_LOGE("Cannot translate variant field class option: " - "name=\"%s\"", name); + "name=\"%s\"", prot_opt_name); goto end; } @@ -643,6 +1196,11 @@ int translate_variant_field_class(struct ctx *ctx) } end: + if (name_buf) { + g_string_free(name_buf, TRUE); + } + + bt_value_put_ref(prot_opt_names); return ret; } @@ -660,7 +1218,7 @@ int translate_static_array_field_class(struct ctx *ctx) BT_ASSERT(fc); append_to_parent_field_class(ctx, (void *) fc); - ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc, + ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc, (void *) fc); if (ret) { BT_COMP_LOGE_STR("Cannot translate static array field class element."); @@ -698,10 +1256,10 @@ int translate_dynamic_array_field_class(struct ctx *ctx) resolve_field_class(ctx, bt_field_class_dynamic_array_borrow_length_field_path_const( fc->base.base.ir_fc), - fc->length_ref, &fc->length_is_before); + fc->length_ref, &fc->length_is_before, NULL); append_to_parent_field_class(ctx, (void *) fc); - ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc, + ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc, (void *) fc); if (ret) { BT_COMP_LOGE_STR("Cannot translate dynamic array field class element."); @@ -794,7 +1352,9 @@ int translate_field_class(struct ctx *ctx) case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: ret = translate_dynamic_array_field_class(ctx); break; - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: ret = translate_variant_field_class(ctx); break; default: @@ -1009,7 +1569,7 @@ int translate_scope_field_class(struct ctx *ctx, bt_scope scope, BT_ASSERT(*fc); ctx->cur_scope = scope; BT_ASSERT(ctx->cur_path->len == 0); - ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, ir_fc, NULL); + ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL); if (ret) { BT_COMP_LOGE("Cannot translate scope structure field class: " "scope=%d", scope); @@ -1179,11 +1739,19 @@ int translate_stream_class(struct fs_sink_comp *fs_sink, if (name) { /* Try original name, protected */ + g_string_assign((*out_sc)->default_clock_class_name, + ""); + + if (must_protect_identifier(name)) { + g_string_assign( + (*out_sc)->default_clock_class_name, + "_"); + } + g_string_assign((*out_sc)->default_clock_class_name, name); - ret = fs_sink_ctf_protect_name( - (*out_sc)->default_clock_class_name); - if (ret) { + if (!ist_valid_identifier( + (*out_sc)->default_clock_class_name->str)) { /* Invalid: create a new name */ make_unique_default_clock_class_name(*out_sc); ret = 0; @@ -1275,7 +1843,7 @@ struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir( bt_trace_borrow_environment_entry_by_index_const( ir_trace, i, &name, &val); - if (!fs_sink_ctf_ist_valid_identifier(name)) { + if (!ist_valid_identifier(name)) { BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level, fs_sink->self_comp, "Unsupported trace class's environment entry name: " diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c index 60c52e5d..5acad418 100644 --- a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c +++ b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c @@ -319,9 +319,11 @@ void copy_field_content(const bt_field *in_field, bt_field *out_field, } break; } - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { - bt_field_variant_select_option_field_status sel_opt_status; + bt_field_variant_select_option_field_by_index_status sel_opt_status; uint64_t in_selected_option_idx; const bt_field *in_option_field; bt_field *out_option_field; @@ -329,7 +331,7 @@ void copy_field_content(const bt_field *in_field, bt_field *out_field, in_selected_option_idx = bt_field_variant_get_selected_option_field_index( in_field); - sel_opt_status = bt_field_variant_select_option_field(out_field, + sel_opt_status = bt_field_variant_select_option_field_by_index(out_field, in_selected_option_idx); if (sel_opt_status != BT_FIELD_VARIANT_SELECT_OPTION_FIELD_STATUS_OK) { diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c index c3f80a94..30c87014 100644 --- a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c +++ b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c @@ -74,7 +74,9 @@ const bt_field_class *walk_field_path(struct trace_ir_metadata_maps *md_maps, member); break; } - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: { const bt_field_class_variant_option *option; @@ -207,44 +209,21 @@ int field_class_unsigned_enumeration_copy( enum_mapping_count = bt_field_class_enumeration_get_mapping_count(in_field_class); for (i = 0; i < enum_mapping_count; i++) { const char *label; + const bt_integer_range_set_unsigned *range_set; const bt_field_class_unsigned_enumeration_mapping *u_mapping; const bt_field_class_enumeration_mapping *mapping; - uint64_t range_index, range_count; - /* Get the ranges and the range count. */ u_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( in_field_class, i); mapping = bt_field_class_unsigned_enumeration_mapping_as_mapping_const( u_mapping); - range_count = - bt_field_class_enumeration_mapping_get_range_count( - mapping); - label = bt_field_class_enumeration_mapping_get_label( - mapping); - - /* - * Iterate over all the ranges to add them to copied field - * class. - */ - for (range_index = 0; range_index < range_count; range_index++) { - uint64_t lower, upper; - bt_field_class_unsigned_enumeration_mapping_get_range_by_index( - u_mapping, range_index, &lower, &upper); - - BT_COMP_LOGD("Copying range in enumeration field class: " - "label=%s, lower=%"PRId64", upper=%"PRId64, - label, lower, upper); - - /* Add the label and its range to the copy field class. */ - if (bt_field_class_unsigned_enumeration_map_range( - out_field_class, label, lower, upper) != - BT_FIELD_CLASS_ENUMERATION_MAP_RANGE_STATUS_OK) { - BT_COMP_LOGE_STR("Failed to add range to unsigned " - "enumeration."); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class); - ret = -1; - goto error; - } + label = bt_field_class_enumeration_mapping_get_label(mapping); + range_set = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + u_mapping); + ret = bt_field_class_unsigned_enumeration_add_mapping( + out_field_class, label, range_set); + if (ret) { + goto error; } } @@ -277,44 +256,21 @@ int field_class_signed_enumeration_copy( bt_field_class_enumeration_get_mapping_count(in_field_class); for (i = 0; i < enum_mapping_count; i++) { const char *label; - const bt_field_class_signed_enumeration_mapping *i_mapping; + const bt_integer_range_set_signed *range_set; + const bt_field_class_signed_enumeration_mapping *s_mapping; const bt_field_class_enumeration_mapping *mapping; - uint64_t range_index, range_count; - /* Get the ranges and the range count. */ - i_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const( + s_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const( in_field_class, i); mapping = bt_field_class_signed_enumeration_mapping_as_mapping_const( - i_mapping); - range_count = - bt_field_class_enumeration_mapping_get_range_count( - mapping); - label = bt_field_class_enumeration_mapping_get_label( - mapping); - - /* - * Iterate over all the ranges to add them to copied field - * class. - */ - for (range_index = 0; range_index < range_count; range_index++) { - int64_t lower, upper; - bt_field_class_signed_enumeration_mapping_get_range_by_index( - i_mapping, range_index, &lower, &upper); - - BT_COMP_LOGD("Copying range in enumeration field class: " - "label=%s, lower=%"PRId64", upper=%"PRId64, - label, lower, upper); - - /* Add the label and its range to the copy field class. */ - if (bt_field_class_signed_enumeration_map_range( - out_field_class, label, lower, upper) != - BT_FIELD_CLASS_ENUMERATION_MAP_RANGE_STATUS_OK) { - BT_COMP_LOGE_STR("Failed to add range to signed " - "enumeration."); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class); - ret = -1; - goto error; - } + s_mapping); + label = bt_field_class_enumeration_mapping_get_label(mapping); + range_set = bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + s_mapping); + ret = bt_field_class_signed_enumeration_add_mapping( + out_field_class, label, range_set); + if (ret) { + goto error; } } @@ -422,31 +378,12 @@ int field_class_variant_copy( { bt_field_class *out_tag_field_class = NULL; uint64_t i, variant_option_count; - const bt_field_path *tag_fp; - const bt_field_class *tag_fc; + bt_field_class_type fc_type = bt_field_class_get_type(in_field_class); int ret = 0; BT_COMP_LOGD("Copying content of variant field class: " "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class); - - tag_fp = bt_field_class_variant_borrow_selector_field_path_const( - in_field_class); - if (tag_fp) { - tag_fc = resolve_field_path_to_field_class(tag_fp, - md_maps); - - out_tag_field_class = g_hash_table_lookup( - md_maps->field_class_map, tag_fc); - if (!out_tag_field_class) { - BT_COMP_LOGE_STR("Cannot find the tag field class."); - ret = -1; - goto error; - } - bt_field_class_variant_set_selector_field_class(out_field_class, - out_tag_field_class); - } - variant_option_count = bt_field_class_variant_get_option_count(in_field_class); for (i = 0; i < variant_option_count; i++) { @@ -475,14 +412,52 @@ int field_class_variant_copy( goto error; } - if (bt_field_class_variant_append_option( - out_field_class, option_name, - out_option_field_class) != - BT_FIELD_CLASS_VARIANT_APPEND_OPTION_STATUS_OK) { - BT_COMP_LOGE_STR("Cannot append option to variant field class'"); - BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); - ret = -1; - goto error; + if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) { + const bt_field_class_variant_with_unsigned_selector_option *spec_opt = + bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const( + in_field_class, i); + const bt_integer_range_set_unsigned *ranges = + bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const( + spec_opt); + + if (bt_field_class_variant_with_unsigned_selector_append_option( + out_field_class, option_name, + out_option_field_class, ranges) != + BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_APPEND_OPTION_STATUS_OK) { + BT_COMP_LOGE_STR("Cannot append option to variant field class with unsigned selector'"); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); + ret = -1; + goto error; + } + } else if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { + const bt_field_class_variant_with_signed_selector_option *spec_opt = + bt_field_class_variant_with_signed_selector_borrow_option_by_index_const( + in_field_class, i); + const bt_integer_range_set_signed *ranges = + bt_field_class_variant_with_signed_selector_option_borrow_ranges_const( + spec_opt); + + if (bt_field_class_variant_with_signed_selector_append_option( + out_field_class, option_name, + out_option_field_class, ranges) != + BT_FIELD_CLASS_VARIANT_WITH_SELECTOR_APPEND_OPTION_STATUS_OK) { + BT_COMP_LOGE_STR("Cannot append option to variant field class with signed selector'"); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); + ret = -1; + goto error; + } + } else { + BT_ASSERT(fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR); + + if (bt_field_class_variant_without_selector_append_option( + out_field_class, option_name, + out_option_field_class) != + BT_FIELD_CLASS_VARIANT_WITHOUT_SELECTOR_APPEND_OPTION_STATUS_OK) { + BT_COMP_LOGE_STR("Cannot append option to variant field class'"); + BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class); + ret = -1; + goto error; + } } } @@ -610,11 +585,12 @@ bt_field_class *create_field_class_copy_internal(struct trace_ir_metadata_maps * const bt_field_class *in_field_class) { bt_field_class *out_field_class = NULL; + bt_field_class_type fc_type = bt_field_class_get_type(in_field_class); BT_COMP_LOGD("Creating bare field class based on field class: in-fc-addr=%p", in_field_class); - switch(bt_field_class_get_type(in_field_class)) { + switch (fc_type) { case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: out_field_class = bt_field_class_unsigned_integer_create( md_maps->output_trace_class); @@ -681,10 +657,32 @@ bt_field_class *create_field_class_copy_internal(struct trace_ir_metadata_maps * out_elem_fc); break; } - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: + { + bt_field_class *out_sel_fc = NULL; + + if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || + fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { + const bt_field_class *in_sel_fc; + const bt_field_path *sel_fp = + bt_field_class_variant_with_selector_borrow_selector_field_path_const( + in_field_class); + + BT_ASSERT(sel_fp); + in_sel_fc = resolve_field_path_to_field_class(sel_fp, + md_maps); + BT_ASSERT(in_sel_fc); + out_sel_fc = g_hash_table_lookup( + md_maps->field_class_map, in_sel_fc); + BT_ASSERT(out_sel_fc); + } + out_field_class = bt_field_class_variant_create( - md_maps->output_trace_class); + md_maps->output_trace_class, out_sel_fc); break; + } default: abort(); } @@ -753,7 +751,9 @@ int copy_field_class_content_internal( ret = field_class_dynamic_array_copy(md_maps, in_field_class, out_field_class); break; - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: ret = field_class_variant_copy(md_maps, in_field_class, out_field_class); break; diff --git a/src/plugins/text/details/write.c b/src/plugins/text/details/write.c index 1606599c..a0728b1c 100644 --- a/src/plugins/text/details/write.c +++ b/src/plugins/text/details/write.c @@ -367,7 +367,7 @@ void write_int_field_class_props(struct details_write_ctx *ctx, } } -struct enum_field_class_mapping_range { +struct int_range { union { uint64_t u; int64_t i; @@ -383,7 +383,7 @@ struct enum_field_class_mapping { /* Weak */ const char *label; - /* Array of `struct enum_field_class_mapping_range` */ + /* Array of `struct int_range` */ GArray *ranges; }; @@ -395,9 +395,7 @@ gint compare_enum_field_class_mappings(struct enum_field_class_mapping **a, } static -gint compare_enum_field_class_mapping_ranges_signed( - struct enum_field_class_mapping_range *a, - struct enum_field_class_mapping_range *b) +gint compare_int_ranges_signed(struct int_range *a, struct int_range *b) { if (a->lower.i < b->lower.i) { @@ -416,9 +414,7 @@ gint compare_enum_field_class_mapping_ranges_signed( } static -gint compare_enum_field_class_mapping_ranges_unsigned( - struct enum_field_class_mapping_range *a, - struct enum_field_class_mapping_range *b) +gint compare_int_ranges_unsigned(struct int_range *a, struct int_range *b) { if (a->lower.u < b->lower.u) { return -1; @@ -435,6 +431,58 @@ gint compare_enum_field_class_mapping_ranges_unsigned( } } +static +GArray *range_set_to_int_ranges(const void *spec_range_set, bool is_signed) +{ + uint64_t i; + const bt_integer_range_set *range_set; + GArray *ranges = g_array_new(FALSE, TRUE, sizeof(struct int_range)); + + if (!ranges) { + goto end; + } + + if (is_signed) { + range_set = bt_integer_range_set_signed_as_range_set_const( + spec_range_set); + } else { + range_set = bt_integer_range_set_unsigned_as_range_set_const( + spec_range_set); + } + + for (i = 0; i < bt_integer_range_set_get_range_count(range_set); i++) { + struct int_range range; + + if (is_signed) { + const bt_integer_range_signed *orig_range = + bt_integer_range_set_signed_borrow_range_by_index_const( + spec_range_set, i); + + range.lower.i = bt_integer_range_signed_get_lower(orig_range); + range.upper.i = bt_integer_range_signed_get_upper(orig_range); + } else { + const bt_integer_range_unsigned *orig_range = + bt_integer_range_set_unsigned_borrow_range_by_index_const( + spec_range_set, i); + + range.lower.u = bt_integer_range_unsigned_get_lower(orig_range); + range.upper.u = bt_integer_range_unsigned_get_upper(orig_range); + } + + g_array_append_val(ranges, range); + } + + if (is_signed) { + g_array_sort(ranges, (GCompareFunc) compare_int_ranges_signed); + } else { + g_array_sort(ranges, + (GCompareFunc) compare_int_ranges_unsigned); + } + +end: + return ranges; +} + static void destroy_enum_field_class_mapping(struct enum_field_class_mapping *mapping) { @@ -447,8 +495,14 @@ void destroy_enum_field_class_mapping(struct enum_field_class_mapping *mapping) } static -void write_enum_field_class_mapping_range(struct details_write_ctx *ctx, - struct enum_field_class_mapping_range *range, bool is_signed) +struct int_range *int_range_at(GArray *ranges, uint64_t index) +{ + return &g_array_index(ranges, struct int_range, index); +} + +static +void write_int_range(struct details_write_ctx *ctx, + struct int_range *range, bool is_signed) { g_string_append(ctx->str, "["); @@ -458,12 +512,14 @@ void write_enum_field_class_mapping_range(struct details_write_ctx *ctx, write_int_prop_value(ctx, range->lower.u); } - g_string_append(ctx->str, ", "); + if (range->lower.u != range->upper.u) { + g_string_append(ctx->str, ", "); - if (is_signed) { - write_int_prop_value(ctx, range->upper.i); - } else { - write_int_prop_value(ctx, range->upper.u); + if (is_signed) { + write_int_prop_value(ctx, range->upper.i); + } else { + write_int_prop_value(ctx, range->upper.u); + } } g_string_append(ctx->str, "]"); @@ -489,66 +545,37 @@ void write_enum_field_class_mappings(struct details_write_ctx *ctx, */ for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) { const void *fc_mapping; + const void *fc_range_set; struct enum_field_class_mapping *mapping = g_new0( struct enum_field_class_mapping, 1); BT_ASSERT(mapping); - mapping->ranges = g_array_new(FALSE, TRUE, - sizeof(struct enum_field_class_mapping_range)); - BT_ASSERT(mapping->ranges); if (is_signed) { fc_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const( fc, i); + fc_range_set = bt_field_class_signed_enumeration_mapping_borrow_ranges_const( + fc_mapping); } else { fc_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const( fc, i); + fc_range_set = bt_field_class_unsigned_enumeration_mapping_borrow_ranges_const( + fc_mapping); } mapping->label = bt_field_class_enumeration_mapping_get_label( bt_field_class_signed_enumeration_mapping_as_mapping_const( fc_mapping)); - - for (range_i = 0; - range_i < bt_field_class_enumeration_mapping_get_range_count( - bt_field_class_signed_enumeration_mapping_as_mapping_const(fc_mapping)); - range_i++) { - struct enum_field_class_mapping_range range; - - if (is_signed) { - bt_field_class_signed_enumeration_mapping_get_range_by_index( - fc_mapping, range_i, - &range.lower.i, &range.upper.i); - } else { - bt_field_class_unsigned_enumeration_mapping_get_range_by_index( - fc_mapping, range_i, - &range.lower.u, &range.upper.u); - } - - g_array_append_val(mapping->ranges, range); - } - + mapping->ranges = range_set_to_int_ranges(fc_range_set, + is_signed); + BT_ASSERT(mapping->ranges); g_ptr_array_add(mappings, mapping); } - /* Sort mappings, and for each mapping, sort ranges */ + /* Sort mappings (ranges are already sorted within mappings) */ g_ptr_array_sort(mappings, (GCompareFunc) compare_enum_field_class_mappings); - for (i = 0; i < mappings->len; i++) { - struct enum_field_class_mapping *mapping = mappings->pdata[i]; - - if (is_signed) { - g_array_sort(mapping->ranges, - (GCompareFunc) - compare_enum_field_class_mapping_ranges_signed); - } else { - g_array_sort(mapping->ranges, - (GCompareFunc) - compare_enum_field_class_mapping_ranges_unsigned); - } - } - /* Write mappings */ for (i = 0; i < mappings->len; i++) { struct enum_field_class_mapping *mapping = mappings->pdata[i]; @@ -556,28 +583,12 @@ void write_enum_field_class_mappings(struct details_write_ctx *ctx, write_nl(ctx); write_compound_member_name(ctx, mapping->label); - if (mapping->ranges->len == 1) { - /* Single one: write on same line */ - write_sp(ctx); - write_enum_field_class_mapping_range(ctx, - &g_array_index(mapping->ranges, - struct enum_field_class_mapping_range, - 0), is_signed); - continue; - } - - incr_indent(ctx); - for (range_i = 0; range_i < mapping->ranges->len; range_i++) { - write_nl(ctx); - write_indent(ctx); - write_enum_field_class_mapping_range(ctx, - &g_array_index(mapping->ranges, - struct enum_field_class_mapping_range, - range_i), is_signed); + write_sp(ctx); + write_int_range(ctx, + int_range_at(mapping->ranges, range_i), + is_signed); } - - decr_indent(ctx); } g_ptr_array_free(mappings, TRUE); @@ -635,19 +646,119 @@ void write_field_path(struct details_write_ctx *ctx, } static -void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc, - const char *name) +void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc); + +static +void write_variant_field_class_option(struct details_write_ctx *ctx, + const bt_field_class *fc, uint64_t index) { - uint64_t i; - const char *type; bt_field_class_type fc_type = bt_field_class_get_type(fc); + const bt_field_class_variant_option *option = + bt_field_class_variant_borrow_option_by_index_const( + fc, index); + const void *orig_ranges; + GArray *int_ranges = NULL; + bool is_signed; - /* Write field class's name */ - if (name) { - write_compound_member_name(ctx, name); + write_nl(ctx); + write_compound_member_name(ctx, + bt_field_class_variant_option_get_name(option)); + + if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) { + const bt_field_class_variant_with_unsigned_selector_option *spec_opt = + bt_field_class_variant_with_unsigned_selector_borrow_option_by_index_const( + fc, index); + + orig_ranges = + bt_field_class_variant_with_unsigned_selector_option_borrow_ranges_const( + spec_opt); + is_signed = false; + } else { + const bt_field_class_variant_with_signed_selector_option *spec_opt = + bt_field_class_variant_with_signed_selector_borrow_option_by_index_const( + fc, index); + + orig_ranges = + bt_field_class_variant_with_signed_selector_option_borrow_ranges_const( + spec_opt); + is_signed = true; + } + + if (orig_ranges) { + uint64_t i; + + int_ranges = range_set_to_int_ranges(orig_ranges, is_signed); + BT_ASSERT(int_ranges); + + for (i = 0; i < int_ranges->len; i++) { + struct int_range *range = int_range_at(int_ranges, i); + + write_sp(ctx); + write_int_range(ctx, range, is_signed); + } + + g_string_append(ctx->str, ": "); + } else { write_sp(ctx); } + write_field_class(ctx, + bt_field_class_variant_option_borrow_field_class_const(option)); + + if (int_ranges) { + g_array_free(int_ranges, TRUE); + } +} + +static +void write_variant_field_class(struct details_write_ctx *ctx, + const bt_field_class *fc) +{ + bt_field_class_type fc_type = bt_field_class_get_type(fc); + uint64_t option_count = + bt_field_class_variant_get_option_count(fc); + const bt_field_path *sel_field_path = NULL; + + if (fc_type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR) { + sel_field_path = + bt_field_class_variant_with_selector_borrow_selector_field_path_const( + fc); + BT_ASSERT(sel_field_path); + } + + g_string_append(ctx->str, " ("); + write_uint_prop_value(ctx, option_count); + g_string_append_printf(ctx->str, " option%s, ", + plural(option_count)); + + if (sel_field_path) { + g_string_append(ctx->str, "Selector field path "); + write_field_path(ctx, sel_field_path); + } + + g_string_append_c(ctx->str, ')'); + + if (option_count > 0) { + uint64_t i; + + g_string_append_c(ctx->str, ':'); + incr_indent(ctx); + + for (i = 0; i < option_count; i++) { + write_variant_field_class_option(ctx, fc, i); + } + + decr_indent(ctx); + } +} + +static +void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc) +{ + uint64_t i; + const char *type; + bt_field_class_type fc_type = bt_field_class_get_type(fc); + /* Write field class's type */ switch (fc_type) { case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: @@ -677,8 +788,14 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc, case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: type = "Dynamic array"; break; - case BT_FIELD_CLASS_TYPE_VARIANT: - type = "Variant"; + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + type = "Variant (no selector)"; + break; + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + type = "Variant (unsigned selector)"; + break; + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: + type = "Variant (signed selector)"; break; default: abort(); @@ -744,9 +861,11 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc, fc, i); write_nl(ctx); - write_field_class(ctx, - bt_field_class_structure_member_borrow_field_class_const(member), + write_compound_member_name(ctx, bt_field_class_structure_member_get_name(member)); + write_sp(ctx); + write_field_class(ctx, + bt_field_class_structure_member_borrow_field_class_const(member)); } decr_indent(ctx); @@ -776,51 +895,17 @@ void write_field_class(struct details_write_ctx *ctx, const bt_field_class *fc, g_string_append_c(ctx->str, ':'); write_nl(ctx); incr_indent(ctx); + write_compound_member_name(ctx, "Element"); + write_sp(ctx); write_field_class(ctx, - bt_field_class_array_borrow_element_field_class_const(fc), - "Element"); + bt_field_class_array_borrow_element_field_class_const(fc)); decr_indent(ctx); break; - case BT_FIELD_CLASS_TYPE_VARIANT: - { - uint64_t option_count = - bt_field_class_variant_get_option_count(fc); - const bt_field_path *sel_field_path = - bt_field_class_variant_borrow_selector_field_path_const( - fc); - - g_string_append(ctx->str, " ("); - write_uint_prop_value(ctx, option_count); - g_string_append_printf(ctx->str, " option%s, ", - plural(option_count)); - - if (sel_field_path) { - g_string_append(ctx->str, "Selector field path "); - write_field_path(ctx, sel_field_path); - } - - g_string_append_c(ctx->str, ')'); - - if (option_count > 0) { - g_string_append_c(ctx->str, ':'); - incr_indent(ctx); - - for (i = 0; i < option_count; i++) { - const bt_field_class_variant_option *option = - bt_field_class_variant_borrow_option_by_index_const( - fc, i); - - write_nl(ctx); - write_field_class(ctx, - bt_field_class_variant_option_borrow_field_class_const(option), - bt_field_class_variant_option_get_name(option)); - } - - decr_indent(ctx); - } - + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: + write_variant_field_class(ctx, fc); break; - } default: break; } @@ -835,7 +920,7 @@ void write_root_field_class(struct details_write_ctx *ctx, const char *name, write_indent(ctx); write_prop_name(ctx, name); g_string_append(ctx->str, ": "); - write_field_class(ctx, fc, NULL); + write_field_class(ctx, fc); write_nl(ctx); } @@ -1499,7 +1584,9 @@ void write_field(struct details_write_ctx *ctx, const bt_field *field, decr_indent(ctx); break; } - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: write_field(ctx, bt_field_variant_borrow_selected_option_field_const( field), NULL); diff --git a/src/plugins/text/pretty/print.c b/src/plugins/text/pretty/print.c index cdb15e23..b83febb4 100644 --- a/src/plugins/text/pretty/print.c +++ b/src/plugins/text/pretty/print.c @@ -1013,7 +1013,9 @@ int print_field(struct pretty_component *pretty, case BT_FIELD_CLASS_TYPE_STRUCTURE: return print_struct(pretty, field, print_names, filter_fields, filter_array_len); - case BT_FIELD_CLASS_TYPE_VARIANT: + case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: + case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: return print_variant(pretty, field, print_names); case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: return print_array(pretty, field, print_names); diff --git a/tests/Makefile.am b/tests/Makefile.am index e5f36bac..ad8ded96 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,3 +1,5 @@ +#5149916 + SUBDIRS = utils lib bitfield ctf-writer plugins # Directories added to EXTRA_DIST will be recursively copied to the distribution. diff --git a/tests/bindings/python/bt2/test_event.py b/tests/bindings/python/bt2/test_event.py index eedc9688..77415000 100644 --- a/tests/bindings/python/bt2/test_event.py +++ b/tests/bindings/python/bt2/test_event.py @@ -81,20 +81,20 @@ class EventTestCase(unittest.TestCase): cc = None if with_cc: cc = tc.create_structure_field_class() - cc += OrderedDict(( + cc += [ ('cpu_id', tc.create_signed_integer_field_class(8)), ('stuff', tc.create_real_field_class()), - )) + ] # packet context (stream-class-defined) pc = None if with_packet: pc = tc.create_structure_field_class() - pc += OrderedDict(( + pc += [ ('something', tc.create_unsigned_integer_field_class(8)), ('something_else', tc.create_real_field_class()), - )) + ] stream_class = tc.create_stream_class(default_clock_class=clock_class, event_common_context_field_class=cc, @@ -105,20 +105,20 @@ class EventTestCase(unittest.TestCase): sc = None if with_sc: sc = tc.create_structure_field_class() - sc += OrderedDict(( + sc += [ ('ant', tc.create_signed_integer_field_class(16)), ('msg', tc.create_string_field_class()), - )) + ] # event payload ep = None if with_ep: ep = tc.create_structure_field_class() - ep += OrderedDict(( + ep += [ ('giraffe', tc.create_signed_integer_field_class(32)), ('gnu', tc.create_signed_integer_field_class(8)), ('mosquito', tc.create_signed_integer_field_class(8)), - )) + ] event_class = stream_class.create_event_class(name='garou', specific_context_field_class=sc, diff --git a/tests/bindings/python/bt2/test_field.py b/tests/bindings/python/bt2/test_field.py index db640445..f92142bc 100644 --- a/tests/bindings/python/bt2/test_field.py +++ b/tests/bindings/python/bt2/test_field.py @@ -816,11 +816,11 @@ class SignedIntegerFieldTestCase(_TestIntegerFieldCommon, unittest.TestCase): class SignedEnumerationFieldTestCase(_TestIntegerFieldCommon, unittest.TestCase): def _create_fc(self, tc): fc = tc.create_signed_enumeration_field_class(32) - fc.map_range('something', 17) - fc.map_range('speaker', 12, 16) - fc.map_range('can', 18, 2540) - fc.map_range('whole range', -(2 ** 31), (2 ** 31) - 1) - fc.map_range('zip', -45, 1001) + fc.add_mapping('something', bt2.SignedIntegerRangeSet([(17, 17)])) + fc.add_mapping('speaker', bt2.SignedIntegerRangeSet([(12, 16)])) + fc.add_mapping('can', bt2.SignedIntegerRangeSet([(18, 2540)])) + fc.add_mapping('whole range', bt2.SignedIntegerRangeSet([(-(2 ** 31), (2 ** 31) - 1)])) + fc.add_mapping('zip', bt2.SignedIntegerRangeSet([(-45, 1001)])) return fc def setUp(self): @@ -1455,26 +1455,16 @@ class StructureFieldTestCase(unittest.TestCase): class VariantFieldTestCase(unittest.TestCase): def _create_fc(self, tc): - selector_fc = tc.create_signed_enumeration_field_class(field_value_range=32) - selector_fc.map_range('corner', 23) - selector_fc.map_range('zoom', 17, 20) - selector_fc.map_range('mellotron', 1001) - selector_fc.map_range('giorgio', 2000, 3000) - ft0 = tc.create_signed_integer_field_class(32) ft1 = tc.create_string_field_class() ft2 = tc.create_real_field_class() ft3 = tc.create_signed_integer_field_class(17) - fc = tc.create_variant_field_class() fc.append_option('corner', ft0) fc.append_option('zoom', ft1) fc.append_option('mellotron', ft2) fc.append_option('giorgio', ft3) - fc.selector_field_class = selector_fc - top_fc = tc.create_structure_field_class() - top_fc.append_member('selector_field', selector_fc) top_fc.append_member('variant_field', fc) return top_fc diff --git a/tests/bindings/python/bt2/test_field_class.py b/tests/bindings/python/bt2/test_field_class.py index afdf9b63..09303363 100644 --- a/tests/bindings/python/bt2/test_field_class.py +++ b/tests/bindings/python/bt2/test_field_class.py @@ -19,6 +19,7 @@ import bt2.field import unittest import bt2 +import collections from utils import get_default_trace_class @@ -93,172 +94,126 @@ class RealFieldClassTestCase(unittest.TestCase): # # [(lower0, upper0), (lower1, upper1), ...] -def enum_mapping_to_list(mapping): - return sorted([(x.lower, x.upper) for x in mapping]) +def enum_mapping_to_set(mapping): + return {(x.lower, x.upper) for x in mapping.ranges} -class EnumerationFieldClassTestCase(_TestIntegerFieldClassProps): +class _EnumerationFieldClassTestCase(_TestIntegerFieldClassProps): def setUp(self): self._tc = get_default_trace_class() + self._spec_set_up() + self._fc = self._create_func() def test_create_from_invalid_type(self): with self.assertRaises(TypeError): self._create_func('coucou') def test_add_mapping_simple(self): - self._fc.map_range('hello', 24) + self._fc.add_mapping('hello', self._ranges1) mapping = self._fc['hello'] self.assertEqual(mapping.label, 'hello') - - ranges = enum_mapping_to_list(mapping) - self.assertEqual(ranges, [(24, 24)]) + self.assertEqual(mapping.ranges, self._ranges1) def test_add_mapping_simple_kwargs(self): - self._fc.map_range(label='hello', lower=17, upper=23) + self._fc.add_mapping(label='hello', ranges=self._ranges1) mapping = self._fc['hello'] self.assertEqual(mapping.label, 'hello') + self.assertEqual(mapping.ranges, self._ranges1) - ranges = enum_mapping_to_list(mapping) - self.assertEqual(ranges, [(17, 23)]) + def test_add_mapping_invalid_name(self): + with self.assertRaises(TypeError): + self._fc.add_mapping(17, self._ranges1) - def test_add_mapping_range(self): - self._fc.map_range('hello', 21, 199) - mapping = self._fc['hello'] - self.assertEqual(mapping.label, 'hello') + def test_add_mapping_invalid_range(self): + with self.assertRaises(TypeError): + self._fc.add_mapping('allo', 'meow') - ranges = enum_mapping_to_list(mapping) - self.assertEqual(ranges, [(21, 199)]) + def test_add_mapping_dup_label(self): + with self.assertRaises(bt2.Error): + self._fc.add_mapping('a', self._ranges1) + self._fc.add_mapping('a', self._ranges2) - def test_add_mapping_invalid_name(self): + def test_add_mapping_invalid_ranges_signedness(self): with self.assertRaises(TypeError): - self._fc.map_range(17, 21, 199) + self._fc.add_mapping('allo', self._inval_ranges) def test_iadd(self): - enum_fc = self._tc.create_signed_enumeration_field_class(field_value_range=16) - enum_fc.map_range('c', 4, 5) - enum_fc.map_range('d', 6, 18) - enum_fc.map_range('e', 20, 27) - self._fc.map_range('a', 0, 2) - self._fc.map_range('b', 3) - self._fc += enum_fc + self._fc.add_mapping('c', self._ranges1) - self.assertEqual(self._fc['a'].label, 'a') - self.assertEqual(enum_mapping_to_list(self._fc['a']), [(0, 2)]) - - self.assertEqual(self._fc['b'].label, 'b') - self.assertEqual(enum_mapping_to_list(self._fc['b']), [(3, 3)]) + self._fc += [ + ('d', self._ranges2), + ('e', self._ranges3), + ] + self.assertEqual(len(self._fc), 3) self.assertEqual(self._fc['c'].label, 'c') - self.assertEqual(enum_mapping_to_list(self._fc['c']), [(4, 5)]) - + self.assertEqual(self._fc['c'].ranges, self._ranges1) self.assertEqual(self._fc['d'].label, 'd') - self.assertEqual(enum_mapping_to_list(self._fc['d']), [(6, 18)]) - + self.assertEqual(self._fc['d'].ranges, self._ranges2) self.assertEqual(self._fc['e'].label, 'e') - self.assertEqual(enum_mapping_to_list(self._fc['e']), [(20, 27)]) + self.assertEqual(self._fc['e'].ranges, self._ranges3) def test_bool_op(self): self.assertFalse(self._fc) - self._fc.map_range('a', 0) + self._fc.add_mapping('a', self._ranges1) self.assertTrue(self._fc) def test_len(self): - self._fc.map_range('a', 0) - self._fc.map_range('b', 1) - self._fc.map_range('c', 2) + self._fc.add_mapping('a', self._ranges1) + self._fc.add_mapping('b', self._ranges2) + self._fc.add_mapping('c', self._ranges3) self.assertEqual(len(self._fc), 3) def test_getitem(self): - self._fc.map_range('a', 0) - self._fc.map_range('b', 1, 3) - self._fc.map_range('a', 5) - self._fc.map_range('a', 17, 123) - self._fc.map_range('C', 5) + self._fc.add_mapping('a', self._ranges1) + self._fc.add_mapping('b', self._ranges2) + self._fc.add_mapping('c', self._ranges3) mapping = self._fc['a'] - self.assertEqual(mapping.label, 'a') - ranges = enum_mapping_to_list(mapping) - self.assertEqual(ranges, [(0, 0), (5, 5), (17, 123)]) + self.assertEqual(mapping.ranges, self._ranges1) + def test_getitem_nonexistent(self): with self.assertRaises(KeyError): self._fc['doesnotexist'] - def test_contains(self): - self._fc.map_range('a', 0) - self._fc.map_range('a', 2, 23) - self._fc.map_range('b', 2) - self._fc.map_range('c', 5) - - a_mapping = self._fc['a'] - b_mapping = self._fc['b'] - first_range = next(iter(a_mapping)) - - self.assertIn(first_range, a_mapping) - self.assertNotIn(first_range, b_mapping) - def test_iter(self): - self._fc.map_range('a', 1, 5) - self._fc.map_range('b', 10, 17) - self._fc.map_range('c', 20, 1504) - - self._fc.map_range('d', 22510, 99999) + self._fc.add_mapping('a', self._ranges1) + self._fc.add_mapping('b', self._ranges2) + self._fc.add_mapping('c', self._ranges3) # This exercises iteration. labels = sorted(self._fc) - self.assertEqual(labels, ['a', 'b', 'c', 'd']) + self.assertEqual(labels, ['a', 'b', 'c']) def test_find_by_value(self): - self._fc.map_range('a', 0) - self._fc.map_range('b', 1, 3) - self._fc.map_range('c', 5, 19) - self._fc.map_range('d', 8, 15) - self._fc.map_range('e', 10, 21) - self._fc.map_range('f', 0) - self._fc.map_range('g', 14) - - labels = self._fc.labels_for_value(14) - - expected_labels = ['c', 'd', 'e', 'g'] - - self.assertTrue(all(label in labels for label in expected_labels)) - - -class UnsignedEnumerationFieldClassTestCase(EnumerationFieldClassTestCase, unittest.TestCase): - def setUp(self): - super().setUp() + self._fc.add_mapping('a', self._ranges1) + self._fc.add_mapping('b', self._ranges2) + self._fc.add_mapping('c', self._ranges3) + mappings = self._fc.mappings_for_value(self._value_in_range_1_and_3) + labels = set([mapping.label for mapping in mappings]) + expected_labels = set(['a', 'c']) + self.assertEqual(labels, expected_labels) + + +class UnsignedEnumerationFieldClassTestCase(_EnumerationFieldClassTestCase, unittest.TestCase): + def _spec_set_up(self): + self._ranges1 = bt2.UnsignedIntegerRangeSet([(1, 4), (18, 47)]) + self._ranges2 = bt2.UnsignedIntegerRangeSet([(5, 5)]) + self._ranges3 = bt2.UnsignedIntegerRangeSet([(8, 22), (48, 99)]) + self._inval_ranges = bt2.SignedIntegerRangeSet([(-8, -5), (48, 1928)]) + self._value_in_range_1_and_3 = 20 self._create_func = self._tc.create_unsigned_enumeration_field_class - self._fc = self._tc.create_unsigned_enumeration_field_class() - - def test_add_mapping_invalid_signedness_lower(self): - with self.assertRaises(ValueError): - self._fc.map_range('hello', -21, 199) - def test_add_mapping_invalid_signedness_upper(self): - with self.assertRaises(ValueError): - self._fc.map_range('hello', 21, -199) - -class SignedEnumerationFieldClassTestCase(EnumerationFieldClassTestCase, unittest.TestCase): - def setUp(self): - super().setUp() +class SignedEnumerationFieldClassTestCase(_EnumerationFieldClassTestCase, unittest.TestCase): + def _spec_set_up(self): + self._ranges1 = bt2.SignedIntegerRangeSet([(-10, -4), (18, 47)]) + self._ranges2 = bt2.SignedIntegerRangeSet([(-3, -3)]) + self._ranges3 = bt2.SignedIntegerRangeSet([(-100, -1), (8, 16), (48, 99)]) + self._inval_ranges = bt2.UnsignedIntegerRangeSet([(8, 16), (48, 99)]) + self._value_in_range_1_and_3 = -7 self._create_func = self._tc.create_signed_enumeration_field_class - self._fc = self._tc.create_signed_enumeration_field_class() - - def test_add_mapping_simple_signed(self): - self._fc.map_range('hello', -24) - mapping = self._fc['hello'] - self.assertEqual(mapping.label, 'hello') - - ranges = enum_mapping_to_list(mapping) - self.assertEqual(ranges, [(-24, -24)]) - - def test_add_mapping_range_signed(self): - self._fc.map_range('hello', -21, 199) - mapping = self._fc['hello'] - self.assertEqual(mapping.label, 'hello') - ranges = enum_mapping_to_list(mapping) - self.assertEqual(ranges, [(-21, 199)]) class StringFieldClassTestCase(unittest.TestCase): @@ -270,17 +225,24 @@ class StringFieldClassTestCase(unittest.TestCase): self.assertIsNotNone(self._fc) -class _TestFieldContainer(): +class _TestElementContainer(): + def setUp(self): + self._tc = get_default_trace_class() + self._fc = self._create_default_fc() + + def test_create_default(self): + self.assertIsNotNone(self._fc) + def test_append_element(self): int_field_class = self._tc.create_signed_integer_field_class(32) self._append_element_method(self._fc, 'int32', int_field_class) - field_class = self._fc['int32'] + field_class = self._fc['int32'].field_class self.assertEqual(field_class.addr, int_field_class.addr) - def test_append_elemenbt_kwargs(self): + def test_append_element_kwargs(self): int_field_class = self._tc.create_signed_integer_field_class(32) self._append_element_method(self._fc, name='int32', field_class=int_field_class) - field_class = self._fc['int32'] + field_class = self._fc['int32'].field_class self.assertEqual(field_class.addr, int_field_class.addr) def test_append_element_invalid_name(self): @@ -293,24 +255,38 @@ class _TestFieldContainer(): with self.assertRaises(TypeError): self._append_element_method(self._fc, 'yes', object()) + def test_append_element_dup_name(self): + sub_fc1 = self._tc.create_string_field_class() + sub_fc2 = self._tc.create_string_field_class() + + with self.assertRaises(bt2.Error): + self._append_element_method(self._fc, 'yes', sub_fc1) + self._append_element_method(self._fc, 'yes', sub_fc2) + def test_iadd(self): - struct_fc = self._tc.create_structure_field_class() - c_field_class = self._tc.create_string_field_class() - d_field_class = self._tc.create_signed_enumeration_field_class(field_value_range=32) - e_field_class = self._tc.create_structure_field_class() - self._append_element_method(struct_fc, 'c_string', c_field_class) - self._append_element_method(struct_fc, 'd_enum', d_field_class) - self._append_element_method(struct_fc, 'e_struct', e_field_class) + other_fc = self._create_default_fc() a_field_class = self._tc.create_real_field_class() b_field_class = self._tc.create_signed_integer_field_class(17) self._append_element_method(self._fc, 'a_float', a_field_class) self._append_element_method(self._fc, 'b_int', b_field_class) - self._fc += struct_fc - self.assertEqual(self._fc['a_float'].addr, a_field_class.addr) - self.assertEqual(self._fc['b_int'].addr, b_field_class.addr) - self.assertEqual(self._fc['c_string'].addr, c_field_class.addr) - self.assertEqual(self._fc['d_enum'].addr, d_field_class.addr) - self.assertEqual(self._fc['e_struct'].addr, e_field_class.addr) + c_field_class = self._tc.create_string_field_class() + d_field_class = self._tc.create_signed_enumeration_field_class(field_value_range=32) + e_field_class = self._tc.create_structure_field_class() + self._fc += [ + ('c_string', c_field_class), + ('d_enum', d_field_class), + ('e_struct', e_field_class), + ] + self.assertEqual(self._fc['a_float'].field_class.addr, a_field_class.addr) + self.assertEqual(self._fc['a_float'].name, 'a_float') + self.assertEqual(self._fc['b_int'].field_class.addr, b_field_class.addr) + self.assertEqual(self._fc['b_int'].name, 'b_int') + self.assertEqual(self._fc['c_string'].field_class.addr, c_field_class.addr) + self.assertEqual(self._fc['c_string'].name, 'c_string') + self.assertEqual(self._fc['d_enum'].field_class.addr, d_field_class.addr) + self.assertEqual(self._fc['d_enum'].name, 'd_enum') + self.assertEqual(self._fc['e_struct'].field_class.addr, e_field_class.addr) + self.assertEqual(self._fc['e_struct'].name, 'e_struct') def test_bool_op(self): self.assertFalse(self._fc) @@ -318,10 +294,9 @@ class _TestFieldContainer(): self.assertTrue(self._fc) def test_len(self): - fc = self._tc.create_string_field_class() - self._append_element_method(self._fc, 'a', fc) - self._append_element_method(self._fc, 'b', fc) - self._append_element_method(self._fc, 'c', fc) + self._append_element_method(self._fc, 'a', self._tc.create_string_field_class()) + self._append_element_method(self._fc, 'b', self._tc.create_string_field_class()) + self._append_element_method(self._fc, 'c', self._tc.create_string_field_class()) self.assertEqual(len(self._fc), 3) def test_getitem(self): @@ -331,7 +306,8 @@ class _TestFieldContainer(): self._append_element_method(self._fc, 'a', a_fc) self._append_element_method(self._fc, 'b', b_fc) self._append_element_method(self._fc, 'c', c_fc) - self.assertEqual(self._fc['b'].addr, b_fc.addr) + self.assertEqual(self._fc['b'].field_class.addr, b_fc.addr) + self.assertEqual(self._fc['b'].name, 'b') def test_getitem_invalid_key_type(self): with self.assertRaises(TypeError): @@ -350,18 +326,19 @@ class _TestFieldContainer(): a_fc = self._tc.create_signed_integer_field_class(32) b_fc = self._tc.create_string_field_class() c_fc = self._tc.create_real_field_class() - fields = ( + elements = ( ('a', a_fc), ('b', b_fc), ('c', c_fc), ) - for field in fields: - self._append_element_method(self._fc, *field) + for elem in elements: + self._append_element_method(self._fc, *elem) - for (name, fc_field_class), field in zip(self._fc.items(), fields): - self.assertEqual(name, field[0]) - self.assertEqual(fc_field_class.addr, field[1].addr) + for (name, element), test_elem in zip(self._fc.items(), elements): + self.assertEqual(element.name, test_elem[0]) + self.assertEqual(name, element.name) + self.assertEqual(element.field_class.addr, test_elem[1].addr) def test_at_index(self): a_fc = self._tc.create_signed_integer_field_class(32) @@ -370,7 +347,9 @@ class _TestFieldContainer(): self._append_element_method(self._fc, 'c', c_fc) self._append_element_method(self._fc, 'a', a_fc) self._append_element_method(self._fc, 'b', b_fc) - self.assertEqual(self._at_index_method(self._fc, 1).addr, a_fc.addr) + elem = self._at_index_method(self._fc, 1) + self.assertEqual(elem.field_class.addr, a_fc.addr) + self.assertEqual(elem.name, 'a') def test_at_index_invalid(self): self._append_element_method(self._fc, 'c', self._tc.create_signed_integer_field_class(32)) @@ -385,63 +364,207 @@ class _TestFieldContainer(): self._at_index_method(self._fc, len(self._fc)) -class StructureFieldClassTestCase(_TestFieldContainer, unittest.TestCase): +class StructureFieldClassTestCase(_TestElementContainer, unittest.TestCase): + _append_element_method = staticmethod(bt2.field_class._StructureFieldClass.append_member) + _at_index_method = staticmethod(bt2.field_class._StructureFieldClass.member_at_index) + + def _create_default_fc(self): + return self._tc.create_structure_field_class() + + +class VariantFieldClassWithoutSelectorTestCase(_TestElementContainer, unittest.TestCase): + _append_element_method = staticmethod(bt2.field_class._VariantFieldClassWithoutSelector.append_option) + _at_index_method = staticmethod(bt2.field_class._VariantFieldClassWithoutSelector.option_at_index) + + def _create_default_fc(self): + return self._tc.create_variant_field_class() + + +class _VariantFieldClassWithSelectorTestCase: def setUp(self): - self._append_element_method = bt2.field_class._StructureFieldClass.append_member - self._at_index_method = bt2.field_class._StructureFieldClass.member_at_index self._tc = get_default_trace_class() - self._fc = self._tc.create_structure_field_class() + self._spec_set_up() + self._fc = self._create_default_fc() + + def _create_default_fc(self): + return self._tc.create_variant_field_class(self._selector_fc) def test_create_default(self): self.assertIsNotNone(self._fc) + def test_append_element(self): + str_field_class = self._tc.create_string_field_class() + self._fc.append_option('str', str_field_class, self._ranges1) + opt = self._fc['str'] + self.assertEqual(opt.field_class.addr, str_field_class.addr) + self.assertEqual(opt.name, 'str') + self.assertEqual(opt.ranges.addr, self._ranges1.addr) + + def test_append_element_kwargs(self): + int_field_class = self._tc.create_signed_integer_field_class(32) + self._fc.append_option(name='int32', field_class=int_field_class, + ranges=self._ranges1) + opt = self._fc['int32'] + self.assertEqual(opt.field_class.addr, int_field_class.addr) + self.assertEqual(opt.name, 'int32') + self.assertEqual(opt.ranges.addr, self._ranges1.addr) + + def test_append_element_invalid_name(self): + sub_fc = self._tc.create_string_field_class() -class VariantFieldClassTestCase(_TestFieldContainer, unittest.TestCase): - def setUp(self): - self._append_element_method = bt2.field_class._VariantFieldClass.append_option - self._at_index_method = bt2.field_class._VariantFieldClass.option_at_index - self._tc = get_default_trace_class() - self._fc = self._tc.create_variant_field_class() + with self.assertRaises(TypeError): + self._fc.append_option(self._fc, 23, sub_fc) - def test_create_default(self): - fc = self._tc.create_variant_field_class() + def test_append_element_invalid_field_class(self): + with self.assertRaises(TypeError): + self._fc.append_option(self._fc, 'yes', object()) - self.assertIsNone(fc.selector_field_path) + def test_append_element_invalid_ranges(self): + sub_fc = self._tc.create_string_field_class() - def _create_field_class_for_field_path_test(self): + with self.assertRaises(TypeError): + self._fc.append_option(self._fc, sub_fc, 'lel') + + def test_append_element_dup_name(self): + sub_fc1 = self._tc.create_string_field_class() + sub_fc2 = self._tc.create_string_field_class() + + with self.assertRaises(bt2.Error): + self._fc.append_option('yes', sub_fc1, self._ranges1) + self._fc.append_option('yes', sub_fc2, self._ranges2) + + def test_append_element_invalid_ranges_signedness(self): + sub_fc = self._tc.create_string_field_class() + + with self.assertRaises(TypeError): + self._fc.append_option(self._fc, sub_fc, self._inval_ranges) + + def test_iadd(self): + other_fc = self._create_default_fc() + a_field_class = self._tc.create_real_field_class() + self._fc.append_option('a_float', a_field_class, self._ranges1) + c_field_class = self._tc.create_string_field_class() + d_field_class = self._tc.create_signed_enumeration_field_class(field_value_range=32) + self._fc += [ + ('c_string', c_field_class, self._ranges2), + ('d_enum', d_field_class, self._ranges3), + ] + self.assertEqual(self._fc['a_float'].field_class.addr, a_field_class.addr) + self.assertEqual(self._fc['a_float'].name, 'a_float') + self.assertEqual(self._fc['a_float'].ranges, self._ranges1) + self.assertEqual(self._fc['c_string'].field_class.addr, c_field_class.addr) + self.assertEqual(self._fc['c_string'].name, 'c_string') + self.assertEqual(self._fc['c_string'].ranges, self._ranges2) + self.assertEqual(self._fc['d_enum'].field_class.addr, d_field_class.addr) + self.assertEqual(self._fc['d_enum'].name, 'd_enum') + self.assertEqual(self._fc['d_enum'].ranges, self._ranges3) + + def test_bool_op(self): + self.assertFalse(self._fc) + self._fc.append_option('a', self._tc.create_string_field_class(), self._ranges1) + self.assertTrue(self._fc) + + def test_len(self): + self._fc.append_option('a', self._tc.create_string_field_class(), self._ranges1) + self._fc.append_option('b', self._tc.create_string_field_class(), self._ranges2) + self._fc.append_option('c', self._tc.create_string_field_class(), self._ranges3) + self.assertEqual(len(self._fc), 3) + + def test_getitem(self): + a_fc = self._tc.create_signed_integer_field_class(32) + b_fc = self._tc.create_string_field_class() + c_fc = self._tc.create_real_field_class() + self._fc.append_option('a', a_fc, self._ranges1) + self._fc.append_option('b', b_fc, self._ranges2) + self._fc.append_option('c', c_fc, self._ranges3) + self.assertEqual(self._fc['b'].field_class.addr, b_fc.addr) + self.assertEqual(self._fc['b'].name, 'b') + self.assertEqual(self._fc['b'].ranges.addr, self._ranges2.addr) + + def test_getitem_invalid_key_type(self): + with self.assertRaises(TypeError): + self._fc[0] + + def test_getitem_invalid_key(self): + with self.assertRaises(KeyError): + self._fc['no way'] + + def test_contains(self): + self.assertFalse('a' in self._fc) + self._fc.append_option('a', self._tc.create_string_field_class(), self._ranges1) + self.assertTrue('a' in self._fc) + + def test_iter(self): + a_fc = self._tc.create_signed_integer_field_class(32) + b_fc = self._tc.create_string_field_class() + c_fc = self._tc.create_real_field_class() + opts = ( + ('a', a_fc, self._ranges1), + ('b', b_fc, self._ranges2), + ('c', c_fc, self._ranges3), + ) + + for opt in opts: + self._fc.append_option(*opt) + + for (name, opt), test_opt in zip(self._fc.items(), opts): + self.assertEqual(opt.name, test_opt[0]) + self.assertEqual(name, opt.name) + self.assertEqual(opt.field_class.addr, test_opt[1].addr) + self.assertEqual(opt.ranges.addr, test_opt[2].addr) + + def test_at_index(self): + a_fc = self._tc.create_signed_integer_field_class(32) + b_fc = self._tc.create_string_field_class() + c_fc = self._tc.create_real_field_class() + self._fc.append_option('c', c_fc, self._ranges1) + self._fc.append_option('a', a_fc, self._ranges2) + self._fc.append_option('b', b_fc, self._ranges3) + self.assertEqual(self._fc.option_at_index(1).field_class.addr, a_fc.addr) + self.assertEqual(self._fc.option_at_index(1).name, 'a') + self.assertEqual(self._fc.option_at_index(1).ranges.addr, self._ranges2.addr) + + def test_at_index_invalid(self): + self._fc.append_option('c', self._tc.create_signed_integer_field_class(32), self._ranges3) + + with self.assertRaises(TypeError): + self._fc.option_at_index('yes') + + def test_at_index_out_of_bounds_after(self): + self._fc.append_option('c', self._tc.create_signed_integer_field_class(32), self._ranges3) + + with self.assertRaises(IndexError): + self._fc.option_at_index(len(self._fc)) + + def _fill_default_fc_for_field_path_test(self): # Create something equivalent to: # # struct outer_struct_fc { # real foo; # struct inner_struct_fc { - # enum { first = 1, second = 2..434 } selector; + # [u]int64_t selector; # string bar; # string baz; - # variant { - # real a; - # int21_t b; - # uint34_t c; + # variant { + # real a; // selected with self._ranges1 + # int21_t b; // selected with self._ranges2 + # uint34_t c; // selected with self._ranges3 # } variant; # } inner_struct[2]; # }; - selector_fc = self._tc.create_unsigned_enumeration_field_class(field_value_range=42) - selector_fc.map_range('first', 1) - selector_fc.map_range('second', 2, 434) - - fc = self._tc.create_variant_field_class(selector_fc) - fc.append_option('a', self._tc.create_real_field_class()) - fc.append_option('b', self._tc.create_signed_integer_field_class(21)) - fc.append_option('c', self._tc.create_unsigned_integer_field_class(34)) + self._fc.append_option('a', self._tc.create_real_field_class(), self._ranges1) + self._fc.append_option('b', self._tc.create_signed_integer_field_class(21), self._ranges2) + self._fc.append_option('c', self._tc.create_unsigned_integer_field_class(34), self._ranges3) foo_fc = self._tc.create_real_field_class() bar_fc = self._tc.create_string_field_class() baz_fc = self._tc.create_string_field_class() inner_struct_fc = self._tc.create_structure_field_class() - inner_struct_fc.append_member('selector', selector_fc) + inner_struct_fc.append_member('selector', self._selector_fc) inner_struct_fc.append_member('bar', bar_fc) inner_struct_fc.append_member('baz', baz_fc) - inner_struct_fc.append_member('variant', fc) + inner_struct_fc.append_member('variant', self._fc) inner_struct_array_fc = self._tc.create_static_array_field_class(inner_struct_fc, 2) @@ -451,17 +574,16 @@ class VariantFieldClassTestCase(_TestFieldContainer, unittest.TestCase): # The path to the selector field is resolved when the sequence is # actually used, for example in a packet context. - self._tc.create_stream_class(supports_packets=True, packet_context_field_class=outer_struct_fc) - - return fc + self._tc.create_stream_class(supports_packets=True, + packet_context_field_class=outer_struct_fc) def test_selector_field_path_length(self): - fc = self._create_field_class_for_field_path_test() - self.assertEqual(len(fc.selector_field_path), 3) + self._fill_default_fc_for_field_path_test() + self.assertEqual(len(self._fc.selector_field_path), 3) def test_selector_field_path_iter(self): - fc = self._create_field_class_for_field_path_test() - path_items = list(fc.selector_field_path) + self._fill_default_fc_for_field_path_test() + path_items = list(self._fc.selector_field_path) self.assertEqual(len(path_items), 3) @@ -474,8 +596,26 @@ class VariantFieldClassTestCase(_TestFieldContainer, unittest.TestCase): self.assertEqual(path_items[2].index, 0) def test_selector_field_path_root_scope(self): - fc = self._create_field_class_for_field_path_test() - self.assertEqual(fc.selector_field_path.root_scope, bt2.field_path.Scope.PACKET_CONTEXT) + self._fill_default_fc_for_field_path_test() + self.assertEqual(self._fc.selector_field_path.root_scope, bt2.field_path.Scope.PACKET_CONTEXT) + + +class VariantFieldClassWithUnsignedSelectorTestCase(_VariantFieldClassWithSelectorTestCase, unittest.TestCase): + def _spec_set_up(self): + self._ranges1 = bt2.UnsignedIntegerRangeSet([(1, 4), (18, 47)]) + self._ranges2 = bt2.UnsignedIntegerRangeSet([(5, 5)]) + self._ranges3 = bt2.UnsignedIntegerRangeSet([(8, 16), (48, 99)]) + self._inval_ranges = bt2.SignedIntegerRangeSet([(-8, 16), (48, 99)]) + self._selector_fc = self._tc.create_unsigned_integer_field_class() + + +class VariantFieldClassWithSignedSelectorTestCase(_VariantFieldClassWithSelectorTestCase, unittest.TestCase): + def _spec_set_up(self): + self._ranges1 = bt2.SignedIntegerRangeSet([(-10, -4), (18, 47)]) + self._ranges2 = bt2.SignedIntegerRangeSet([(-3, -3)]) + self._ranges3 = bt2.SignedIntegerRangeSet([(8, 16), (48, 99)]) + self._inval_ranges = bt2.UnsignedIntegerRangeSet([(8, 16), (48, 99)]) + self._selector_fc = self._tc.create_signed_integer_field_class() class StaticArrayFieldClassTestCase(unittest.TestCase): diff --git a/tests/bindings/python/bt2/test_graph.py b/tests/bindings/python/bt2/test_graph.py index cb447a5a..da9c209f 100644 --- a/tests/bindings/python/bt2/test_graph.py +++ b/tests/bindings/python/bt2/test_graph.py @@ -35,9 +35,9 @@ class _MyIter(bt2._UserMessageIterator): self._ec = self._sc.create_event_class(name='salut') self._my_int_ft = self._tc.create_signed_integer_field_class(32) payload_ft = self._tc.create_structure_field_class() - payload_ft += collections.OrderedDict([ + payload_ft += [ ('my_int', self._my_int_ft), - ]) + ] self._ec.payload_field_type = payload_ft self._stream = self._t.create_stream(self._sc) self._packet = self._stream.create_packet() diff --git a/tests/bindings/python/bt2/test_message.py b/tests/bindings/python/bt2/test_message.py index 6e1999de..a432ec71 100644 --- a/tests/bindings/python/bt2/test_message.py +++ b/tests/bindings/python/bt2/test_message.py @@ -99,9 +99,9 @@ class AllMessagesTestCase(unittest.TestCase): # Create payload field class my_int_fc = tc.create_signed_integer_field_class(32) payload_fc = tc.create_structure_field_class() - payload_fc += collections.OrderedDict([ + payload_fc += [ ('my_int', my_int_fc), - ]) + ] ec = sc.create_event_class(name='salut', payload_field_class=payload_fc) diff --git a/tests/bindings/python/bt2/test_message_iterator.py b/tests/bindings/python/bt2/test_message_iterator.py index bd0a52ee..84912983 100644 --- a/tests/bindings/python/bt2/test_message_iterator.py +++ b/tests/bindings/python/bt2/test_message_iterator.py @@ -344,9 +344,9 @@ class OutputPortMessageIteratorTestCase(unittest.TestCase): # Create payload field class my_int_ft = trace_class.create_signed_integer_field_class(32) payload_ft = trace_class.create_structure_field_class() - payload_ft += collections.OrderedDict([ + payload_ft += [ ('my_int', my_int_ft), - ]) + ] event_class = stream_class.create_event_class(name='salut', payload_field_class=payload_ft) diff --git a/tests/bindings/python/bt2/test_packet.py b/tests/bindings/python/bt2/test_packet.py index 2945f49b..0b2a85b9 100644 --- a/tests/bindings/python/bt2/test_packet.py +++ b/tests/bindings/python/bt2/test_packet.py @@ -33,21 +33,21 @@ class PacketTestCase(unittest.TestCase): # stream event context sec = tc.create_structure_field_class() - sec += OrderedDict(( + sec += [ ('cpu_id', tc.create_signed_integer_field_class(8)), ('stuff', tc.create_real_field_class()), - )) + ] # packet context pc = None if with_pc: pc = tc.create_structure_field_class() - pc += OrderedDict(( + pc += [ ('something', tc.create_signed_integer_field_class(8)), ('something_else', tc.create_real_field_class()), ('events_discarded', tc.create_unsigned_integer_field_class(64)), ('packet_seq_num', tc.create_unsigned_integer_field_class(64)), - )) + ] # stream class sc = tc.create_stream_class(default_clock_class=clock_class, @@ -57,18 +57,18 @@ class PacketTestCase(unittest.TestCase): # event context ec = tc.create_structure_field_class() - ec += OrderedDict(( + ec += [ ('ant', tc.create_signed_integer_field_class(16)), ('msg', tc.create_string_field_class()), - )) + ] # event payload ep = tc.create_structure_field_class() - ep += OrderedDict(( + ep += [ ('giraffe', tc.create_signed_integer_field_class(32)), ('gnu', tc.create_signed_integer_field_class(8)), ('mosquito', tc.create_signed_integer_field_class(8)), - )) + ] # event class event_class = sc.create_event_class(name='ec', payload_field_class=ep) diff --git a/tests/data/ctf-traces/succeed/meta-variant-no-underscore/metadata b/tests/data/ctf-traces/succeed/meta-variant-no-underscore/metadata new file mode 100644 index 00000000..dd8bcb8d --- /dev/null +++ b/tests/data/ctf-traces/succeed/meta-variant-no-underscore/metadata @@ -0,0 +1,24 @@ +/* CTF 1.8 */ + +trace { + major = 1; + minor = 8; + byte_order = be; +}; + +event { + name = yo; + fields := struct { + enum : integer { size = 8; } { + COSSETTE, + PELCHAT, + VOISINE, + } tag; + + variant { + string COSSETTE; + string PELCHAT; + string VOISINE; + } var; + }; +}; diff --git a/tests/data/ctf-traces/succeed/meta-variant-no-underscore/stream b/tests/data/ctf-traces/succeed/meta-variant-no-underscore/stream new file mode 100644 index 0000000000000000000000000000000000000000..f54d73fe2a29848286b21a7464eaa1c8631c5455 GIT binary patch literal 15 WcmZQ{NzBVk%~9}4EX&VKWdHyrl?2ZK literal 0 HcmV?d00001 diff --git a/tests/data/ctf-traces/succeed/meta-variant-one-underscore/metadata b/tests/data/ctf-traces/succeed/meta-variant-one-underscore/metadata new file mode 100644 index 00000000..0c6206ff --- /dev/null +++ b/tests/data/ctf-traces/succeed/meta-variant-one-underscore/metadata @@ -0,0 +1,24 @@ +/* CTF 1.8 */ + +trace { + major = 1; + minor = 8; + byte_order = be; +}; + +event { + name = yo; + fields := struct { + enum : integer { size = 8; } { + COSSETTE, + PELCHAT, + _VOISINE, + } tag; + + variant { + string COSSETTE; + string PELCHAT; + string _VOISINE; + } var; + }; +}; diff --git a/tests/data/ctf-traces/succeed/meta-variant-one-underscore/stream b/tests/data/ctf-traces/succeed/meta-variant-one-underscore/stream new file mode 100644 index 0000000000000000000000000000000000000000..f54d73fe2a29848286b21a7464eaa1c8631c5455 GIT binary patch literal 15 WcmZQ{NzBVk%~9}4EX&VKWdHyrl?2ZK literal 0 HcmV?d00001 diff --git a/tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/metadata b/tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/metadata new file mode 100644 index 00000000..18af2f9a --- /dev/null +++ b/tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/metadata @@ -0,0 +1,74 @@ +/* CTF 1.8 */ + +trace { + major = 1; + minor = 8; + byte_order = be; +}; + +event { + name = yo; + fields := struct { + enum : integer { size = 8; } { + _align, + _callsite, + _const, + _char, + _clock, + _double, + _enum, + _env, + _event, + _floating_point, + _float, + _integer, + _int, + _long, + _short, + _signed, + _stream, + _string, + _struct, + _trace, + _typealias, + _typedef, + _unsigned, + _variant, + _void, + __Bool, + __Complex, + __Imaginary, + } tag; + + variant { + string _align; + string _callsite; + string _const; + string _char; + string _clock; + string _double; + string _enum; + string _env; + string _event; + string _floating_point; + string _float; + string _integer; + string _int; + string _long; + string _short; + string _signed; + string _stream; + string _string; + string _struct; + string _trace; + string _typealias; + string _typedef; + string _unsigned; + string _variant; + string _void; + string __Bool; + string __Complex; + string __Imaginary; + } var; + }; +}; diff --git a/tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/stream b/tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/stream new file mode 100644 index 0000000000000000000000000000000000000000..f54d73fe2a29848286b21a7464eaa1c8631c5455 GIT binary patch literal 15 WcmZQ{NzBVk%~9}4EX&VKWdHyrl?2ZK literal 0 HcmV?d00001 diff --git a/tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/metadata b/tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/metadata new file mode 100644 index 00000000..be1b0cdf --- /dev/null +++ b/tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/metadata @@ -0,0 +1,24 @@ +/* CTF 1.8 */ + +trace { + major = 1; + minor = 8; + byte_order = be; +}; + +event { + name = yo; + fields := struct { + enum : integer { size = 8; } { + COSSETTE, + _PELCHAT, + __PELCHAT, + } tag; + + variant { + string COSSETTE; + string _PELCHAT; + string __PELCHAT; + } var; + }; +}; diff --git a/tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/stream b/tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/stream new file mode 100644 index 0000000000000000000000000000000000000000..f54d73fe2a29848286b21a7464eaa1c8631c5455 GIT binary patch literal 15 WcmZQ{NzBVk%~9}4EX&VKWdHyrl?2ZK literal 0 HcmV?d00001 diff --git a/tests/data/ctf-traces/succeed/meta-variant-two-underscores/metadata b/tests/data/ctf-traces/succeed/meta-variant-two-underscores/metadata new file mode 100644 index 00000000..4eb669d2 --- /dev/null +++ b/tests/data/ctf-traces/succeed/meta-variant-two-underscores/metadata @@ -0,0 +1,24 @@ +/* CTF 1.8 */ + +trace { + major = 1; + minor = 8; + byte_order = be; +}; + +event { + name = yo; + fields := struct { + enum : integer { size = 8; } { + COSSETTE, + __PELCHAT, + VOISINE, + } tag; + + variant { + string COSSETTE; + string __PELCHAT; + string VOISINE; + } var; + }; +}; diff --git a/tests/data/ctf-traces/succeed/meta-variant-two-underscores/stream b/tests/data/ctf-traces/succeed/meta-variant-two-underscores/stream new file mode 100644 index 0000000000000000000000000000000000000000..f54d73fe2a29848286b21a7464eaa1c8631c5455 GIT binary patch literal 15 WcmZQ{NzBVk%~9}4EX&VKWdHyrl?2ZK literal 0 HcmV?d00001 diff --git a/tests/data/plugins/sink.ctf.fs/succeed/trace-double.expect b/tests/data/plugins/sink.ctf.fs/succeed/trace-double.expect index 57f0dc83..0d4b5fb6 100644 --- a/tests/data/plugins/sink.ctf.fs/succeed/trace-double.expect +++ b/tests/data/plugins/sink.ctf.fs/succeed/trace-double.expect @@ -8,7 +8,7 @@ Trace class: Supports discarded packets: Yes Discarded packets have default clock snapshots: Yes Default clock class: - Name: _default + Name: default Frequency (Hz): 1,000,000,000 Precision (cycles): 1 Offset (s): 0 diff --git a/tests/data/plugins/sink.ctf.fs/succeed/trace-float.expect b/tests/data/plugins/sink.ctf.fs/succeed/trace-float.expect index a0780df3..23806cca 100644 --- a/tests/data/plugins/sink.ctf.fs/succeed/trace-float.expect +++ b/tests/data/plugins/sink.ctf.fs/succeed/trace-float.expect @@ -8,7 +8,7 @@ Trace class: Supports discarded packets: Yes Discarded packets have default clock snapshots: Yes Default clock class: - Name: _default + Name: default Frequency (Hz): 1,000,000,000 Precision (cycles): 1 Offset (s): 0 diff --git a/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-no-underscore.expect b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-no-underscore.expect new file mode 100644 index 00000000..bdca129f --- /dev/null +++ b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-no-underscore.expect @@ -0,0 +1,38 @@ +Trace class: + Stream class (ID 0): + Supports packets: Yes + Packets have beginning default clock snapshot: No + Packets have end default clock snapshot: No + Supports discarded events: No + Supports discarded packets: Yes + Discarded packets have default clock snapshots: No + Event class `yo` (ID 0): + Payload field class: Structure (2 members): + tag: Unsigned enumeration (8-bit, Base 10, 3 mappings): + COSSETTE: [0] + PELCHAT: [1] + VOISINE: [2] + var: Variant (unsigned selector) (3 options, Selector field path [Event payload: 0]): + COSSETTE: [0]: String + PELCHAT: [1]: String + VOISINE: [2]: String + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream beginning: + Trace: + Stream (ID 0, Class ID 0) + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet beginning: + +{Trace 0, Stream class ID 0, Stream ID 0} +Event `yo` (Class ID 0): + Payload: + tag: 1 + var: Daniel Lavoie + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet end + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream end diff --git a/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-one-underscore.expect b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-one-underscore.expect new file mode 100644 index 00000000..8eadeecd --- /dev/null +++ b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-one-underscore.expect @@ -0,0 +1,38 @@ +Trace class: + Stream class (ID 0): + Supports packets: Yes + Packets have beginning default clock snapshot: No + Packets have end default clock snapshot: No + Supports discarded events: No + Supports discarded packets: Yes + Discarded packets have default clock snapshots: No + Event class `yo` (ID 0): + Payload field class: Structure (2 members): + tag: Unsigned enumeration (8-bit, Base 10, 3 mappings): + COSSETTE: [0] + PELCHAT: [1] + _VOISINE: [2] + var: Variant (unsigned selector) (3 options, Selector field path [Event payload: 0]): + COSSETTE: [0]: String + PELCHAT: [1]: String + VOISINE: [2]: String + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream beginning: + Trace: + Stream (ID 0, Class ID 0) + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet beginning: + +{Trace 0, Stream class ID 0, Stream ID 0} +Event `yo` (Class ID 0): + Payload: + tag: 1 + var: Daniel Lavoie + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet end + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream end diff --git a/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-reserved-keywords.expect b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-reserved-keywords.expect new file mode 100644 index 00000000..cda3466c --- /dev/null +++ b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-reserved-keywords.expect @@ -0,0 +1,88 @@ +Trace class: + Stream class (ID 0): + Supports packets: Yes + Packets have beginning default clock snapshot: No + Packets have end default clock snapshot: No + Supports discarded events: No + Supports discarded packets: Yes + Discarded packets have default clock snapshots: No + Event class `yo` (ID 0): + Payload field class: Structure (2 members): + tag: Unsigned enumeration (8-bit, Base 10, 28 mappings): + __Bool: [25] + __Complex: [26] + __Imaginary: [27] + _align: [0] + _callsite: [1] + _char: [3] + _clock: [4] + _const: [2] + _double: [5] + _enum: [6] + _env: [7] + _event: [8] + _float: [10] + _floating_point: [9] + _int: [12] + _integer: [11] + _long: [13] + _short: [14] + _signed: [15] + _stream: [16] + _string: [17] + _struct: [18] + _trace: [19] + _typealias: [20] + _typedef: [21] + _unsigned: [22] + _variant: [23] + _void: [24] + var: Variant (unsigned selector) (28 options, Selector field path [Event payload: 0]): + align: [0]: String + callsite: [1]: String + const: [2]: String + char: [3]: String + clock: [4]: String + double: [5]: String + enum: [6]: String + env: [7]: String + event: [8]: String + floating_point: [9]: String + float: [10]: String + integer: [11]: String + int: [12]: String + long: [13]: String + short: [14]: String + signed: [15]: String + stream: [16]: String + string: [17]: String + struct: [18]: String + trace: [19]: String + typealias: [20]: String + typedef: [21]: String + unsigned: [22]: String + variant: [23]: String + void: [24]: String + _Bool: [25]: String + _Complex: [26]: String + _Imaginary: [27]: String + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream beginning: + Trace: + Stream (ID 0, Class ID 0) + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet beginning: + +{Trace 0, Stream class ID 0, Stream ID 0} +Event `yo` (Class ID 0): + Payload: + tag: 1 + var: Daniel Lavoie + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet end + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream end diff --git a/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-same-with-underscore.expect b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-same-with-underscore.expect new file mode 100644 index 00000000..545d6f97 --- /dev/null +++ b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-same-with-underscore.expect @@ -0,0 +1,38 @@ +Trace class: + Stream class (ID 0): + Supports packets: Yes + Packets have beginning default clock snapshot: No + Packets have end default clock snapshot: No + Supports discarded events: No + Supports discarded packets: Yes + Discarded packets have default clock snapshots: No + Event class `yo` (ID 0): + Payload field class: Structure (2 members): + tag: Unsigned enumeration (8-bit, Base 10, 3 mappings): + COSSETTE: [0] + _PELCHAT: [1] + __PELCHAT: [2] + var: Variant (unsigned selector) (3 options, Selector field path [Event payload: 0]): + COSSETTE: [0]: String + PELCHAT: [1]: String + _PELCHAT: [2]: String + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream beginning: + Trace: + Stream (ID 0, Class ID 0) + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet beginning: + +{Trace 0, Stream class ID 0, Stream ID 0} +Event `yo` (Class ID 0): + Payload: + tag: 1 + var: Daniel Lavoie + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet end + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream end diff --git a/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-two-underscores.expect b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-two-underscores.expect new file mode 100644 index 00000000..bd0ebcf0 --- /dev/null +++ b/tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-two-underscores.expect @@ -0,0 +1,38 @@ +Trace class: + Stream class (ID 0): + Supports packets: Yes + Packets have beginning default clock snapshot: No + Packets have end default clock snapshot: No + Supports discarded events: No + Supports discarded packets: Yes + Discarded packets have default clock snapshots: No + Event class `yo` (ID 0): + Payload field class: Structure (2 members): + tag: Unsigned enumeration (8-bit, Base 10, 3 mappings): + COSSETTE: [0] + VOISINE: [2] + __PELCHAT: [1] + var: Variant (unsigned selector) (3 options, Selector field path [Event payload: 0]): + COSSETTE: [0]: String + _PELCHAT: [1]: String + VOISINE: [2]: String + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream beginning: + Trace: + Stream (ID 0, Class ID 0) + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet beginning: + +{Trace 0, Stream class ID 0, Stream ID 0} +Event `yo` (Class ID 0): + Payload: + tag: 1 + var: Daniel Lavoie + +{Trace 0, Stream class ID 0, Stream ID 0} +Packet end + +{Trace 0, Stream class ID 0, Stream ID 0} +Stream end diff --git a/tests/plugins/sink.ctf.fs/succeed/test_succeed b/tests/plugins/sink.ctf.fs/succeed/test_succeed index fa5f3751..5c2547d6 100755 --- a/tests/plugins/sink.ctf.fs/succeed/test_succeed +++ b/tests/plugins/sink.ctf.fs/succeed/test_succeed @@ -36,24 +36,15 @@ source "$UTILSSH" this_dir_relative="plugins/sink.ctf.fs/succeed" this_dir_build="$BT_TESTS_BUILDDIR/$this_dir_relative" expect_dir="$BT_TESTS_DATADIR/$this_dir_relative" +succeed_traces="$BT_CTF_TRACES_PATH/succeed" -test_ctf_gen_single() { - name="$1" - temp_gen_trace_dir="$(mktemp -d)" - temp_out_trace_dir="$(mktemp -d)" - - diag "Generating trace '$name'" - - if ! "$this_dir_build/gen-trace-$name" "$temp_gen_trace_dir"; then - # this is not part of the test itself; it must not fail - echo "ERROR: \"$this_dir_build/gen-trace-$name" "$temp_gen_trace_dir\" failed" >&2 - rm -rf "$temp_gen_trace_dir" - rm -rf "$temp_out_trace_dir" - exit 1 - fi +test_ctf_single() { + local name="$1" + local in_trace_dir="$2" + local temp_out_trace_dir="$(mktemp -d)" diag "Converting trace '$name' to CTF through 'sink.ctf.fs'" - "$BT_TESTS_BT2_BIN" >/dev/null "$temp_gen_trace_dir" -o ctf -w "$temp_out_trace_dir" + "$BT_TESTS_BT2_BIN" >/dev/null "$in_trace_dir" -o ctf -w "$temp_out_trace_dir" ret=$? ok $ret "'sink.ctf.fs' component succeeds with input trace '$name'" converted_test_name="Converted trace '$name' gives the expected output" @@ -61,17 +52,45 @@ test_ctf_gen_single() { if [ $ret -eq 0 ]; then bt_diff_details_ctf_single "$expect_dir/trace-$name.expect" \ "$temp_out_trace_dir" \ - "-p" "with-uuid=no,with-trace-name=no,with-stream-name=no" + '-p' 'with-uuid=no,with-trace-name=no,with-stream-name=no' ok $? "$converted_test_name" else fail "$converted_test_name" fi - rm -rf "$temp_gen_trace_dir" rm -rf "$temp_out_trace_dir" } -plan_tests 4 +test_ctf_existing_single() { + local name="$1" + local trace_dir="$succeed_traces/$name" + + test_ctf_single "$name" "$trace_dir" +} + +test_ctf_gen_single() { + local name="$1" + local temp_gen_trace_dir="$(mktemp -d)" + + diag "Generating trace '$name'" + + if ! "$this_dir_build/gen-trace-$name" "$temp_gen_trace_dir"; then + # this is not part of the test itself; it must not fail + echo "ERROR: \"$this_dir_build/gen-trace-$name" "$temp_gen_trace_dir\" failed" >&2 + rm -rf "$temp_gen_trace_dir" + exit 1 + fi + + test_ctf_single "$name" "$temp_gen_trace_dir" + rm -rf "$temp_gen_trace_dir" +} + +plan_tests 14 test_ctf_gen_single float test_ctf_gen_single double +test_ctf_existing_single meta-variant-no-underscore +test_ctf_existing_single meta-variant-one-underscore +test_ctf_existing_single meta-variant-reserved-keywords +test_ctf_existing_single meta-variant-same-with-underscore +test_ctf_existing_single meta-variant-two-underscores -- 2.34.1