lib: decouple variant FC option names from selector FC mapping names
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 12 Jul 2019 19:03:40 +0000 (15:03 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 18 Jul 2019 13:42:13 +0000 (09:42 -0400)
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 <tag> {
        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 <tag> {
        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 <tag> {
        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 <tag> {
        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 <tag> {
        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 <tag> {
              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 <tag> {
              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 <tag> {
              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 <eeppeliteloop@gmail.com>
Change-Id: I084b03ea816ff8bee03ef5315c24fa24cfe74d80
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1717
Tested-by: jenkins <jenkins@lttng.org>
54 files changed:
include/babeltrace2/trace-ir/field-class-const.h
include/babeltrace2/trace-ir/field-class.h
include/babeltrace2/trace-ir/field-const.h
include/babeltrace2/trace-ir/field.h
include/babeltrace2/types.h
src/bindings/python/bt2/bt2/field.py
src/bindings/python/bt2/bt2/field_class.py
src/bindings/python/bt2/bt2/native_bt_field_class.i
src/bindings/python/bt2/bt2/trace_class.py
src/common/common.h
src/lib/lib-logging.c
src/lib/trace-ir/field-class.c
src/lib/trace-ir/field-class.h
src/lib/trace-ir/field.c
src/lib/trace-ir/field.h
src/lib/trace-ir/resolve-field-path.c
src/plugins/ctf/common/metadata/ctf-meta-resolve.c
src/plugins/ctf/common/metadata/ctf-meta-translate.c
src/plugins/ctf/common/metadata/ctf-meta.h
src/plugins/ctf/common/metadata/visitor-generate-ir.c
src/plugins/ctf/common/msg-iter/msg-iter.c
src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h
src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c
src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c
src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c
src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c
src/plugins/text/details/write.c
src/plugins/text/pretty/print.c
tests/Makefile.am
tests/bindings/python/bt2/test_event.py
tests/bindings/python/bt2/test_field.py
tests/bindings/python/bt2/test_field_class.py
tests/bindings/python/bt2/test_graph.py
tests/bindings/python/bt2/test_message.py
tests/bindings/python/bt2/test_message_iterator.py
tests/bindings/python/bt2/test_packet.py
tests/data/ctf-traces/succeed/meta-variant-no-underscore/metadata [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-no-underscore/stream [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-one-underscore/metadata [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-one-underscore/stream [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/metadata [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/stream [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/metadata [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/stream [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-two-underscores/metadata [new file with mode: 0644]
tests/data/ctf-traces/succeed/meta-variant-two-underscores/stream [new file with mode: 0644]
tests/data/plugins/sink.ctf.fs/succeed/trace-double.expect
tests/data/plugins/sink.ctf.fs/succeed/trace-float.expect
tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-no-underscore.expect [new file with mode: 0644]
tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-one-underscore.expect [new file with mode: 0644]
tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-reserved-keywords.expect [new file with mode: 0644]
tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-same-with-underscore.expect [new file with mode: 0644]
tests/data/plugins/sink.ctf.fs/succeed/trace-meta-variant-two-underscores.expect [new file with mode: 0644]
tests/plugins/sink.ctf.fs/succeed/test_succeed

index 0f8536b17e2d5533402d4e471bee4a0d44f731b2..844c9e32e8de45c841526c652c476c78dccb28ca 100644 (file)
@@ -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);
index 31c81229bc3dac798638bc04718e3257ec05e712..a8c3feafe4f4a4e4cda2ce5937ca4f9c6c279472 100644 (file)
@@ -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
 }
index 6509dcb8edc09cef0114410b0c6d67ae80d5da99..e9190f472da2105cb9656bfba90a4edb2c952666 100644 (file)
@@ -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
index 27fd1539858e7956a6af508ea345039f13093526..c3b921510161ff1d9dd03f76058194d501a99369 100644 (file)
@@ -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(
index a3992ba05bb6e44091d4b6412bed09589fe43c2a..43357d8fbe846d167f7c9f3325c4457974676883 100644 (file)
@@ -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;
index 0f3e5e7ee32eb11b797f370723f52de5145ca098..a1c2bf32c25fd0a96dfb8fe6973697f9d997bacd 100644 (file)
@@ -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,
 }
index 16d46922b59f89966f427bb398f6c39b3f70929d..0ccea041ebab21fb136066bbdc796721fd38a7d1 100644 (file)
@@ -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,
 }
index e5ed2a89c379f713c7bcf2fc28edbb4ef82e9c4d..674d6938d84373a5db2c0579418c81ab4f4a3741 100644 (file)
        }
 }
 
-/* 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 <babeltrace2/trace-ir/field-class-const.h>
 %include <babeltrace2/trace-ir/field-class.h>
index 9c8258429c55e2066c3ee5aa1a1fe918ee8f5228..d5f63712199dff1dc8e1bc62cbe97a8301b003c7 100644 (file)
@@ -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.
 
index 0fdad32fcd54cad9a1498fa0b2b06a44c51bb9c7..b7245275832466c196ab464a54c3aa7e6ade6f01 100644 (file)
@@ -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)";
        }
index 836ee9ad02ac2d5d8f9318f3a4c8de4ae7d62454..fe72253d7f8eaa9edd42165081454e7e4c078327 100644 (file)
@@ -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;
 
index 30f85dbf4ed8adf8c80e8eef12a1895c6d20ae56..fb2e99ec75b095556f6035ae543755e72cdef229 100644 (file)
@@ -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);
                }
index 447eaab3298cd9f59bf83ea49bd5a08079a18449..476b86dc3b8b3a63fb8f96a7a26a7ef6da612806 100644 (file)
@@ -28,6 +28,7 @@
 #include <babeltrace2/trace-ir/clock-class.h>
 #include <babeltrace2/trace-ir/field-class.h>
 #include "common/macros.h"
+#include "common/common.h"
 #include "lib/object.h"
 #include <babeltrace2/types.h>
 #include <stdint.h>
 #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)
 #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))
 
 
 #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);
 
index 26def356315090b30d4bd6f42ae839db53babb9e..b0a5b5320bea5462578593cff6e4ab6f9973f536 100644 (file)
@@ -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);
 }
 
index f20378fcfc4edc9dc9f4c624fd7d1c0ebdb9b20c..ce595f9726a100c263c38db2aac6dfb161b1a8e9 100644 (file)
                ((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);
 
index 59fc0164f53bdc656b37816de67a9c0eb59e11d6..610e9cc003551b8db6493226692c0e089cf6a358 100644 (file)
@@ -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) {
index 05b67e93e5310f6e121127a2db9d590224f1d193..6666d9eb05cb6b19c22fd89f6e55cf12bf6660c5 100644 (file)
@@ -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) {
                                /*
index af788824754c92fc968db9f34072e4793933f5a2..b8372f245bf12e97964567cd95b20ea54585b215 100644 (file)
@@ -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);
        }
index e62b40ada6b2c07ed990606c65552fe91e2fecc8..45d49d16122e60f87a75104e3e6cf5b855ededad 100644 (file)
@@ -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;
index 5b64ad28c953c90fbd91fdcc32f5fc5e3968ca28..3413ac17cd679b7f162d75eac1b4b941b7f9e244 100644 (file)
@@ -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;
 
index 27d51779251e049a5c90d3f27035d5ff97f9df80..12fc7885c75d0f6abb1ad1aecc41245ea0631388 100644 (file)
@@ -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: "
index 72d47d4aaf53313925039d66b85546f048e9603f..19912afb7b5aa2ad1bbdfb6026c01e0fe787fa0a 100644 (file)
@@ -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 */
index 99739e2fd1f48d0afdc7e7b41106971ea4dd9d34..f867edbf683a78ac1dce84056b4b9eb47a603d30 100644 (file)
@@ -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(
index 1534c96cf2da7caf118ffc7f20f45297da821646..c7be897e657ce06415b9ed34942b51216d27523e 100644 (file)
@@ -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 <tag> {
+ *         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 <tag> {
+ *         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 <tag> {
+ *         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: "
index 60c52e5d78bbb8dcf59f1bc7c913f24f87182190..5acad41810c43f29d033f1a55ae0e45d5a81ce61 100644 (file)
@@ -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) {
index c3f80a941ff64817d601859fdd21c0376941b34a..30c87014febaa8d36b1351790fda7241845eef53 100644 (file)
@@ -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;
index 1606599c28fec3a9c751fadf1de30d01b120df16..a0728b1c6d0ed991136eda037a0fe1abbfccd3d7 100644 (file)
@@ -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);
index cdb15e231387e5e1eb77c07f0b47a5fb7a061521..b83febb4ca4c9575476456f9de21f7cd61d91ae3 100644 (file)
@@ -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);
index e5f36bac31b7202af0a2c11e3a1012a44eb81956..ad8ded962cb1f55aadc5192a15db9fb1b8989092 100644 (file)
@@ -1,3 +1,5 @@
+#5149916
+
 SUBDIRS = utils lib bitfield ctf-writer plugins
 
 # Directories added to EXTRA_DIST will be recursively copied to the distribution.
index eedc9688b306ae7ec799866dc83b28c6a483495d..774150008ff3a1a3f3e1262c150f5a23edc40c7c 100644 (file)
@@ -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,
index db6404455cfc26609384341e35828b1fe031bbb5..f92142bc13518b3f5c8e18fc0ce4c24b8f1fee96 100644 (file)
@@ -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
 
index afdf9b63088ac4156951ef3ef68e877803eeb317..09303363698e2f66b772c1f64bcc3315c066a845 100644 (file)
@@ -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<selector> {
-        #       real a;
-        #       int21_t b;
-        #       uint34_t c;
+        #     variant <selector> {
+        #       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):
index cb447a5a7f7593d592af8ad58c8d3b104a5bd040..da9c209ff68e44b76c7896df01321e127fdb0821 100644 (file)
@@ -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()
index 6e1999de47e501437e34a28ab2cdff7331dcc074..a432ec71db6de421ef5931c9e9015e722cd96ada 100644 (file)
@@ -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)
 
index bd0a52eefc9860d3cbd9fbbf2d335a0006c4b953..84912983cb3db7ed133dd0f8f0762e3fc64e971a 100644 (file)
@@ -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)
 
index 2945f49b56f2e300f7e8ebb51a27198d2ee5d197..0b2a85b94f7541428ceca55b6fd73e2dde6c7b84 100644 (file)
@@ -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 (file)
index 0000000..dd8bcb8
--- /dev/null
@@ -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 <tag> {
+                       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 (file)
index 0000000..f54d73f
Binary files /dev/null and b/tests/data/ctf-traces/succeed/meta-variant-no-underscore/stream differ
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 (file)
index 0000000..0c6206f
--- /dev/null
@@ -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 <tag> {
+                       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 (file)
index 0000000..f54d73f
Binary files /dev/null and b/tests/data/ctf-traces/succeed/meta-variant-one-underscore/stream differ
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 (file)
index 0000000..18af2f9
--- /dev/null
@@ -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 <tag> {
+                       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 (file)
index 0000000..f54d73f
Binary files /dev/null and b/tests/data/ctf-traces/succeed/meta-variant-reserved-keywords/stream differ
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 (file)
index 0000000..be1b0cd
--- /dev/null
@@ -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 <tag> {
+                       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 (file)
index 0000000..f54d73f
Binary files /dev/null and b/tests/data/ctf-traces/succeed/meta-variant-same-with-underscore/stream differ
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 (file)
index 0000000..4eb669d
--- /dev/null
@@ -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 <tag> {
+                       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 (file)
index 0000000..f54d73f
Binary files /dev/null and b/tests/data/ctf-traces/succeed/meta-variant-two-underscores/stream differ
index 57f0dc830923bfb3a4922873175fbaa062d5cff7..0d4b5fb64f56a9825555bcd344e6854077edab73 100644 (file)
@@ -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
index a0780df3b759909b4c0b06795a81e8dcdeb7d69c..23806ccaaa5bb246189877fcbf30cae4e67da702 100644 (file)
@@ -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 (file)
index 0000000..bdca129
--- /dev/null
@@ -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 (file)
index 0000000..8eadeec
--- /dev/null
@@ -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 (file)
index 0000000..cda3466
--- /dev/null
@@ -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 (file)
index 0000000..545d6f9
--- /dev/null
@@ -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 (file)
index 0000000..bd0ebcf
--- /dev/null
@@ -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
index fa5f3751ec9c36e63c977081ead9df98a23aae69..5c2547d6afaf0e35e703e759d992751d6af2df94 100755 (executable)
@@ -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
This page took 0.148073 seconds and 4 git commands to generate.