Make API CTF-agnostic
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 23 Aug 2018 15:43:54 +0000 (11:43 -0400)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Thu, 2 May 2019 20:50:15 +0000 (20:50 +0000)
The main purpose of this patch is to make the Babeltrace 2 API unrelated
to the Common Trace Format. This makes the Babeltrace 2 API easier to
use and data structures are more compact: you don't need to know the
implicit and explicit CTF rules to use the Babeltrace 2 API. It also
prepares the Babeltrace 2 API to be ready, as much as possible, for the
upcoming CTF 2.

General API changes
-------------------
* To make the API simpler, most object properties are optional. This
  includes the names of event classes, stream classes, traces, and
  clock classes, for example.

  Event classes and stream classes still have unique IDs. This makes it
  easier to deterministically identify metadata objects. You can call
  one of:

  bt_event_class_create():
      Create an event class with an automatic ID. I believe most sources
      will use this version.

  bt_event_class_create_with_id():
      Create an event class with an explicit unique ID (within its
      parent stream class).

  You cannot call bt_event_class_create() and
  bt_event_class_create_with_id() to create event classes which belong
  to the same stream class: the stream class has a manual or automatic
  event class ID assignment mode (automatic by default) which you can
  change with bt_stream_class_set_assigns_automatic_event_class_id()
  before adding any event class. The same strategy is used for a stream
  class and a stream (its parents being a trace).

* All API functions return some status code (sometimes a simple `int`
  which can be 0 (success) or negative (error)) IF and only if they can
  fail. Simple property getters never fail, so they return the
  property's value directly. This means that many functions now return
  the `uint64_t` type: the caller does not need to check for an error
  (for example, bt_stream_class_get_id(), because a stream class always
  has an ID).

  Just in case, all property setters can still fail (although most won't
  currently; they always return 0), so they return a status code. This
  could help us add caches and create lazy setters eventually.

  When a function returns a pointer, for example, `const char *` or
  `struct bt_field_type *`, `NULL` does NOT indicate an error: it means
  the property is absent. A function which could fail and which needs to
  return a pointer sets an output parameter instead and returns a status
  code.

  A function can return `enum bt_property_availability` and set (or not)
  an output parameter for non-pointer optional properties. An example is
  bt_event_class_get_log_level(): it is possible that an event class has
  no log level.

  This also means that all `*_UNKNOWN` enumeration labels set to -1 are
  gone.

* The public metadata visitor API is removed as it is not used anywhere.
  We could reintroduce it later, with care, if need be.

* The `babeltrace/ctf-ir/utils.h` file is removed completely. It only
  contained a function to check if a given string is a valid CTF
  identifier.

* Terminology: "nanoseconds from Epoch" becomes "nanoseconds from
  origin". When a clock class is not absolute, it has an offset from a
  given origin, not from the Unix Epoch.

* New `bt_uuid` type alias for `const uint8_t *`.

* All API functions which increment an object's reference count
  ("getting" functions) are removed, as it is preferred and encouraged
  to use borrowing functions. You can still do, for example:

      struct bt_stream_class *sc =
          bt_get(bt_event_class_borrow_stream_class(ec));

* Conditional precondition checking (BT_ASSERT_PRE()) is used at many
  more places now, even in the metadata API, as you could call this API
  on the fast path anyway.

* Various functions are renamed for consistency and terminology
  accuracy.

* Most of the API documentation is removed because it is not accurate
  anymore.

Clock class API changes
-----------------------
* bt_clock_class_create() has no parameters: the name property is
  optional (not set by default), and the default frequency is 1 GHz.

* You set and get both offsets at the same time because you often need
  both of them any: bt_clock_class_set_offset() and
  bt_clock_class_get_offset().

* The name property can have any value: it is not limited to CTF
  identifiers anymore.

* The absolute property is true by default: a default clock class's
  origin is the Unix Epoch.

* The cycle part of the offset MUST be less than the frequency. The
  library validates this in developer mode when calling both
  bt_clock_class_set_offset() and bt_clock_class_set_frequency().

  This makes some time conversion easier to compute and more precise.

Clock value API changes
-----------------------
* A clock value can be known or unknown. As of Babeltrace 2.0, there's
  no function to make a clock value unknown, but the API to get this
  state exists (returned by bt_event_borrow_default_clock_value(), for
  example).

  The bt_stream_class_default_clock_is_always_known() function indicates
  if, for all the streams created from this stream class, their default
  clocks are always known (the default clock value accessors never
  return `BT_CLOCK_VALUE_STATUS_UNKNOWN`). As of this patch, this
  function always returns `BT_TRUE`.

Event class API changes
-----------------------
* Terminology: "context field type" becomes "specific context field
  type" to differentiate this scope from the "common context field type"
  defined at the stream class level.

Event class, stream class, and trace API changes
------------------------------------------------
* You need to pass a trace object to bt_stream_class_create() and a
  stream class object to bt_event_class_create(). In other words, you
  cannot create a "free" stream class, add event classes to it, and then
  add the stream class object to a trace object. This makes validation a
  lot easier and a great quantity of code was sent to the Recycle Bin
  thanks to this contraint.

  bt_trace_add_stream_class() and bt_stream_class_add_event_class() are
  removed because creating an event class or a stream class
  automatically adds it to its parent.

Event header field API changes
------------------------------
* Replace bt_stream_class_create_event_header_field() with
  bt_event_header_field_create(). This is more consistent with this API
  where you typically create an object with its own API an pass whatever
  is needed (e.g., bt_event_class_create() instead of
  bt_stream_class_create_event_class()).

Event API changes
-----------------
* Terminology: "context field type" becomes "specific context field" to
  differentiate this scope from the "common context field".

* New bt_event_set_default_clock_value() and
  bt_event_borrow_default_clock_value() to set and get the event's
  default clock value.

  You MUST set an event's default clock value if its stream class has a
  default clock class (see bt_stream_class_set_default_clock_class()).

  With bt_event_set_default_clock_value(), you don't need to specify the
  clock class as this function uses the stream class's default clock
  class. When multiple clock classes per stream class become supported
  eventually, we'll introduce bt_event_set_clock_value() where you
  specify a clock class for which to set a clock value.

Field type API and concept changes
----------------------------------
* Field types do not have any attached semantics anymore. This includes:

  * Special fields identified by name. Examples are `uuid`, `id`,
    `packet_size`, and `events_discarded`.

    This removes some redundancy between fields and metadata objects,
    for example a packet's header field's `uuid` field always contains
    the same value as the trace object's UUID property (if any). The
    same goes for the stream class ID, the stream ID, the event class
    ID, etc.

  * Mapped clock classes. Mapping an integer field type to a clock class
    makes things complicated because of the CTF clock updating mechanism
    (with automatic wrapping for compression). Instead, packet and event
    objects have a "default clock value" property which the source or
    filter explicitly sets. Therefore, the CTF clock updating mechanism
    is part of the CTF plugin now (in `notif-iter.c`).

* All field type objects, within a given trace object (recursively),
  MUST be unique. The library validates this in developer mode. This
  means you cannot create a single integer field type, for example, and
  add it more than one time to a given structure field type.

  This makes it possible to uniquely identify a field type by its
  address, and it makes validation easier. Also, weird side effects like
  variant or sequence field types being copied during validation are
  gone with this constraint.

  Field type objects are still shared, although most components should
  only need to borrow them.

* The byte order, alignment, and integer/string field type encoding
  properties are removed. They are not needed by the IR API: they are
  CTF concepts.

* bt_field_type_integer_create(), bt_field_type_integer_set_is_signed(),
  and bt_field_type_integer_is_signed() are removed. Now there's an
  unsigned and a signed integer type:
  `BT_FIELD_TYPE_ID_UNSIGNED_INTEGER` and
  `BT_FIELD_TYPE_ID_SIGNED_INTEGER`. This is because integer field type
  and field APIs can be different depending on the signedness (return
  types, for example).

  bt_field_type_unsigned_integer_create() and
  bt_field_type_signed_integer_create() have no parameters: they create
  default integer field types with a 64-bit equivalent value range.

* An enumeration field type is now conceptually an integer field type.

* bt_field_type_enumeration_create() is removed. Now there's an unsigned
  and a signed enumeration type: `BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION`
  and `BT_FIELD_TYPE_ID_SIGNED_ENUMERATION`. This is because enumeration
  field type and field APIs can be different depending on the signedness
  (return types, for example).

  bt_field_type_unsigned_enumeration_create() and
  bt_field_type_signed_enumeration_create() have no parameters: they
  don't need an "underlying" integer field type because they ARE integer
  field types.

* Functions named bt_field_type_integer_*() apply to any integer
  (including enumeration) field type (unsigned or signed).

* Functions named bt_field_type_enumeration_*() apply to any enumeration
  field type (unsigned or signed).

* Terminology: the "size" integer field type property becomes "field
  value range". This property indicates the expected minimum and maximum
  values of fields created from a given integer field type. The
  bt_field_type_integer_set_field_value_range() function accepts a
  parameter which is N in the following formulas:

  * Unsigned integer range: [0, 2^N - 1]
  * Signed integer range: [-2^(N - 1), 2^(N - 1) - 1]

* Terminology: "base" becomes "preferred display base". The default
  preferred display base is 10. It is kept as a property to satisfy the
  CTF 1.8 use case, although it should eventually be part of a custom
  user attribute when we change the API to support CTF 2 features.

* Terminology: "floating point number field type" becomes "real field
  type" (as in _real number_).

* The only property of a real field type is if it's single precision or
  not (double precision). The accessors are
  bt_field_type_real_is_single_precision() and
  bt_field_type_real_set_is_single_precision().

  We don't need explicit exponent and mantissa sizes as those are
  CTF/encoding concepts.

* The concept of an enumeration field type mapping iterator is removed.
  Instead:

  * We change the "mapping" concept: an enumeration field type mapping
    is a label and a set of ranges. Mapping labels are unique within
    an enumeration field type, but the same ranges can exist in
    different mappings (overlaps).

    The functions to get mappings are
    bt_field_type_enumeration_get_mapping_count(),
    bt_field_type_unsigned_enumeration_borrow_mapping_by_index(), and
    bt_field_type_signed_enumeration_borrow_mapping_by_index(),
    depending on the enumeration field type's signedness.

    The functions to add mappings look similar to what they used to:
    bt_field_type_unsigned_enumeration_map_range() and
    bt_field_type_signed_enumeration_map_range(). Those functions find
    any existing mapping sharing the label and add the given range to it
    (or create a new mapping).

    Then it becomes trivial to get all the ranges of a given mapping
    by label: they are already stored as such in the object.

  * To get all the mapping labels which contain a given value within
    their ranges, call
    bt_field_type_unsigned_enumeration_get_mapping_labels_by_value() or
    bt_field_type_signed_enumeration_get_mapping_labels_by_value().

    Those functions accept a
    `bt_field_type_enumeration_mapping_label_array` parameter which is
    `const char * const *`. There's no copy to the user here: the
    functions fill an array internal to the enumeration field type
    object and return its address. Then the array is valid as long as
    you don't call those functions again for the same object.

    This should be enough as what you want is often all the labels,
    not just the first one, and use cases where there are thousands of
    labels matching a given value are nonexistent AFAIK.

* Terminology: "structure field type field" becomes "structure field
  type member".

* Terminology: "variant field type field" becomes "variant field type
  option".

* Structure field type member and variant field type option names can
  have any value (as long as they are unique within their parent): they
  are not limited by CTF identifiers anymore.

* Terminology: "adding a structure field type member" becomes "appending
  a structure field type member". Members are ordered, so "append" makes
  sense here (like Python's list's append() method). The same goes for
  variant field types.

* bt_field_type_array_create() and bt_field_type_sequence_create() are
  remove.

  Conceptually, with this patch, there are static and dynamic array
  field types. Both are array field types, although you cannot create
  an (abstract) array field type.

  Use bt_field_type_static_array_create() and
  bt_field_type_dynamic_array_create() to create static and dynamic
  field types. Both require an element field type, and
  bt_field_type_static_array_create() also requires the static length.

  The common API is bt_field_type_array_borrow_element_field_type().

* Terminology: "variant field type tag" becomes "variant field type
  selector". This is more in line with the concept of a "selected
  field", for example.

* For both the dynamic array and variant field types, the
  length/selector field type is now optional. This is a CTF concept: a
  source can create dynamic array fields without having another field
  which contains its length. You set a dynamic array field's length with
  bt_field_dynamic_array_set_length(). Having another field contain its
  length is just an encoding concept. The same is true for a variant
  field and its selector field.

  You can still link a dynamic array or variant field type to its length
  of selector field type with
  bt_field_type_dynamic_array_set_length_field_type() or
  bt_field_type_variant_set_selector_field_type(). Those functions take
  the linked field type and set the field paths automatically. This is
  possible now because an event class is always within a stream class
  which is always within a trace, so the linked field type should be
  visible (validated in developer mode).

Field API changes
-----------------
* In general, field type API changes are reflected on the field API. For
  example, since an enumeration field type is conceptually an integer
  field type, an enumeration field is conceptually an integer field.
  This means that you can call bt_field_signed_integer_get_value() to
  get the integer value of a signed enumeration field.

* bt_field_array_get_length() is a common array field API which applies
  to both static and dynamic array fields. When you call it with a
  static array field, it returns its field type's static length.

* bt_field_array_borrow_element_field_by_index() is a common array
  field API which applies to both static and dynamic array fields.

* Because a variant field has no link to its selector field now (it is
  optional), you need to set the selected option by index with
  bt_field_variant_select_option_field(). Then you can get the selected
  option with bt_field_variant_borrow_selected_option_field() (and its
  index with bt_field_variant_get_selected_option_field_index()).

Packet context field API changes
--------------------------------
* Replace bt_stream_class_create_packet_context_field() with
  bt_packet_context_field_create(). This is more consistent with this
  API where you typically create an object with its own API an pass
  whatever is needed (e.g., bt_event_class_create() instead of
  bt_stream_class_create_event_class()).

Packet header field API changes
-------------------------------
* Replace bt_trace_create_packet_header_field() with
  bt_packet_header_field_create(). This is more consistent with this API
  where you typically create an object with its own API an pass whatever
  is needed (e.g., bt_event_class_create() instead of
  bt_stream_class_create_event_class()).

Packet API changes
------------------
* A packet does not contain its previous packet's properties anymore.
  Any component which needs to compute the difference between the
  properties of two consecutive packets needs to keep the previous one
  manually.

  Therefore, everything related to the previous packet in the API is
  removed.

* A packet contains _snapshots_ of stream properties:

  * Default clock value at beginning of packet.
  * Default clock value at end of packet.
  * Discarded event counter at end of packet.
  * Packet counter (sequence number) at end of packet.

  You MUST set those snapshot properties if the packet's stream class
  has them enabled: see
  bt_stream_class_packets_have_discarded_event_counter_snapshot(),
  bt_stream_class_packets_have_packet_counter_snapshot(),
  bt_stream_class_packets_have_default_beginning_clock_value(), and
  bt_stream_class_packets_have_default_end_clock_value(). All those
  functions return `BT_FALSE` by default.

Stream class API changes
------------------------
* Terminology: "event context field type" becomes "event common context
  field type".

* Use bt_stream_class_set_default_clock_class() to set a stream class's
  default clock class. When a stream class has a default clock class,
  all the events which belong to a stream created from this stream class
  MUST have default clock values (bt_event_set_default_clock_value()).

* There are new properties which indicate if packets which belong to a
  stream created from a given stream class have specific stream property
  snapshots:
  bt_stream_class_packets_have_discarded_event_counter_snapshot(),
  bt_stream_class_packets_have_packet_counter_snapshot(),
  bt_stream_class_packets_have_default_beginning_clock_value(), and
  bt_stream_class_packets_have_default_end_clock_value(). All those
  functions return `BT_FALSE` by default.

Trace API changes
-----------------
* The native byte order property is removed. Is is not needed by the IR
  API: it is a CTF concept.

* Terminology: "environment field" becomes "environment entry".

Inactivity notification API changes
-----------------------------------
* bt_notification_inactivity_create() accepts a default clock class
  parameter so that you can call
  bt_notification_inactivity_set_default_clock_value() without
  specifying a clock class.

Stream notification API changes
-------------------------------
* bt_notification_stream_begin_set_default_clock_value() and
  bt_notification_stream_end_set_default_clock_value() do not accept a
  clock class parameter anymore: you set the default clock class at the
  stream class level.

Internal API changes
--------------------
* BT_LIB_LOG*(): the `%!u` conversion specifier formats a UUID
  (`bt_uuid`). `%!l` is now used to format a plugin object. `%!r` is
  removed (reference count) in favor of `%!O` which now formats any
  Babeltrace object (`struct bt_object *`).

* All freezing functions are only enabled in developer mode.

* New `include/babeltrace/property-internal.h` file with data structures
  and functions to deal with object properties (used for optional
  properties, like an event class's log level).

* `clock-class-internal.h`: new base offset value (ns) to compute
  nanoseconds from origin in clock values more efficiently.

* `field-types-internal.h`: new BT_ASSERT_PRE_FT_IS_*() macros to deal
  with integer, enumeration, and array field types which now have more
  than one field type ID.

* `fields-internal.h`: new BT_ASSERT_PRE_FIELD_IS_*() macros to deal
  with integer, enumeration, and array field which now have more than
  one field type ID.

* `utils-internal.h`: prefix function names with `bt_util_`.

* `validation-internal.h`: removed because all field types are valid
  since they have no attached semantics. Scoped validations are
  performed in property setters instead (developer mode).

* `visitor-internal.h`: removed because the visitor API is removed.

`ctf` plugin update
-------------------
Because the library's IR now misses important properties for decoding
purposes (alignment, byte order, linked field), the `ctf` plugin has its
own CTF metadata IR in `ctf-meta.h`. This file contains raw data
structures for:

* Field types
* Field path
* Event class
* Stream class
* Trace class

The IR generator AST visitor `visitor-generate-ir.c` converts the AST to
those data structures. All objects are uniquely allocated (no reference
count; they are not Babeltrace objects). Once the visitor has built a
basic CTF IR trace class, a sequence of filters are applied over it to
make it work for decoding purposes:

1. ctf_trace_class_update_default_clock_classes(): Set any stream
   class's default clock class based on integer field types mapped to
   clock classes within it.

2. ctf_trace_class_update_meanings(): Attaches meanings to specific
   integer field types.

   A meaning is a special quality which is needed to properly decode a
   data stream, for example, `CTF_FIELD_TYPE_MEANING_EVENT_CLASS_ID`,
   `CTF_FIELD_TYPE_MEANING_MAGIC`, and
   `CTF_FIELD_TYPE_MEANING_EXP_PACKET_TOTAL_SIZE`.

   For CTF 1.8, field types with meanings are found by name in specific
   scopes.

   When a field type has a meaning, it is not considered as an important
   value for subsequent filters and sinks, so the field type is marked
   as not having its equivalent library IR object. For example, the
   `packet_size` field type does not need to exist for connected filters
   and sinks because it's not holding trace information. If all the
   members of a structure field type, or all the options of a variant
   field type, recursively have no equivalent library IR objects, then
   this structure/variant field type has no equivalent library IR object
   either. Therefore, because the typical CTF packet header field type
   contains only the `magic` (magic number), `uuid` (UUID), `stream_id`
   (stream class ID), and `stream_instance_id` (stream ID) members, they
   all have meanings, thus the corresponding `bt_trace` object has no
   packet header field type.

3. ctf_trace_class_update_text_array_sequence(): Marks array and
   sequence field types containing only 8-bit aligned 8-bit integer
   field types with an encoding as being _text_ array and sequences.
   The equivalent library IR field types will be string field types.

4. ctf_trace_class_resolve_field_types(): Does what `resolve.c` used
   to do, but at the CTF IR level.

5. ctf_trace_class_update_in_ir(): Sets whether or not, depending on
   some conditions (meanings, mapped clock classes, etc.), CTF IR field
   types have equivalent library IR field types.

6. ctf_trace_class_update_value_storing_indexes(): Sets the indexes
   where to store decoded integer values, and from where to read those
   values for sequence lengths and variant tags.

   During decoding, when we need the length of a sequence or the tag of
   a variant, we don't look into existing `bt_field` objects. Instead,
   the length or tag was already stored at a specific index within an
   array of `uint64_t`/`int64_t` values, and we get this value back by
   index.

7. ctf_trace_class_validate(): Validates the whole trace class.

8. ctf_trace_class_translate(): Translates the CTF IR trace class into
   a `bt_trace` and marks translated CTF IR objects.

It is possible to add event classes or stream classes to an existing
trace class, and call all those functions again: they only update what's
not translated yet, and ctf_trace_class_translate() only translates
what's not translated yet.

When decoding (`notif-iter.c`), the bt_btr_start() function reads a CTF
IR field type to decode a data stream. When it calls back
bt_notif_iter_*() functions, they only set `bt_field` objects if they
need to. Of particular interest is the btr_unsigned_int_cb() callback:

This one:

1. Applies the meaning action if its CTF IR field type has a meaning.
   For example, if its meaning is `CTF_FIELD_TYPE_MEANING_DATA_STREAM_ID`,
   it sets the current data stream ID:

       case CTF_FIELD_TYPE_MEANING_DATA_STREAM_ID:
           notit->cur_data_stream_id = value;
           break;

2. If the integer field type has a mapped clock class, it updates the
   stream's default clock value using the CTF clock update mechanism.

3. If the integer field type has a storing index, it stores the decoded
   integer value to a specific location within the stored values:

       g_array_index(notit->stored_values, uint64_t,
           (uint64_t) int_ft->storing_index) = value;

4. If the integer field type has an equivalent library IR field type, it
   sets the appropriate `bt_field` object with the decoded value.

Other plugin updates
--------------------
`src.text.dmesg`, `sink.text.pretty`, and `flt.utils.muxer` are adapted
to the new API.

Test updates
------------
* `tests/lib/test_bt_ctf_field_type_validation.c`: removed because it is
  now a precondition that the metadata be valid now. What's left to
  validate is still done in developer mode.

* `tests/plugins/test-utils-muxer.c`: removed because it will be easier
  to test with the Python bindings once they are updated instead of
  wasting time adapting this one.

* Other tests are adapted to the new API.

Performance update
------------------
This patch makes the performance of Babeltrace 2 go from 40 % to 82 %
the Babeltrace 1's performance with:

    babeltrace /path/to/trace -o dummy

with a 1.4 GiB LTTng kernel trace (four streams) and configured as such:

    BABELTRACE_DEV_MODE=0 BABELTRACE_DEBUG_MODE=0 \
    BABELTRACE_MINIMAL_LOG_LEVEL=INFO CFLAGS='-O3 -DNDEBUG' ./configure

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
114 files changed:
common/common.c
include/Makefile.am
include/babeltrace/babeltrace.h
include/babeltrace/common-internal.h
include/babeltrace/ctf-ir/clock-class-internal.h
include/babeltrace/ctf-ir/clock-class.h
include/babeltrace/ctf-ir/clock-value-internal.h
include/babeltrace/ctf-ir/clock-value-set-internal.h
include/babeltrace/ctf-ir/clock-value.h
include/babeltrace/ctf-ir/event-class-internal.h
include/babeltrace/ctf-ir/event-class.h
include/babeltrace/ctf-ir/event-header-field.h
include/babeltrace/ctf-ir/event-internal.h
include/babeltrace/ctf-ir/event.h
include/babeltrace/ctf-ir/field-path-internal.h
include/babeltrace/ctf-ir/field-path.h
include/babeltrace/ctf-ir/field-types-internal.h
include/babeltrace/ctf-ir/field-types.h
include/babeltrace/ctf-ir/fields-internal.h
include/babeltrace/ctf-ir/fields.h
include/babeltrace/ctf-ir/packet-context-field.h
include/babeltrace/ctf-ir/packet-header-field.h
include/babeltrace/ctf-ir/packet-internal.h
include/babeltrace/ctf-ir/packet.h
include/babeltrace/ctf-ir/resolve-field-path-internal.h [new file with mode: 0644]
include/babeltrace/ctf-ir/stream-class-internal.h
include/babeltrace/ctf-ir/stream-class.h
include/babeltrace/ctf-ir/stream-internal.h
include/babeltrace/ctf-ir/stream.h
include/babeltrace/ctf-ir/trace-internal.h
include/babeltrace/ctf-ir/trace.h
include/babeltrace/ctf-ir/utils-internal.h
include/babeltrace/ctf-ir/utils.h [deleted file]
include/babeltrace/ctf-ir/validation-internal.h [deleted file]
include/babeltrace/ctf-ir/visitor-internal.h [deleted file]
include/babeltrace/ctf-ir/visitor.h [deleted file]
include/babeltrace/ctf-writer/serialize-internal.h
include/babeltrace/ctf-writer/visitor-internal.h
include/babeltrace/endian-internal.h
include/babeltrace/graph/notification-inactivity-internal.h
include/babeltrace/graph/notification-inactivity.h
include/babeltrace/graph/notification-stream-internal.h
include/babeltrace/graph/notification-stream.h
include/babeltrace/lib-logging-internal.h
include/babeltrace/property-internal.h [new file with mode: 0644]
include/babeltrace/property.h [new file with mode: 0644]
include/babeltrace/types.h
lib/ctf-ir/Makefile.am
lib/ctf-ir/clock-class.c
lib/ctf-ir/clock-value.c [new file with mode: 0644]
lib/ctf-ir/event-class.c
lib/ctf-ir/event-header-field.c
lib/ctf-ir/event.c
lib/ctf-ir/field-path.c
lib/ctf-ir/field-types.c
lib/ctf-ir/field-wrapper.c
lib/ctf-ir/fields.c
lib/ctf-ir/packet-context-field.c
lib/ctf-ir/packet-header-field.c
lib/ctf-ir/packet.c
lib/ctf-ir/resolve-field-path.c [new file with mode: 0644]
lib/ctf-ir/resolve.c [deleted file]
lib/ctf-ir/stream-class.c
lib/ctf-ir/stream.c
lib/ctf-ir/trace.c
lib/ctf-ir/utils.c
lib/ctf-ir/validation.c [deleted file]
lib/ctf-ir/visitor.c [deleted file]
lib/ctf-writer/serialize.c
lib/ctf-writer/stream-class.c
lib/ctf-writer/trace.c
lib/ctf-writer/writer.c
lib/graph/notification/event.c
lib/graph/notification/inactivity.c
lib/graph/notification/packet.c
lib/graph/notification/stream.c
lib/lib-logging.c
plugins/Makefile.am
plugins/ctf/common/Makefile.am
plugins/ctf/common/btr/btr.c
plugins/ctf/common/btr/btr.h
plugins/ctf/common/metadata/Makefile.am
plugins/ctf/common/metadata/ast.h
plugins/ctf/common/metadata/ctf-meta-resolve.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-translate.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-update-in-ir.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-update-meanings.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-validate.c [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta-visitors.h [new file with mode: 0644]
plugins/ctf/common/metadata/ctf-meta.h [new file with mode: 0644]
plugins/ctf/common/metadata/decoder.c
plugins/ctf/common/metadata/decoder.h
plugins/ctf/common/metadata/visitor-generate-ir.c
plugins/ctf/common/notif-iter/notif-iter.c
plugins/ctf/common/notif-iter/notif-iter.h
plugins/ctf/common/utils/utils.c
plugins/ctf/common/utils/utils.h
plugins/ctf/fs-src/data-stream-file.c
plugins/ctf/fs-src/data-stream-file.h
plugins/ctf/fs-src/fs.c
plugins/ctf/fs-src/fs.h
plugins/ctf/fs-src/metadata.c
plugins/text/dmesg/dmesg.c
plugins/text/pretty/print.c
plugins/utils/muxer/muxer.c
tests/lib/Makefile.am
tests/lib/test_bt_ctf_field_type_validation.c [deleted file]
tests/lib/test_bt_notification_iterator.c
tests/lib/test_ctf_ir_ref.c
tests/plugins/Makefile.am
tests/plugins/test-utils-muxer.c [deleted file]

index 78ed26ab79205332fedacded6bf1b0421be9b0b2..1c49a465ccfcee27ec228fa2c1862cbe8717fbe2 100644 (file)
@@ -1334,27 +1334,27 @@ static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
        }
 
        /* format (PRI*64) */
-       if (strncmp(fmt_ch, PRId64, sizeof(PRId64)) == 0) {
+       if (strncmp(fmt_ch, PRId64, sizeof(PRId64) - 1) == 0) {
                fmt_ch += sizeof(PRId64);
                BUF_STD_APPEND_SINGLE_ARG(int64_t);
                goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIu64, sizeof(PRIu64)) == 0) {
+       } else if (strncmp(fmt_ch, PRIu64, sizeof(PRIu64) - 1) == 0) {
                fmt_ch += sizeof(PRIu64);
                BUF_STD_APPEND_SINGLE_ARG(uint64_t);
                goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIx64, sizeof(PRIx64)) == 0) {
+       } else if (strncmp(fmt_ch, PRIx64, sizeof(PRIx64) - 1) == 0) {
                fmt_ch += sizeof(PRIx64);
                BUF_STD_APPEND_SINGLE_ARG(uint64_t);
                goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIX64, sizeof(PRIX64)) == 0) {
+       } else if (strncmp(fmt_ch, PRIX64, sizeof(PRIX64) - 1) == 0) {
                fmt_ch += sizeof(PRIX64);
                BUF_STD_APPEND_SINGLE_ARG(uint64_t);
                goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIo64, sizeof(PRIo64)) == 0) {
+       } else if (strncmp(fmt_ch, PRIo64, sizeof(PRIo64) - 1) == 0) {
                fmt_ch += sizeof(PRIo64);
                BUF_STD_APPEND_SINGLE_ARG(uint64_t);
                goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIi64, sizeof(PRIi64)) == 0) {
+       } else if (strncmp(fmt_ch, PRIi64, sizeof(PRIi64) - 1) == 0) {
                fmt_ch += sizeof(PRIi64);
                BUF_STD_APPEND_SINGLE_ARG(int64_t);
                goto update_rw_fmt;
index 004a337cfa3194587ea7259bbda22adb213f3d8a..0bdd90a836867b01a77e4270618b8615de72fc6a 100644 (file)
@@ -116,9 +116,7 @@ babeltracectfirinclude_HEADERS = \
        babeltrace/ctf-ir/packet-header-field.h \
        babeltrace/ctf-ir/stream-class.h \
        babeltrace/ctf-ir/stream.h \
-       babeltrace/ctf-ir/trace.h \
-       babeltrace/ctf-ir/utils.h \
-       babeltrace/ctf-ir/visitor.h
+       babeltrace/ctf-ir/trace.h
 
 # Plugin and plugin development API
 babeltracepluginincludedir = "$(includedir)/babeltrace/plugin"
@@ -207,7 +205,6 @@ noinst_HEADERS = \
        babeltrace/ctf-ir/packet-internal.h \
        babeltrace/ctf-ir/event-class-internal.h \
        babeltrace/ctf-ir/utils-internal.h \
-       babeltrace/ctf-ir/validation-internal.h \
        babeltrace/ctf-ir/fields-internal.h \
        babeltrace/ctf-ir/stream-class-internal.h \
        babeltrace/ctf-ir/event-internal.h \
@@ -217,11 +214,9 @@ noinst_HEADERS = \
        babeltrace/ctf-ir/clock-class-internal.h \
        babeltrace/ctf-ir/field-types-internal.h \
        babeltrace/ctf-ir/clock-value-internal.h \
-       babeltrace/ctf-ir/clock-value-set-internal.h \
        babeltrace/ctf-ir/attributes-internal.h \
        babeltrace/ctf-ir/stream-internal.h \
-       babeltrace/ctf-ir/resolve-internal.h \
-       babeltrace/ctf-ir/visitor-internal.h \
+       babeltrace/ctf-ir/resolve-field-path-internal.h \
        babeltrace/prio-heap-internal.h \
        babeltrace/lib-logging-internal.h \
        babeltrace/compiler-internal.h \
index ec07b88fa87d9443e8ed5fff988483ca14293bda..3f99631db27815e6069140b49069222566507e66 100644 (file)
@@ -65,8 +65,6 @@
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/trace.h>
-#include <babeltrace/ctf-ir/utils.h>
-#include <babeltrace/ctf-ir/visitor.h>
 
 /* Plugin and plugin development API */
 #include <babeltrace/plugin/plugin-dev.h>
index 6428adda4a93d84e979c360e184d4f3b6a8e7a73..e22a9231a8590b6d661a8d3375a10ef0dc22bde3 100644 (file)
@@ -8,6 +8,8 @@
 #include <babeltrace/ctf-ir/field-path.h>
 #include <babeltrace/ctf-ir/event-class.h>
 #include <stdarg.h>
+#include <inttypes.h>
+#include <stdint.h>
 #include <glib.h>
 
 #define BT_COMMON_COLOR_RESET              "\033[0m"
@@ -282,22 +284,24 @@ static inline
 const char *bt_common_field_type_id_string(enum bt_field_type_id type_id)
 {
        switch (type_id) {
-       case BT_FIELD_TYPE_ID_UNKNOWN:
-               return "BT_FIELD_TYPE_ID_UNKNOWN";
-       case BT_FIELD_TYPE_ID_INTEGER:
-               return "BT_FIELD_TYPE_ID_INTEGER";
-       case BT_FIELD_TYPE_ID_FLOAT:
-               return "BT_FIELD_TYPE_ID_FLOAT";
-       case BT_FIELD_TYPE_ID_ENUM:
-               return "BT_FIELD_TYPE_ID_ENUM";
+       case BT_FIELD_TYPE_ID_UNSIGNED_INTEGER:
+               return "BT_FIELD_TYPE_ID_UNSIGNED_INTEGER";
+       case BT_FIELD_TYPE_ID_SIGNED_INTEGER:
+               return "BT_FIELD_TYPE_ID_SIGNED_INTEGER";
+       case BT_FIELD_TYPE_ID_REAL:
+               return "BT_FIELD_TYPE_ID_REAL";
+       case BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION:
+               return "BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION";
+       case BT_FIELD_TYPE_ID_SIGNED_ENUMERATION:
+               return "BT_FIELD_TYPE_ID_SIGNED_ENUMERATION";
        case BT_FIELD_TYPE_ID_STRING:
                return "BT_FIELD_TYPE_ID_STRING";
-       case BT_FIELD_TYPE_ID_STRUCT:
-               return "BT_FIELD_TYPE_ID_STRUCT";
-       case BT_FIELD_TYPE_ID_ARRAY:
-               return "BT_FIELD_TYPE_ID_ARRAY";
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               return "BT_FIELD_TYPE_ID_SEQUENCE";
+       case BT_FIELD_TYPE_ID_STRUCTURE:
+               return "BT_FIELD_TYPE_ID_STRUCTURE";
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
+               return "BT_FIELD_TYPE_ID_STATIC_ARRAY";
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
+               return "BT_FIELD_TYPE_ID_DYNAMIC_ARRAY";
        case BT_FIELD_TYPE_ID_VARIANT:
                return "BT_FIELD_TYPE_ID_VARIANT";
        default:
@@ -306,59 +310,17 @@ const char *bt_common_field_type_id_string(enum bt_field_type_id type_id)
 };
 
 static inline
-const char *bt_common_byte_order_string(enum bt_byte_order bo)
-{
-       switch (bo) {
-       case BT_BYTE_ORDER_UNKNOWN:
-               return "BT_BYTE_ORDER_UNKNOWN";
-       case BT_BYTE_ORDER_UNSPECIFIED:
-               return "BT_BYTE_ORDER_UNSPECIFIED";
-       case BT_BYTE_ORDER_NATIVE:
-               return "BT_BYTE_ORDER_NATIVE";
-       case BT_BYTE_ORDER_LITTLE_ENDIAN:
-               return "BT_BYTE_ORDER_LITTLE_ENDIAN";
-       case BT_BYTE_ORDER_BIG_ENDIAN:
-               return "BT_BYTE_ORDER_BIG_ENDIAN";
-       case BT_BYTE_ORDER_NETWORK:
-               return "BT_BYTE_ORDER_NETWORK";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_common_string_encoding_string(enum bt_string_encoding encoding)
-{
-       switch (encoding) {
-       case BT_STRING_ENCODING_UNKNOWN:
-               return "BT_STRING_ENCODING_UNKNOWN";
-       case BT_STRING_ENCODING_NONE:
-               return "BT_STRING_ENCODING_NONE";
-       case BT_STRING_ENCODING_UTF8:
-               return "BT_STRING_ENCODING_UTF8";
-       case BT_STRING_ENCODING_ASCII:
-               return "BT_STRING_ENCODING_ASCII";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_common_integer_base_string(enum bt_integer_base base)
+const char *bt_common_field_type_integer_preferred_display_base_string(enum bt_field_type_integer_preferred_display_base base)
 {
        switch (base) {
-       case BT_INTEGER_BASE_UNKNOWN:
-               return "BT_INTEGER_BASE_UNKNOWN";
-       case BT_INTEGER_BASE_UNSPECIFIED:
-               return "BT_INTEGER_BASE_UNSPECIFIED";
-       case BT_INTEGER_BASE_BINARY:
-               return "BT_INTEGER_BASE_BINARY";
-       case BT_INTEGER_BASE_OCTAL:
-               return "BT_INTEGER_BASE_OCTAL";
-       case BT_INTEGER_BASE_DECIMAL:
-               return "BT_INTEGER_BASE_DECIMAL";
-       case BT_INTEGER_BASE_HEXADECIMAL:
-               return "BT_INTEGER_BASE_HEXADECIMAL";
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
+               return "BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_BINARY";
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
+               return "BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL";
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
+               return "BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL";
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
+               return "BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL";
        default:
                return "(unknown)";
        }
@@ -368,22 +330,18 @@ static inline
 const char *bt_common_scope_string(enum bt_scope scope)
 {
        switch (scope) {
-       case BT_SCOPE_UNKNOWN:
-               return "BT_SCOPE_UNKNOWN";
-       case BT_SCOPE_TRACE_PACKET_HEADER:
-               return "BT_SCOPE_TRACE_PACKET_HEADER";
-       case BT_SCOPE_STREAM_PACKET_CONTEXT:
-               return "BT_SCOPE_STREAM_PACKET_CONTEXT";
-       case BT_SCOPE_STREAM_EVENT_HEADER:
-               return "BT_SCOPE_STREAM_EVENT_HEADER";
-       case BT_SCOPE_STREAM_EVENT_CONTEXT:
-               return "BT_SCOPE_STREAM_EVENT_CONTEXT";
-       case BT_SCOPE_EVENT_CONTEXT:
-               return "BT_SCOPE_EVENT_CONTEXT";
+       case BT_SCOPE_PACKET_HEADER:
+               return "BT_SCOPE_PACKET_HEADER";
+       case BT_SCOPE_PACKET_CONTEXT:
+               return "BT_SCOPE_PACKET_CONTEXT";
+       case BT_SCOPE_EVENT_HEADER:
+               return "BT_SCOPE_EVENT_HEADER";
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               return "BT_SCOPE_EVENT_COMMON_CONTEXT";
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               return "BT_SCOPE_EVENT_SPECIFIC_CONTEXT";
        case BT_SCOPE_EVENT_PAYLOAD:
                return "BT_SCOPE_EVENT_PAYLOAD";
-       case BT_SCOPE_ENV:
-               return "BT_SCOPE_ENV";
        default:
                return "(unknown)";
        }
@@ -394,10 +352,6 @@ const char *bt_common_event_class_log_level_string(
                enum bt_event_class_log_level level)
 {
        switch (level) {
-       case BT_EVENT_CLASS_LOG_LEVEL_UNKNOWN:
-               return "BT_EVENT_CLASS_LOG_LEVEL_UNKNOWN";
-       case BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED:
-               return "BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED";
        case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
                return "BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY";
        case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
@@ -437,7 +391,7 @@ static inline
 GString *bt_field_path_string(struct bt_field_path *path)
 {
        GString *str = g_string_new(NULL);
-       size_t i;
+       uint64_t i;
 
        BT_ASSERT(path);
 
@@ -449,9 +403,8 @@ GString *bt_field_path_string(struct bt_field_path *path)
                bt_field_path_get_root_scope(path)));
 
        for (i = 0; i < bt_field_path_get_index_count(path); i++) {
-               int index = bt_field_path_get_index(path, i);
-
-               g_string_append_printf(str, ", %d", index);
+               g_string_append_printf(str, ", %" PRIu64,
+                       bt_field_path_get_index_by_index(path, i));
        }
 
        g_string_append(str, "]");
index 9f4f23fe1e1ccc67d009d13bb01ed9e1a8de7a46..aab9cb44809eb6b9dc6d870922f8236f00e2f052 100644 (file)
 #include <babeltrace/object-pool-internal.h>
 #include <babeltrace/compat/uuid-internal.h>
 #include <babeltrace/types.h>
+#include <babeltrace/property-internal.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <glib.h>
 
 struct bt_clock_class {
        struct bt_object base;
-       GString *name;
-       GString *description;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } description;
+
        uint64_t frequency;
        uint64_t precision;
-       int64_t offset_s;       /* Offset in seconds */
-       int64_t offset;         /* Offset in ticks */
-       unsigned char uuid[BABELTRACE_UUID_LEN];
-       int uuid_set;
-       int absolute;
+       int64_t offset_seconds;
+       uint64_t offset_cycles;
+
+       struct {
+               uint8_t uuid[BABELTRACE_UUID_LEN];
+
+               /* NULL or `uuid` above */
+               bt_uuid value;
+       } uuid;
+
+       bool is_absolute;
 
        /*
-        * A clock's properties can't be modified once it is added to a stream
-        * class.
+        * This is computed every time you call
+        * bt_clock_class_set_frequency() or
+        * bt_clock_class_set_offset(), as well as initially. It is the
+        * base offset in nanoseconds including both `offset_seconds`
+        * and `offset_cycles` above in the result. It is used to
+        * accelerate future calls to
+        * bt_clock_value_get_ns_from_origin() and
+        * bt_clock_class_cycles_to_ns_from_origin().
+        *
+        * `overflows` is true if the base offset cannot be computed
+        * because of an overflow.
         */
-       int frozen;
+       struct {
+               int64_t value_ns;
+               bool overflows;
+       } base_offset;
 
        /* Pool of `struct bt_clock_value *` */
        struct bt_object_pool cv_pool;
+
+       bool frozen;
 };
 
 BT_HIDDEN
-void bt_clock_class_freeze(struct bt_clock_class *clock_class);
+void _bt_clock_class_freeze(struct bt_clock_class *clock_class);
 
-BT_HIDDEN
-bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class);
+#ifdef BT_DEV_MODE
+# define bt_clock_class_freeze         _bt_clock_class_freeze
+#else
+# define bt_clock_class_freeze(_cc)
+#endif
 
 BT_HIDDEN
-int bt_clock_class_compare(struct bt_clock_class *clock_class_a,
-               struct bt_clock_class *clock_class_b);
+bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class);
 
 #endif /* BABELTRACE_CTF_IR_CLOCK_CLASS_INTERNAL_H */
index e9af453c950bc0e70e0a8b15eedf8739d0fe70c5..40f53ad3afe06a9306c4064da837aa0ca1615eff 100644 (file)
@@ -5,7 +5,7 @@
  * BabelTrace - CTF IR: Clock class
  *
  * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
  *
  * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
  *
@@ -33,7 +33,7 @@
 
 #include <stdint.h>
 
-/* For bt_bool */
+/* For bt_bool, bt_uuid */
 #include <babeltrace/types.h>
 
 #ifdef __cplusplus
@@ -43,43 +43,50 @@ extern "C" {
 struct bt_clock_class;
 struct bt_clock_value;
 
-extern struct bt_clock_class *bt_clock_class_create(const char *name,
-               uint64_t freq);
-extern const char *bt_clock_class_get_name(
-               struct bt_clock_class *clock_class);
+extern struct bt_clock_class *bt_clock_class_create(void);
+
+extern const char *bt_clock_class_get_name(struct bt_clock_class *clock_class);
+
 extern int bt_clock_class_set_name(struct bt_clock_class *clock_class,
                const char *name);
+
 extern const char *bt_clock_class_get_description(
                struct bt_clock_class *clock_class);
-extern int bt_clock_class_set_description(
-               struct bt_clock_class *clock_class,
-               const char *desc);
+
+extern int bt_clock_class_set_description(struct bt_clock_class *clock_class,
+               const char *description);
+
 extern uint64_t bt_clock_class_get_frequency(
                struct bt_clock_class *clock_class);
-extern int bt_clock_class_set_frequency(
-               struct bt_clock_class *clock_class, uint64_t freq);
+
+extern int bt_clock_class_set_frequency(struct bt_clock_class *clock_class,
+               uint64_t freq);
+
 extern uint64_t bt_clock_class_get_precision(
                struct bt_clock_class *clock_class);
-extern int bt_clock_class_set_precision(
-               struct bt_clock_class *clock_class, uint64_t precision);
-extern int bt_clock_class_get_offset_s(
-               struct bt_clock_class *clock_class, int64_t *seconds);
-extern int bt_clock_class_set_offset_s(
-               struct bt_clock_class *clock_class, int64_t seconds);
-extern int bt_clock_class_get_offset_cycles(
-               struct bt_clock_class *clock_class, int64_t *cycles);
-extern int bt_clock_class_set_offset_cycles(
-               struct bt_clock_class *clock_class, int64_t cycles);
-extern bt_bool bt_clock_class_is_absolute(
-               struct bt_clock_class *clock_class);
-extern int bt_clock_class_set_is_absolute(
-               struct bt_clock_class *clock_class, bt_bool is_absolute);
-extern const unsigned char *bt_clock_class_get_uuid(
-               struct bt_clock_class *clock_class);
+
+extern int bt_clock_class_set_precision(struct bt_clock_class *clock_class,
+               uint64_t precision);
+
+extern void bt_clock_class_get_offset(struct bt_clock_class *clock_class,
+               int64_t *seconds, uint64_t *cycles);
+
+extern int bt_clock_class_set_offset(struct bt_clock_class *clock_class,
+               int64_t seconds, uint64_t cycles);
+
+extern bt_bool bt_clock_class_is_absolute(struct bt_clock_class *clock_class);
+
+extern int bt_clock_class_set_is_absolute(struct bt_clock_class *clock_class,
+               bt_bool is_absolute);
+
+extern bt_uuid bt_clock_class_get_uuid(struct bt_clock_class *clock_class);
+
 extern int bt_clock_class_set_uuid(struct bt_clock_class *clock_class,
-               const unsigned char *uuid);
-extern int bt_clock_class_cycles_to_ns(struct bt_clock_class *clock_class,
-               uint64_t cycles, int64_t *ns);
+               bt_uuid uuid);
+
+extern int bt_clock_class_cycles_to_ns_from_origin(
+               struct bt_clock_class *clock_class,
+               uint64_t cycles, int64_t *ns_from_origin);
 
 #ifdef __cplusplus
 }
index 11b80a36a7d60b2fb494a9afdf5f3df0c304bc98..1beb9fac732b8eb2bebd322c9357ae56af5bcfa2 100644 (file)
@@ -26,6 +26,7 @@
 #include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/ctf-ir/clock-class-internal.h>
+#include <babeltrace/ctf-ir/utils-internal.h>
 #include <stdbool.h>
 #include <stdint.h>
 
@@ -34,11 +35,10 @@ struct bt_clock_class;
 struct bt_clock_value {
        struct bt_object base;
        struct bt_clock_class *clock_class;
-       uint64_t value;
-       bool ns_from_epoch_overflows;
-       int64_t ns_from_epoch;
+       uint64_t value_cycles;
+       bool ns_from_origin_overflows;
+       int64_t ns_from_origin;
        bool is_set;
-       bool frozen;
 };
 
 static inline
@@ -55,180 +55,14 @@ void bt_clock_value_reset(struct bt_clock_value *clock_value)
        clock_value->is_set = false;
 }
 
-BT_UNUSED
 static inline
-void _bt_clock_value_set_is_frozen(struct bt_clock_value *clock_value,
-               bool is_frozen)
+void set_ns_from_origin(struct bt_clock_value *clock_value)
 {
-       BT_ASSERT(clock_value);
-       clock_value->frozen = is_frozen;
-}
-
-static inline
-uint64_t ns_from_value(uint64_t frequency, uint64_t value)
-{
-       uint64_t ns;
-
-       if (frequency == UINT64_C(1000000000)) {
-               ns = value;
-       } else {
-               double dblres = ((1e9 * (double) value) / (double) frequency);
-
-               if (dblres >= (double) UINT64_MAX) {
-                       /* Overflows uint64_t */
-                       ns = -1ULL;
-               } else {
-                       ns = (uint64_t) dblres;
-               }
-       }
-
-       return ns;
-}
-
-static inline
-int ns_from_epoch(struct bt_clock_class *clock_class, uint64_t value,
-               int64_t *ns_from_epoch, bool *overflows)
-{
-       int ret = 0;
-       int64_t diff;
-       int64_t s_ns;
-       uint64_t u_ns;
-       uint64_t cycles;
-
-       *overflows = false;
-
-       /* Initialize nanosecond timestamp to clock's offset in seconds */
-       if (clock_class->offset_s <= (INT64_MIN / INT64_C(1000000000)) ||
-                       clock_class->offset_s >= (INT64_MAX / INT64_C(1000000000))) {
-               /*
-                * Overflow: offset in seconds converted to nanoseconds
-                * is outside the int64_t range.
-                */
-               *overflows = true;
-               goto end;
-       }
-
-       *ns_from_epoch = clock_class->offset_s * INT64_C(1000000000);
-
-       /* Add offset in cycles */
-       if (clock_class->offset < 0) {
-               cycles = (uint64_t) -clock_class->offset;
-       } else {
-               cycles = (uint64_t) clock_class->offset;
-       }
-
-       u_ns = ns_from_value(clock_class->frequency, cycles);
-
-       if (u_ns == UINT64_C(-1) || u_ns >= INT64_MAX) {
-               /*
-                * Overflow: offset in cycles converted to nanoseconds
-                * is outside the int64_t range.
-                */
-               *overflows = true;
-               goto end;
-       }
-
-       s_ns = (int64_t) u_ns;
-       BT_ASSERT(s_ns >= 0);
-
-       if (clock_class->offset < 0) {
-               if (*ns_from_epoch >= 0) {
-                       /*
-                        * Offset in cycles is negative so it must also
-                        * be negative once converted to nanoseconds.
-                        */
-                       s_ns = -s_ns;
-                       goto offset_ok;
-               }
-
-               diff = *ns_from_epoch - INT64_MIN;
-
-               if (s_ns >= diff) {
-                       /*
-                        * Overflow: current timestamp in nanoseconds
-                        * plus the offset in cycles converted to
-                        * nanoseconds is outside the int64_t range.
-                        */
-                       *overflows = true;
-                       goto end;
-               }
-
-               /*
-                * Offset in cycles is negative so it must also be
-                * negative once converted to nanoseconds.
-                */
-               s_ns = -s_ns;
-       } else {
-               if (*ns_from_epoch <= 0) {
-                       goto offset_ok;
-               }
-
-               diff = INT64_MAX - *ns_from_epoch;
-
-               if (s_ns >= diff) {
-                       /*
-                        * Overflow: current timestamp in nanoseconds
-                        * plus the offset in cycles converted to
-                        * nanoseconds is outside the int64_t range.
-                        */
-                       *overflows = true;
-                       goto end;
-               }
-       }
-
-offset_ok:
-       *ns_from_epoch += s_ns;
-
-       /* Add clock value (cycles) */
-       u_ns = ns_from_value(clock_class->frequency, value);
-
-       if (u_ns == -1ULL || u_ns >= INT64_MAX) {
-               /*
-                * Overflow: value converted to nanoseconds is outside
-                * the int64_t range.
-                */
-               *overflows = true;
-               goto end;
-       }
-
-       s_ns = (int64_t) u_ns;
-       BT_ASSERT(s_ns >= 0);
-
-       /* Clock value (cycles) is always positive */
-       if (*ns_from_epoch <= 0) {
-               goto value_ok;
-       }
-
-       diff = INT64_MAX - *ns_from_epoch;
-
-       if (s_ns >= diff) {
-               /*
-                * Overflow: current timestamp in nanoseconds plus the
-                * clock value converted to nanoseconds is outside the
-                * int64_t range.
-                */
-               *overflows = true;
-               goto end;
+       if (bt_util_ns_from_origin(clock_value->clock_class, clock_value->value_cycles,
+                       &clock_value->ns_from_origin)) {
+               clock_value->ns_from_origin_overflows = true;
        }
 
-value_ok:
-       *ns_from_epoch += s_ns;
-
-end:
-       if (*overflows) {
-               *ns_from_epoch = 0;
-               ret = -1;
-       }
-
-       return ret;
-}
-
-static inline
-void set_ns_from_epoch(struct bt_clock_value *clock_value)
-{
-       (void) ns_from_epoch(clock_value->clock_class,
-               clock_value->value, &clock_value->ns_from_epoch,
-               &clock_value->ns_from_epoch_overflows);
 }
 
 static inline
@@ -236,33 +70,23 @@ void bt_clock_value_set_raw_value(struct bt_clock_value *clock_value,
                uint64_t cycles)
 {
        BT_ASSERT(clock_value);
-
-       clock_value->value = cycles;
-       set_ns_from_epoch(clock_value);
+       clock_value->value_cycles = cycles;
+       set_ns_from_origin(clock_value);
        bt_clock_value_set(clock_value);
 }
 
 static inline
-int bt_clock_value_set_value_inline(struct bt_clock_value *clock_value,
+void bt_clock_value_set_value_inline(struct bt_clock_value *clock_value,
                uint64_t raw_value)
 {
-#ifdef BT_ASSERT_PRE_NON_NULL
-       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
-#endif
-
-#ifdef BT_ASSERT_PRE_HOT
-       BT_ASSERT_PRE_HOT(clock_value, "Clock value", ": %!+k", clock_value);
-#endif
-
        bt_clock_value_set_raw_value(clock_value, raw_value);
-       return 0;
 }
 
-#ifdef BT_DEV_MODE
-# define bt_clock_value_set_is_frozen  _bt_clock_value_set_is_frozen
-#else
-# define bt_clock_value_set_is_frozen(_x, _f)
-#endif /* BT_DEV_MODE */
+BT_HIDDEN
+void bt_clock_value_destroy(struct bt_clock_value *clock_value);
+
+BT_HIDDEN
+struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class);
 
 BT_HIDDEN
 struct bt_clock_value *bt_clock_value_create(
index c5a1ce575b85b13e155aab46c1a9c46ea1b8ea89..43205d082d2ac76ef46ba2071ba9960d4af783a4 100644 (file)
@@ -71,7 +71,6 @@ void bt_clock_value_set_reset(struct bt_clock_value_set *cv_set)
 
                BT_ASSERT(cv);
                bt_clock_value_reset(cv);
-               bt_clock_value_set_is_frozen(cv, false);
        }
 
        cv_set->default_cv = NULL;
@@ -100,10 +99,8 @@ void bt_clock_value_set_finalize(struct bt_clock_value_set *cv_set)
 }
 
 static inline
-int bt_clock_value_set_set_clock_value(
-               struct bt_clock_value_set *cv_set,
-               struct bt_clock_class *cc, uint64_t raw_value,
-               bt_bool is_default)
+int bt_clock_value_set_set_clock_value(struct bt_clock_value_set *cv_set,
+               struct bt_clock_class *cc, uint64_t raw_value)
 {
        int ret = 0;
        struct bt_clock_value *clock_value = NULL;
@@ -112,7 +109,12 @@ int bt_clock_value_set_set_clock_value(
        BT_ASSERT(cv_set);
        BT_ASSERT(cc);
 
-       /* Check if we already have a value for this clock class */
+       /*
+        * Check if we already have a value for this clock class.
+        *
+        * TODO: When we have many clock classes, make this more
+        * efficient.
+        */
        for (i = 0; i < cv_set->clock_values->len; i++) {
                struct bt_clock_value *cv = cv_set->clock_values->pdata[i];
 
@@ -139,21 +141,19 @@ int bt_clock_value_set_set_clock_value(
                g_ptr_array_add(cv_set->clock_values, clock_value);
        }
 
-#ifdef BT_ASSERT_PRE_HOT
-       BT_ASSERT_PRE_HOT(clock_value, "Clock value", ": %!+k", clock_value);
-#endif
-
-       ret = bt_clock_value_set_value_inline(clock_value, raw_value);
-       if (ret) {
-               goto end;
-       }
-
-       if (is_default) {
-               cv_set->default_cv = clock_value;
-       }
+       bt_clock_value_set_value_inline(clock_value, raw_value);
 
 end:
        return ret;
 }
 
+static inline
+void  bt_clock_value_set_set_default_clock_value(
+               struct bt_clock_value_set *cv_set, uint64_t raw_value)
+{
+       BT_ASSERT(cv_set);
+       BT_ASSERT(cv_set->default_cv);
+       bt_clock_value_set_value_inline(cv_set->default_cv, raw_value);
+}
+
 #endif /* BABELTRACE_GRAPH_CLOCK_VALUE_SET_H */
index 19b9aec6f3a381ba01b85c6222caa85795641c7f..5f30242793cde1b42879657916d9b8f56be4b455 100644 (file)
@@ -31,9 +31,6 @@
  * http://www.efficios.com/ctf
  */
 
-/* For bt_get() */
-#include <babeltrace/ref.h>
-
 #include <stdint.h>
 
 #ifdef __cplusplus
@@ -43,20 +40,19 @@ extern "C" {
 struct bt_clock_class;
 struct bt_clock_value;
 
-extern struct bt_clock_class *bt_clock_value_borrow_class(
+enum bt_clock_value_status {
+       BT_CLOCK_VALUE_STATUS_KNOWN,
+       BT_CLOCK_VALUE_STATUS_UNKNOWN,
+};
+
+extern struct bt_clock_class *bt_clock_value_borrow_clock_class(
                struct bt_clock_value *clock_value);
 
-static inline
-struct bt_clock_class *bt_clock_value_get_class(
-               struct bt_clock_value *clock_value)
-{
-       return bt_get(bt_clock_value_borrow_class(clock_value));
-}
+extern uint64_t bt_clock_value_get_value(
+               struct bt_clock_value *clock_value);
 
-extern int bt_clock_value_get_value(
-               struct bt_clock_value *clock_value, uint64_t *raw_value);
-extern int bt_clock_value_get_value_ns_from_epoch(
-               struct bt_clock_value *clock_value, int64_t *value_ns);
+extern int bt_clock_value_get_ns_from_origin(
+               struct bt_clock_value *clock_value, int64_t *ns_from_origin);
 
 #ifdef __cplusplus
 }
index ec1a06930a45cd82a0392190ce22e18fe097797b..8fa2ba087c929ee42fbdc4526fd2e48b6b9e7cd1 100644 (file)
 #include <babeltrace/object-internal.h>
 #include <babeltrace/assert-internal.h>
 #include <babeltrace/object-pool-internal.h>
+#include <babeltrace/property-internal.h>
 #include <glib.h>
+#include <stdbool.h>
 
 struct bt_event_class {
        struct bt_object base;
-       struct bt_field_type *context_field_type;
-       struct bt_field_type *payload_field_type;
-       int frozen;
+       struct bt_field_type *specific_context_ft;
+       struct bt_field_type *payload_ft;
 
-       /*
-        * This flag indicates if the event class is valid. A valid
-        * event class is _always_ frozen. However, an event class
-        * may be frozen, but not valid yet. This is okay, as long as
-        * no events are created out of this event class.
-        */
-       int valid;
+       struct {
+               GString *str;
 
-       /* Attributes */
-       GString *name;
-       int64_t id;
-       int log_level;
-       GString *emf_uri;
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       uint64_t id;
+       struct bt_property_uint log_level;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } emf_uri;
 
        /* Pool of `struct bt_event *` */
        struct bt_object_pool event_pool;
+
+       bool frozen;
 };
 
 BT_HIDDEN
-void bt_event_class_freeze(struct bt_event_class *event_class);
+void _bt_event_class_freeze(struct bt_event_class *event_class);
 
-typedef struct bt_field_type *(*bt_field_type_structure_create_func)();
+#ifdef BT_DEV_MODE
+# define bt_event_class_freeze         _bt_event_class_freeze
+#else
+# define bt_event_class_freeze(_ec)
+#endif
 
-BT_HIDDEN
-int bt_event_class_validate_single_clock_class(
-               struct bt_event_class *event_class,
-               struct bt_clock_class **expected_clock_class);
+static inline
+struct bt_stream_class *bt_event_class_borrow_stream_class_inline(
+               struct bt_event_class *event_class)
+{
+       BT_ASSERT(event_class);
+       return (void *) bt_object_borrow_parent(&event_class->base);
+}
 
 #endif /* BABELTRACE_CTF_IR_EVENT_CLASS_INTERNAL_H */
index 12d78015c90be8297fecee8f3f46c4a5f58b492e..8752b406d9dda64368cded8620280d4e676ae39f 100644 (file)
@@ -30,8 +30,8 @@
  * http://www.efficios.com/ctf
  */
 
-/* For bt_get() */
-#include <babeltrace/ref.h>
+/* For enum bt_property_availability */
+#include <babeltrace/property.h>
 
 #include <stdint.h>
 #include <stddef.h>
 extern "C" {
 #endif
 
-struct bt_value;
-
-/**
-@defgroup ctfireventclass CTF IR event class
-@ingroup ctfir
-@brief CTF IR event class.
-
-@code
-#include <babeltrace/ctf-ir/event-class.h>
-@endcode
-
-A CTF IR <strong><em>event class</em></strong> is a template that you
-can use to create concrete \link ctfirevent CTF IR events\endlink.
-
-An event class has the following properties:
-
-- A \b name.
-- A numeric \b ID (\em must be unique amongst all the event classes
-  contained in the same
-  \link ctfirstreamclass CTF IR stream class\endlink).
-- A optional <strong>log level</strong>.
-- An optional <strong>Eclipse Modeling Framework URI</strong>.
-
-A CTF IR event class owns two
-\link ctfirfieldtypes field types\endlink:
-
-- An optional <strong>event context</strong> field type, which
-  represents the \c event.context CTF scope.
-- A mandatory <strong>event payload</strong> field type, which
-  represents the \c event.fields CTF scope.
-
-Both field types \em must be structure field types as of
-Babeltrace \btversion.
-The event payload field type <em>must not</em> be empty.
-
-As a reminder, here's the structure of a CTF packet:
-
-@imgpacketstructure
-
-In the Babeltrace CTF IR system, a \link ctfirtraceclass trace
-class\endlink contains zero or more \link ctfirstreamclass stream
-classes\endlink, and a stream class contains zero or more event classes.
-
-Before you can create an event from an event class with
-bt_event_create(), you \em must add the prepared event class to a
-stream class by calling bt_stream_class_add_event_class(). This
-function, when successful, \em freezes the event class, disallowing any
-future modification of its properties and field types by the user.
-
-As with any Babeltrace object, CTF IR event class objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-bt_stream_class_add_event_class() \em freezes its event class
-parameter on success. You cannot modify a frozen event class: it is
-considered immutable, except for \link refs reference counting\endlink.
-
-@sa ctfirevent
-@sa ctfirstreamclass
-
-@file
-@brief CTF IR event class type and functions.
-@sa ctfireventclass
-
-@addtogroup ctfireventclass
-@{
-*/
-
-/**
-@struct bt_event_class
-@brief A CTF IR event class.
-@sa ctfireventclass
-*/
 struct bt_event_class;
-struct bt_field;
 struct bt_field_type;
 struct bt_stream_class;
 
-/**
-@brief Log level of an event class.
-*/
 enum bt_event_class_log_level {
-       /// Unknown, used for errors.
-       BT_EVENT_CLASS_LOG_LEVEL_UNKNOWN        = -1,
-
-       /// Unspecified log level.
-       BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED    = 255,
-
-       /// System is unusable.
-       BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY      = 0,
-
-       /// Action must be taken immediately.
-       BT_EVENT_CLASS_LOG_LEVEL_ALERT          = 1,
-
-       /// Critical conditions.
-       BT_EVENT_CLASS_LOG_LEVEL_CRITICAL       = 2,
-
-       /// Error conditions.
-       BT_EVENT_CLASS_LOG_LEVEL_ERROR          = 3,
-
-       /// Warning conditions.
-       BT_EVENT_CLASS_LOG_LEVEL_WARNING        = 4,
-
-       /// Normal, but significant, condition.
-       BT_EVENT_CLASS_LOG_LEVEL_NOTICE         = 5,
-
-       /// Informational message.
-       BT_EVENT_CLASS_LOG_LEVEL_INFO           = 6,
-
-       /// Debug information with system-level scope (set of programs).
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM   = 7,
-
-       /// Debug information with program-level scope (set of processes).
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM  = 8,
-
-       /// Debug information with process-level scope (set of modules).
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS  = 9,
-
-       /// Debug information with module (executable/library) scope (set of units).
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE   = 10,
-
-       /// Debug information with compilation unit scope (set of functions).
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT     = 11,
-
-       /// Debug information with function-level scope.
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION = 12,
-
-       /// Debug information with line-level scope (default log level).
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE     = 13,
-
-       /// Debug-level message.
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG          = 14,
+       BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY,
+       BT_EVENT_CLASS_LOG_LEVEL_ALERT,
+       BT_EVENT_CLASS_LOG_LEVEL_CRITICAL,
+       BT_EVENT_CLASS_LOG_LEVEL_ERROR,
+       BT_EVENT_CLASS_LOG_LEVEL_WARNING,
+       BT_EVENT_CLASS_LOG_LEVEL_NOTICE,
+       BT_EVENT_CLASS_LOG_LEVEL_INFO,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG,
 };
 
-/**
-@name Creation and parent access functions
-@{
-*/
-
-/**
-@brief Creates a default CTF IR event class named \p name­.
-
-On success, the context and payload field types are empty structure
-field types. You can modify those default field types after the
-event class is created with
-bt_event_class_set_context_field_type() and
-bt_event_class_set_payload_field_type().
-
-Upon creation, the event class's ID is <em>not set</em>. You
-can set it to a specific value with bt_event_class_set_id(). If it
-is still unset when you call bt_stream_class_add_event_class(), then
-the stream class assigns a unique ID to this event class before
-freezing it.
-
-The created event class's log level is initially set to
-#BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED and it has no Eclipse Modeling
-Framework URI.
+extern struct bt_event_class *bt_event_class_create(
+               struct bt_stream_class *stream_class);
 
-@param[in] name        Name of the event class to create (copied on success).
-@returns       Created event class, or \c NULL on error.
-
-@prenotnull{name}
-@postsuccessrefcountret1
-*/
-extern struct bt_event_class *bt_event_class_create(const char *name);
+extern struct bt_event_class *bt_event_class_create_with_id(
+               struct bt_stream_class *stream_class, uint64_t id);
 
 extern struct bt_stream_class *bt_event_class_borrow_stream_class(
                struct bt_event_class *event_class);
 
-/**
-@brief Returns the parent CTF IR stream class of the CTF IR event
-       class \p event_class.
-
-It is possible that the event class was not added to a stream class
-yet, in which case this function returns \c NULL. You can add an
-event class to a stream class with
-bt_stream_class_add_event_class().
-
-@param[in] event_class Event class of which to get the parent
-                       stream class.
-@returns               Parent stream class of \p event_class,
-                       or \c NULL if \p event_class was not
-                       added to a stream class yet or on error.
-
-@prenotnull{event_class}
-@postrefcountsame{event_class}
-@postsuccessrefcountretinc
-
-@sa bt_stream_class_add_event_class(): Add an event class to
-       a stream class.
-*/
-static inline
-struct bt_stream_class *bt_event_class_get_stream_class(
-               struct bt_event_class *event_class)
-{
-       return bt_get(bt_event_class_borrow_stream_class(event_class));
-}
-
-/** @} */
-
-/**
-@name Attribute functions
-@{
-*/
-
-/**
-@brief Returns the name of the CTF IR event class \p event_class.
+extern const char *bt_event_class_get_name(struct bt_event_class *event_class);
 
-On success, \p event_class remains the sole owner of the returned
-string.
-
-@param[in] event_class Event class of which to get the name.
-@returns               Name of event class \p event_class, or
-                       \c NULL on error.
-
-@prenotnull{event_class}
-@postrefcountsame{event_class}
-*/
-extern const char *bt_event_class_get_name(
-               struct bt_event_class *event_class);
+extern int bt_event_class_set_name(struct bt_event_class *event_class,
+               const char *name);
 
-/**
-@brief Returns the numeric ID of the CTF IR event class \p event_class.
+extern uint64_t bt_event_class_get_id(struct bt_event_class *event_class);
 
-@param[in] event_class Event class of which to get the numeric ID.
-@returns               ID of event class \p event_class, or a
-                       negative value on error.
-
-@prenotnull{event_class}
-@postrefcountsame{event_class}
-
-@sa bt_event_class_set_id(): Sets the numeric ID of a given
-       event class.
-*/
-extern int64_t bt_event_class_get_id(
-               struct bt_event_class *event_class);
-
-/**
-@brief Sets the numeric ID of the CTF IR event class
-       \p event_class to \p id.
-
-\p id must be unique amongst the IDs of all the event classes
-of the stream class to which you eventually add \p event_class.
-
-@param[in] event_class Event class of which to set the numeric ID.
-@param[in] id          ID of the event class.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event_class}
-@prehot{event_class}
-@pre \p id is lesser than or equal to 9223372036854775807 (\c INT64_MAX).
-@postrefcountsame{event_class}
-
-@sa bt_event_class_get_id(): Returns the numeric ID of a given
-       event class.
-*/
-extern int bt_event_class_set_id(
-               struct bt_event_class *event_class, uint64_t id);
-
-/**
-@brief Returns the log level of the CTF IR event class \p event_class.
-
-@param[in] event_class Event class of which to get the log level.
-@returns               Log level of event class \p event_class,
-                       #BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED if
-                       not specified, or
-                       #BT_EVENT_CLASS_LOG_LEVEL_UNKNOWN on error.
-
-@prenotnull{event_class}
-@postrefcountsame{event_class}
-
-@sa bt_event_class_set_log_level(): Sets the log level of a given
-       event class.
-*/
-extern enum bt_event_class_log_level bt_event_class_get_log_level(
-               struct bt_event_class *event_class);
-
-/**
-@brief Sets the log level of the CTF IR event class
-       \p event_class to \p log_level.
-
-@param[in] event_class Event class of which to set the log level.
-@param[in] log_level   Log level of the event class.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event_class}
-@prehot{event_class}
-@pre \p log_level is #BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED,
-       #BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY,
-       #BT_EVENT_CLASS_LOG_LEVEL_ALERT,
-       #BT_EVENT_CLASS_LOG_LEVEL_CRITICAL,
-       #BT_EVENT_CLASS_LOG_LEVEL_ERROR,
-       #BT_EVENT_CLASS_LOG_LEVEL_WARNING,
-       #BT_EVENT_CLASS_LOG_LEVEL_NOTICE,
-       #BT_EVENT_CLASS_LOG_LEVEL_INFO,
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM,
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM,
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS,
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE,
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT,
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION,
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE, or
-       #BT_EVENT_CLASS_LOG_LEVEL_DEBUG.
-@postrefcountsame{event_class}
-
-@sa bt_event_class_get_log_level(): Returns the log level of a given
-       event class.
-*/
-extern int bt_event_class_set_log_level(
+extern enum bt_property_availability bt_event_class_get_log_level(
                struct bt_event_class *event_class,
-               enum bt_event_class_log_level log_level);
-
-/**
-@brief  Returns the Eclipse Modeling Framework URI of the CTF IR event
-       class \p event_class.
+               enum bt_event_class_log_level *log_level);
 
-@param[in] event_class Event class of which to get the
-                       Eclipse Modeling Framework URI.
-@returns               Eclipse Modeling Framework URI of event
-                       class \p event_class, or \c NULL on error.
-
-@prenotnull{event_class}
-@postrefcountsame{event_class}
+extern int bt_event_class_set_log_level(struct bt_event_class *event_class,
+               enum bt_event_class_log_level log_level);
 
-@sa bt_event_class_set_emf_uri(): Sets the Eclipse Modeling
-       Framework URI of a given event class.
-*/
 extern const char *bt_event_class_get_emf_uri(
                struct bt_event_class *event_class);
 
-/**
-@brief Sets the Eclipse Modeling Framework URI of the CTF IR event class
-       \p event_class to \p emf_uri, or unsets the event class's EMF URI.
-
-@param[in] event_class Event class of which to set the
-                       Eclipse Modeling Framework URI.
-@param[in] emf_uri     Eclipse Modeling Framework URI of the
-                       event class (copied on success), or \c NULL
-                       to unset the current EMF URI.
-@returns               0 on success, or a negative value if there's
-                       no EMF URI or on error.
-
-@prenotnull{event_class}
-@prenotnull{emf_uri}
-@prehot{event_class}
-@postrefcountsame{event_class}
-
-@sa bt_event_class_get_emf_uri(): Returns the Eclipse Modeling
-       Framework URI of a given event class.
-*/
-extern int bt_event_class_set_emf_uri(
-               struct bt_event_class *event_class,
+extern int bt_event_class_set_emf_uri(struct bt_event_class *event_class,
                const char *emf_uri);
 
-/** @} */
-
-/**
-@name Contained field types functions
-@{
-*/
-
-extern struct bt_field_type *bt_event_class_borrow_context_field_type(
+extern struct bt_field_type *bt_event_class_borrow_specific_context_field_type(
                struct bt_event_class *event_class);
 
-/**
-@brief Returns the context field type of the CTF IR event class
-       \p event_class.
-
-@param[in] event_class Event class of which to get the context field type.
-@returns               Context field type of \p event_class, or \c NULL if
-                       \p event_class has no context field type or on error.
-
-@prenotnull{event_class}
-@postrefcountsame{event_class}
-@post <strong>On success, if the return value is a field type</strong>, its
-       reference count is incremented.
-
-@sa bt_event_class_set_context_field_type(): Sets the context field type of a
-       given event class.
-*/
-static inline
-struct bt_field_type *bt_event_class_get_context_field_type(
-               struct bt_event_class *event_class)
-{
-       return bt_get(bt_event_class_borrow_context_field_type(event_class));
-}
-
-/**
-@brief Sets the context field type of the CTF IR event class \p event_class to
-       \p context_type, or unsets the current context field type from
-       \p event_class.
-
-If \p context_type is \c NULL, then this function unsets the current context
-field type from \p event_class, effectively making \p event_class an event class
-without a context field type.
-
-As of Babeltrace \btversion, if \p context_type is not \c NULL,
-\p context_type \em must be a CTF IR structure field type object.
-
-@param[in] event_class         Event class of which to set the context field
-                               type.
-@param[in] context_type                Context field type, or \c NULL to unset the
-                               current context field type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{event_class}
-@prehot{event_class}
-@pre <strong>If \p context_type is not \c NULL</strong>, \p context_type is a
-       CTF IR structure field type.
-@postrefcountsame{event_class}
-@post <strong>On success, if \p context_type is not \c NULL</strong>,
-       the reference count of \p context_type is incremented.
-
-@sa bt_event_class_get_context_field_type(): Returns the context field type of a
-       given event class.
-*/
-extern int bt_event_class_set_context_field_type(
+extern int bt_event_class_set_specific_context_field_type(
                struct bt_event_class *event_class,
-               struct bt_field_type *context_type);
+               struct bt_field_type *field_type);
 
 extern struct bt_field_type *bt_event_class_borrow_payload_field_type(
                struct bt_event_class *event_class);
 
-/**
-@brief Returns the payload field type of the CTF IR event class
-       \p event_class.
-
-@param[in] event_class Event class of which to get the payload field type.
-@returns               Payload field type of \p event_class, or \c NULL if
-                       \p event_class has no payload field type or on error.
-
-@prenotnull{event_class}
-@postrefcountsame{event_class}
-@post <strong>On success, if the return value is a field type</strong>, its
-       reference count is incremented.
-
-@sa bt_event_class_set_payload_field_type(): Sets the payload field type of a
-       given event class.
-*/
-static inline
-struct bt_field_type *bt_event_class_get_payload_field_type(
-               struct bt_event_class *event_class)
-{
-       return bt_get(bt_event_class_borrow_payload_field_type(event_class));
-}
-
-/**
-@brief Sets the payload field type of the CTF IR event class \p event_class to
-       \p payload_type, or unsets the current payload field type from
-       \p event_class.
-
-If \p payload_type is \c NULL, then this function unsets the current payload
-field type from \p event_class, effectively making \p event_class an event class
-without a payload field type.
-
-As of Babeltrace \btversion, if \p payload_type is not \c NULL,
-\p payload_type \em must be a CTF IR structure field type object.
-
-@param[in] event_class         Event class of which to set the payload field
-                               type.
-@param[in] payload_type                Payload field type, or \c NULL to unset the
-                               current payload field type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{event_class}
-@prehot{event_class}
-@pre <strong>If \p payload_type is not \c NULL</strong>, \p payload_type is a
-       CTF IR structure field type.
-@postrefcountsame{event_class}
-@post <strong>On success, if \p payload_type is not \c NULL</strong>,
-       the reference count of \p payload_type is incremented.
-
-@sa bt_event_class_get_payload_field_type(): Returns the payload field type of a
-       given event class.
-*/
 extern int bt_event_class_set_payload_field_type(
                struct bt_event_class *event_class,
-               struct bt_field_type *payload_type);
-
-/** @} */
-
-/** @} */
+               struct bt_field_type *field_type);
 
 #ifdef __cplusplus
 }
index 0ff6d583480112aab2c19bfdf770205d55b36cd0..0ac9eeaf4fa9c62be3e04a8ac42a0fa549fa0694 100644 (file)
 extern "C" {
 #endif
 
+struct bt_stream_class;
 struct bt_event_header_field;
 struct bt_field;
 
+extern
+struct bt_event_header_field *bt_event_header_field_create(
+               struct bt_stream_class *stream_class);
+
 extern
 struct bt_field *bt_event_header_field_borrow_field(
                struct bt_event_header_field *field);
index 7925cc4eed9e598dc750f18990d2acd19d228fe3..39efd2f8de166d3dad1b5137eb50d1e40895db39 100644 (file)
  * SOFTWARE.
  */
 
+/* Protection: this file uses BT_LIB_LOG*() macros directly */
+#ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
+# error Please define include <babeltrace/lib-logging-internal.h> before including this file.
+#endif
+
 #include <babeltrace/assert-pre-internal.h>
 #include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/values.h>
+#include <babeltrace/ctf-ir/clock-value-internal.h>
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/stream-internal.h>
 #include <babeltrace/ctf-ir/fields.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/event-class-internal.h>
-#include <babeltrace/ctf-ir/clock-value-set-internal.h>
 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/assert-internal.h>
 #include <glib.h>
 
-struct bt_stream_pos;
+#define BT_ASSERT_PRE_EVENT_HOT(_event) \
+       BT_ASSERT_PRE_HOT((_event), "Event", ": %!+e", (_event))
 
 struct bt_event {
        struct bt_object base;
        struct bt_event_class *class;
+       struct bt_packet *packet;
        struct bt_field_wrapper *header_field;
-       struct bt_field *stream_event_context_field;
-       struct bt_field *context_field;
+       struct bt_field *common_context_field;
+       struct bt_field *specific_context_field;
        struct bt_field *payload_field;
-       struct bt_clock_value_set cv_set;
-       struct bt_packet *packet;
-       int frozen;
+       struct bt_clock_value *default_cv;
+       bool frozen;
 };
 
 BT_HIDDEN
@@ -74,14 +79,6 @@ void _bt_event_set_is_frozen(struct bt_event *event, bool is_frozen);
 # define bt_event_set_is_frozen(_event, _is_frozen)
 #endif
 
-#define BT_ASSERT_PRE_EVENT_HOT(_event, _name)                 \
-       BT_ASSERT_PRE_HOT((_event), (_name), ": %!+e", (_event))
-
-typedef void *(*create_field_func)(void *);
-typedef void (*release_field_func)(void *);
-typedef void *(*create_header_field_func)(void *, void *);
-typedef void (*release_header_field_func)(void *, void *);
-
 BT_UNUSED
 static inline
 void _bt_event_reset_dev_mode(struct bt_event *event)
@@ -89,29 +86,29 @@ void _bt_event_reset_dev_mode(struct bt_event *event)
        BT_ASSERT(event);
 
        if (event->header_field) {
-               bt_field_set_is_frozen_recursive(
+               bt_field_set_is_frozen(
                        event->header_field->field, false);
-               bt_field_reset_recursive(
+               bt_field_reset(
                        event->header_field->field);
        }
 
-       if (event->stream_event_context_field) {
-               bt_field_set_is_frozen_recursive(
-                       event->stream_event_context_field, false);
-               bt_field_reset_recursive(
-                       event->stream_event_context_field);
+       if (event->common_context_field) {
+               bt_field_set_is_frozen(
+                       event->common_context_field, false);
+               bt_field_reset(
+                       event->common_context_field);
        }
 
-       if (event->context_field) {
-               bt_field_set_is_frozen_recursive(
-                       event->context_field, false);
-               bt_field_reset_recursive(event->context_field);
+       if (event->specific_context_field) {
+               bt_field_set_is_frozen(
+                       event->specific_context_field, false);
+               bt_field_reset(event->specific_context_field);
        }
 
        if (event->payload_field) {
-               bt_field_set_is_frozen_recursive(
+               bt_field_set_is_frozen(
                        event->payload_field, false);
-               bt_field_reset_recursive(event->payload_field);
+               bt_field_reset(event->payload_field);
        }
 }
 
@@ -125,8 +122,13 @@ static inline
 void bt_event_reset(struct bt_event *event)
 {
        BT_ASSERT(event);
+       BT_LIB_LOGD("Resetting event: %!+e", event);
        bt_event_set_is_frozen(event, false);
-       bt_clock_value_set_reset(&event->cv_set);
+
+       if (event->default_cv) {
+               bt_clock_value_reset(event->default_cv);
+       }
+
        bt_object_put_no_null_check(&event->packet->base);
        event->packet = NULL;
 }
@@ -174,21 +176,17 @@ void bt_event_set_packet(struct bt_event *event, struct bt_packet *packet)
 {
        BT_ASSERT_PRE_NON_NULL(event, "Event");
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_EVENT_HOT(event, "Event");
+       BT_ASSERT_PRE_EVENT_HOT(event);
        BT_ASSERT_PRE(bt_event_class_borrow_stream_class(
-               event->class) == packet->stream->stream_class,
+               event->class) == packet->stream->class,
                "Packet's stream class and event's stream class differ: "
-               "%![event-]+e, %![packet-]+a",
-               event, packet);
+               "%![event-]+e, %![packet-]+a", event, packet);
 
        BT_ASSERT(!event->packet);
        event->packet = packet;
        bt_object_get_no_null_check_no_parent_check(&event->packet->base);
-       BT_LOGV("Set event's packet: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "packet-addr=%p",
-               event, bt_event_class_get_name(event->class),
-               bt_event_class_get_id(event->class), packet);
+       BT_LIB_LOGV("Set event's packet: %![event-]+e, %![packet-]+a",
+               event, packet);
 }
 
 static inline
@@ -201,11 +199,11 @@ struct bt_event *bt_event_create(struct bt_event_class *event_class,
        event = bt_object_pool_create_object(&event_class->event_pool);
        if (unlikely(!event)) {
                BT_LIB_LOGE("Cannot allocate one event from event class's event pool: "
-                       "%![event-class-]+E", event_class);
+                       "%![ec-]+E", event_class);
                goto end;
        }
 
-       if (unlikely(!event->class)) {
+       if (likely(!event->class)) {
                event->class = event_class;
                bt_object_get_no_null_check(&event_class->base);
        }
index 44112125d69ca09802c9cc260da6943d778eff96..67df08b5e53c390f67592c9ba34e87727500ecd6 100644 (file)
  * http://www.efficios.com/ctf
  */
 
-/* For bt_get() */
-#include <babeltrace/ref.h>
-
-/* For bt_bool */
-#include <babeltrace/types.h>
-
 #include <stdint.h>
 #include <stddef.h>
 
+/* For enum bt_clock_value_status */
+#include <babeltrace/ctf-ir/clock-value.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-struct bt_value;
-struct bt_clock_class;
-
-/**
-@defgroup ctfirevent CTF IR event
-@ingroup ctfir
-@brief CTF IR event.
-
-@code
-#include <babeltrace/ctf-ir/event.h>
-@endcode
-
-A CTF IR <strong><em>event</em></strong> is a container of event
-fields:
-
-- <strong>Stream event header</strong> field, described by the
-  <em>stream event header field type</em> of a
-  \link ctfirstreamclass CTF IR stream class\endlink.
-- <strong>Stream event context</strong> field, described by the
-  <em>stream event context field type</em> of a stream class.
-- <strong>Event context</strong> field, described by the
-  <em>event context field type</em> of a
-  \link ctfireventclass CTF IR event class\endlink.
-- <strong>Event payload</strong>, described by the
-  <em>event payload field type</em> of an event class.
-
-As a reminder, here's the structure of a CTF packet:
-
-@imgpacketstructure
-
-You can create a CTF IR event \em from a
-\link ctfireventclass CTF IR event class\endlink with
-bt_event_create(). The event class you use to create an event
-object becomes its parent.
-
-If the \link ctfirtraceclass CTF IR trace class\endlink of an event
-object (parent of its \link ctfirstreamclass CTF IR stream class\endlink,
-which is the parent of its event class) was created by a
-\link ctfwriter CTF writer\endlink object, then the only possible
-action you can do with this event object is to append it to a
-\link ctfirstream CTF IR stream\endlink with
-bt_stream_append_event(). Otherwise, you can create an event
-notification with bt_notification_event_create(). The event you pass
-to this function \em must have an attached packet object first.
-
-You can attach a \link ctfirpacket CTF IR packet object\endlink to an
-event object with bt_event_set_packet().
-
-A CTF IR event has a mapping of
-\link ctfirclockvalue CTF IR clock values\endlink. A clock value is
-an instance of a specific
-\link ctfirclockclass CTF IR clock class\endlink when the event is
-emitted. You can set an event object's clock value with
-bt_event_set_clock_value().
-
-As with any Babeltrace object, CTF IR event objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-bt_notification_event_create() \em freezes its event parameter on
-success. You cannot modify a frozen event object: it is considered
-immutable, except for \link refs reference counting\endlink.
-
-@sa ctfireventclass
-@sa ctfirpacket
-
-@file
-@brief CTF IR event type and functions.
-@sa ctfirevent
-
-@addtogroup ctfirevent
-@{
-*/
-
-/**
-@struct bt_event
-@brief A CTF IR event.
-@sa ctfirevent
-*/
 struct bt_event;
 struct bt_event_header_field;
-struct bt_clock;
 struct bt_clock_value;
 struct bt_event_class;
 struct bt_field;
-struct bt_field_type;
-struct bt_stream_class;
 struct bt_packet;
 
-/**
-@name Creation and parent access functions
-@{
-*/
-
-/**
-@brief  Creates a default CTF IR event from the CTF IR event class
-       \p event_class.
-
-\p event_class \em must have a parent
-\link ctfirstreamclass CTF IR stream class\endlink.
-
-On success, the four fields of the created event object are not set. You
-can set them with bt_event_set_header(),
-bt_event_set_stream_event_context(),
-bt_event_set_context(), and bt_event_set_payload().
-
-This function tries to resolve the needed
-\link ctfirfieldtypes CTF IR field type\endlink of the dynamic field
-types that are found anywhere in the context or payload field
-types of \p event_class and in the root field types of the
-parent stream class of \p event_class. If any automatic resolving fails,
-this function fails. This means that, if any dynamic field type need
-a field type which should be found in the trace packet header root
-field type, and if the parent stream class of \p event_class was not
-added to a \link ctfirtraceclass CTF IR trace class\endlink yet
-with bt_trace_add_stream_class(), then this function fails.
-
-@param[in] event_class CTF IR event class to use to create the
-                       CTF IR event.
-@returns               Created event object, or \c NULL on error.
-
-@prenotnull{event_class}
-@pre \p event_class has a parent stream class.
-@postsuccessrefcountret1
-*/
 extern struct bt_event_class *bt_event_borrow_class(struct bt_event *event);
 
-/**
-@brief Returns the parent CTF IR event class of the CTF IR event
-       \p event.
-
-This function returns a reference to the event class which was used to
-create the event object in the first place with bt_event_create().
-
-@param[in] event       Event of which to get the parent event class.
-@returns               Parent event class of \p event,
-                       or \c NULL on error.
-
-@prenotnull{event}
-@postrefcountsame{event}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_event_class *bt_event_get_class(struct bt_event *event)
-{
-       return bt_get(bt_event_borrow_class(event));
-}
-
 extern struct bt_packet *bt_event_borrow_packet(struct bt_event *event);
 
-/**
-@brief Returns the CTF IR packet associated to the CTF IR event
-       \p event.
-
-This function returns a reference to the event class which was set to
-\p event in the first place with bt_event_set_packet().
-
-@param[in] event       Event of which to get the associated packet.
-@returns               Packet associated to \p event,
-                       or \c NULL if no packet is associated to
-                       \p event or on error.
-
-@prenotnull{event}
-@postrefcountsame{event}
-@postsuccessrefcountretinc
-
-@sa bt_event_set_packet(): Associates a given event to a given
-       packet.
-*/
-static inline
-struct bt_packet *bt_event_get_packet(struct bt_event *event)
-{
-       return bt_get(bt_event_borrow_packet(event));
-}
-
 extern struct bt_stream *bt_event_borrow_stream(struct bt_event *event);
 
-/**
-@brief Returns the parent CTF IR stream associated to the CTF IR event
-       \p event.
-
-@param[in] event       Event of which to get the parent stream.
-@returns               Parent stream of \p event, or \c NULL on error.
-
-@prenotnull{event}
-@postrefcountsame{event}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_stream *bt_event_get_stream(struct bt_event *event)
-{
-       return bt_get(bt_event_borrow_stream(event));
-}
-
-/** @} */
-
-/**
-@name Contained fields functions
-@{
-*/
-
-extern struct bt_field *bt_event_borrow_header(struct bt_event *event);
+extern struct bt_field *bt_event_borrow_header_field(struct bt_event *event);
 
 extern int bt_event_move_header(struct bt_event *event,
                struct bt_event_header_field *header);
 
-extern struct bt_field *bt_event_borrow_stream_event_context(
+extern struct bt_field *bt_event_borrow_common_context_field(
                struct bt_event *event);
 
-extern struct bt_field *bt_event_borrow_context(struct bt_event *event);
-
-extern struct bt_field *bt_event_borrow_payload(struct bt_event *event);
-
-/** @} */
-
-/**
-@name Clock value functions
-@{
-*/
-
-extern int bt_event_set_clock_value(struct bt_event *event,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default);
-
-extern struct bt_clock_value *bt_event_borrow_default_clock_value(
+extern struct bt_field *bt_event_borrow_specific_context_field(
                struct bt_event *event);
 
-/** @} */
+extern struct bt_field *bt_event_borrow_payload_field(struct bt_event *event);
+
+extern int bt_event_set_default_clock_value(struct bt_event *event,
+               uint64_t value_cycles);
 
-/** @} */
+extern enum bt_clock_value_status bt_event_borrow_default_clock_value(
+               struct bt_event *event, struct bt_clock_value **clock_value);
 
 #ifdef __cplusplus
 }
index 907be9b2dcfe17b43f88df4ca43a324e3f8a6957..f8cb13674a70faea105ce198df4521a338617c1f 100644 (file)
@@ -28,8 +28,8 @@
  * http://www.efficios.com/ctf
  */
 
-#include <babeltrace/common-internal.h>
 #include <babeltrace/object-internal.h>
+#include <babeltrace/ctf-ir/field-path.h>
 #include <babeltrace/assert-internal.h>
 #include <glib.h>
 
@@ -37,23 +37,20 @@ struct bt_field_path {
        struct bt_object base;
        enum bt_scope root;
 
-       /*
-        * Array of integers (int) indicating the index in either
-        * structures, variants, arrays, or sequences that make up
-        * the path to a field type. -1 means the "current element
-        * of an array or sequence type".
-        */
+       /* Array of `uint64_t` (indexes) */
        GArray *indexes;
 };
 
 BT_HIDDEN
 struct bt_field_path *bt_field_path_create(void);
 
-BT_HIDDEN
-void bt_field_path_clear(struct bt_field_path *field_path);
-
-BT_HIDDEN
-struct bt_field_path *bt_field_path_copy(
-               struct bt_field_path *path);
+static inline
+uint64_t bt_field_path_get_index_by_index_inline(
+               struct bt_field_path *field_path, uint64_t index)
+{
+       BT_ASSERT(field_path);
+       BT_ASSERT(index < field_path->indexes->len);
+       return g_array_index(field_path->indexes, uint64_t, index);
+}
 
 #endif /* BABELTRACE_CTF_IR_FIELD_PATH_INTERNAL */
index d5e5e43dc9e12e9ced15fd5472282b9b63142637..7c435abcda81e22405a94a4fd3255d564dab33da 100644 (file)
@@ -4,7 +4,7 @@
 /*
  * BabelTrace - CTF IR: Field path
  *
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
 extern "C" {
 #endif
 
-struct bt_field_type;
-
-/**
-@defgroup ctfirfieldpath CTF IR field path
-@ingroup ctfir
-@brief CTF IR field path.
-
-@code
-#include <babeltrace/ctf-ir/field-path.h>
-@endcode
-
-A CTF IR <strong><em>field path</em></strong> represents an absolute
-path to a field in the hierarchy of a
-\link ctfirtraceclass CTF IR trace class\endlink, of a
-\link ctfirstreamclass CTF IR stream class\endlink, or of a
-\link ctfireventclass CTF IR event class\endlink.
-
-As a reminder, here's the structure of a CTF packet:
-
-@imgpacketstructure
-
-Sequence and variant \link ctfirfieldtypes CTF IR field types\endlink
-can return a field path to resp. their length field and tag field
-with resp. bt_field_type_sequence_get_length_field_path() and
-bt_field_type_variant_get_tag_field_path().
-
-A field path has a <em>root scope</em> which indicates from which of the
-six CTF scopes to begin. It also has a list of structure field <em>path
-indexes</em> which indicate the path to take to reach the destination
-field. A path index set to -1 means that you need to continue the lookup
-within the current element of an array or sequence field.
-
-As with any Babeltrace object, CTF IR field path objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-@file
-@brief CTF IR field path type and functions.
-@sa ctfirfieldpath
-
-@addtogroup ctfirfieldpath
-@{
-*/
-
-/**
-@struct bt_field_path
-@brief A CTF IR field path.
-@sa ctfirfieldpath
-*/
 struct bt_field_path;
 
-/**
-@brief Returns the root scope of the CTF IR field path \p field_path.
+enum bt_scope {
+       BT_SCOPE_PACKET_HEADER,
+       BT_SCOPE_PACKET_CONTEXT,
+       BT_SCOPE_EVENT_HEADER,
+       BT_SCOPE_EVENT_COMMON_CONTEXT,
+       BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
+       BT_SCOPE_EVENT_PAYLOAD,
+};
 
-@param[in] field_path  Field path of which to get the root scope.
-@returns               Root scope of \p field_path, or
-                       #BT_SCOPE_UNKNOWN on error.
-
-@prenotnull{field_path}
-@postrefcountsame{field_path}
-*/
 extern enum bt_scope bt_field_path_get_root_scope(
-               const struct bt_field_path *field_path);
-
-/**
-@brief Returns the number of path indexes contained in the CTF IR field
-       path \p field_path.
-
-@param[in] field_path  Field path of which to get the number of
-                       path indexes.
-@returns               Number of path indexes contained in
-                       \p field_path, or a negative value on error.
-
-@prenotnull{field_path}
-@postrefcountsame{field_path}
-*/
-extern int64_t bt_field_path_get_index_count(
-               const struct bt_field_path *field_path);
-
-/**
-@brief Returns the path index contained in the CTF IR field
-       path \p field_path at index \p index.
-
-@param[in] field_path  Field path of which to get the path index
-                       at index \p index.
-@param[in] index       Index of path index to get.
-@returns               Path index of \p field_path at index \p index,
-                       or \c INT_MIN on error.
+               struct bt_field_path *field_path);
 
-@prenotnull{field_path}
-@pre \p index is lesser than the number of path indexes contained in the
-       field path \p field_path (see
-       bt_field_path_get_index_count()).
-@postrefcountsame{field_path}
-*/
-extern int bt_field_path_get_index(
-               const struct bt_field_path *field_path, uint64_t index);
+extern uint64_t bt_field_path_get_index_count(
+               struct bt_field_path *field_path);
 
-/** @} */
+extern uint64_t bt_field_path_get_index_by_index(
+               struct bt_field_path *field_path, uint64_t index);
 
 #ifdef __cplusplus
 }
index 2acb5bbbe41193b6706579130d16cc5211bdd3f9..fcefa0637c9ce019f9a88efe6c31756c410c13a2 100644 (file)
 #include <stdint.h>
 #include <glib.h>
 
-#define BT_ASSERT_PRE_FT_HAS_ID(_ft, _type_id, _name)          \
-       BT_ASSERT_PRE(((struct bt_field_type *) (_ft))->id == (_type_id), \
-               _name " has the wrong type ID: expected-type-id=%s, "   \
-               "%![ft-]+F", bt_common_field_type_id_string(_type_id), (_ft))
+#define BT_ASSERT_PRE_FT_IS_INT(_ft, _name)                            \
+       BT_ASSERT_PRE(                                                  \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_UNSIGNED_INTEGER || \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_SIGNED_INTEGER || \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION || \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_SIGNED_ENUMERATION, \
+               _name " is not an integer field type: %![ft-]+F", (_ft))
+
+#define BT_ASSERT_PRE_FT_IS_UNSIGNED_INT(_ft, _name)                   \
+       BT_ASSERT_PRE(                                                  \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_UNSIGNED_INTEGER || \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION, \
+               _name " is not an unsigned integer field type: %![ft-]+F", (_ft))
+
+#define BT_ASSERT_PRE_FT_IS_ENUM(_ft, _name)                           \
+       BT_ASSERT_PRE(                                                  \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION || \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_SIGNED_ENUMERATION, \
+               _name " is not an enumeration field type: %![ft-]+F", (_ft))
+
+#define BT_ASSERT_PRE_FT_IS_ARRAY(_ft, _name)                          \
+       BT_ASSERT_PRE(                                                  \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_STATIC_ARRAY || \
+               ((struct bt_field_type *) (_ft))->id == BT_FIELD_TYPE_ID_DYNAMIC_ARRAY, \
+               _name " is not an array field type: %![ft-]+F", (_ft))
+
+#define BT_ASSERT_PRE_FT_HAS_ID(_ft, _id, _name)                       \
+       BT_ASSERT_PRE(((struct bt_field_type *) (_ft))->id == (_id),    \
+               _name " has the wrong ID: expected-id=%s, "             \
+               "%![ft-]+F", bt_common_field_type_id_string(_id), (_ft))
 
 #define BT_ASSERT_PRE_FT_HOT(_ft, _name)                               \
-       BT_ASSERT_PRE_HOT((_ft), (_name), ": %!+F", (_ft))
+       BT_ASSERT_PRE_HOT((struct bt_field_type *) (_ft),               \
+               (_name), ": %!+F", (_ft))
 
-#define BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(_ft, _index)    \
-       (&g_array_index(((struct bt_field_type_structure *) (_ft))->fields, \
-               struct bt_field_type_structure_field, (_index)))
+#define BT_FIELD_TYPE_NAMED_FT_AT_INDEX(_ft, _index)           \
+       (&g_array_index(((struct bt_field_type_named_field_types_container *) (_ft))->named_fts, \
+               struct bt_named_field_type, (_index)))
 
-#define BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(_ft, _index)     \
-       (&g_array_index(((struct bt_field_type_variant *) (_ft))->choices, \
-               struct bt_field_type_variant_choice, (_index)))
+#define BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(_ft, _index)               \
+       (&g_array_index(((struct bt_field_type_enumeration *) (_ft))->mappings, \
+               struct bt_field_type_enumeration_mapping, (_index)))
+
+#define BT_FIELD_TYPE_ENUM_MAPPING_RANGE_AT_INDEX(_mapping, _index)    \
+       (&g_array_index((_mapping)->ranges,                             \
+               struct bt_field_type_enumeration_mapping_range, (_index)))
 
 struct bt_field;
 struct bt_field_type;
 
-typedef void (*bt_field_type_method_freeze)(
-               struct bt_field_type *);
-typedef int (*bt_field_type_method_validate)(
-               struct bt_field_type *);
-typedef void (*bt_field_type_method_set_byte_order)(
-               struct bt_field_type *, enum bt_byte_order);
-typedef struct bt_field_type *(*bt_field_type_method_copy)(
-               struct bt_field_type *);
-typedef int (*bt_field_type_method_compare)(
-               struct bt_field_type *,
-               struct bt_field_type *);
-
-struct bt_field_type_methods {
-       bt_field_type_method_freeze freeze;
-       bt_field_type_method_validate validate;
-       bt_field_type_method_set_byte_order set_byte_order;
-       bt_field_type_method_copy copy;
-       bt_field_type_method_compare compare;
-};
-
 struct bt_field_type {
        struct bt_object base;
        enum bt_field_type_id id;
-       unsigned int alignment;
-
-       /* Virtual table */
-       struct bt_field_type_methods *methods;
-
-       /*
-        * A type can't be modified once it is added to an event or after a
-        * a field has been instanciated from it.
-        */
-       int frozen;
+       bool frozen;
 
        /*
-        * This flag indicates if the field type is valid. A valid
-        * field type is _always_ frozen. All the nested field types of
-        * a valid field type are also valid (and thus frozen).
+        * Only used in developer mode, this flag indicates whether or
+        * not this field type is part of a trace.
         */
-       int valid;
+       bool part_of_trace;
 };
 
 struct bt_field_type_integer {
        struct bt_field_type common;
 
-       /* Owned by this */
-       struct bt_clock_class *mapped_clock_class;
+       /*
+        * Value range of fields built from this integer field type:
+        * this is an equivalent integer size in bits. More formally,
+        * `range` is `n` in:
+        *
+        * Unsigned range: [0, 2^n - 1]
+        * Signed range: [-2^(n - 1), 2^(n - 1) - 1]
+        */
+       uint64_t range;
 
-       enum bt_byte_order user_byte_order;
-       bt_bool is_signed;
-       unsigned int size;
-       enum bt_integer_base base;
-       enum bt_string_encoding encoding;
+       enum bt_field_type_integer_preferred_display_base base;
 };
 
-struct enumeration_mapping {
+struct bt_field_type_enumeration_mapping_range {
        union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_start;
+               uint64_t u;
+               int64_t i;
+       } lower;
+
        union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_end;
-       GQuark string;
+               uint64_t u;
+               int64_t i;
+       } upper;
 };
 
-struct bt_field_type_enumeration {
-       struct bt_field_type common;
-
-       /* Owned by this */
-       struct bt_field_type_integer *container_ft;
+struct bt_field_type_enumeration_mapping {
+       GString *label;
 
-       /* Array of `struct enumeration_mapping *`, owned by this */
-       GPtrArray *entries;
-
-       /* Only set during validation */
-       bt_bool has_overlapping_ranges;
+       /* Array of `struct bt_field_type_enumeration_mapping_range` */
+       GArray *ranges;
 };
 
-enum bt_field_type_enumeration_mapping_iterator_type {
-       ITERATOR_BY_NAME,
-       ITERATOR_BY_SIGNED_VALUE,
-       ITERATOR_BY_UNSIGNED_VALUE,
-};
+struct bt_field_type_enumeration {
+       struct bt_field_type_integer common;
 
-struct bt_field_type_enumeration_mapping_iterator {
-       struct bt_object base;
+       /* Array of `struct bt_field_type_enumeration_mapping *` */
+       GArray *mappings;
 
-       /* Owned by this */
-       struct bt_field_type_enumeration *enumeration_ft;
+       /*
+        * This is an array of `const char *` which acts as a temporary
+        * (potentially growing) buffer for
+        * bt_field_type_unsigned_enumeration_get_mapping_labels_by_value()
+        * and
+        * bt_field_type_signed_enumeration_get_mapping_labels_by_value().
+        *
+        * The actual strings are owned by the mappings above.
+        */
+       GPtrArray *label_buf;
+};
 
-       enum bt_field_type_enumeration_mapping_iterator_type type;
-       int index;
-       union {
-               GQuark name_quark;
-               int64_t signed_value;
-               uint64_t unsigned_value;
-       } u;
+struct bt_field_type_real {
+       struct bt_field_type common;
+       bool is_single_precision;
 };
 
-struct bt_field_type_floating_point {
+struct bt_field_type_string {
        struct bt_field_type common;
-       enum bt_byte_order user_byte_order;
-       unsigned int exp_dig;
-       unsigned int mant_dig;
 };
 
-struct bt_field_type_structure_field {
-       GQuark name;
+/* A named field type is a (name, field type) pair */
+struct bt_named_field_type {
+       GString *name;
 
        /* Owned by this */
-       struct bt_field_type *type;
+       struct bt_field_type *ft;
 };
 
-struct bt_field_type_structure {
+/*
+ * This is the base field type for a container of named field types.
+ * Structure and variant field types inherit this.
+ */
+struct bt_field_type_named_field_types_container {
        struct bt_field_type common;
-       GHashTable *field_name_to_index;
 
        /*
-        * Array of `struct bt_field_type_structure_field`,
-        * owned by this
+        * Key: `const char *`, not owned by this (owned by named field
+        * type objects contained in `named_fts` below).
         */
-       GArray *fields;
-};
+       GHashTable *name_to_index;
 
-struct bt_field_type_variant_choice_range {
-       union {
-               int64_t i;
-               uint64_t u;
-       } lower;
-       union {
-               int64_t i;
-               uint64_t u;
-       } upper;
+       /* Array of `struct bt_named_field_type` */
+       GArray *named_fts;
 };
 
-struct bt_field_type_variant_choice {
-       GQuark name;
-
-       /* Owned by this */
-       struct bt_field_type *type;
-
-       /* Array of `struct bt_field_type_variant_choice_range` */
-       GArray *ranges;
-};
-
-struct bt_field_type_variant {
-       struct bt_field_type common;
-       GString *tag_name;
-       bool choices_up_to_date;
-
-       /* Owned by this */
-       struct bt_field_type_enumeration *tag_ft;
-
-       /* Owned by this */
-       struct bt_field_path *tag_field_path;
-
-       GHashTable *choice_name_to_index;
-
-       /*
-        * Array of `struct bt_field_type_variant_choice`,
-        * owned by this */
-       GArray *choices;
+struct bt_field_type_structure {
+       struct bt_field_type_named_field_types_container common;
 };
 
 struct bt_field_type_array {
@@ -226,81 +194,62 @@ struct bt_field_type_array {
 
        /* Owned by this */
        struct bt_field_type *element_ft;
+};
 
-       unsigned int length;
+struct bt_field_type_static_array {
+       struct bt_field_type_array common;
+       uint64_t length;
 };
 
-struct bt_field_type_sequence {
-       struct bt_field_type common;
+struct bt_field_type_dynamic_array {
+       struct bt_field_type_array common;
 
-       /* Owned by this */
-       struct bt_field_type *element_ft;
-
-       GString *length_field_name;
+       /* Weak: never dereferenced, only use to find it elsewhere */
+       struct bt_field_type *length_ft;
 
        /* Owned by this */
        struct bt_field_path *length_field_path;
 };
 
-struct bt_field_type_string {
-       struct bt_field_type common;
-       enum bt_string_encoding encoding;
-};
+struct bt_field_type_variant {
+       struct bt_field_type_named_field_types_container common;
+
+       /* Weak: never dereferenced, only use to find it elsewhere */
+       struct bt_field_type *selector_ft;
 
-typedef struct bt_field *(* bt_field_create_func)(
-               struct bt_field_type *);
+       /* Owned by this */
+       struct bt_field_path *selector_field_path;
+};
 
-BT_ASSERT_FUNC
-static inline bool bt_field_type_has_known_id(
-               struct bt_field_type *ft)
+static inline
+bool bt_field_type_has_known_id(struct bt_field_type *ft)
 {
-       return (int) ft->id > BT_FIELD_TYPE_ID_UNKNOWN ||
-               (int) ft->id < BT_FIELD_TYPE_ID_NR;
+       return ft->id >= BT_FIELD_TYPE_ID_UNSIGNED_INTEGER &&
+               ft->id <= BT_FIELD_TYPE_ID_VARIANT;
 }
 
 BT_HIDDEN
-int bt_field_type_variant_update_choices(
-               struct bt_field_type *ft);
-
-BT_HIDDEN
-void bt_field_type_freeze(struct bt_field_type *ft);
-
-BT_HIDDEN
-int bt_field_type_validate(struct bt_field_type *ft);
-
-BT_HIDDEN
-int bt_field_type_sequence_set_length_field_path(
-               struct bt_field_type *ft, struct bt_field_path *path);
-
-BT_HIDDEN
-int bt_field_type_variant_set_tag_field_path(
-               struct bt_field_type *ft,
-               struct bt_field_path *path);
-
-BT_HIDDEN
-int bt_field_type_variant_set_tag_field_type(
-               struct bt_field_type *ft,
-               struct bt_field_type *tag_ft);
+void _bt_field_type_freeze(struct bt_field_type *field_type);
 
-BT_HIDDEN
-int64_t bt_field_type_get_field_count(struct bt_field_type *ft);
-
-BT_HIDDEN
-struct bt_field_type *bt_field_type_borrow_field_at_index(
-               struct bt_field_type *ft, int index);
-
-BT_HIDDEN
-int bt_field_type_get_field_index(struct bt_field_type *ft,
-               const char *name);
+#ifdef BT_DEV_MODE
+# define bt_field_type_freeze          _bt_field_type_freeze
+#else
+# define bt_field_type_freeze(_ft)
+#endif
 
+/*
+ * This function recursively marks `field_type` and its children as
+ * being part of a trace. This is used to validate that all field types
+ * are used at a single location within trace objects even if they are
+ * shared objects for other purposes.
+ */
 BT_HIDDEN
-int bt_field_type_validate_single_clock_class(
-               struct bt_field_type *ft,
-               struct bt_clock_class **expected_clock_class);
+void _bt_field_type_make_part_of_trace(struct bt_field_type *field_type);
 
-BT_HIDDEN
-int64_t bt_field_type_variant_find_choice_index(
-               struct bt_field_type *ft, uint64_t uval,
-               bool is_signed);
+#ifdef BT_DEV_MODE
+# define bt_field_type_make_part_of_trace      _bt_field_type_make_part_of_trace
+#else
+# define bt_field_type_make_part_of_trace(_ft) ((void) _ft)
+#endif
 
 #endif /* BABELTRACE_CTF_IR_FIELD_TYPES_INTERNAL_H */
index 951fb48b5563456f48b632ec6da4c513c0bfed36..95bc646c7d8ee3574e3d186986ea594bdfcc69c8 100644 (file)
 extern "C" {
 #endif
 
-/**
-@defgroup ctfirfieldtypes CTF IR field types
-@ingroup ctfir
-@brief CTF IR field types.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>field type</em></strong> is a field type that you
-can use to create concrete @fields.
-
-You can create a @field object from a CTF IR field type object
-with bt_field_create().
-
-In the CTF IR hierarchy, you can set the root field types of three
-objects:
-
-- \ref ctfirtraceclass
-  - Trace packet header field type: bt_trace_set_packet_header_field_type().
-- \ref ctfirstreamclass
-  - Stream packet context field type:
-    bt_stream_class_set_packet_context_field_type().
-  - Stream event header field type:
-    bt_stream_class_set_event_header_field_type().
-  - Stream event context field type:
-    bt_stream_class_set_event_context_field_type().
-- \ref ctfireventclass
-  - Event context field type: bt_event_class_set_context_field_type().
-  - Event payload field type: bt_event_class_set_payload_field_type().
-
-As of Babeltrace \btversion, those six previous "root" field types
-\em must be @structft objects.
-
-If, at any level within a given root field type, you add a @seqft or a
-@varft, you do not need to specify its associated length
-or tag field type: the length or tag string is enough for the Babeltrace
-system to resolve the needed field type depending on where this
-dynamic field type is located within the whole hierarchy. It is
-guaranteed that this automatic resolving is performed for all the field
-types contained in a given
-\link ctfirstreamclass CTF IR stream class\endlink (and in its
-children \link ctfireventclass CTF IR event classes\endlink) once you
-add it to a \link ctfirtraceclass CTF IR trace class\endlink with
-bt_trace_add_stream_class(). Once a stream class is the child of
-a trace class, this automatic resolving is performed for the field
-types of an event class when you add it with
-bt_stream_class_add_event_class(). If the system cannot find a path
-to a field in the hierarchy for a dynamic field type, the adding
-function fails.
-
-The standard CTF field types are:
-
-<table>
-  <tr>
-    <th>Type ID
-    <th>CTF IR field type
-    <th>CTF IR field which you can create from this field type
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_INTEGER
-    <td>\ref ctfirintfieldtype
-    <td>\ref ctfirintfield
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_FLOAT
-    <td>\ref ctfirfloatfieldtype
-    <td>\ref ctfirfloatfield
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_ENUM
-    <td>\ref ctfirenumfieldtype
-    <td>\ref ctfirenumfield
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_STRING
-    <td>\ref ctfirstringfieldtype
-    <td>\ref ctfirstringfield
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_STRUCT
-    <td>\ref ctfirstructfieldtype
-    <td>\ref ctfirstructfield
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_ARRAY
-    <td>\ref ctfirarrayfieldtype
-    <td>\ref ctfirarrayfield
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_SEQUENCE
-    <td>\ref ctfirseqfieldtype
-    <td>\ref ctfirseqfield
-  </tr>
-  <tr>
-    <td>#BT_FIELD_TYPE_ID_VARIANT
-    <td>\ref ctfirvarfieldtype
-    <td>\ref ctfirvarfield
-  </tr>
-</table>
-
-Each field type has its own <strong>type ID</strong> (see
-#bt_field_type_id). You get the type ID of a field type object
-with bt_field_type_get_type_id().
-
-You can get a deep copy of a field type with bt_field_type_copy().
-This function resets, in the field type copy, the resolved field type
-of the dynamic field types. The automatic resolving can be done again
-when you eventually call bt_event_create(),
-bt_stream_class_add_event_class(), or
-bt_trace_add_stream_class().
-
-You \em must always use bt_field_type_compare() to compare two
-field types. Since some parts of the Babeltrace system can copy field
-types behind the scenes, you \em cannot rely on a simple field type
-pointer comparison.
-
-As with any Babeltrace object, CTF IR field type objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-The following functions can \em freeze field type objects:
-
-- bt_field_create() freezes its field type parameter.
-- bt_stream_class_add_event_class(), if its
-  \link ctfirstreamclass CTF IR stream class\endlink parameter has a
-  \link ctfirtraceclass CTF IR trace class\endlink parent, freezes
-  the root field types of its
-  \link ctfireventclass CTF IR event class\endlink parameter.
-- bt_trace_add_stream_class() freezes the root field types of the
-  whole trace class hierarchy (trace class, children stream classes,
-  and their children event classes).
-- bt_writer_create_stream() freezes the root field types of the
-  whole CTF writer's trace class hierarchy.
-- bt_event_create() freezes the root field types of its event class
-  parameter and of ther parent stream class of this event class.
-
-You cannot modify a frozen field type object: it is considered
-immutable, except for \link refs reference counting\endlink.
-
-@sa ctfirfields
-@sa \ref ctfirfieldtypesexamples "Examples"
-
-@file
-@brief CTF IR field types type and functions.
-@sa ctfirfieldtypes
-
-@addtogroup ctfirfieldtypes
-@{
-*/
-
-/**
-@struct bt_field_type
-@brief A CTF IR field type.
-@sa ctfirfieldtypes
-*/
 struct bt_field_type;
-struct bt_event_class;
-struct bt_event;
-struct bt_field;
 struct bt_field_path;
-struct bt_field_type_enumeration_mapping_iterator;
-
-/**
-@brief CTF scope.
-*/
-enum bt_scope {
-       /// Unknown, used for errors.
-       BT_SCOPE_UNKNOWN                = -1,
-
-       /// Trace packet header.
-       BT_SCOPE_TRACE_PACKET_HEADER    = 1,
-
-       /// Stream packet context.
-       BT_SCOPE_STREAM_PACKET_CONTEXT  = 2,
+struct bt_field_type_signed_enumeration_mapping_ranges;
+struct bt_field_type_unsigned_enumeration_mapping_ranges;
 
-       /// Stream event header.
-       BT_SCOPE_STREAM_EVENT_HEADER    = 3,
+typedef const char * const *bt_field_type_enumeration_mapping_label_array;
 
-       /// Stream event context.
-       BT_SCOPE_STREAM_EVENT_CONTEXT   = 4,
-
-       /// Event context.
-       BT_SCOPE_EVENT_CONTEXT          = 5,
-
-       /// Event payload.
-       BT_SCOPE_EVENT_PAYLOAD          = 6,
-
-       /// @cond DOCUMENT
-       BT_SCOPE_ENV                    = 0,
-       BT_SCOPE_EVENT_FIELDS           = 6,
-       /// @endcond
-};
-
-/**
-@name Type information
-@{
-*/
-
-/**
-@brief Type ID of a @ft.
-*/
 enum bt_field_type_id {
-       /// Unknown, used for errors.
-       BT_FIELD_TYPE_ID_UNKNOWN        = -1,
-
-       /// \ref ctfirintfieldtype
-       BT_FIELD_TYPE_ID_INTEGER        = 0,
-
-       /// \ref ctfirfloatfieldtype
-       BT_FIELD_TYPE_ID_FLOAT          = 1,
-
-       /// \ref ctfirenumfieldtype
-       BT_FIELD_TYPE_ID_ENUM           = 2,
-
-       /// \ref ctfirstringfieldtype
-       BT_FIELD_TYPE_ID_STRING         = 3,
-
-       /// \ref ctfirstructfieldtype
-       BT_FIELD_TYPE_ID_STRUCT         = 4,
-
-       /// \ref ctfirarrayfieldtype
-       BT_FIELD_TYPE_ID_ARRAY          = 6,
-
-       /// \ref ctfirseqfieldtype
-       BT_FIELD_TYPE_ID_SEQUENCE       = 7,
-
-       /// \ref ctfirvarfieldtype
-       BT_FIELD_TYPE_ID_VARIANT        = 5,
-
-       /// Number of enumeration entries.
-       BT_FIELD_TYPE_ID_NR             = 8,
+       BT_FIELD_TYPE_ID_UNSIGNED_INTEGER,
+       BT_FIELD_TYPE_ID_SIGNED_INTEGER,
+       BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION,
+       BT_FIELD_TYPE_ID_SIGNED_ENUMERATION,
+       BT_FIELD_TYPE_ID_REAL,
+       BT_FIELD_TYPE_ID_STRING,
+       BT_FIELD_TYPE_ID_STRUCTURE,
+       BT_FIELD_TYPE_ID_STATIC_ARRAY,
+       BT_FIELD_TYPE_ID_DYNAMIC_ARRAY,
+       BT_FIELD_TYPE_ID_VARIANT,
 };
 
-/**
-@brief Returns the type ID of the @ft \p field_type.
-
-@param[in] field_type  Field type of which to get the type ID.
-@returns               Type ID of \p field_type,
-                       or #BT_FIELD_TYPE_ID_UNKNOWN on error.
-
-@prenotnull{field_type}
-@postrefcountsame{field_type}
+enum bt_field_type_integer_preferred_display_base {
+       BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_BINARY,
+       BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL,
+       BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+       BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
+};
 
-@sa #bt_field_type_id: CTF IR field type ID.
-@sa bt_field_type_is_integer(): Returns whether or not a given
-       field type is a @intft.
-@sa bt_field_type_is_floating_point(): Returns whether or not a
-       given field type is a @floatft.
-@sa bt_field_type_is_enumeration(): Returns whether or not a given
-       field type is a @enumft.
-@sa bt_field_type_is_string(): Returns whether or not a given
-       field type is a @stringft.
-@sa bt_field_type_is_structure(): Returns whether or not a given
-       field type is a @structft.
-@sa bt_field_type_is_array(): Returns whether or not a given
-       field type is a @arrayft.
-@sa bt_field_type_is_sequence(): Returns whether or not a given
-       field type is a @seqft.
-@sa bt_field_type_is_variant(): Returns whether or not a given
-       field type is a @varft.
-*/
 extern enum bt_field_type_id bt_field_type_get_type_id(
                struct bt_field_type *field_type);
 
-/**
-@brief Returns whether or not the @ft \p field_type is a @intft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is an integer field type,
-                       or #BT_FALSE otherwise (including if \p field_type is
-                       \c NULL).
-
-@prenotnull{field_type}
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_integer(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) ==
-               BT_FIELD_TYPE_ID_INTEGER;
-}
+extern struct bt_field_type *bt_field_type_unsigned_integer_create(void);
 
-/**
-@brief Returns whether or not the @ft \p field_type is a @floatft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is a floating point
-                       #BT_FALSE field type,
-                       or 0 otherwise (including if \p field_type is
-                       \c NULL).
-
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_floating_point(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) == BT_FIELD_TYPE_ID_FLOAT;
-}
-
-/**
-@brief Returns whether or not the @ft \p field_type is a @enumft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is an enumeration field type,
-                       or #BT_FALSE otherwise (including if \p field_type is
-                       \c NULL).
-
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_enumeration(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) == BT_FIELD_TYPE_ID_ENUM;
-}
-
-/**
-@brief Returns whether or not the @ft \p field_type is a @stringft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is a string field type,
-                       or #BT_FALSE otherwise (including if \p field_type is
-                       \c NULL).
-
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_string(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) == BT_FIELD_TYPE_ID_STRING;
-}
+extern struct bt_field_type *bt_field_type_signed_integer_create(void);
 
-/**
-@brief Returns whether or not the @ft \p field_type is a @structft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is a structure field type,
-                       or #BT_FALSE otherwise (including if \p field_type is
-                       \c NULL).
-
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_structure(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) == BT_FIELD_TYPE_ID_STRUCT;
-}
-
-/**
-@brief Returns whether or not the @ft \p field_type is a @arrayft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is an array field type,
-                       or #BT_FALSE otherwise (including if \p field_type is
-                       \c NULL).
-
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_array(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) == BT_FIELD_TYPE_ID_ARRAY;
-}
-
-/**
-@brief Returns whether or not the @ft \p field_type is a @seqft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is a sequence field type,
-                       or #BT_FALSE otherwise (including if \p field_type is
-                       \c NULL).
-
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_sequence(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) ==
-               BT_FIELD_TYPE_ID_SEQUENCE;
-}
-
-/**
-@brief Returns whether or not the @ft \p field_type is a @varft.
-
-@param[in] field_type  Field type to check (can be \c NULL).
-@returns               #BT_TRUE if \p field_type is a variant field type,
-                       or #BT_FALSE otherwise (including if \p field_type is
-                       \c NULL).
-
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_type_id(): Returns the type ID of a given
-       field type.
-*/
-static inline
-bt_bool bt_field_type_is_variant(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) ==
-               BT_FIELD_TYPE_ID_VARIANT;
-}
-
-/** @} */
-
-/**
-@name Common properties types and functions
-@{
-*/
-
-/**
-@brief <a href="https://en.wikipedia.org/wiki/Endianness">Byte order</a>
-       of a @ft.
-*/
-enum bt_byte_order {
-       /// Unknown, used for errors.
-       BT_BYTE_ORDER_UNKNOWN   = -1,
-
-       /*
-        * Note that native, in the context of the CTF specification, is defined
-        * as "the byte order described in the trace" and does not mean that the
-        * host's endianness will be used.
-        */
-       /// Native (default) byte order.
-       BT_BYTE_ORDER_NATIVE    = 0,
-
-       /**
-       Unspecified byte order; the initial native byte order of a
-       \link ctfirtraceclass CTF IR trace class\endlink.
-       */
-       BT_BYTE_ORDER_UNSPECIFIED,
-
-       /// Little-endian.
-       BT_BYTE_ORDER_LITTLE_ENDIAN,
-
-       /// Big-endian.
-       BT_BYTE_ORDER_BIG_ENDIAN,
-
-       /// Network byte order (big-endian).
-       BT_BYTE_ORDER_NETWORK,
-};
-
-/**
-@brief String encoding of a @ft.
-*/
-enum bt_string_encoding {
-       /// Unknown, used for errors.
-       BT_STRING_ENCODING_UNKNOWN      = -1,
-
-       /// No encoding.
-       BT_STRING_ENCODING_NONE,
-
-       /// <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a>.
-       BT_STRING_ENCODING_UTF8,
-
-       /// <a href="https://en.wikipedia.org/wiki/ASCII">ASCII</a>.
-       BT_STRING_ENCODING_ASCII,
-};
-
-/**
-@brief  Returns the alignment of the @fields described by
-       the @ft \p field_type.
-
-@param[in] field_type  Field type which describes the
-                       fields of which to get the alignment.
-@returns               Alignment of the fields described by
-                       \p field_type, or a negative value on error.
-
-@prenotnull{field_type}
-@postrefcountsame{field_type}
-
-@sa bt_field_type_set_alignment(): Sets the alignment
-       of the fields described by a given field type.
-*/
-extern int bt_field_type_get_alignment(
+extern uint64_t bt_field_type_integer_get_field_value_range(
                struct bt_field_type *field_type);
 
-/**
-@brief  Sets the alignment of the @fields described by the
-       @ft \p field_type to \p alignment.
-
-\p alignment \em must be greater than 0 and a power of two.
-
-@param[in] field_type  Field type which describes the fields of
-                       which to set the alignment.
-@param[in] alignment   Alignment of the fields described by
-                       \p field_type.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{field_type}
-@prehot{field_type}
-@pre \p alignment is greater than 0 and a power of two.
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_alignment(): Returns the alignment of the
-       fields described by a given field type.
-*/
-extern int bt_field_type_set_alignment(struct bt_field_type *field_type,
-               unsigned int alignment);
-
-/**
-@brief  Returns the byte order of the @fields described by
-       the @ft \p field_type.
-
-You can only call this function if \p field_type is a @intft, a
-@floatft, or a @enumft.
-
-@param[in] field_type  Field type which describes the
-                       fields of which to get the byte order.
-@returns               Byte order of the fields described by
-                       \p field_type, or #BT_BYTE_ORDER_UNKNOWN on
-                       error.
+extern int bt_field_type_integer_set_field_value_range(
+               struct bt_field_type *field_type, uint64_t size);
 
-@prenotnull{field_type}
-@pre \p field_type is a @intft, a @floatft, or a @enumft.
-@postrefcountsame{field_type}
-
-@sa bt_field_type_set_byte_order(): Sets the byte order
-       of the fields described by a given field type.
-*/
-extern enum bt_byte_order bt_field_type_get_byte_order(
+extern enum bt_field_type_integer_preferred_display_base
+bt_field_type_integer_get_preferred_display_base(
                struct bt_field_type *field_type);
 
-/**
-@brief  Sets the byte order of the @fields described by the
-       @ft \p field_type to \p byte_order.
-
-If \p field_type is a compound field type, this function also
-recursively sets the byte order of its children to \p byte_order.
-
-@param[in] field_type  Field type which describes the fields of
-                       which to set the byte order.
-@param[in] byte_order  Alignment of the fields described by
-                       \p field_type.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{field_type}
-@prehot{field_type}
-@pre \p byte_order is #BT_BYTE_ORDER_NATIVE,
-       #BT_BYTE_ORDER_LITTLE_ENDIAN, #BT_BYTE_ORDER_BIG_ENDIAN,
-       or #BT_BYTE_ORDER_NETWORK.
-@postrefcountsame{field_type}
-
-@sa bt_field_type_get_byte_order(): Returns the byte order of the
-       fields described by a given field type.
-*/
-extern int bt_field_type_set_byte_order(
+extern int bt_field_type_integer_set_preferred_display_base(
                struct bt_field_type *field_type,
-               enum bt_byte_order byte_order);
-
-/** @} */
-
-/**
-@name Utility functions
-@{
-*/
-
-/**
-@brief Returns whether or not the @ft \p field_type_a
-       is equivalent to the field type \p field_type_b.
-
-You \em must use this function to compare two field types: it is not
-safe to compare two pointer values directly, because, for internal
-reasons, some parts of the Babeltrace system can copy user field types
-and discard the original ones.
-
-@param[in] field_type_a        Field type to compare to \p field_type_b.
-@param[in] field_type_b Field type to compare to \p field_type_a.
-@returns               0 if \p field_type_a is equivalent to
-                       \p field_type_b, 1 if they are not equivalent,
-                       or a negative value on error.
-
-@prenotnull{field_type_a}
-@prenotnull{field_type_b}
-@postrefcountsame{field_type_a}
-@postrefcountsame{field_type_b}
-*/
-extern int bt_field_type_compare(struct bt_field_type *field_type_a,
-               struct bt_field_type *field_type_b);
-
-/**
-@brief Creates a \em deep copy of the @ft \p field_type.
-
-You can copy a frozen field type: the resulting copy is
-<em>not frozen</em>.
-
-This function resets the tag field type of a copied @varft. The
-automatic field resolving which some functions of the API perform
-can set it again when the returned field type is used (learn more
-in the detailed description of this module).
+               enum bt_field_type_integer_preferred_display_base base);
 
-@param[in] field_type  Field type to copy.
-@returns               Deep copy of \p field_type on success,
-                       or \c NULL on error.
+extern struct bt_field_type *bt_field_type_real_create(void);
 
-@prenotnull{field_type}
-@postrefcountsame{field_type}
-@postsuccessrefcountret1
-@post <strong>On success</strong>, the returned field type is not frozen.
-*/
-extern struct bt_field_type *bt_field_type_copy(
+extern bt_bool bt_field_type_real_is_single_precision(
                struct bt_field_type *field_type);
 
-/** @} */
-
-/** @} */
-
-/**
-@defgroup ctfirintfieldtype CTF IR integer field type
-@ingroup ctfirfieldtypes
-@brief CTF IR integer field type.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>integer field type</em></strong> is a field type that
-you can use to create concrete @intfield objects.
-
-You can create an integer field type
-with bt_field_type_integer_create().
-
-An integer field type has the following properties:
-
-<table>
-  <tr>
-    <th>Property
-    <th>Value at creation
-    <th>Getter
-    <th>Setter
-  </tr>
-  <tr>
-    <td>\b Alignment (bits) of the described integer fields
-    <td>1
-    <td>bt_field_type_get_alignment()
-    <td>bt_field_type_set_alignment()
-  </tr>
-  <tr>
-    <td><strong>Byte order</strong> of the described integer fields
-    <td>#BT_BYTE_ORDER_NATIVE
-    <td>bt_field_type_get_byte_order()
-    <td>bt_field_type_set_byte_order()
-  </tr>
-  <tr>
-    <td><strong>Storage size</strong> (bits) of the described
-        integer fields
-    <td>Specified at creation
-    <td>bt_field_type_integer_get_size()
-    <td>bt_field_type_integer_set_size()
-  </tr>
-  <tr>
-    <td><strong>Signedness</strong> of the described integer fields
-    <td>Unsigned
-    <td>bt_field_type_integer_is_signed()
-    <td>bt_field_type_integer_set_is_signed()
-  </tr>
-  <tr>
-    <td><strong>Preferred display base</strong> of the described
-        integer fields
-    <td>#BT_INTEGER_BASE_DECIMAL
-    <td>bt_field_type_integer_get_base()
-    <td>bt_field_type_integer_set_base()
-  </tr>
-  <tr>
-    <td>\b Encoding of the described integer fields
-    <td>#BT_STRING_ENCODING_NONE
-    <td>bt_field_type_integer_get_encoding()
-    <td>bt_field_type_integer_set_encoding()
-  </tr>
-  <tr>
-    <td><strong>Mapped
-        \link ctfirclockclass CTF IR clock class\endlink</strong>
-    <td>None
-    <td>bt_field_type_integer_get_mapped_clock_class()
-    <td>bt_field_type_integer_set_mapped_clock_class()
-  </tr>
-</table>
-
-@sa ctfirintfield
-@sa ctfirfieldtypes
-@sa \ref ctfirfieldtypesexamples_intfieldtype "Examples"
-
-@addtogroup ctfirintfieldtype
-@{
-*/
-
-/**
-@brief Preferred display base (radix) of a @intft.
-*/
-enum bt_integer_base {
-       /// Unknown, used for errors.
-       BT_INTEGER_BASE_UNKNOWN         = -1,
-
-       /// Unspecified by the tracer.
-       BT_INTEGER_BASE_UNSPECIFIED     = 0,
-
-       /// Binary.
-       BT_INTEGER_BASE_BINARY          = 2,
-
-       /// Octal.
-       BT_INTEGER_BASE_OCTAL           = 8,
-
-       /// Decimal.
-       BT_INTEGER_BASE_DECIMAL         = 10,
-
-       /// Hexadecimal.
-       BT_INTEGER_BASE_HEXADECIMAL     = 16,
-};
-
-/**
-@brief  Creates a default @intft with \p size bits as the storage size
-       of the @intfields it describes.
-
-You can change the storage size of the integer fields described by
-the created integer field type later with
-bt_field_type_integer_set_size().
-
-@param[in] size        Storage size (bits) of the described integer fields.
-@returns       Created integer field type, or \c NULL on error.
-
-@pre \p size is greater than 0 and lesser than or equal to 64.
-@postsuccessrefcountret1
-*/
-extern struct bt_field_type *bt_field_type_integer_create(
-               unsigned int size);
-
-/**
-@brief Returns the storage size, in bits, of the @intfields
-       described by the @intft \p int_field_type.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to get the
-                               storage size.
-@returns                       Storage size (bits) of the integer
-                               fields described by \p int_field_type,
-                               or a negative value on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_set_size(): Sets the storage size of the
-       integer fields described by a given integer field type.
-*/
-extern int bt_field_type_integer_get_size(
-               struct bt_field_type *int_field_type);
-
-/**
-@brief Sets the storage size, in bits, of the @intfields described by
-       the @intft \p int_field_type.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to set the
-                               storage size.
-@param[in] size                        Storage size (bits) of the integer fields
-                               described by \p int_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@prehot{int_field_type}
-@pre \p size is greater than 0 and lesser than or equal to 64.
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_get_size(): Returns the storage size of
-       the integer fields described by a given integer field type.
-*/
-extern int bt_field_type_integer_set_size(
-               struct bt_field_type *int_field_type, unsigned int size);
-
-/**
-@brief  Returns whether or not the @intfields described by the @intft
-       \p int_field_type are signed.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to get the
-                               signedness.
-@returns                       #BT_TRUE if the integer fields described by
-                               \p int_field_type are signed, #BT_FALSE if they
-                               are unsigned.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_set_is_signed(): Sets the signedness of the
-       integer fields described by a given integer field type.
-*/
-extern bt_bool bt_field_type_integer_is_signed(
-               struct bt_field_type *int_field_type);
-
-/**
-@brief Sets whether or not the @intfields described by
-       the @intft \p int_field_type are signed.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to set the
-                               signedness.
-@param[in] is_signed           Signedness of the integer fields
-                               described by \p int_field_type; #BT_FALSE means
-                               \em unsigned, #BT_TRUE means \em signed.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@prehot{int_field_type}
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_is_signed(): Returns the signedness of
-       the integer fields described by a given integer field type.
-*/
-extern int bt_field_type_integer_set_is_signed(
-               struct bt_field_type *int_field_type, bt_bool is_signed);
-
-/**
-@brief  Returns the preferred display base (radix) of the @intfields
-       described by the @intft \p int_field_type.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to get the
-                               preferred display base.
-@returns                       Preferred display base of the integer
-                               fields described by \p int_field_type,
-                               #BT_INTEGER_BASE_UNSPECIFIED if
-                               not specified, or
-                               #BT_INTEGER_BASE_UNKNOWN on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_set_base(): Sets the preferred display
-       base of the integer fields described by a given integer field
-       type.
-*/
-extern enum bt_integer_base bt_field_type_integer_get_base(
-               struct bt_field_type *int_field_type);
-
-/**
-@brief  Sets the preferred display base (radix) of the @intfields
-       described by the @intft \p int_field_type to \p base.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to set the
-                               preferred display base.
-@param[in] base                        Preferred display base of the integer
-                               fields described by \p int_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@prehot{int_field_type}
-@pre \p base is #BT_INTEGER_BASE_UNSPECIFIED,
-       #BT_INTEGER_BASE_BINARY, #BT_INTEGER_BASE_OCTAL,
-       #BT_INTEGER_BASE_DECIMAL, or #BT_INTEGER_BASE_HEXADECIMAL.
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_get_base(): Returns the preferred display
-       base of the integer fields described by a given
-       integer field type.
-*/
-extern int bt_field_type_integer_set_base(
-               struct bt_field_type *int_field_type,
-               enum bt_integer_base base);
-
-/**
-@brief  Returns the encoding of the @intfields described by
-       the @intft \p int_field_type.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to get the
-                               encoding.
-@returns                       Encoding of the integer
-                               fields described by \p int_field_type,
-                               or #BT_STRING_ENCODING_UNKNOWN on
-                               error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_set_encoding(): Sets the encoding
-       of the integer fields described by a given integer field type.
-*/
-extern enum bt_string_encoding bt_field_type_integer_get_encoding(
-               struct bt_field_type *int_field_type);
-
-/**
-@brief  Sets the encoding of the @intfields described by the @intft
-       \p int_field_type to \p encoding.
-
-You can use this property, in CTF IR, to create "text" @arrayfts or
-@seqfts. A text array field type is array field type with an unsigned,
-8-bit integer field type having an encoding as its element field type.
-
-@param[in] int_field_type      Integer field type which describes the
-                               integer fields of which to set the
-                               encoding.
-@param[in] encoding            Encoding of the integer
-                               fields described by \p int_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@prehot{int_field_type}
-@pre \p encoding is #BT_STRING_ENCODING_NONE,
-       #BT_STRING_ENCODING_ASCII, or
-       #BT_STRING_ENCODING_UTF8.
-@postrefcountsame{int_field_type}
-
-@sa bt_field_type_integer_get_encoding(): Returns the encoding of
-       the integer fields described by a given integer field type.
-*/
-extern int bt_field_type_integer_set_encoding(
-               struct bt_field_type *int_field_type,
-               enum bt_string_encoding encoding);
-
-extern struct bt_clock_class *bt_field_type_integer_borrow_mapped_clock_class(
-               struct bt_field_type *int_field_type);
-
-/**
-@brief  Returns the \link ctfirclockclass CTF IR clock class\endlink
-       mapped to the @intft \p int_field_type.
-
-The mapped clock class, if any, indicates the class of the clock which
-an @intfield described by \p int_field_type should sample or update.
-This mapped clock class is only indicative.
-
-@param[in] int_field_type      Integer field type of which to get the
-                               mapped clock class.
-@returns                       Mapped clock class of \p int_field_type,
-                               or \c NULL if there's no mapped clock
-                               class or on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@postrefcountsame{int_field_type}
-@postsuccessrefcountretinc
-
-@sa bt_field_type_integer_set_mapped_clock_class(): Sets the mapped
-       clock class of a given integer field type.
-*/
-static inline
-struct bt_clock_class *bt_field_type_integer_get_mapped_clock_class(
-               struct bt_field_type *int_field_type)
-{
-       return bt_get(bt_field_type_integer_borrow_mapped_clock_class(
-               int_field_type));
-}
-
-/**
-@brief Sets the \link ctfirclockclass CTF IR clock class\endlink mapped
-       to the @intft \p int_field_type to \p clock_class.
-
-The mapped clock class, if any, indicates the class of the clock which
-an integer field described by \p int_field_type should sample or update.
-This mapped clock class is only indicative.
-
-@param[in] int_field_type      Integer field type of which to set the
-                               mapped clock class.
-@param[in] clock_class         Mapped clock class of \p int_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{int_field_type}
-@prenotnull{clock_class}
-@preisintft{int_field_type}
-@prehot{int_field_type}
-@postrefcountsame{int_field_type}
-@postsuccessrefcountinc{clock_class}
-
-@sa bt_field_type_integer_get_mapped_clock_class(): Returns the mapped
-       clock class of a given integer field type.
-*/
-extern int bt_field_type_integer_set_mapped_clock_class(
-               struct bt_field_type *int_field_type,
-               struct bt_clock_class *clock_class);
-
-/** @} */
-
-/**
-@defgroup ctfirfloatfieldtype CTF IR floating point number field type
-@ingroup ctfirfieldtypes
-@brief CTF IR floating point number field type.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>floating point number field type</em></strong> is
-a field type that you can use to create concrete @floatfields.
-
-You can create a floating point number field type
-with bt_field_type_floating_point_create().
-
-A floating point number field type has the following properties:
-
-<table>
-  <tr>
-    <th>Property
-    <th>Value at creation
-    <th>Getter
-    <th>Setter
-  </tr>
-  <tr>
-    <td>\b Alignment (bits) of the described floating point
-        number fields
-    <td>1
-    <td>bt_field_type_get_alignment()
-    <td>bt_field_type_set_alignment()
-  </tr>
-  <tr>
-    <td><strong>Byte order</strong> of the described floating point
-        number fields
-    <td>#BT_BYTE_ORDER_NATIVE
-    <td>bt_field_type_get_byte_order()
-    <td>bt_field_type_set_byte_order()
-  </tr>
-  <tr>
-    <td><strong>Exponent storage size</strong> (bits) of the described
-        floating point number fields
-    <td>8
-    <td>bt_field_type_floating_point_get_exponent_digits()
-    <td>bt_field_type_floating_point_set_exponent_digits()
-  </tr>
-  <tr>
-    <td><strong>Mantissa and sign storage size</strong> (bits) of the
-        described floating point number fields
-    <td>24 (23-bit mantissa, 1-bit sign)
-    <td>bt_field_type_floating_point_get_mantissa_digits()
-    <td>bt_field_type_floating_point_set_mantissa_digits()
-  </tr>
-</table>
-
-@sa ctfirfloatfield
-@sa ctfirfieldtypes
-@sa \ref ctfirfieldtypesexamples_floatfieldtype "Examples"
-
-@addtogroup ctfirfloatfieldtype
-@{
-*/
-
-/**
-@brief Creates a default @floatft.
-
-@returns       Created floating point number field type,
-               or \c NULL on error.
-
-@postsuccessrefcountret1
-*/
-extern struct bt_field_type *bt_field_type_floating_point_create(void);
-
-/**
-@brief  Returns the exponent storage size of the @floatfields
-       described by the @floatft \p float_field_type.
-
-@param[in] float_field_type    Floating point number field type which
-                               describes the floating point number
-                               fields of which to get the exponent
-                               storage size.
-@returns                       Exponent storage size of the
-                               floating point number fields
-                               described by \p float_field_type,
-                               or a negative value on error.
-
-@prenotnull{float_field_type}
-@preisfloatft{float_field_type}
-@postrefcountsame{float_field_type}
-
-@sa bt_field_type_floating_point_set_exponent_digits(): Sets the
-       exponent storage size of the floating point number fields
-       described by a given floating point number field type.
-*/
-extern int bt_field_type_floating_point_get_exponent_digits(
-               struct bt_field_type *float_field_type);
-
-/**
-@brief  Sets the exponent storage size of the @floatfields described by
-       the @floatft \p float_field_type to \p exponent_size.
-
-As of Babeltrace \btversion, \p exponent_size can only be 8 or 11.
-
-@param[in] float_field_type    Floating point number field type which
-                               describes the floating point number
-                               fields of which to set the exponent
-                               storage size.
-@param[in] exponent_size       Exponent storage size of the floating
-                               point number fields described by \p
-                               float_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{float_field_type}
-@preisfloatft{float_field_type}
-@prehot{float_field_type}
-@pre \p exponent_size is 8 or 11.
-@postrefcountsame{float_field_type}
-
-@sa bt_field_type_floating_point_get_exponent_digits(): Returns the
-       exponent storage size of the floating point number fields
-       described by a given floating point number field type.
-*/
-extern int bt_field_type_floating_point_set_exponent_digits(
-               struct bt_field_type *float_field_type,
-               unsigned int exponent_size);
-
-/**
-@brief  Returns the mantissa and sign storage size of the @floatfields
-       described by the @floatft \p float_field_type.
-
-On success, the returned value is the sum of the mantissa \em and
-sign storage sizes.
-
-@param[in] float_field_type    Floating point number field type which
-                               describes the floating point number
-                               fields of which to get the mantissa and
-                               sign storage size.
-@returns                       Mantissa and sign storage size of the
-                               floating point number fields
-                               described by \p float_field_type,
-                               or a negative value on error.
-
-@prenotnull{float_field_type}
-@preisfloatft{float_field_type}
-@postrefcountsame{float_field_type}
-
-@sa bt_field_type_floating_point_set_mantissa_digits(): Sets the
-       mantissa and size storage size of the floating point number
-       fields described by a given floating point number field type.
-*/
-extern int bt_field_type_floating_point_get_mantissa_digits(
-               struct bt_field_type *float_field_type);
-
-/**
-@brief  Sets the mantissa and sign storage size of the @floatfields
-       described by the @floatft \p float_field_type to \p
-       mantissa_sign_size.
-
-As of Babeltrace \btversion, \p mantissa_sign_size can only be 24 or 53.
-
-@param[in] float_field_type    Floating point number field type which
-                               describes the floating point number
-                               fields of which to set the mantissa and
-                               sign storage size.
-@param[in] mantissa_sign_size  Mantissa and sign storage size of the
-                               floating point number fields described
-                               by \p float_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{float_field_type}
-@preisfloatft{float_field_type}
-@prehot{float_field_type}
-@pre \p mantissa_sign_size is 24 or 53.
-@postrefcountsame{float_field_type}
-
-@sa bt_field_type_floating_point_get_mantissa_digits(): Returns the
-       mantissa and sign storage size of the floating point number
-       fields described by a given floating point number field type.
-*/
-extern int bt_field_type_floating_point_set_mantissa_digits(
-               struct bt_field_type *float_field_type,
-               unsigned int mantissa_sign_size);
-
-/** @} */
-
-/**
-@defgroup ctfirenumfieldtype CTF IR enumeration field type
-@ingroup ctfirfieldtypes
-@brief CTF IR enumeration field type.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>enumeration field type</em></strong> is
-a field type that you can use to create concrete @enumfields.
-
-You can create an enumeration field type with
-bt_field_type_enumeration_create(). This function needs a @intft
-which represents the storage field type of the created enumeration field
-type. In other words, an enumeration field type wraps an integer field
-type and adds label-value mappings to it.
-
-An enumeration mapping has:
-
-- A <strong>name</strong>.
-- A <strong>range of values</strong> given by a beginning and an ending
-  value, both included in the range.
-
-You can add a mapping to an enumeration field type with
-bt_field_type_enumeration_signed_add_mapping() or
-bt_field_type_enumeration_unsigned_add_mapping(), depending on the
-signedness of the wrapped @intft.
-
-You can find mappings by name or by value with the following find
-operations:
-
-- bt_field_type_enumeration_find_mappings_by_name(): Finds the
-  mappings with a given name.
-- bt_field_type_enumeration_unsigned_find_mappings_by_value():
-  Finds the mappings which contain a given unsigned value in their
-  range.
-- bt_field_type_enumeration_signed_find_mappings_by_value():
-  Finds the mappings which contain a given signed value in their range.
-
-Those functions return a @enumftiter on the result set of the find
-operation.
-
-Many mappings can share the same name, and the ranges of a given
-enumeration field type are allowed to overlap. For example,
-this is a valid set of mappings:
-
-@verbatim
-APPLE  -> [  3, 19]
-BANANA -> [-15,  1]
-CHERRY -> [ 25, 34]
-APPLE  -> [ 55, 55]
-@endverbatim
-
-The following set of mappings is also valid:
-
-@verbatim
-APPLE  -> [  3, 19]
-BANANA -> [-15,  1]
-CHERRY -> [ 25, 34]
-APPLE  -> [ 30, 55]
-@endverbatim
-
-Here, the range of the second \c APPLE mapping overlaps the range of
-the \c CHERRY mapping.
-
-@sa ctfirenumftmappingiter
-@sa ctfirenumfield
-@sa ctfirfieldtypes
-
-@addtogroup ctfirenumfieldtype
-@{
-*/
-
-/**
-@brief Creates a default @enumft wrapping the @intft \p int_field_type.
-
-@param[in] int_field_type      Integer field type wrapped by the
-                               created enumeration field type.
-@returns                       Created enumeration field type,
-                               or \c NULL on error.
-
-@prenotnull{int_field_type}
-@preisintft{int_field_type}
-@postsuccessrefcountinc{int_field_type}
-@postsuccessrefcountret1
-*/
-extern struct bt_field_type *bt_field_type_enumeration_create(
-               struct bt_field_type *int_field_type);
-
-extern
-struct bt_field_type *bt_field_type_enumeration_borrow_container_field_type(
-               struct bt_field_type *enum_field_type);
-
-/**
-@brief  Returns the @intft wrapped by the @enumft \p enum_field_type.
-
-@param[in] enum_field_type     Enumeration field type of which to get
-                               the wrapped integer field type.
-@returns                       Integer field type wrapped by
-                               \p enum_field_type, or \c NULL on
-                               error.
-
-@prenotnull{enum_field_type}
-@preisenumft{enum_field_type}
-@postrefcountsame{enum_field_type}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field_type *bt_field_type_enumeration_get_container_field_type(
-               struct bt_field_type *enum_field_type)
-{
-       return bt_get(bt_field_type_enumeration_borrow_container_field_type(
-               enum_field_type));
-}
-
-/**
-@brief  Returns the number of mappings contained in the
-       @enumft \p enum_field_type.
-
-@param[in] enum_field_type     Enumeration field type of which to get
-                               the number of contained mappings.
-@returns                       Number of mappings contained in
-                               \p enum_field_type, or a negative
-                               value on error.
-
-@prenotnull{enum_field_type}
-@preisenumft{enum_field_type}
-@postrefcountsame{enum_field_type}
-*/
-extern int64_t bt_field_type_enumeration_get_mapping_count(
-               struct bt_field_type *enum_field_type);
-
-/**
-@brief Returns the signed mapping of the @enumft
-       \p enum_field_type at index \p index.
-
-The @intft wrapped by \p enum_field_type, as returned by
-bt_field_type_enumeration_get_container_field_type(), must be \b signed
-to use this function.
-
-On success, \p enum_field_type remains the sole owner of \p *name.
-
-@param[in] enum_field_type     Enumeration field type of which to get
-                               the mapping at index \p index.
-@param[in] index               Index of the mapping to get from
-                               \p enum_field_type.
-@param[out] name               Returned name of the mapping at index
-                               \p index.
-@param[out] range_begin                Returned beginning of the range
-                               (included) of the mapping at index \p
-                               index.
-@param[out] range_end          Returned end of the range (included) of
-                               the mapping at index \p index.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{enum_field_type}
-@prenotnull{name}
-@prenotnull{range_begin}
-@prenotnull{range_end}
-@preisenumft{enum_field_type}
-@pre The wrapped @intft of \p enum_field_type is signed.
-@pre \p index is lesser than the number of mappings contained in the
-       enumeration field type \p enum_field_type (see
-       bt_field_type_enumeration_get_mapping_count()).
-@postrefcountsame{enum_field_type}
-
-@sa bt_field_type_enumeration_unsigned_get_mapping_by_index(): Returns the
-       unsigned mapping contained by a given enumeration field type
-       at a given index.
-*/
-extern int bt_field_type_enumeration_signed_get_mapping_by_index(
-               struct bt_field_type *enum_field_type, uint64_t index,
-               const char **name, int64_t *range_begin, int64_t *range_end);
-
-/**
-@brief  Returns the unsigned mapping of the @enumft
-       \p enum_field_type at index \p index.
-
-The @intft wrapped by \p enum_field_type, as returned by
-bt_field_type_enumeration_get_container_field_type(), must be
-\b unsigned to use this function.
-
-On success, \p enum_field_type remains the sole owner of \p *name.
-
-@param[in] enum_field_type     Enumeration field type of which to get
-                               the mapping at index \p index.
-@param[in] index               Index of the mapping to get from
-                               \p enum_field_type.
-@param[out] name               Returned name of the mapping at index
-                               \p index.
-@param[out] range_begin                Returned beginning of the range
-                               (included) of the mapping at index \p
-                               index.
-@param[out] range_end          Returned end of the range (included) of
-                               the mapping at index \p index.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{enum_field_type}
-@prenotnull{name}
-@prenotnull{range_begin}
-@prenotnull{range_end}
-@preisenumft{enum_field_type}
-@pre The wrapped @intft of \p enum_field_type is unsigned.
-@pre \p index is lesser than the number of mappings contained in the
-       enumeration field type \p enum_field_type (see
-       bt_field_type_enumeration_get_mapping_count()).
-@postrefcountsame{enum_field_type}
-
-@sa bt_field_type_enumeration_signed_get_mapping_by_index(): Returns the
-       signed mapping contained by a given enumeration field type
-       at a given index.
-*/
-extern int bt_field_type_enumeration_unsigned_get_mapping_by_index(
-               struct bt_field_type *enum_field_type, uint64_t index,
-               const char **name, uint64_t *range_begin,
-               uint64_t *range_end);
-
-/**
-@brief  Finds the mappings of the @enumft \p enum_field_type which
-       are named \p name.
-
-This function returns an iterator on the result set of this find
-operation. See \ref ctfirenumftmappingiter for more details.
-
-@param[in] enum_field_type     Enumeration field type of which to find
-                               the mappings named \p name.
-@param[in] name                        Name of the mappings to find in
-                               \p enum_field_type.
-@returns                       @enumftiter on the set of mappings named
-                               \p name in \p enum_field_type, or
-                               \c NULL if no mappings were found or
-                               on error.
-
-@prenotnull{enum_field_type}
-@prenotnull{name}
-@preisenumft{enum_field_type}
-@postrefcountsame{enum_field_type}
-@postsuccessrefcountret1
-@post <strong>On success</strong>, the returned @enumftiter can iterate
-       on at least one mapping.
-
-@sa bt_field_type_enumeration_signed_find_mappings_by_value(): Finds
-       the mappings of a given enumeration field type which contain
-       a given signed value in their range.
-@sa bt_field_type_enumeration_unsigned_find_mappings_by_value(): Finds
-       the mappings of a given enumeration field type which contain
-       a given unsigned value in their range.
-*/
-extern struct bt_field_type_enumeration_mapping_iterator *
-bt_field_type_enumeration_find_mappings_by_name(
-               struct bt_field_type *enum_field_type,
-               const char *name);
-
-/**
-@brief  Finds the mappings of the @enumft \p enum_field_type which
-       contain the signed value \p value in their range.
-
-This function returns an iterator on the result set of this find
-operation. See \ref ctfirenumftmappingiter for more details.
-
-@param[in] enum_field_type     Enumeration field type of which to find
-                               the mappings which contain \p value.
-@param[in] value               Value to find in the ranges of the
-                               mappings of \p enum_field_type.
-@returns                       @enumftiter on the set of mappings of
-                               \p enum_field_type which contain
-                               \p value in their range, or \c NULL if
-                               no mappings were found or on error.
-
-@prenotnull{enum_field_type}
-@preisenumft{enum_field_type}
-@postrefcountsame{enum_field_type}
-@postsuccessrefcountret1
-@post <strong>On success</strong>, the returned @enumftiter can iterate
-       on at least one mapping.
-
-@sa bt_field_type_enumeration_find_mappings_by_name(): Finds the
-       mappings of a given enumeration field type which have a given
-       name.
-@sa bt_field_type_enumeration_unsigned_find_mappings_by_value(): Finds
-       the mappings of a given enumeration field type which contain
-       a given unsigned value in their range.
-*/
-extern struct bt_field_type_enumeration_mapping_iterator *
-bt_field_type_enumeration_signed_find_mappings_by_value(
-               struct bt_field_type *enum_field_type,
-               int64_t value);
-
-/**
-@brief  Finds the mappings of the @enumft \p enum_field_type which
-       contain the unsigned value \p value in their range.
-
-This function returns an iterator on the result set of this find
-operation. See \ref ctfirenumftmappingiter for more details.
-
-@param[in] enum_field_type     Enumeration field type of which to find
-                               the mappings which contain \p value.
-@param[in] value               Value to find in the ranges of the
-                               mappings of \p enum_field_type.
-@returns                       @enumftiter on the set of mappings of
-                               \p enum_field_type which contain
-                               \p value in their range, or \c NULL
-                               if no mappings were found or
-                               on error.
-
-@prenotnull{enum_field_type}
-@preisenumft{enum_field_type}
-@postrefcountsame{enum_field_type}
-@postsuccessrefcountret1
-@post <strong>On success</strong>, the returned @enumftiter can iterate
-       on at least one mapping.
-
-@sa bt_field_type_enumeration_find_mappings_by_name(): Finds the
-       mappings of a given enumeration field type which have a given
-       name.
-@sa bt_field_type_enumeration_signed_find_mappings_by_value(): Finds
-       the mappings of a given enumeration field type which contain
-       a given unsigned value in their range.
-*/
-extern struct bt_field_type_enumeration_mapping_iterator *
-bt_field_type_enumeration_unsigned_find_mappings_by_value(
-               struct bt_field_type *enum_field_type,
-               uint64_t value);
-
-/**
-@brief  Adds a mapping to the @enumft \p enum_field_type which maps the
-       name \p name to the signed range \p range_begin (included) to
-       \p range_end (included).
-
-Make \p range_begin and \p range_end the same value to add a mapping
-to a single value.
-
-The @intft wrapped by \p enum_field_type, as returned by
-bt_field_type_enumeration_get_container_field_type(), must be
-\b signed to use this function.
-
-A mapping in \p enum_field_type can exist with the name \p name.
-
-@param[in] enum_field_type     Enumeration field type to which to add
-                               a mapping.
-@param[in] name                        Name of the mapping to add (copied
-                               on success).
-@param[in] range_begin         Beginning of the range of the mapping
-                               (included).
-@param[in] range_end           End of the range of the mapping
-                               (included).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{enum_field_type}
-@prenotnull{name}
-@prehot{enum_field_type}
-@preisenumft{enum_field_type}
-@pre The wrapped @intft of \p enum_field_type is signed.
-@pre \p range_end is greater than or equal to \p range_begin.
-@postrefcountsame{enum_field_type}
-
-@sa bt_field_type_enumeration_unsigned_add_mapping(): Adds an
-       unsigned mapping to a given enumeration field type.
-*/
-extern int bt_field_type_enumeration_signed_add_mapping(
-               struct bt_field_type *enum_field_type, const char *name,
-               int64_t range_begin, int64_t range_end);
-
-/**
-@brief Adds a mapping to the @enumft \p enum_field_type which maps
-       the name \p name to the unsigned
-       range \p range_begin (included) to \p range_end (included).
-
-Make \p range_begin and \p range_end the same value to add a mapping
-to a single value.
-
-The @intft wrapped by \p enum_field_type, as returned by
-bt_field_type_enumeration_get_container_field_type(), must be
-\b unsigned to use this function.
-
-A mapping in \p enum_field_type can exist with the name \p name.
-
-@param[in] enum_field_type     Enumeration field type to which to add
-                               a mapping.
-@param[in] name                        Name of the mapping to add (copied
-                               on success).
-@param[in] range_begin         Beginning of the range of the mapping
-                               (included).
-@param[in] range_end           End of the range of the mapping
-                               (included).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{enum_field_type}
-@prenotnull{name}
-@prehot{enum_field_type}
-@preisenumft{enum_field_type}
-@pre The wrapped @intft of \p enum_field_type is unsigned.
-@pre \p range_end is greater than or equal to \p range_begin.
-@postrefcountsame{enum_field_type}
-
-@sa bt_field_type_enumeration_signed_add_mapping(): Adds a signed
-       mapping to a given enumeration field type.
-*/
-extern int bt_field_type_enumeration_unsigned_add_mapping(
-               struct bt_field_type *enum_field_type, const char *name,
-               uint64_t range_begin, uint64_t range_end);
-
-/** @} */
-
-/**
-@defgroup ctfirenumftmappingiter CTF IR enumeration field type mapping iterator
-@ingroup ctfirenumfieldtype
-@brief CTF IR enumeration field type mapping iterator.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>enumeration field type mapping
-iterator</em></strong> is an iterator on @enumft mappings.
-
-You can get an enumeration mapping iterator from one of the following
-functions:
-
-- Find operations of an @enumft object:
-  - bt_field_type_enumeration_find_mappings_by_name(): Finds the
-    mappings with a given name.
-  - bt_field_type_enumeration_unsigned_find_mappings_by_value():
-    Finds the mappings which contain a given unsigned value in their
-    range.
-  - bt_field_type_enumeration_signed_find_mappings_by_value():
-    Finds the mappings which contain a given signed value in their range.
-- bt_field_enumeration_get_mappings(): Finds the mappings in the
-  @enumft of an @enumfield containing its current integral value in
-  their range.
-
-Those functions guarantee that the returned iterator can iterate on
-at least one mapping. Otherwise, they return \c NULL.
-
-You can get the name and the range of a mapping iterator's current
-mapping with
-bt_field_type_enumeration_mapping_iterator_signed_get()
-or
-bt_field_type_enumeration_mapping_iterator_unsigned_get(),
-depending on the signedness of the @intft wrapped by the
-@enumft. If you only need the name of the current mapping, you can
-use any of the two functions and set the \p range_begin and \p range_end
-parameters to \c NULL.
-
-You can advance an enumeration field type mapping iterator to the next
-mapping with
-bt_field_type_enumeration_mapping_iterator_next(). This
-function returns a negative value when you reach the end of the
-result set.
-
-As with any Babeltrace object, CTF IR enumeration field type mapping
-iterator objects have <a
-href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-@sa ctfirenumfieldtype
-
-@addtogroup ctfirenumftmappingiter
-@{
-*/
-
-/**
-@struct bt_field_type_enumeration_mapping_iterator
-@brief A CTF IR enumeration field type mapping iterator.
-@sa ctfirenumftmappingiter
-*/
-
-/**
-@brief  Returns the name and the range of the current (signed) mapping
-       of the @enumftiter \p iter.
-
-If one of \p range_begin or \p range_end is not \c NULL, the @intft
-wrapped by the @enumft from which \p iter was obtained, as returned by
-bt_field_type_enumeration_get_container_field_type(), must be
-\b signed to use this function. Otherwise, if you only need to get the
-name of the current mapping, set \p range_begin and \p range_end to
-\c NULL.
-
-On success, if \p name is not \c NULL, \p *name remains valid as long
-as \p iter exists and
-bt_field_type_enumeration_mapping_iterator_next() is
-\em not called on \p iter.
-
-@param[in] iter                        Enumeration field type mapping iterator
-                               of which to get the range of the current
-                               mapping.
-@param[out] name               Returned name of the current mapping of
-                               \p iter (can be \c NULL to ignore).
-@param[out] range_begin                Returned beginning of the range
-                               (included) of the current mapping of
-                               \p iter (can be \c NULL to ignore).
-@param[out] range_end          Returned end of the range
-                               (included) of the current mapping of
-                               \p iter (can be \c NULL to ignore).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{iter}
-@postrefcountsame{iter}
-
-@sa bt_field_type_enumeration_mapping_iterator_unsigned_get():
-       Returns the name and the unsigned range of the current mapping
-       of a given enumeration field type mapping iterator.
-*/
-extern int bt_field_type_enumeration_mapping_iterator_signed_get(
-               struct bt_field_type_enumeration_mapping_iterator *iter,
-               const char **name, int64_t *range_begin, int64_t *range_end);
-
-/**
-@brief  Returns the name and the range of the current (unsigned) mapping
-       of the @enumftiter \p iter.
-
-If one of \p range_begin or \p range_end is not \c NULL, the @intft
-wrapped by the @enumft from which \p iter was obtained, as returned by
-bt_field_type_enumeration_get_container_field_type(), must be
-\b unsigned to use this function. Otherwise, if you only need to get the
-name of the current mapping, set \p range_begin and \p range_end to
-\c NULL.
-
-On success, if \p name is not \c NULL, \p *name remains valid as long
-as \p iter exists and
-bt_field_type_enumeration_mapping_iterator_next() is
-\em not called on \p iter.
-
-@param[in] iter                        Enumeration field type mapping iterator
-                               of which to get the range of the current
-                               mapping.
-@param[out] name               Returned name of the current mapping of
-                               \p iter (can be \c NULL to ignore).
-@param[out] range_begin                Returned beginning of the range
-                               (included) of the current mapping of
-                               \p iter (can be \c NULL to ignore).
-@param[out] range_end          Returned end of the range
-                               (included) of the current mapping of
-                               \p iter (can be \c NULL to ignore).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{iter}
-@postrefcountsame{iter}
-
-@sa
-       bt_field_type_enumeration_mapping_iterator_signed_get():
-       Returns the name and the signed range of the current mapping of
-       a given enumeration field type mapping iterator.
-*/
-extern int bt_field_type_enumeration_mapping_iterator_unsigned_get(
-               struct bt_field_type_enumeration_mapping_iterator *iter,
-               const char **name, uint64_t *range_begin, uint64_t *range_end);
+extern int bt_field_type_real_set_is_single_precision(
+               struct bt_field_type *field_type,
+               bt_bool is_single_precision);
 
-/**
-@brief Advances the @enumftiter \p iter to the next mapping.
+extern struct bt_field_type *bt_field_type_unsigned_enumeration_create(void);
 
-@param[in] iter                Enumeration field type mapping iterator to
-                       advance.
-@returns               0 on success, or a negative value on error or
-                       when you reach the end of the set.
+extern struct bt_field_type *bt_field_type_signed_enumeration_create(void);
 
-@prenotnull{iter}
-@postrefcountsame{iter}
-*/
-extern int bt_field_type_enumeration_mapping_iterator_next(
-               struct bt_field_type_enumeration_mapping_iterator *iter);
+extern uint64_t bt_field_type_enumeration_get_mapping_count(
+               struct bt_field_type *field_type);
 
-/** @} */
+extern void bt_field_type_unsigned_enumeration_borrow_mapping_by_index(
+               struct bt_field_type *field_type, uint64_t index,
+               const char **label,
+               struct bt_field_type_unsigned_enumeration_mapping_ranges **ranges);
 
-/**
-@defgroup ctfirstringfieldtype CTF IR string field type
-@ingroup ctfirfieldtypes
-@brief CTF IR string field type.
+extern void bt_field_type_signed_enumeration_borrow_mapping_by_index(
+               struct bt_field_type *field_type, uint64_t index,
+               const char **label,
+               struct bt_field_type_signed_enumeration_mapping_ranges **ranges);
 
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
+extern uint64_t bt_field_type_unsigned_enumeration_mapping_ranges_get_range_count(
+               struct bt_field_type_unsigned_enumeration_mapping_ranges *ranges);
 
-A CTF IR <strong><em>string field type</em></strong> is a field type that
-you can use to create concrete @stringfields.
+extern uint64_t bt_field_type_signed_enumeration_mapping_ranges_get_range_count(
+               struct bt_field_type_signed_enumeration_mapping_ranges *ranges);
 
-You can create a string field type
-with bt_field_type_string_create().
+extern void bt_field_type_unsigned_enumeration_mapping_ranges_get_range_by_index(
+               struct bt_field_type_unsigned_enumeration_mapping_ranges *ranges,
+               uint64_t index, uint64_t *lower, uint64_t *upper);
 
-A string field type has only one property: the \b encoding of its
-described @stringfields. By default, the encoding of the string fields
-described by a string field type is #BT_STRING_ENCODING_UTF8. You
-can set the encoding of the string fields described by a string field
-type with bt_field_type_string_set_encoding().
+extern void bt_field_type_signed_enumeration_mapping_ranges_get_range_by_index(
+               struct bt_field_type_unsigned_enumeration_mapping_ranges *ranges,
+               uint64_t index, int64_t *lower, int64_t *upper);
 
-@sa ctfirstringfield
-@sa ctfirfieldtypes
+extern int bt_field_type_unsigned_enumeration_get_mapping_labels_by_value(
+               struct bt_field_type *field_type, uint64_t value,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count);
 
-@addtogroup ctfirstringfieldtype
-@{
-*/
+extern int bt_field_type_signed_enumeration_get_mapping_labels_by_value(
+               struct bt_field_type *field_type, int64_t value,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count);
 
-/**
-@brief Creates a default @stringft.
+extern int bt_field_type_unsigned_enumeration_map_range(
+               struct bt_field_type *field_type, const char *label,
+               uint64_t range_lower, uint64_t range_upper);
 
-@returns       Created string field type, or \c NULL on error.
+extern int bt_field_type_signed_enumeration_map_range(
+               struct bt_field_type *field_type, const char *label,
+               int64_t range_lower, int64_t range_upper);
 
-@postsuccessrefcountret1
-*/
 extern struct bt_field_type *bt_field_type_string_create(void);
 
-/**
-@brief  Returns the encoding of the @stringfields described by
-       the @stringft \p string_field_type.
-
-@param[in] string_field_type   String field type which describes the
-                               string fields of which to get the
-                               encoding.
-@returns                       Encoding of the string
-                               fields described by \p string_field_type,
-                               or #BT_STRING_ENCODING_UNKNOWN on
-                               error.
-
-@prenotnull{string_field_type}
-@preisstringft{string_field_type}
-@postrefcountsame{string_field_type}
-
-@sa bt_field_type_string_set_encoding(): Sets the encoding
-       of the string fields described by a given string field type.
-*/
-extern enum bt_string_encoding bt_field_type_string_get_encoding(
-               struct bt_field_type *string_field_type);
-
-/**
-@brief  Sets the encoding of the @stringfields described by the
-       @stringft \p string_field_type to \p encoding.
-
-@param[in] string_field_type   String field type which describes the
-                               string fields of which to set the
-                               encoding.
-@param[in] encoding            Encoding of the string fields described
-                               by \p string_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{string_field_type}
-@preisstringft{string_field_type}
-@prehot{string_field_type}
-@pre \p encoding is #BT_STRING_ENCODING_ASCII or
-       #BT_STRING_ENCODING_UTF8.
-@postrefcountsame{string_field_type}
-
-@sa bt_field_type_string_get_encoding(): Returns the encoding of
-       the string fields described by a given string field type.
-*/
-extern int bt_field_type_string_set_encoding(
-               struct bt_field_type *string_field_type,
-               enum bt_string_encoding encoding);
-
-/** @} */
-
-/**
-@defgroup ctfirstructfieldtype CTF IR structure field type
-@ingroup ctfirfieldtypes
-@brief CTF IR structure field type.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>structure field type</em></strong> is
-a field type that you can use to create concrete @structfields.
-
-You can create a structure field type
-with bt_field_type_structure_create(). This function creates
-an empty structure field type, with no fields.
-
-You can add a field to a structure field type with
-bt_field_type_structure_add_field(). Two fields in a structure
-field type cannot have the same name.
-
-You can set the \em minimum alignment of the structure fields described
-by a structure field type with the common
-bt_field_type_set_alignment() function. The \em effective alignment
-of the structure fields described by a structure field type, as per
-<a href="http://diamon.org/ctf/">CTF</a>, is the \em maximum value amongst
-the effective alignments of all its fields. Note that the effective
-alignment of @varfields is always 1.
-
-You can set the byte order of <em>all the contained fields</em>,
-recursively, of a structure field type with the common
-bt_field_type_set_byte_order() function.
-
-@sa ctfirstructfield
-@sa ctfirfieldtypes
-
-@addtogroup ctfirstructfieldtype
-@{
-*/
-
-/**
-@brief Creates a default, empty @structft.
-
-@returns                       Created structure field type,
-                               or \c NULL on error.
-
-@postsuccessrefcountret1
-*/
 extern struct bt_field_type *bt_field_type_structure_create(void);
 
-/**
-@brief Returns the number of fields contained in the
-       @structft \p struct_field_type.
-
-@param[in] struct_field_type   Structure field type of which to get
-                               the number of contained fields.
-@returns                       Number of fields contained in
-                               \p struct_field_type, or a negative
-                               value on error.
-
-@prenotnull{struct_field_type}
-@preisstructft{struct_field_type}
-@postrefcountsame{struct_field_type}
-*/
-extern int64_t bt_field_type_structure_get_field_count(
-               struct bt_field_type *struct_field_type);
-
-extern int bt_field_type_structure_borrow_field_by_index(
-               struct bt_field_type *struct_field_type,
-               const char **field_name, struct bt_field_type **field_type,
-               uint64_t index);
-
-/**
-@brief Returns the field of the @structft \p struct_field_type
-       at index \p index.
-
-On success, the field's type is placed in \p *field_type if
-\p field_type is not \c NULL. The field's name is placed in
-\p *field_name if \p field_name is not \c NULL.
-\p struct_field_type remains the sole owner of \p *field_name.
-
-@param[in] struct_field_type   Structure field type of which to get
-                               the field at index \p index.
-@param[out] field_name         Returned name of the field at index
-                               \p index (can be \c NULL).
-@param[out] field_type         Returned field type of the field
-                               at index \p index (can be \c NULL).
-­@param[in] index             Index of the field to get from
-                               \p struct_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{struct_field_type}
-@preisstructft{struct_field_type}
-@pre \p index is lesser than the number of fields contained in the
-       structure field type \p struct_field_type (see
-       bt_field_type_structure_get_field_count()).
-@postrefcountsame{struct_field_type}
-@post <strong>On success</strong>, the returned field's type is placed
-       in \p *field_type and its reference count is incremented.
-
-@sa bt_field_type_structure_get_field_type_by_name(): Finds a
-       structure field type's field by name.
-*/
-static inline
-int bt_field_type_structure_get_field_by_index(
-               struct bt_field_type *struct_field_type,
-               const char **field_name, struct bt_field_type **field_type,
-               uint64_t index)
-{
-       int ret = bt_field_type_structure_borrow_field_by_index(
-               struct_field_type, field_name, field_type, index);
-
-       if (ret == 0 && field_type) {
-               bt_get(*field_type);
-       }
+extern uint64_t bt_field_type_structure_get_member_count(
+               struct bt_field_type *field_type);
 
-       return ret;
-}
+extern void bt_field_type_structure_borrow_member_by_index(
+               struct bt_field_type *struct_field_type, uint64_t index,
+               const char **name, struct bt_field_type **field_type);
 
 extern
-struct bt_field_type *bt_field_type_structure_borrow_field_type_by_name(
-               struct bt_field_type *struct_field_type,
-               const char *field_name);
-
-/**
-@brief  Returns the type of the field named \p field_name found in
-       the @structft \p struct_field_type.
-
-@param[in] struct_field_type   Structure field type of which to get
-                               a field's type.
-@param[in] field_name          Name of the field to find.
-@returns                       Type of the field named \p field_name in
-                               \p struct_field_type, or
-                               \c NULL on error.
-
-@prenotnull{struct_field_type}
-@prenotnull{field_name}
-@preisstructft{struct_field_type}
-@postrefcountsame{struct_field_type}
-@postsuccessrefcountretinc
-
-@sa bt_field_type_structure_get_field_by_index(): Finds a
-       structure field type's field by index.
-*/
-static inline
-struct bt_field_type *bt_field_type_structure_get_field_type_by_name(
-               struct bt_field_type *struct_field_type,
-               const char *field_name)
-{
-       return bt_get(bt_field_type_structure_borrow_field_type_by_name(
-               struct_field_type, field_name));
-}
-
-/**
-@brief Adds a field named \p field_name with the @ft
-       \p field_type to the @structft \p struct_field_type.
-
-On success, \p field_type becomes the child of \p struct_field_type.
-
-This function adds the new field after the current last field of
-\p struct_field_type (append mode).
+struct bt_field_type *bt_field_type_structure_borrow_member_field_type_by_name(
+               struct bt_field_type *field_type, const char *name);
 
-You \em cannot add a field named \p field_name if there's already a
-field named \p field_name in \p struct_field_type.
-
-@param[in] struct_field_type   Structure field type to which to add
-                               a new field.
-@param[in] field_type          Field type of the field to add to
-                               \p struct_field_type.
-@param[in] field_name          Name of the field to add to
-                               \p struct_field_type
-                               (copied on success).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{struct_field_type}
-@prenotnull{field_type}
-@prenotnull{field_name}
-@preisstructft{struct_field_type}
-@pre \p field_type is not and does not contain \p struct_field_type,
-       recursively, as a field's type.
-@prehot{struct_field_type}
-@postrefcountsame{struct_field_type}
-@postsuccessrefcountinc{field_type}
-*/
-extern int bt_field_type_structure_add_field(
-               struct bt_field_type *struct_field_type,
-               struct bt_field_type *field_type,
-               const char *field_name);
-
-/** @} */
-
-/**
-@defgroup ctfirarrayfieldtype CTF IR array field type
-@ingroup ctfirfieldtypes
-@brief CTF IR array field type.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>array field type</em></strong> is a field type that
-you can use to create concrete @arrayfields.
-
-You can create an array field type
-with bt_field_type_array_create(). This function needs
-the @ft of the fields contained by the array fields described by the
-array field type to create.
-
-@sa ctfirarrayfield
-@sa ctfirfieldtypes
-
-@addtogroup ctfirarrayfieldtype
-@{
-*/
-
-/**
-@brief Creates a default @arrayft with
-       \p element_field_type as the field type of the fields contained
-       in its described @arrayfields of length \p length.
+extern int bt_field_type_structure_append_member(
+               struct bt_field_type *struct_field_type, const char *name,
+               struct bt_field_type *field_type);
 
-@param[in] element_field_type  Field type of the fields contained in
-                               the array fields described by the
-                               created array field type.
-@param[in] length              Length of the array fields described by
-                               the created array field type.
-@returns                       Created array field type, or
-                               \c NULL on error.
+extern struct bt_field_type *bt_field_type_static_array_create(
+               struct bt_field_type *elem_field_type,
+               uint64_t length);
 
-@prenotnull{element_field_type}
-@postsuccessrefcountinc{element_field_type}
-@postsuccessrefcountret1
-*/
-extern struct bt_field_type *bt_field_type_array_create(
-               struct bt_field_type *element_field_type,
-               unsigned int length);
+extern struct bt_field_type *bt_field_type_dynamic_array_create(
+               struct bt_field_type *elem_field_type);
 
 extern struct bt_field_type *bt_field_type_array_borrow_element_field_type(
-               struct bt_field_type *array_field_type);
-
-/**
-@brief Returns the @ft of the @fields contained in
-       the @arrayfields described by the @arrayft \p array_field_type.
-
-@param[in] array_field_type    Array field type of which to get
-                               the type of the fields contained in its
-                               described array fields.
-@returns                       Type of the fields contained in the
-                               array fields described by
-                               \p array_field_type, or \c NULL
-                               on error.
-
-@prenotnull{array_field_type}
-@preisarrayft{array_field_type}
-@postrefcountsame{array_field_type}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field_type *bt_field_type_array_get_element_field_type(
-               struct bt_field_type *array_field_type)
-{
-       return bt_get(bt_field_type_array_borrow_element_field_type(
-               array_field_type));
-}
-
-/**
-@brief Returns the number of @fields contained in the
-       @arrayfields described by the @arrayft \p array_field_type.
-
-@param[in] array_field_type    Array field type of which to get
-                               the number of fields contained in its
-                               described array fields.
-@returns                       Number of fields contained in the
-                               array fields described by
-                               \p array_field_type, or a negative value
-                               on error.
-
-@prenotnull{array_field_type}
-@preisarrayft{array_field_type}
-@postrefcountsame{array_field_type}
-*/
-extern int64_t bt_field_type_array_get_length(
-               struct bt_field_type *array_field_type);
-
-/** @} */
-
-/**
-@defgroup ctfirseqfieldtype CTF IR sequence field type
-@ingroup ctfirfieldtypes
-@brief CTF IR sequence field type.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>sequence field type</em></strong> is
-a field type that you can use to create concrete @seqfields.
-
-You can create a sequence field type with
-bt_field_type_sequence_create(). This function needs the @ft
-of the fields contained by the sequence fields described by the created
-sequence field type. This function also needs the length name of the
-sequence field type to create. The length name is used to automatically
-resolve the length's field type. See \ref ctfirfieldtypes to learn more
-about the automatic resolving.
-
-@sa ctfirseqfield
-@sa ctfirfieldtypes
-
-@addtogroup ctfirseqfieldtype
-@{
-*/
-
-/**
-@brief Creates a default @seqft with \p element_field_type as the
-       @ft of the @fields contained in its described @seqfields
-       with the length name \p length_name.
-
-\p length_name can be an absolute or relative reference. See
-<a href="http://diamon.org/ctf/">CTF</a> for more details.
-
-@param[in] element_field_type  Field type of the fields contained in
-                               the sequence fields described by the
-                               created sequence field type.
-@param[in] length_name         Length name (copied on success).
-@returns                       Created array field type, or
-                               \c NULL on error.
-
-@prenotnull{element_field_type}
-@prenotnull{length_name}
-@postsuccessrefcountinc{element_field_type}
-@postsuccessrefcountret1
-*/
-extern struct bt_field_type *bt_field_type_sequence_create(
-               struct bt_field_type *element_field_type,
-               const char *length_name);
-
-extern struct bt_field_type *bt_field_type_sequence_borrow_element_field_type(
-               struct bt_field_type *sequence_field_type);
-
-/**
-@brief Returns the @ft of the @fields contained in the @seqft
-       described by the @seqft \p sequence_field_type.
-
-@param[in] sequence_field_type Sequence field type of which to get
-                               the type of the fields contained in its
-                               described sequence fields.
-@returns                       Type of the fields contained in the
-                               sequence fields described by
-                               \p sequence_field_type, or \c NULL
-                               on error.
-
-@prenotnull{sequence_field_type}
-@preisseqft{sequence_field_type}
-@postrefcountsame{sequence_field_type}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field_type *bt_field_type_sequence_get_element_field_type(
-               struct bt_field_type *sequence_field_type)
-{
-       return bt_get(bt_field_type_sequence_borrow_element_field_type(
-               sequence_field_type));
-}
-
-/**
-@brief  Returns the length name of the @seqft \p sequence_field_type.
-
-On success, \p sequence_field_type remains the sole owner of
-the returned string.
-
-@param[in] sequence_field_type Sequence field type of which to get the
-                               length name.
-@returns                       Length name of \p sequence_field_type,
-                               or \c NULL on error.
-
-@prenotnull{sequence_field_type}
-@preisseqft{sequence_field_type}
-
-@sa bt_field_type_sequence_get_length_field_path(): Returns the
-       length's CTF IR field path of a given sequence field type.
-*/
-extern const char *bt_field_type_sequence_get_length_field_name(
-               struct bt_field_type *sequence_field_type);
-
-extern struct bt_field_path *bt_field_type_sequence_borrow_length_field_path(
-               struct bt_field_type *sequence_field_type);
-
-/**
-@brief  Returns the length's CTF IR field path of the @seqft
-       \p sequence_field_type.
-
-The length's field path of a sequence field type is set when automatic
-resolving is performed (see \ref ctfirfieldtypes).
-
-@param[in] sequence_field_type Sequence field type of which to get the
-                               length's field path.
-@returns                       Length's field path of
-                               \p sequence_field_type, or
-                               \c NULL if the length's field path is
-                               not set yet is not set or on error.
-
-@prenotnull{sequence_field_type}
-@preisseqft{sequence_field_type}
-@postsuccessrefcountretinc
-
-@sa bt_field_type_sequence_get_length_field_name(): Returns the
-       length's name of a given sequence field type.
-*/
-static inline
-struct bt_field_path *bt_field_type_sequence_get_length_field_path(
-               struct bt_field_type *sequence_field_type)
-{
-       return bt_get(bt_field_type_sequence_borrow_length_field_path(
-               sequence_field_type));
-}
-
-/** @} */
-
-/**
-@defgroup ctfirvarfieldtype CTF IR variant field type
-@ingroup ctfirfieldtypes
-@brief CTF IR variant field type.
-
-@code
-#include <babeltrace/ctf-ir/field-types.h>
-@endcode
-
-A CTF IR <strong><em>variant field type</em></strong> is
-a field type that you can use to create concrete @varfields.
-
-You can create a variant field type with
-bt_field_type_variant_create(). This function expects you to pass
-both the tag's @enumft and the tag name of the variant field type to
-create. The tag's field type is optional, as the Babeltrace system can
-automatically resolve it using the tag name. You can leave the tag name
-to \c NULL initially, and set it later with
-bt_field_type_variant_set_tag_name(). The tag name must be set when
-the variant field type is frozen. See \ref ctfirfieldtypes to learn more
-about the automatic resolving and the conditions under which a field
-type can be frozen.
-
-You can add a field to a variant field type with
-bt_field_type_variant_add_field(). All the field names of a
-variant field type \em must exist as mapping names in its tag's @enumft.
-
-The effective alignment of the @varfields described by a
-variant field type is always 1, but the individual fields of a
-@varfield can have custom alignments.
-
-You can set the byte order of <em>all the contained fields</em>,
-recursively, of a variant field type with the common
-bt_field_type_set_byte_order() function.
-
-@sa ctfirvarfield
-@sa ctfirfieldtypes
-
-@addtogroup ctfirvarfieldtype
-@{
-*/
-
-/**
-@brief  Creates a default, empty @varft with the tag's @enumft
-       \p tag_field_type and the tag name \p tag_name.
-
-\p tag_field_type can be \c NULL; the tag's field type can be
-automatically resolved from the variant field type's tag name (see
-\ref ctfirfieldtypes). If \p tag_name is \c NULL, it \em must be set
-with bt_field_type_variant_set_tag_name() \em before the variant
-field type is frozen.
-
-\p tag_name can be an absolute or relative reference. See
-<a href="http://diamon.org/ctf/">CTF</a> for more details.
-
-@param[in] tag_field_type      Tag's enumeration field type
-                               (can be \c NULL).
-@param[in] tag_name            Tag name (copied on success,
-                               can be \c NULL).
-@returns                       Created variant field type, or
-                               \c NULL on error.
-
-@pre \p tag_field_type is an enumeration field type or \c NULL.
-@post <strong>On success, if \p tag_field_type is not \c NULL</strong>,
-       its reference count is incremented.
-@postsuccessrefcountret1
-*/
-extern struct bt_field_type *bt_field_type_variant_create(
-               struct bt_field_type *tag_field_type,
-               const char *tag_name);
-
-extern struct bt_field_type *bt_field_type_variant_borrow_tag_field_type(
-               struct bt_field_type *variant_field_type);
-
-/**
-@brief Returns the tag's @enumft of the @varft \p variant_field_type.
-
-@param[in] variant_field_type  Variant field type of which to get
-                               the tag's enumeration field type.
-@returns                       Tag's enumeration field type of
-                               \p variant_field_type, or \c NULL if the
-                               tag's field type is not set or on
-                               error.
-
-@prenotnull{variant_field_type}
-@preisvarft{variant_field_type}
-@postrefcountsame{variant_field_type}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field_type *bt_field_type_variant_get_tag_field_type(
-               struct bt_field_type *variant_field_type)
-{
-       return bt_get(bt_field_type_variant_borrow_tag_field_type(
-               variant_field_type));
-}
-
-/**
-@brief  Returns the tag name of the @varft \p variant_field_type.
-
-On success, \p variant_field_type remains the sole owner of
-the returned string.
-
-@param[in] variant_field_type  Variant field type of which to get the
-                               tag name.
-@returns                       Tag name of \p variant_field_type, or
-                               \c NULL if the tag name is not set or
-                               on error.
-
-@prenotnull{variant_field_type}
-@preisvarft{variant_field_type}
-
-@sa bt_field_type_variant_set_tag_name(): Sets the tag name of
-       a given variant field type.
-@sa bt_field_type_variant_get_tag_field_path(): Returns the tag's
-       CTF IR field path of a given variant field type.
-*/
-extern const char *bt_field_type_variant_get_tag_name(
-               struct bt_field_type *variant_field_type);
-
-/**
-@brief Sets the tag name of the @varft \p variant_field_type.
-
-\p tag_name can be an absolute or relative reference. See
-<a href="http://diamon.org/ctf/">CTF</a> for more details.
-
-@param[in] variant_field_type  Variant field type of which to set
-                               the tag name.
-@param[in] tag_name            Tag name of \p variant_field_type
-                               (copied on success).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{variant_field_type}
-@prenotnull{name}
-@prehot{variant_field_type}
-@postrefcountsame{variant_field_type}
-
-@sa bt_field_type_variant_get_tag_name(): Returns the tag name of
-       a given variant field type.
-*/
-extern int bt_field_type_variant_set_tag_name(
-               struct bt_field_type *variant_field_type,
-               const char *tag_name);
-
-extern struct bt_field_path *bt_field_type_variant_borrow_tag_field_path(
-               struct bt_field_type *variant_field_type);
-
-/**
-@brief  Returns the tag's CTF IR field path of the @varft
-       \p variant_field_type.
-
-The tag's field path of a variant field type is set when automatic
-resolving is performed (see \ref ctfirfieldtypes).
-
-@param[in] variant_field_type  Variant field type of which to get the
-                               tag's field path.
-@returns                       Tag's field path of
-                               \p variant_field_type, or
-                               \c NULL if the tag's field path is not
-                               set yet is not set or on error.
-
-@prenotnull{variant_field_type}
-@preisvarft{variant_field_type}
-@postsuccessrefcountretinc
-
-@sa bt_field_type_variant_get_tag_name(): Returns the tag's
-       name of a given variant field type.
-*/
-static inline
-struct bt_field_path *bt_field_type_variant_get_tag_field_path(
-               struct bt_field_type *variant_field_type)
-{
-       return bt_get(bt_field_type_variant_borrow_tag_field_path(
-               variant_field_type));
-}
-
-/**
-@brief Returns the number of fields (choices) contained in the @varft
-       \p variant_field_type.
-
-@param[in] variant_field_type  Variant field type of which to get
-                               the number of contained fields.
-@returns                       Number of fields contained in
-                               \p variant_field_type, or a negative
-                               value on error.
-
-@prenotnull{variant_field_type}
-@preisvarft{variant_field_type}
-@postrefcountsame{variant_field_type}
-*/
-extern int64_t bt_field_type_variant_get_field_count(
-               struct bt_field_type *variant_field_type);
-
-extern int bt_field_type_variant_borrow_field_by_index(
-               struct bt_field_type *variant_field_type,
-               const char **field_name,
-               struct bt_field_type **field_type, uint64_t index);
-
-/**
-@brief Returns the field (choice) of the @varft \p variant_field_type
-       at index \p index.
-
-On success, the field's type is placed in \p *field_type if
-\p field_type is not \c NULL. The field's name is placed in
-\p *field_name if \p field_name is not \c NULL.
-\p variant_field_type remains the sole owner of \p *field_name.
-
-@param[in] variant_field_type  Variant field type of which to get
-                               the field at index \p index.
-@param[out] field_name         Returned name of the field at index
-                               \p index (can be \c NULL).
-@param[out] field_type         Returned field type of the field
-                               at index \p index (can be \c NULL).
-­@param[in] index             Index of the field to get from
-                               \p variant_field_type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{variant_field_type}
-@preisvarft{variant_field_type}
-@pre \p index is lesser than the number of fields contained in the
-       variant field type \p variant_field_type (see
-       bt_field_type_variant_get_field_count()).
-@postrefcountsame{variant_field_type}
-@post <strong>On success</strong>, the returned field's type is placed
-       in \p *field_type and its reference count is incremented.
+               struct bt_field_type *field_type);
 
-@sa bt_field_type_variant_get_field_type_by_name(): Finds a variant
-       field type's field by name.
-@sa bt_field_type_variant_get_field_type_from_tag(): Finds a variant
-       field type's field by current tag value.
-*/
-static inline
-int bt_field_type_variant_get_field_by_index(
-               struct bt_field_type *variant_field_type,
-               const char **field_name,
-               struct bt_field_type **field_type, uint64_t index)
-{
-       int ret = bt_field_type_variant_borrow_field_by_index(
-               variant_field_type, field_name, field_type, index);
+extern uint64_t bt_field_type_static_array_get_length(
+               struct bt_field_type *field_type);
 
-       if (ret == 0 && field_type) {
-               bt_get(*field_type);
-       }
+extern struct bt_field_path *
+bt_field_type_dynamic_array_borrow_length_field_path(
+               struct bt_field_type *field_type);
 
-       return ret;
-}
+extern int bt_field_type_dynamic_array_set_length_field_type(
+               struct bt_field_type *field_type,
+               struct bt_field_type *length_field_type);
 
-extern
-struct bt_field_type *bt_field_type_variant_borrow_field_type_by_name(
-               struct bt_field_type *variant_field_type,
-               const char *field_name);
+extern struct bt_field_type *bt_field_type_variant_create(void);
 
-/**
-@brief  Returns the type of the field (choice) named \p field_name
-       found in the @varft \p variant_field_type.
+extern struct bt_field_path *
+bt_field_type_variant_borrow_selector_field_path(
+               struct bt_field_type *field_type);
 
-@param[in] variant_field_type  Variant field type of which to get
-                               a field's type.
-@param[in] field_name          Name of the field to find.
-@returns                       Type of the field named \p field_name in
-                               \p variant_field_type, or
-                               \c NULL on error.
+extern int bt_field_type_variant_set_selector_field_type(
+               struct bt_field_type *field_type,
+               struct bt_field_type *selector_field_type);
 
-@prenotnull{variant_field_type}
-@prenotnull{field_name}
-@preisvarft{variant_field_type}
-@postrefcountsame{variant_field_type}
-@postsuccessrefcountretinc
+extern uint64_t bt_field_type_variant_get_option_count(
+               struct bt_field_type *field_type);
 
-@sa bt_field_type_variant_get_field_by_index(): Finds a variant field type's
-       field by index.
-@sa bt_field_type_variant_get_field_type_from_tag(): Finds a variant
-       field type's field by current tag value.
-*/
-static inline
-struct bt_field_type *bt_field_type_variant_get_field_type_by_name(
-               struct bt_field_type *variant_field_type,
-               const char *field_name)
-{
-       return bt_get(bt_field_type_variant_borrow_field_type_by_name(
-               variant_field_type, field_name));
-}
+extern void bt_field_type_variant_borrow_option_by_index(
+               struct bt_field_type *variant_field_type, uint64_t index,
+               const char **name, struct bt_field_type **field_type);
 
 extern
-struct bt_field_type *bt_field_type_variant_borrow_field_type_from_tag(
-               struct bt_field_type *variant_field_type,
-               struct bt_field *tag_field);
-
-/**
-@brief  Returns the type of the field (choice) selected by the value of
-       the @enumfield \p tag_field in the @varft \p variant_field_type.
-
-\p tag_field is the current tag value.
-
-The field type of \p tag_field, as returned by bt_field_get_type(),
-\em must be equivalent to the field type returned by
-bt_field_type_variant_get_tag_field_type() for \p variant_field_type.
-
-@param[in] variant_field_type  Variant field type of which to get
-                               a field's type.
-@param[in] tag_field           Current tag value (variant field type's
-                               selector).
-@returns                       Type of the field selected by
-                               \p tag_field in \p variant_field_type,
-                               or \c NULL on error.
-
-@prenotnull{variant_field_type}
-@prenotnull{tag_field}
-@preisvarft{variant_field_type}
-@preisenumfield{tag_field}
-@postrefcountsame{variant_field_type}
-@postrefcountsame{tag_field}
-@postsuccessrefcountretinc
-
-@sa bt_field_type_variant_get_field_by_index(): Finds a variant field type's
-       field by index.
-@sa bt_field_type_variant_get_field_type_by_name(): Finds a variant
-       field type's field by name.
-*/
-static inline
-struct bt_field_type *bt_field_type_variant_get_field_type_from_tag(
-               struct bt_field_type *variant_field_type,
-               struct bt_field *tag_field)
-{
-       return bt_get(bt_field_type_variant_borrow_field_type_from_tag(
-               variant_field_type, tag_field));
-}
-
-/**
-@brief Adds a field (a choice) named \p field_name with the @ft
-       \p field_type to the @varft \p variant_field_type.
-
-On success, \p field_type becomes the child of \p variant_field_type.
-
-You \em cannot add a field named \p field_name if there's already a
-field named \p field_name in \p variant_field_type.
-
-\p field_name \em must name an existing mapping in the tag's
-enumeration field type of \p variant_field_type.
-
-@param[in] variant_field_type  Variant field type to which to add
-                               a new field.
-@param[in] field_type          Field type of the field to add to
-                               \p variant_field_type.
-@param[in] field_name          Name of the field to add to
-                               \p variant_field_type
-                               (copied on success).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{variant_field_type}
-@prenotnull{field_type}
-@prenotnull{field_name}
-@preisvarft{variant_field_type}
-@pre \p field_type is not and does not contain \p variant_field_type,
-       recursively, as a field's type.
-@prehot{variant_field_type}
-@postrefcountsame{variant_field_type}
-@postsuccessrefcountinc{field_type}
-*/
-extern int bt_field_type_variant_add_field(
-               struct bt_field_type *variant_field_type,
+struct bt_field_type *bt_field_type_variant_borrow_option_field_type_by_name(
                struct bt_field_type *field_type,
-               const char *field_name);
+               const char *name);
 
-/** @} */
+extern int bt_field_type_variant_append_option(
+               struct bt_field_type *var_field_type,
+               const char *name, struct bt_field_type *field_type);
 
 #ifdef __cplusplus
 }
index 765502c77eb6c838934217d4480c15821a3445b3..31ec621329b1f8b7afa7d662d43c5c131648a062 100644 (file)
 #include <glib.h>
 
 #define BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(_field, _type_id, _name)       \
-       BT_ASSERT_PRE((_field)->type->id == ((int) (_type_id)),         \
+       BT_ASSERT_PRE(((struct bt_field *) (_field))->type->id == (_type_id), \
                _name " has the wrong type ID: expected-type-id=%s, "   \
-               "%![field-]+f",                                 \
-               bt_common_field_type_id_string((int) (_type_id)), (_field))
-
-#define BT_ASSERT_PRE_FIELD_IS_SET(_field, _name)              \
-       BT_ASSERT_PRE(bt_field_is_set_recursive(_field),                \
+               "%![field-]+f",                                         \
+               bt_common_field_type_id_string(_type_id), (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(_field, _name)             \
+       BT_ASSERT_PRE(                                                  \
+               ((struct bt_field *) (_field))->type->id == BT_FIELD_TYPE_ID_UNSIGNED_INTEGER || \
+               ((struct bt_field *) (_field))->type->id == BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION, \
+               _name " is not an unsigned integer field: %![field-]+f", \
+               (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(_field, _name)               \
+       BT_ASSERT_PRE(                                                  \
+               ((struct bt_field *) (_field))->type->id == BT_FIELD_TYPE_ID_SIGNED_INTEGER || \
+               ((struct bt_field *) (_field))->type->id == BT_FIELD_TYPE_ID_SIGNED_ENUMERATION, \
+               _name " is not a signed integer field: %![field-]+f", \
+               (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_ARRAY(_field, _name)                    \
+       BT_ASSERT_PRE(                                                  \
+               ((struct bt_field *) (_field))->type->id == BT_FIELD_TYPE_ID_STATIC_ARRAY || \
+               ((struct bt_field *) (_field))->type->id == BT_FIELD_TYPE_ID_DYNAMIC_ARRAY, \
+               _name " is not an array field: %![field-]+f", (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_SET(_field, _name)                      \
+       BT_ASSERT_PRE(bt_field_is_set(_field),                          \
                _name " is not set: %!+f", (_field))
 
-#define BT_ASSERT_PRE_FIELD_HOT(_field, _name)                 \
-       BT_ASSERT_PRE_HOT((_field), (_name), ": %!+f", (_field))
+#define BT_ASSERT_PRE_FIELD_HOT(_field, _name)                         \
+       BT_ASSERT_PRE_HOT((struct bt_field *) (_field), (_name),        \
+               ": %!+f", (_field))
 
 struct bt_field;
 
-typedef void (*bt_field_method_set_is_frozen)(struct bt_field *,
-               bool);
-typedef int (*bt_field_method_validate)(struct bt_field *);
-typedef bt_bool (*bt_field_method_is_set)(struct bt_field *);
+typedef struct bt_field *(* bt_field_create_func)(struct bt_field_type *);
+typedef void (*bt_field_method_set_is_frozen)(struct bt_field *, bool);
+typedef bool (*bt_field_method_is_set)(struct bt_field *);
 typedef void (*bt_field_method_reset)(struct bt_field *);
 
 struct bt_field_methods {
        bt_field_method_set_is_frozen set_is_frozen;
-       bt_field_method_validate validate;
        bt_field_method_is_set is_set;
        bt_field_method_reset reset;
 };
 
 struct bt_field {
        struct bt_object base;
+
+       /* Owned by this */
        struct bt_field_type *type;
+
+       /* Virtual table for slow path (dev mode) operations */
        struct bt_field_methods *methods;
-       bool payload_set;
+
+       bool is_set;
        bool frozen;
 };
 
 struct bt_field_integer {
        struct bt_field common;
-       union {
-               int64_t signd;
-               uint64_t unsignd;
-       } payload;
-};
 
-struct bt_field_enumeration {
-       struct bt_field_integer common;
+       union {
+               uint64_t u;
+               int64_t i;
+       } value;
 };
 
-struct bt_field_floating_point {
+struct bt_field_real {
        struct bt_field common;
-       double payload;
+       double value;
 };
 
 struct bt_field_structure {
@@ -103,13 +124,11 @@ struct bt_field_structure {
 struct bt_field_variant {
        struct bt_field common;
 
-       union {
-               uint64_t u;
-               int64_t i;
-       } tag_value;
+       /* Weak: belongs to `fields` below */
+       struct bt_field *selected_field;
 
-       /* Weak: belongs to `choices` below */
-       struct bt_field *current_field;
+       /* Index of currently selected field */
+       uint64_t selected_index;
 
        /* Array of `struct bt_field *`, owned by this */
        GPtrArray *fields;
@@ -119,70 +138,35 @@ struct bt_field_array {
        struct bt_field common;
 
        /* Array of `struct bt_field *`, owned by this */
-       GPtrArray *elements;
-};
-
-struct bt_field_sequence {
-       struct bt_field common;
+       GPtrArray *fields;
 
-       /*
-        * This is the true sequence field's length: its value can be
-        * less than `elements->len` below because we never shrink the
-        * array of elements to avoid reallocation.
-        */
+       /* Current effective length */
        uint64_t length;
-
-       /* Array of `struct bt_field *`, owned by this */
-       GPtrArray *elements;
 };
 
 struct bt_field_string {
        struct bt_field common;
        GArray *buf;
-       size_t size;
+       uint64_t length;
 };
 
 #ifdef BT_DEV_MODE
-# define bt_field_validate_recursive                   _bt_field_validate_recursive
-# define bt_field_set_is_frozen_recursive              _bt_field_set_is_frozen_recursive
-# define bt_field_is_set_recursive                     _bt_field_is_set_recursive
-# define bt_field_reset_recursive                      _bt_field_reset_recursive
-# define bt_field_set                                  _bt_field_set
+# define bt_field_set_is_frozen                _bt_field_set_is_frozen
+# define bt_field_is_set               _bt_field_is_set
+# define bt_field_reset                        _bt_field_reset
+# define bt_field_set_single           _bt_field_set_single
 #else
-# define bt_field_validate_recursive(_field)           (-1)
-# define bt_field_set_is_frozen_recursive(_field, _is_frozen)
-# define bt_field_is_set_recursive(_field)             (BT_FALSE)
-# define bt_field_reset_recursive(_field)
-# define bt_field_set(_field, _val)
+# define bt_field_set_is_frozen(_field, _is_frozen)
+# define bt_field_is_set(_field)       (BT_FALSE)
+# define bt_field_reset(_field)
+# define bt_field_set_single(_field, _val)
 #endif
 
 BT_HIDDEN
-void _bt_field_set_is_frozen_recursive(struct bt_field *field,
-               bool is_frozen);
-
-static inline
-int _bt_field_validate_recursive(struct bt_field *field)
-{
-       int ret = 0;
-
-       if (!field) {
-               BT_ASSERT_PRE_MSG("%s", "Invalid field: field is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(bt_field_type_has_known_id(field->type));
-
-       if (field->methods->validate) {
-               ret = field->methods->validate(field);
-       }
-
-end:
-       return ret;
-}
+void _bt_field_set_is_frozen(struct bt_field *field, bool is_frozen);
 
 static inline
-void _bt_field_reset_recursive(struct bt_field *field)
+void _bt_field_reset(struct bt_field *field)
 {
        BT_ASSERT(field);
        BT_ASSERT(field->methods->reset);
@@ -190,14 +174,14 @@ void _bt_field_reset_recursive(struct bt_field *field)
 }
 
 static inline
-void _bt_field_set(struct bt_field *field, bool value)
+void _bt_field_set_single(struct bt_field *field, bool value)
 {
        BT_ASSERT(field);
-       field->payload_set = value;
+       field->is_set = value;
 }
 
 static inline
-bt_bool _bt_field_is_set_recursive(struct bt_field *field)
+bt_bool _bt_field_is_set(struct bt_field *field)
 {
        bt_bool is_set = BT_FALSE;
 
@@ -214,9 +198,9 @@ end:
 }
 
 BT_HIDDEN
-struct bt_field *bt_field_create_recursive(struct bt_field_type *type);
+struct bt_field *bt_field_create(struct bt_field_type *type);
 
 BT_HIDDEN
-void bt_field_destroy_recursive(struct bt_field *field);
+void bt_field_destroy(struct bt_field *field);
 
 #endif /* BABELTRACE_CTF_IR_FIELDS_INTERNAL_H */
index f975e530b32c1e66d5d23732d82263f87923457a..5bf0c3b634743f1d9354928e7d91cba1fc31f2db 100644 (file)
  */
 
 #include <stdint.h>
-#include <stddef.h>
-
-/* For bt_get() */
-#include <babeltrace/ref.h>
 
 /* For bt_bool */
 #include <babeltrace/types.h>
 
-/* For BT_FIELD_TYPE_ID_* */
+/* For enum bt_field_type_id */
 #include <babeltrace/ctf-ir/field-types.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-struct bt_field_type;
-
-/**
-@defgroup ctfirfields CTF IR fields
-@ingroup ctfir
-@brief CTF IR fields.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>field</em></strong> is an object which holds a
-concrete value, and which is described by a @ft.
-
-In the CTF IR hierarchy, you can set the root fields of two objects:
-
-- \ref ctfirpacket
-  - Trace packet header field: bt_packet_set_header().
-  - Stream packet context field: bt_packet_set_context().
-- \ref ctfirevent
-  - Stream event header field: bt_event_set_header().
-  - Stream event context field: bt_event_set_stream_event_context().
-  - Event context field: bt_event_set_event_context().
-  - Event payload field: bt_event_set_payload_field().
-
-There are two categories of fields:
-
-- <strong>Basic fields</strong>:
-  - @intfield: contains an integral value.
-  - @floatfield: contains a floating point number value.
-  - @enumfield: contains an integer field which contains an integral
-    value.
-  - @stringfield: contains a string value.
-- <strong>Compound fields</strong>:
-  - @structfield: contains an ordered list of named fields
-    (possibly with different @fts).
-  - @arrayfield: contains an ordered list of fields which share
-    the same field type.
-  - @seqfield: contains an ordered list of fields which share
-    the same field type.
-  - @varfield: contains a single, current field.
-
-You can create a field object from a @ft object with
-bt_field_create(). The enumeration and compound fields create their
-contained fields with the following getters if such fields do not exist
-yet:
-
-- bt_field_enumeration_get_container()
-- bt_field_structure_get_field_by_name()
-- bt_field_array_get_field()
-- bt_field_sequence_get_field()
-- bt_field_variant_get_field()
-
-If you already have a field object, you can also assign it to a specific
-name within a @structfield with
-bt_field_structure_set_field_by_name().
-
-You can get a reference to the @ft which was used to create a field with
-bt_field_get_type(). You can get the
-\link #bt_field_type_id type ID\endlink of this field type directly with
-bt_field_get_type_id().
-
-You can get a deep copy of a field with bt_field_copy(). The field
-copy, and its contained field copies if it's the case, have the same
-field type as the originals.
-
-As with any Babeltrace object, CTF IR field objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-The functions which freeze CTF IR \link ctfirpacket packet\endlink and
-\link ctfirevent event\endlink objects also freeze their root field
-objects. You cannot modify a frozen field object: it is considered
-immutable, except for \link refs reference counting\endlink.
-
-@sa ctfirfieldtypes
-
-@file
-@brief CTF IR fields type and functions.
-@sa ctfirfields
-
-@addtogroup ctfirfields
-@{
-*/
-
-/**
-@struct bt_field
-@brief A CTF IR field.
-@sa ctfirfields
-*/
 struct bt_field;
-struct bt_event_class;
-struct bt_event;
 struct bt_field_type;
 struct bt_field_type_enumeration_mapping_iterator;
 
-/**
-@name Creation and parent field type access functions
-@{
-*/
-
 extern struct bt_field_type *bt_field_borrow_type(struct bt_field *field);
 
-/**
-@brief Returns the parent @ft of the @field \p field.
-
-This function returns a reference to the field type which was used to
-create the field object in the first place with bt_field_create().
-
-@param[in] field       Field of which to get the parent field type.
-@returns               Parent field type of \p event,
-                       or \c NULL on error.
-
-@prenotnull{field}
-@postrefcountsame{field}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field_type *bt_field_get_type(struct bt_field *field)
-{
-       return bt_get(bt_field_borrow_type(field));
-}
-
-/** @} */
-
-/**
-@name Type information
-@{
-*/
-
-/**
-@brief Returns the type ID of the @ft of the @field \p field.
-
-@param[in] field       Field of which to get the type ID of its
-                       parent field type..
-@returns               Type ID of the parent field type of \p field,
-                       or #BT_FIELD_TYPE_ID_UNKNOWN on error.
-
-@prenotnull{field}
-@postrefcountsame{field}
-
-@sa #bt_field_type_id: CTF IR field type ID.
-@sa bt_field_is_integer(): Returns whether or not a given field is a
-       @intfield.
-@sa bt_field_is_floating_point(): Returns whether or not a given
-       field is a @floatfield.
-@sa bt_field_is_enumeration(): Returns whether or not a given field
-       is a @enumfield.
-@sa bt_field_is_string(): Returns whether or not a given field is a
-       @stringfield.
-@sa bt_field_is_structure(): Returns whether or not a given field is
-       a @structfield.
-@sa bt_field_is_array(): Returns whether or not a given field is a
-       @arrayfield.
-@sa bt_field_is_sequence(): Returns whether or not a given field is
-       a @seqfield.
-@sa bt_field_is_variant(): Returns whether or not a given field is a
-       @varfield.
-*/
 extern enum bt_field_type_id bt_field_get_type_id(struct bt_field *field);
 
-/**
-@brief Returns whether or not the @field \p field is a @intfield.
-
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is an integer field, or
-                       #BT_FALSE otherwise (including if \p field is
-                       \c NULL).
-
-@prenotnull{field}
-@postrefcountsame{field}
-
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_integer(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_INTEGER;
-}
-
-/**
-@brief Returns whether or not the @field \p field is a @floatfield.
-
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is a floating point number fiel
-                       #BT_FALSE or 0 otherwise (including if \p field is
-                       \c NULL).
-
-@prenotnull{field}
-@postrefcountsame{field}
-
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_floating_point(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_FLOAT;
-}
-
-/**
-@brief Returns whether or not the @field \p field is a @enumfield.
-
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is an enumeration field, or
-                       #BT_FALSE otherwise (including if \p field is
-                       \c NULL).
-
-@prenotnull{field}
-@postrefcountsame{field}
-
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_enumeration(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_ENUM;
-}
-
-/**
-@brief Returns whether or not the @field \p field is a @stringfield.
-
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is a string field, or
-                       #BT_FALSE otherwise (including if \p field is
-                       \c NULL).
+extern int64_t bt_field_signed_integer_get_value(struct bt_field *field);
 
-@prenotnull{field}
-@postrefcountsame{field}
+extern void bt_field_signed_integer_set_value(struct bt_field *field,
+               int64_t value);
 
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_string(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_STRING;
-}
-
-/**
-@brief Returns whether or not the @field \p field is a @structfield.
+extern uint64_t bt_field_unsigned_integer_get_value(struct bt_field *field);
 
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is a structure field, or
-                       #BT_FALSE otherwise (including if \p field is
-                       \c NULL).
+extern void bt_field_unsigned_integer_set_value(struct bt_field *field,
+               uint64_t value);
 
-@prenotnull{field}
-@postrefcountsame{field}
-
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_structure(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_STRUCT;
-}
+extern double bt_field_real_get_value(struct bt_field *field);
 
-/**
-@brief Returns whether or not the @field \p field is a @arrayfield.
+extern void bt_field_real_set_value(struct bt_field *field, double value);
 
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is an array field, or
-                       #BT_FALSE otherwise (including if \p field is
-                       \c NULL).
-
-@prenotnull{field}
-@postrefcountsame{field}
-
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_array(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_ARRAY;
-}
+extern int bt_field_unsigned_enumeration_get_mapping_labels(
+               struct bt_field *field,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count);
 
-/**
-@brief Returns whether or not the @field \p field is a @seqfield.
+extern int bt_field_signed_enumeration_get_mapping_labels(
+               struct bt_field *field,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count);
 
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is a sequence field, or
-                       #BT_FALSE otherwise (including if \p field is
-                       \c NULL).
+extern const char *bt_field_string_get_value(struct bt_field *field);
 
-@prenotnull{field}
-@postrefcountsame{field}
+extern uint64_t bt_field_string_get_length(struct bt_field *field);
 
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_sequence(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_SEQUENCE;
-}
-
-/**
-@brief Returns whether or not the @field \p field is a @varfield.
-
-@param[in] field       Field to check (can be \c NULL).
-@returns                #BT_TRUE if \p field is a variant field, or
-                       #BT_FALSE otherwise (including if \p field is
-                       \c NULL).
-
-@prenotnull{field}
-@postrefcountsame{field}
-
-@sa bt_field_get_type_id(): Returns the type ID of a given
-       field's type.
-*/
-static inline
-bt_bool bt_field_is_variant(struct bt_field *field)
-{
-       return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_VARIANT;
-}
+extern int bt_field_string_set_value(struct bt_field *field, const char *value);
 
-/** @} */
-
-/**
-@name Misc. functions
-@{
-*/
-
-/** @} */
-
-/** @} */
-
-/**
-@defgroup ctfirintfield CTF IR integer field
-@ingroup ctfirfields
-@brief CTF IR integer field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>integer field</em></strong> is a @field which
-holds a signed or unsigned integral value, and which is described by
-a @intft.
-
-An integer field object is considered \em unsigned if
-bt_field_type_integer_get_signed() on its parent field type returns
-0. Otherwise it is considered \em signed. You \em must use
-bt_field_integer_unsigned_get_value() and
-bt_field_integer_unsigned_set_value() with an unsigned integer
-field, and bt_field_integer_signed_get_value() and
-bt_field_integer_signed_set_value() with a signed integer field.
-
-After you create an integer field with bt_field_create(), you
-\em must set an integral value with
-bt_field_integer_unsigned_set_value() or
-bt_field_integer_signed_set_value() before you can get the
-field's value with bt_field_integer_unsigned_get_value() or
-bt_field_integer_signed_get_value().
-
-@sa ctfirintfieldtype
-@sa ctfirfields
-
-@addtogroup ctfirintfield
-@{
-*/
-
-/**
-@brief Returns the signed integral value of the @intfield
-       \p integer_field.
-
-@param[in] integer_field       Integer field of which to get the
-                               signed integral value.
-@param[out] value              Returned signed integral value of
-                               \p integer_field.
-@returns                       0 on success, or a negative value on
-                               error, including if \p integer_field
-                               has no integral value yet.
-
-@prenotnull{integer_field}
-@prenotnull{value}
-@preisintfield{integer_field}
-@pre bt_field_type_integer_get_signed() returns 1 for the parent
-       @ft of \p integer_field.
-@pre \p integer_field contains a signed integral value previously
-       set with bt_field_integer_signed_set_value().
-@postrefcountsame{integer_field}
-
-@sa bt_field_integer_signed_set_value(): Sets the signed integral
-       value of a given integer field.
-*/
-extern int bt_field_integer_signed_get_value(
-               struct bt_field *integer_field, int64_t *value);
-
-/**
-@brief Sets the signed integral value of the @intfield
-       \p integer_field to \p value.
-
-@param[in] integer_field       Integer field of which to set
-                               the signed integral value.
-@param[in] value               New signed integral value of
-                               \p integer_field.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{integer_field}
-@preisintfield{integer_field}
-@prehot{integer_field}
-@pre bt_field_type_integer_get_signed() returns 1 for the parent
-       @ft of \p integer_field.
-@postrefcountsame{integer_field}
-
-@sa bt_field_integer_signed_get_value(): Returns the signed integral
-       value of a given integer field.
-*/
-extern int bt_field_integer_signed_set_value(
-               struct bt_field *integer_field, int64_t value);
-
-/**
-@brief Returns the unsigned integral value of the @intfield
-       \p integer_field.
-
-@param[in] integer_field       Integer field of which to get the
-                               unsigned integral value.
-@param[out] value              Returned unsigned integral value of
-                               \p integer_field.
-@returns                       0 on success, or a negative value on
-                               error, including if \p integer_field
-                               has no integral value yet.
-
-@prenotnull{integer_field}
-@prenotnull{value}
-@preisintfield{integer_field}
-@pre bt_field_type_integer_get_signed() returns 0 for the parent
-       @ft of \p integer_field.
-@pre \p integer_field contains an unsigned integral value previously
-       set with bt_field_integer_unsigned_set_value().
-@postrefcountsame{integer_field}
-
-@sa bt_field_integer_unsigned_set_value(): Sets the unsigned
-       integral value of a given integer field.
-*/
-extern int bt_field_integer_unsigned_get_value(
-               struct bt_field *integer_field, uint64_t *value);
-
-/**
-@brief Sets the unsigned integral value of the @intfield
-       \p integer_field to \p value.
-
-@param[in] integer_field       Integer field of which to set
-                               the unsigned integral value.
-@param[in] value               New unsigned integral value of
-                               \p integer_field.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{integer_field}
-@preisintfield{integer_field}
-@prehot{integer_field}
-@pre bt_field_type_integer_get_signed() returns 0 for the parent
-       @ft of \p integer_field.
-@postrefcountsame{integer_field}
-
-@sa bt_field_integer_unsigned_get_value(): Returns the unsigned
-       integral value of a given integer field.
-*/
-extern int bt_field_integer_unsigned_set_value(
-               struct bt_field *integer_field, uint64_t value);
-
-/** @} */
-
-/**
-@defgroup ctfirfloatfield CTF IR floating point number field
-@ingroup ctfirfields
-@brief CTF IR floating point number field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>floating point number field</em></strong> is a
-@field which holds a floating point number value, and which is
-described by a @floatft.
-
-After you create a floating point number field with bt_field_create(), you
-\em must set a floating point number value with
-bt_field_floating_point_set_value() before you can get the
-field's value with bt_field_floating_point_get_value().
-
-@sa ctfirfloatfieldtype
-@sa ctfirfields
-
-@addtogroup ctfirfloatfield
-@{
-*/
-
-/**
-@brief Returns the floating point number value of the @floatfield
-       \p float_field.
-
-@param[in] float_field Floating point number field of which to get the
-                       floating point number value.
-@param[out] value      Returned floating point number value of
-                       \p float_field.
-@returns                0 on success, or a negative value on error,
-                       including if \p float_field has no floating
-                       point number value yet.
-
-@prenotnull{float_field}
-@prenotnull{value}
-@preisfloatfield{float_field}
-@pre \p float_field contains a floating point number value previously
-       set with bt_field_floating_point_set_value().
-@postrefcountsame{float_field}
-
-@sa bt_field_floating_point_set_value(): Sets the floating point
-       number value of a given floating point number field.
-*/
-extern int bt_field_floating_point_get_value(
-               struct bt_field *float_field, double *value);
-
-/**
-@brief Sets the floating point number value of the @floatfield
-       \p float_field to \p value.
-
-@param[in] float_field Floating point number field of which to set
-                       the floating point number value.
-@param[in] value       New floating point number value of
-                       \p float_field.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{float_field}
-@preisfloatfield{float_field}
-@prehot{float_field}
-@postrefcountsame{float_field}
-
-@sa bt_field_floating_point_get_value(): Returns the floating point
-       number value of a given floating point number field.
-*/
-extern int bt_field_floating_point_set_value(
-               struct bt_field *float_field, double value);
-
-/** @} */
-
-/**
-@brief Returns a @enumftiter on all the mappings of the field type of
-       \p enum_field which contain the current integral value of the
-       @enumfield \p enum_field in their range.
-
-This function is the equivalent of using
-bt_field_type_enumeration_find_mappings_by_unsigned_value() or
-bt_field_type_enumeration_find_mappings_by_signed_value() with the
-current integral value of \p enum_field.
-
-@param[in] enum_field  Enumeration field of which to get the mappings
-                       containing the current integral value of \p
-                       enum_field in their range.
-@returns                @enumftiter on the set of mappings of the field
-                       type of \p enum_field which contain the current
-                       integral value of \p enum_field in their range,
-                       or \c NULL if no mappings were found or on
-                       error.
-
-@prenotnull{enum_field}
-@preisenumfield{enum_field}
-@pre The wrapped integer field of \p enum_field contains an integral
-       value.
-@postrefcountsame{enum_field}
-@postsuccessrefcountret1
-@post <strong>On success</strong>, the returned @enumftiter can iterate
-       on at least one mapping.
-*/
-extern struct bt_field_type_enumeration_mapping_iterator *
-bt_field_enumeration_get_mappings(struct bt_field *enum_field);
-
-/** @} */
-
-/**
-@defgroup ctfirstringfield CTF IR string field
-@ingroup ctfirfields
-@brief CTF IR string field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>string field</em></strong> is a @field which holds
-a string value, and which is described by a @stringft.
-
-Use bt_field_string_set_value() to set the current string value
-of a string field object. You can also use bt_field_string_append()
-and bt_field_string_append_len() to append a string to the current
-value of a string field.
-
-After you create a string field with bt_field_create(), you
-\em must set a string value with
-bt_field_string_set_value(), bt_field_string_append(), or
-bt_field_string_append_len() before you can get the
-field's value with bt_field_string_get_value().
-
-@sa ctfirstringfieldtype
-@sa ctfirfields
-
-@addtogroup ctfirstringfield
-@{
-*/
-
-/**
-@brief Returns the string value of the @stringfield \p string_field.
-
-On success, \p string_field remains the sole owner of the returned
-value.
-
-@param[in] string_field        String field field of which to get the
-                       string value.
-@returns                String value, or \c NULL on error.
-
-@prenotnull{string_field}
-@prenotnull{value}
-@preisstringfield{string_field}
-@pre \p string_field contains a string value previously
-       set with bt_field_string_set_value(),
-       bt_field_string_append(), or
-       bt_field_string_append_len().
-@postrefcountsame{string_field}
-
-@sa bt_field_string_set_value(): Sets the string value of a given
-       string field.
-*/
-extern const char *bt_field_string_get_value(struct bt_field *string_field);
-
-/**
-@brief Sets the string value of the @stringfield \p string_field to
-       \p value.
-
-@param[in] string_field        String field of which to set
-                       the string value.
-@param[in] value       New string value of \p string_field (copied
-                       on success).
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{string_field}
-@prenotnull{value}
-@preisstringfield{string_field}
-@prehot{string_field}
-@postrefcountsame{string_field}
-
-@sa bt_field_string_get_value(): Returns the string value of a
-       given string field.
-*/
-extern int bt_field_string_set_value(struct bt_field *string_field,
-               const char *value);
-
-/**
-@brief Appends the string \p value to the current string value of
-       the @stringfield \p string_field.
-
-This function is the equivalent of:
-
-@code
-bt_field_string_append_len(string_field, value, strlen(value));
-@endcode
-
-@param[in] string_field        String field of which to append \p value to
-                       its current value.
-@param[in] value       String to append to the current string value
-                       of \p string_field (copied on success).
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{string_field}
-@prenotnull{value}
-@preisstringfield{string_field}
-@prehot{string_field}
-@postrefcountsame{string_field}
-
-@sa bt_field_string_set_value(): Sets the string value of a given
-       string field.
-*/
-extern int bt_field_string_append(struct bt_field *string_field,
-               const char *value);
-
-/**
-@brief Appends the first \p length characters of \p value to the
-       current string value of the @stringfield \p string_field.
-
-If \p string_field has no current string value, this function first
-sets an empty string as the string value of \p string_field and then
-appends the first \p length characters of \p value.
-
-@param[in] string_field        String field of which to append the first
-                       \p length characters of \p value to
-                       its current value.
-@param[in] value       String containing the characters to append to
-                       the current string value of \p string_field
-                       (copied on success).
-@param[in] length      Number of characters of \p value to append to
-                       the current string value of \p string_field.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{string_field}
-@prenotnull{value}
-@preisstringfield{string_field}
-@prehot{string_field}
-@postrefcountsame{string_field}
-
-@sa bt_field_string_set_value(): Sets the string value of a given
-       string field.
-*/
-extern int bt_field_string_append_len(
-               struct bt_field *string_field, const char *value,
-               unsigned int length);
-
-extern int bt_field_string_clear(struct bt_field *string_field);
-
-/** @} */
-
-/**
-@defgroup ctfirstructfield CTF IR structure field
-@ingroup ctfirfields
-@brief CTF IR structure field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>structure field</em></strong> is a @field which
-contains an ordered list of zero or more named @fields which can be
-different @fts, and which is described by a @structft.
-
-To set the value of a specific field of a structure field, you need to
-first get the field with bt_field_structure_get_field_by_name() or
-bt_field_structure_get_field_by_index(). If you already have a
-field object, you can assign it to a specific name within a structure
-field with bt_field_structure_set_field_by_name().
-
-@sa ctfirstructfieldtype
-@sa ctfirfields
-
-@addtogroup ctfirstructfield
-@{
-*/
-
-extern struct bt_field *bt_field_structure_borrow_field_by_name(
-               struct bt_field *struct_field, const char *name);
-
-extern struct bt_field *bt_field_structure_borrow_field_by_index(
-               struct bt_field *struct_field, uint64_t index);
-
-/** @} */
-
-/**
-@defgroup ctfirarrayfield CTF IR array field
-@ingroup ctfirfields
-@brief CTF IR array field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>array field</em></strong> is a @field which
-contains an ordered list of zero or more @fields sharing the same @ft,
-and which is described by a @arrayft.
-
-To set the value of a specific field of an array field, you need to
-first get the field with bt_field_array_get_field().
-
-@sa ctfirarrayfieldtype
-@sa ctfirfields
-
-@addtogroup ctfirarrayfield
-@{
-*/
-
-extern struct bt_field *bt_field_array_borrow_field(
-               struct bt_field *array_field, uint64_t index);
-
-/** @} */
-
-/**
-@defgroup ctfirseqfield CTF IR sequence field
-@ingroup ctfirfields
-@brief CTF IR sequence field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>sequence field</em></strong> is a @field which
-contains an ordered list of zero or more @fields sharing the same @ft,
-and which is described by a @seqft.
-
-Before you can get a specific field of a sequence field with
-bt_field_sequence_get_field(), you need to set its current length
-@intfield with bt_field_sequence_set_length(). The integral value of
-the length field of a sequence field indicates the number of fields
-it contains.
+extern int bt_field_string_append(struct bt_field *field, const char *value);
 
-@sa ctfirseqfieldtype
-@sa ctfirfields
+extern int bt_field_string_append_with_length(struct bt_field *field,
+               const char *value, uint64_t length);
 
-@addtogroup ctfirseqfield
-@{
-*/
+extern int bt_field_string_clear(struct bt_field *field);
 
-extern struct bt_field *bt_field_sequence_borrow_field(
-               struct bt_field *sequence_field, uint64_t index);
+extern struct bt_field *bt_field_structure_borrow_member_field_by_index(
+               struct bt_field *field, uint64_t index);
 
-extern int64_t bt_field_sequence_get_length(struct bt_field *sequence_field);
+extern struct bt_field *bt_field_structure_borrow_member_field_by_name(
+               struct bt_field *field, const char *name);
 
-/**
-@brief Sets the length @intfield of the @seqfield \p sequence_field
-       to \p length_field.
+extern uint64_t bt_field_array_get_length(struct bt_field *field);
 
-The current integral value of \p length_field indicates the number of
-fields contained in \p sequence_field.
+extern struct bt_field *bt_field_array_borrow_element_field_by_index(
+               struct bt_field *field, uint64_t index);
 
-@param[in] sequence_field      Sequence field of which to set the
-                               length field.
-@param[in] length_field                Length field of \p sequence_field.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{sequence_field}
-@prenotnull{length_field}
-@preisseqfield{sequence_field}
-@preisintfield{length_field}
-@prehot{sequence_field}
-@postrefcountsame{sequence_field}
-@postsuccessrefcountinc{length_field}
-
-@sa bt_field_sequence_get_length(): Returns the length field of a
-       given sequence field.
-*/
-extern int bt_field_sequence_set_length(struct bt_field *sequence_field,
+extern int bt_field_dynamic_array_set_length(struct bt_field *field,
                uint64_t length);
 
-/** @} */
-
-/**
-@defgroup ctfirvarfield CTF IR variant field
-@ingroup ctfirfields
-@brief CTF IR variant field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>variant field</em></strong> is a @field which
-contains a current @field amongst one or more choices, and which is
-described by a @varft.
-
-Use bt_field_variant_get_field() to get the @field selected by
-a specific tag @enumfield. Once you call this function, you can call
-bt_field_variant_get_current_field() afterwards to get this last
-field again.
-
-@sa ctfirvarfieldtype
-@sa ctfirfields
-
-@addtogroup ctfirvarfield
-@{
-*/
-
-extern int bt_field_variant_set_tag_signed(struct bt_field *variant_field,
-               int64_t tag);
-
-extern int bt_field_variant_set_tag_unsigned(struct bt_field *variant_field,
-               uint64_t tag);
-
-extern int bt_field_variant_get_tag_signed(struct bt_field *variant_field,
-               int64_t *tag);
-
-extern int bt_field_variant_get_tag_unsigned(struct bt_field *variant_field,
-               uint64_t *tag);
+extern int bt_field_variant_select_option_field(struct bt_field *field,
+               uint64_t index);
 
-extern struct bt_field *bt_field_variant_borrow_current_field(
-               struct bt_field *variant_field);
+extern uint64_t bt_field_variant_get_selected_option_field_index(
+               struct bt_field *field);
 
-/** @} */
+extern struct bt_field *bt_field_variant_borrow_selected_option_field(
+               struct bt_field *field);
 
 #ifdef __cplusplus
 }
index 02fad682d8df17f971a804d6a0086b56498fd8c0..19625422655bc667cbd762cd67340aab1acd3679 100644 (file)
 extern "C" {
 #endif
 
+struct bt_stream_class;
 struct bt_packet_context_field;
 struct bt_field;
 
+extern
+struct bt_packet_context_field *bt_packet_context_field_create(
+               struct bt_stream_class *stream_class);
+
 extern
 struct bt_field *bt_packet_context_field_borrow_field(
                struct bt_packet_context_field *field);
index 9494d028e5409ffb046eda35404788e885630da6..1e14a8cdfb38c2a54b6214b84966cda9098cba0f 100644 (file)
 extern "C" {
 #endif
 
+struct bt_trace;
 struct bt_packet_header_field;
 struct bt_field;
 
+extern
+struct bt_packet_header_field *bt_packet_header_field_create(
+               struct bt_trace *trace);
+
 extern
 struct bt_field *bt_packet_header_field_borrow_field(
                struct bt_packet_header_field *field);
index 759c371a38849e023f0c12d72f94c6a9eff6c202..712903a550ca08002f7310f7efa07bec9af133a6 100644 (file)
 
 #include <stdbool.h>
 #include <babeltrace/assert-internal.h>
+#include <babeltrace/ctf-ir/clock-value.h>
 #include <babeltrace/ctf-ir/packet.h>
 #include <babeltrace/ctf-ir/fields.h>
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/ctf-ir/clock-value-set-internal.h>
-
-struct bt_packet_prop_uint64 {
-       enum bt_packet_property_availability avail;
-       uint64_t value;
-};
+#include <babeltrace/property-internal.h>
 
 struct bt_packet {
        struct bt_object base;
-       struct bt_field_wrapper *header;
-       struct bt_field_wrapper *context;
+       struct bt_field_wrapper *header_field;
+       struct bt_field_wrapper *context_field;
        struct bt_stream *stream;
-       struct bt_clock_value_set begin_cv_set;
-       struct bt_clock_value_set end_cv_set;
-       struct bt_packet_prop_uint64 discarded_event_counter;
-       struct bt_packet_prop_uint64 seq_num;
-       struct bt_packet_prop_uint64 discarded_event_count;
-       struct bt_packet_prop_uint64 discarded_packet_count;
-       bool props_are_set;
-
-       struct {
-               /*
-                * We keep this here to avoid keeping a reference on the
-                * previous packet object: those properties are
-                * snapshots of the previous packet's properties when
-                * calling bt_packet_create(). We know that the previous
-                * packet's properties do not change afterwards because
-                * we freeze the previous packet when bt_packet_create()
-                * is successful.
-                */
-               enum bt_packet_previous_packet_availability avail;
-               struct bt_packet_prop_uint64 discarded_event_counter;
-               struct bt_packet_prop_uint64 seq_num;
-               struct {
-                       enum bt_packet_property_availability avail;
-
-                       /* Owned by this (copy of previous packet's or NULL) */
-                       struct bt_clock_value *cv;
-               } default_end_cv;
-       } prev_packet_info;
-
-       int frozen;
+       struct bt_clock_value *default_beginning_cv;
+       struct bt_clock_value *default_end_cv;
+       struct bt_property_uint discarded_event_counter_snapshot;
+       struct bt_property_uint packet_counter_snapshot;
+       bool frozen;
 };
 
 BT_HIDDEN
@@ -95,30 +66,4 @@ void bt_packet_recycle(struct bt_packet *packet);
 BT_HIDDEN
 void bt_packet_destroy(struct bt_packet *packet);
 
-/*
- * Sets a packet's properties using its current context fields and its
- * previous packet's snapshotted properties (if any). The packet context
- * field must not be modified until the packet is recycled.
- *
- * This function does NOT set the `props_are_set` flag (does not
- * validate the properties): call bt_packet_validate_properties() to
- * mark the properties as definitely cached.
- */
-BT_HIDDEN
-int bt_packet_set_properties(struct bt_packet *packet);
-
-static inline
-void bt_packet_invalidate_properties(struct bt_packet *packet)
-{
-       BT_ASSERT(packet);
-       packet->props_are_set = false;
-}
-
-static inline
-void bt_packet_validate_properties(struct bt_packet *packet)
-{
-       BT_ASSERT(packet);
-       packet->props_are_set = true;
-}
-
 #endif /* BABELTRACE_CTF_IR_PACKET_INTERNAL_H */
index 6ff2fba8031a81f1d43a251c6bde5b6c551e9c9f..7ff057f5cf2489f53025ebc3a96697fba4d523a1 100644 (file)
 
 #include <stdint.h>
 
-/* For bt_get() */
-#include <babeltrace/ref.h>
+/* For enum bt_property_availability */
+#include <babeltrace/property.h>
 
-/* For bt_bool */
-#include <babeltrace/types.h>
+/* For enum bt_clock_value_status */
+#include <babeltrace/ctf-ir/clock-value.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/**
-@defgroup ctfirpacket CTF IR packet
-@ingroup ctfir
-@brief CTF IR packet.
-
-@code
-#include <babeltrace/ctf-ir/packet.h>
-@endcode
-
-A CTF IR <strong><em>packet</em></strong> is a container of packet
-fields, that is, of the <strong>trace packet header</strong> and
-<strong>stream packet context</strong> fields.
-
-As a reminder, here's the structure of a CTF packet:
-
-@imgpacketstructure
-
-You can create a CTF IR packet \em from a
-\link ctfirstream CTF IR stream\endlink with bt_packet_create(). The
-stream you use to create a packet object becomes its parent.
-
-When you set the trace packet header and stream packet context fields of
-a packet with resp. bt_packet_set_header() and
-bt_packet_set_context(), their field type \em must be equivalent to
-the field types returned by resp. bt_trace_get_packet_header_type()
-and bt_stream_class_get_packet_context_type() for its parent trace
-class and stream class.
-
-You can attach a packet object to a \link ctfirevent CTF IR
-event\endlink object with bt_event_set_packet().
-
-As with any Babeltrace object, CTF IR packet objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-bt_notification_event_create() \em freezes its event parameter on
-success, which in turns freezes the event's associated packet object.
-This is the only way that a CTF IR packet object can be frozen.
-You cannot modify a frozen packet: it is considered immutable,
-except for \link refs reference counting\endlink.
-
-@sa ctfirstream
-@sa ctfirstreamclass
-@sa ctfirtraceclass
-
-@file
-@brief CTF IR packet type and functions.
-@sa ctfirpacket
-
-@addtogroup ctfirpacket
-@{
-*/
-
-/**
-@struct bt_packet
-@brief A CTF IR packet.
-@sa ctfirpacket
-*/
 struct bt_packet;
 struct bt_packet_header_field;
 struct bt_packet_context_field;
 struct bt_stream;
 struct bt_clock_value;
-struct bt_clock_class;
-
-enum bt_packet_previous_packet_availability {
-       BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_ERROR = -1,
-       BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_AVAILABLE,
-       BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NOT_AVAILABLE,
-       BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE,
-};
-
-enum bt_packet_property_availability {
-       BT_PACKET_PROPERTY_AVAILABILITY_ERROR = -1,
-       BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE,
-       BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE,
-};
-
-/**
-@name Creation and parent access functions
-@{
-*/
-
-/**
-@brief Creates a default CTF IR packet with \p stream as its parent
-       CTF IR stream.
-
-On success, the packet object's trace packet header and stream packet
-context fields are not set. You can set them with resp.
-bt_packet_set_header() and bt_packet_set_context().
-
-@param[in] stream      Parent CTF IR stream of the packet to create.
-@returns               Created packet, or \c NULL on error.
-
-@prenotnull{stream}
-@postsuccessrefcountret1
-*/
-extern struct bt_packet *bt_packet_create(struct bt_stream *stream,
-               enum bt_packet_previous_packet_availability previous_packet_availability,
-               struct bt_packet *previous_packet);
 
-extern struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet);
-
-/**
-@brief Returns the parent CTF IR stream of the CTF IR packet \p packet.
-
-This function returns a reference to the stream which was used to create
-the packet object in the first place with bt_packet_create().
-
-@param[in] packet      Packet of which to get the parent stream.
-@returns               Parent stream of \p packet, or \c NULL on error.
-
-@prenotnull{packet}
-@postrefcountsame{packet}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_stream *bt_packet_get_stream(
-               struct bt_packet *packet)
-{
-       return bt_get(bt_packet_borrow_stream(packet));
-}
-
-/** @} */
+extern struct bt_packet *bt_packet_create(struct bt_stream *stream);
 
-/**
-@name Contained fields functions
-@{
-*/
+extern struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet);
 
 extern
-struct bt_field *bt_packet_borrow_header(struct bt_packet *packet);
+struct bt_field *bt_packet_borrow_header_field(struct bt_packet *packet);
 
 extern
-int bt_packet_move_header(struct bt_packet *packet,
+int bt_packet_move_header_field(struct bt_packet *packet,
                struct bt_packet_header_field *header);
 
 extern
-struct bt_field *bt_packet_borrow_context(struct bt_packet *packet);
+struct bt_field *bt_packet_borrow_context_field(struct bt_packet *packet);
 
 extern
-int bt_packet_move_context(struct bt_packet *packet,
+int bt_packet_move_context_field(struct bt_packet *packet,
                struct bt_packet_context_field *context);
 
-/** @} */
-
-extern
-enum bt_packet_property_availability
-bt_packet_borrow_default_beginning_clock_value(struct bt_packet *packet,
-               struct bt_clock_value **clock_value);
-
 extern
-enum bt_packet_property_availability
-bt_packet_borrow_default_end_clock_value(struct bt_packet *packet,
-               struct bt_clock_value **clock_value);
+enum bt_clock_value_status bt_packet_borrow_default_beginning_clock_value(
+               struct bt_packet *packet, struct bt_clock_value **clock_value);
 
 extern
-enum bt_packet_previous_packet_availability
-bt_packet_get_previous_packet_availability(struct bt_packet *packet);
+int bt_packet_set_default_beginning_clock_value(struct bt_packet *packet,
+               uint64_t value_cycles);
 
 extern
-enum bt_packet_property_availability
-bt_packet_borrow_previous_packet_default_end_clock_value(
+enum bt_clock_value_status bt_packet_borrow_default_end_clock_valeu(
                struct bt_packet *packet, struct bt_clock_value **clock_value);
 
 extern
-enum bt_packet_property_availability bt_packet_get_discarded_event_counter(
-               struct bt_packet *packet, uint64_t *counter);
+int bt_packet_set_default_end_clock_value(struct bt_packet *packet,
+               uint64_t value_cycles);
 
 extern
-enum bt_packet_property_availability bt_packet_get_sequence_number(
-               struct bt_packet *packet, uint64_t *sequence_number);
+enum bt_property_availability bt_packet_get_discarded_event_counter_snapshot(
+               struct bt_packet *packet, uint64_t *value);
 
 extern
-enum bt_packet_property_availability bt_packet_get_discarded_event_count(
-               struct bt_packet *packet, uint64_t *count);
+int bt_packet_set_discarded_event_counter_snapshot(struct bt_packet *packet,
+               uint64_t value);
 
 extern
-enum bt_packet_property_availability bt_packet_get_discarded_packet_count(
-               struct bt_packet *packet, uint64_t *count);
+enum bt_property_availability bt_packet_get_packet_counter_snapshot(
+               struct bt_packet *packet, uint64_t *value);
 
-/** @} */
+extern
+int bt_packet_set_packet_counter_snapshot(struct bt_packet *packet,
+               uint64_t value);
 
 #ifdef __cplusplus
 }
diff --git a/include/babeltrace/ctf-ir/resolve-field-path-internal.h b/include/babeltrace/ctf-ir/resolve-field-path-internal.h
new file mode 100644 (file)
index 0000000..f2d0321
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef BABELTRACE_CTF_IR_RESOLVE_FIELD_PATH_INTERNAL
+#define BABELTRACE_CTF_IR_RESOLVE_FIELD_PATH_INTERNAL
+
+/*
+ * BabelTrace - CTF IR: Field path
+ *
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <babeltrace/object-internal.h>
+#include <babeltrace/ctf-ir/field-types.h>
+#include <babeltrace/ctf-ir/field-path.h>
+#include <glib.h>
+
+struct bt_resolve_field_path_context {
+       struct bt_field_type *packet_header;
+       struct bt_field_type *packet_context;
+       struct bt_field_type *event_header;
+       struct bt_field_type *event_common_context;
+       struct bt_field_type *event_specific_context;
+       struct bt_field_type *event_payload;
+};
+
+BT_HIDDEN
+int bt_resolve_field_paths(struct bt_field_type *ft,
+               struct bt_resolve_field_path_context *ctx);
+
+#endif /* BABELTRACE_CTF_IR_RESOLVE_FIELD_PATH_INTERNAL */
index 6a167c9371267cf2302844cf46ca6de1f5b7ad3a..844a0c713de80550330b06ad6358e0d0cfa5b1fb 100644 (file)
 
 #include <babeltrace/assert-internal.h>
 #include <babeltrace/common-internal.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
-#include <babeltrace/ctf-ir/visitor.h>
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/object-pool-internal.h>
 
 struct bt_stream_class {
        struct bt_object base;
-       GString *name;
 
-       /* Array of pointers to event class addresses */
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       uint64_t id;
+       bool assigns_automatic_event_class_id;
+       bool assigns_automatic_stream_id;
+       bool packets_have_discarded_event_counter_snapshot;
+       bool packets_have_packet_counter_snapshot;
+       bool packets_have_default_beginning_cv;
+       bool packets_have_default_end_cv;
+       struct bt_field_type *packet_context_ft;
+       struct bt_field_type *event_header_ft;
+       struct bt_field_type *event_common_context_ft;
+       struct bt_clock_class *default_clock_class;
+
+       /* Array of `struct bt_event_class *` */
        GPtrArray *event_classes;
 
-       /* event class id (int64_t) to event class address */
-       GHashTable *event_classes_ht;
-       int id_set;
-       int64_t id;
-       int64_t next_event_id;
-       struct bt_field_type *packet_context_field_type;
-       struct bt_field_type *event_header_field_type;
-       struct bt_field_type *event_context_field_type;
-       int frozen;
-       int byte_order;
-
-       /*
-        * This flag indicates if the stream class is valid. A valid
-        * stream class is _always_ frozen.
-        */
-       int valid;
-
-       /*
-        * Unique clock class mapped to any field type within this
-        * stream class, including all the stream class's event class
-        * field types. This is only set if the stream class is frozen.
-        *
-        * If the stream class is frozen and this is still NULL, it is
-        * still possible that it becomes non-NULL because
-        * bt_stream_class_add_event_class() can add an event class
-        * containing a field type mapped to some clock class. In this
-        * case, this is the mapped clock class, and at this point, both
-        * the new event class and the stream class are frozen, so the
-        * next added event classes are expected to contain field types
-        * which only map to this specific clock class.
-        *
-        * If this is a CTF writer stream class, then this is the
-        * backing clock class of the `clock` member above.
-        */
-       struct bt_clock_class *clock_class;
-
        /* Pool of `struct bt_field_wrapper *` */
        struct bt_object_pool event_header_field_pool;
 
        /* Pool of `struct bt_field_wrapper *` */
        struct bt_object_pool packet_context_field_pool;
-};
-
-struct bt_event_class;
 
-BT_HIDDEN
-void bt_stream_class_freeze(struct bt_stream_class *stream_class);
+       bool frozen;
+};
 
 BT_HIDDEN
-int bt_stream_class_validate_single_clock_class(
-               struct bt_stream_class *stream_class,
-               struct bt_clock_class **expected_clock_class);
+void _bt_stream_class_freeze(struct bt_stream_class *stream_class);
 
-BT_HIDDEN
-int bt_stream_class_visit(struct bt_stream_class *stream_class,
-               bt_visitor visitor, void *data);
+#ifdef BT_DEV_MODE
+# define bt_stream_class_freeze                _bt_stream_class_freeze
+#else
+# define bt_stream_class_freeze(_sc)
+#endif
 
 static inline
-void _bt_stream_class_set_id(
-               struct bt_stream_class *stream_class, int64_t id)
+struct bt_trace *bt_stream_class_borrow_trace_inline(
+               struct bt_stream_class *stream_class)
 {
        BT_ASSERT(stream_class);
-       stream_class->id = id;
-       stream_class->id_set = 1;
-       BT_LOGV("Set stream class's ID (internal): "
-               "addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class));
-}
-
-static inline
-int bt_stream_class_set_id_no_check(
-               struct bt_stream_class *stream_class, int64_t id)
-{
-       _bt_stream_class_set_id(stream_class, id);
-       return 0;
+       return (void *) bt_object_borrow_parent(&stream_class->base);
 }
 
 #endif /* BABELTRACE_CTF_IR_STREAM_CLASS_INTERNAL_H */
index 225ea45079a28c4d023194975ea9acc39adb56db..ca0b9ef954581a4b8a53b30b2675f68cae6f23ed 100644 (file)
 
 #include <stdint.h>
 
-/* For bt_get() */
-#include <babeltrace/ref.h>
-
-/* For bt_visitor */
-#include <babeltrace/ctf-ir/visitor.h>
+/* For bt_bool */
+#include <babeltrace/types.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/**
-@defgroup ctfirstreamclass CTF IR stream class
-@ingroup ctfir
-@brief CTF IR stream class.
-
-@code
-#include <babeltrace/ctf-ir/stream-class.h>
-@endcode
-
-@note
-See \ref ctfwriterstreamclass which documents additional CTF IR stream
-class functions exclusive to the CTF writer mode.
-
-A CTF IR <strong><em>stream class</em></strong> is a template that you
-can use to create concrete \link ctfirstream CTF IR streams\endlink.
-
-A stream class has the following properties, both of which \em must
-be unique amongst all the stream classes contained in the same
-\link ctfirtraceclass CTF IR trace class\endlink:
-
-- A \b name.
-- A numeric \b ID.
-
-In the Babeltrace CTF IR system, a \link ctfirtraceclass trace class\endlink
-contains zero or more stream classes,
-and a stream class contains zero or more
-\link ctfireventclass event classes\endlink.
-You can add an event class
-to a stream class with bt_stream_class_add_event_class().
-You can add a stream class to a trace class with
-bt_trace_add_stream_class().
-
-A stream class owns three \link ctfirfieldtypes field types\endlink:
-
-- An optional <strong>stream packet context</strong> field type, which
-  represents the \c stream.packet.context CTF scope.
-- An optional <strong>stream event header</strong> field type, which
-  represents the \c stream.event.header CTF scope.
-- An optional <strong>stream event context</strong> field type, which
-  represents the \c stream.event.context CTF scope.
-
-Those three field types \em must be structure field types as of
-Babeltrace \btversion.
-
-As per the CTF specification, the event header field type \em must
-contain a field named \c id if the stream class contains more than one
-event class.
-
-As a reminder, here's the structure of a CTF packet:
-
-@imgpacketstructure
-
-Before you can create a stream from a stream class with
-bt_stream_create(), you \em must add the prepared stream class to a
-trace class by calling bt_trace_add_stream_class().
-
-As with any Babeltrace object, CTF IR stream class objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-The following functions \em freeze their stream class parameter on
-success:
-
-- bt_trace_add_stream_class()
-- bt_event_create()
-- bt_writer_create_stream()
-  (\link ctfwriter CTF writer\endlink mode only)
-
-You cannot modify a frozen stream class: it is considered immutable,
-except for:
-
-- Adding an event class to it with
-  bt_stream_class_add_event_class(). If the stream class's parent
-  \link ctfirtraceclass trace class\endlink is static, however,
-  you cannot call bt_stream_class_add_event_class()
-  (see bt_trace_is_static() and bt_trace_set_is_static()).
-- \link refs Reference counting\endlink.
-
-@sa ctfirstream
-@sa ctfireventclass
-@sa ctfirtraceclass
-@sa ctfwriterstreamclass
-
-@file
-@brief CTF IR stream class type and functions.
-@sa ctfirstreamclass
-
-@addtogroup ctfirstreamclass
-@{
-*/
-
-/**
-@struct bt_stream_class
-@brief A CTF IR stream class.
-@sa ctfirstreamclass
-*/
+struct bt_trace;
 struct bt_stream_class;
 struct bt_event_class;
-struct bt_clock;
+struct bt_clock_class;
 struct bt_event_header_field;
 struct bt_packet_context_field;
 
-/**
-@name Creation and parent access functions
-@{
-*/
-
-/**
-@brief Creates a default CTF IR stream class named \p name­, or a
-       default unnamed stream class if \p name is \c NULL.
-
-On success, the packet context field type of the created stream class
-has the following fields:
-
-- <code>timestamp_begin</code>: a 64-bit unsigned integer field type.
-- <code>timestamp_end</code>: a 64-bit unsigned integer field type.
-- <code>content_size</code>: a 64-bit unsigned integer field type.
-- <code>packet_size</code>: a 64-bit unsigned integer field type.
-- <code>events_discarded</code>: a 64-bit unsigned integer field type.
-
-On success, the event header field type of the created stream class
-has the following fields:
-
-- <code>code</code>: a 32-bit unsigned integer field type.
-- <code>timestamp</code>: a 64-bit unsigned integer field type.
+extern struct bt_stream_class *bt_stream_class_create(struct bt_trace *trace);
 
-You can modify those default field types after the stream class is
-created with bt_stream_class_set_packet_context_field_type() and
-bt_stream_class_set_event_header_field_type().
-
-@param[in] name        Name of the stream class to create (copied on success),
-               or \c NULL to create an unnamed stream class.
-@returns       Created default stream class, or \c NULL on error.
-
-@postsuccessrefcountret1
-
-@sa bt_stream_class_create_empty(): Creates an empty stream class.
-*/
-extern struct bt_stream_class *bt_stream_class_create(const char *name);
+extern struct bt_stream_class *bt_stream_class_create_with_id(
+               struct bt_trace *trace, uint64_t id);
 
 extern struct bt_trace *bt_stream_class_borrow_trace(
                struct bt_stream_class *stream_class);
 
-/**
-@brief Returns the parent CTF IR trace class of the CTF IR stream
-       class \p stream_class.
-
-It is possible that the stream class was not added to a trace class
-yet, in which case this function returns \c NULL. You can add a
-stream class to a trace class with
-bt_trace_add_stream_class().
-
-@param[in] stream_class        Stream class of which to get the parent
-                       trace class.
-@returns               Parent trace class of \p stream_class,
-                       or \c NULL if \p stream_class was not
-                       added to a trace class yet or on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-@postsuccessrefcountretinc
-
-@sa bt_trace_add_stream_class(): Add a stream class to
-       a trace class.
-*/
-static inline
-struct bt_trace *bt_stream_class_get_trace(
-               struct bt_stream_class *stream_class)
-{
-       return bt_get(bt_stream_class_borrow_trace(stream_class));
-}
-
-/** @} */
-
-/**
-@name Properties functions
-@{
-*/
-
-/**
-@brief Returns the name of the CTF IR stream class \p stream_class.
-
-On success, \p stream_class remains the sole owner of the returned
-string.
-
-@param[in] stream_class        Stream class of which to get the name.
-@returns               Name of stream class \p stream_class, or
-                       \c NULL if \p stream_class is unnamed or
-                       on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-
-@sa bt_stream_class_set_name(): Sets the name of a given
-       stream class.
-*/
 extern const char *bt_stream_class_get_name(
                struct bt_stream_class *stream_class);
 
-/**
-@brief Sets the name of the CTF IR stream class
-       \p stream_class to \p name, or resets the name of
-       \p stream_class.
-
-If \p name is not \c NULL, it must be unique amongst the names of all
-the stream classes of the trace class to which you eventually add
-\p stream_class.
-
-@param[in] stream_class        Stream class of which to set the name.
-@param[in] name                Name of the stream class (copied on success), or
-                       \c NULL to reset the name of \p stream_class
-                       (make it unnamed).
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{stream_class}
-@prehot{stream_class}
-@postrefcountsame{stream_class}
-
-@sa bt_stream_class_get_name(): Returns the name of a given
-       stream class.
-*/
-extern int bt_stream_class_set_name(
-               struct bt_stream_class *stream_class, const char *name);
-
-/**
-@brief Returns the numeric ID of the CTF IR stream class \p stream_class.
-
-@param[in] stream_class        Stream class of which to get the numeric ID.
-@returns               ID of stream class \p stream_class, or a
-                       negative value on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-
-@sa bt_stream_class_set_id(): Sets the numeric ID of a given
-       stream class.
-*/
-extern int64_t bt_stream_class_get_id(
-               struct bt_stream_class *stream_class);
-
-/**
-@brief Sets the numeric ID of the CTF IR stream class
-       \p stream_class to \p id.
-
-\p id must be unique amongst the IDs of all the stream classes
-of the trace class to which you eventually add \p stream_class.
+extern int bt_stream_class_set_name(struct bt_stream_class *stream_class,
+               const char *name);
 
-@param[in] stream_class        Stream class of which to set the numeric ID.
-@param[in] id          ID of the stream class.
-@returns               0 on success, or a negative value on error.
+extern bt_bool bt_stream_class_assigns_automatic_event_class_id(
+               struct bt_stream_class *stream_class);
 
-@prenotnull{stream_class}
-@prehot{stream_class}
-@pre \p id is lesser than or equal to 9223372036854775807 (\c INT64_MAX).
-@postrefcountsame{stream_class}
+extern int bt_stream_class_set_assigns_automatic_event_class_id(
+               struct bt_stream_class *stream_class, bt_bool value);
 
-@sa bt_stream_class_get_id(): Returns the numeric ID of a given
-       stream class.
-*/
-extern int bt_stream_class_set_id(
-               struct bt_stream_class *stream_class, uint64_t id);
+extern bt_bool bt_stream_class_assigns_automatic_stream_id(
+               struct bt_stream_class *stream_class);
 
-/** @} */
+extern int bt_stream_class_set_assigns_automatic_stream_id(
+               struct bt_stream_class *stream_class, bt_bool value);
 
-/**
-@name Contained field types functions
-@{
-*/
+extern uint64_t bt_stream_class_get_id(struct bt_stream_class *stream_class);
 
 extern struct bt_field_type *bt_stream_class_borrow_packet_context_field_type(
                struct bt_stream_class *stream_class);
 
-/**
-@brief Returns the packet context field type of the CTF IR stream class
-       \p stream_class.
-
-@param[in] stream_class        Stream class of which to get the packet
-                       context field type.
-@returns               Packet context field type of \p stream_class,
-                       or \c NULL if \p stream_class has no packet context
-                       field type or on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-@post <strong>On success, if the return value is a field type</strong>, its
-       reference count is incremented.
-
-@sa bt_stream_class_set_packet_context_field_type(): Sets the packet
-       context field type of a given stream class.
-*/
-static inline
-struct bt_field_type *bt_stream_class_get_packet_context_field_type(
-               struct bt_stream_class *stream_class)
-{
-       return bt_get(bt_stream_class_borrow_packet_context_field_type(
-               stream_class));
-}
-
-extern
-struct bt_packet_context_field *bt_stream_class_create_packet_context_field(
-               struct bt_stream_class *stream_class);
-
-/**
-@brief Sets the packet context field type of the CTF IR stream class
-       \p stream_class to \p packet_context_type, or unsets the current packet
-       context field type from \p stream_class.
-
-If \p packet_context_type is \c NULL, then this function unsets the current
-packet context field type from \p stream_class, effectively making
-\p stream_class a stream class without a packet context field type.
-
-As of Babeltrace \btversion, if \p packet_context_type is not \c NULL,
-\p packet_context_type \em must be a CTF IR structure field type object.
-
-@param[in] stream_class                Stream class of which to set the packet
-                               context field type.
-@param[in] packet_context_type Packet context field type, or \c NULL to unset
-                               the current packet context field type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{stream_class}
-@prehot{stream_class}
-@pre <strong>\p packet_context_type, if not \c NULL</strong>, is a CTF IR
-       structure field type.
-@postrefcountsame{stream_class}
-@post <strong>On success, if \p packet_context_type is not \c NULL</strong>,
-       the reference count of \p packet_context_type is incremented.
-
-@sa bt_stream_class_get_packet_context_field_type(): Returns the packet
-       context field type of a given stream class.
-*/
 extern int bt_stream_class_set_packet_context_field_type(
                struct bt_stream_class *stream_class,
-               struct bt_field_type *packet_context_type);
+               struct bt_field_type *field_type);
 
 extern struct bt_field_type *
 bt_stream_class_borrow_event_header_field_type(
                struct bt_stream_class *stream_class);
 
-/**
-@brief Returns the event header field type of the CTF IR stream class
-       \p stream_class.
-
-@param[in] stream_class        Stream class of which to get the event header
-                       field type.
-@returns               Event header field type of \p stream_class,
-                       or \c NULL if \p stream_class has no event header field
-                       type or on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-@post <strong>On success, if the return value is a field type</strong>, its
-       reference count is incremented.
-
-@sa bt_stream_class_set_event_header_field_type(): Sets the event
-       header field type of a given stream class.
-*/
-static inline
-struct bt_field_type *bt_stream_class_get_event_header_field_type(
-               struct bt_stream_class *stream_class)
-{
-       return bt_get(bt_stream_class_borrow_event_header_field_type(
-               stream_class));
-}
-
-/**
-@brief Sets the event header field type of the CTF IR stream class
-       \p stream_class to \p event_header_type, or unsets the current event
-       header field type from \p stream_class.
-
-If \p event_header_type is \c NULL, then this function unsets the current
-event header field type from \p stream_class, effectively making \p stream_class
-a stream class without a event header field type.
-
-As of Babeltrace \btversion, if \p event_header_type is not \c NULL,
-\p event_header_type \em must be a CTF IR structure field type object.
-
-@param[in] stream_class                Stream class of which to set the event
-                               header field type.
-@param[in] event_header_type   Event header field type, or \c NULL to unset
-                               the current event header field type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{stream_class}
-@prehot{stream_class}
-@pre <strong>\p event_header_type, if not \c NULL</strong>, is a CTF IR
-       structure field type.
-@postrefcountsame{stream_class}
-@post <strong>On success, if \p event_header_type is not \c NULL</strong>,
-       the reference count of \p event_header_type is incremented.
-
-@sa bt_stream_class_get_event_header_field_type(): Returns the event
-       header field type of a given stream class.
-*/
 extern int bt_stream_class_set_event_header_field_type(
                struct bt_stream_class *stream_class,
-               struct bt_field_type *event_header_type);
-
-extern struct bt_event_header_field *bt_stream_class_create_event_header_field(
-               struct bt_stream_class *stream_class);
+               struct bt_field_type *field_type);
 
 extern struct bt_field_type *
-bt_stream_class_borrow_event_context_field_type(
+bt_stream_class_borrow_event_common_context_field_type(
                struct bt_stream_class *stream_class);
 
-/**
-@brief Returns the event context field type of the CTF IR stream class
-       \p stream_class.
-
-@param[in] stream_class        Stream class of which to get the event context
-                       field type.
-@returns               Event context field type of \p stream_class,
-                       or \c NULL if \p stream_class has no event context field
-                       type or on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-@post <strong>On success, if the return value is a field type</strong>,
-       its reference count is incremented.
-
-
-@sa bt_stream_class_set_event_context_field_type(): Sets the event
-       context field type of a given stream class.
-*/
-static inline
-struct bt_field_type *
-bt_stream_class_get_event_context_field_type(
-               struct bt_stream_class *stream_class)
-{
-       return bt_get(bt_stream_class_borrow_event_context_field_type(
-               stream_class));
-}
-
-/**
-@brief Sets the event context field type of the CTF IR stream class
-       \p stream_class to \p event_context_type, or unsets the current event
-       context field type from \p stream_class.
-
-If \p event_context_type is \c NULL, then this function unsets the current
-event context field type from \p stream_class, effectively making \p
-stream_class a stream class without a event context field type.
-
-As of Babeltrace \btversion, if \p event_context_type is not \c NULL,
-\p event_context_type \em must be a CTF IR structure field type object.
-
-@param[in] stream_class                Stream class of which to set the packet
-                               context field type.
-@param[in] event_context_type  Event context field type, or \c NULL to unset
-                               the current event context field type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{stream_class}
-@prehot{stream_class}
-@pre <strong>\p event_context_type, if not \c NULL</strong>, is a CTF IR
-       structure field type.
-@postrefcountsame{stream_class}
-@post <strong>On success, if \p event_context_type is not \c NULL</strong>,
-       the reference count of \p event_context_type is incremented.
-
-@sa bt_stream_class_get_event_context_field_type(): Returns the event context
-       field type of a given stream class.
-*/
-extern int bt_stream_class_set_event_context_field_type(
+extern int bt_stream_class_set_event_common_context_field_type(
                struct bt_stream_class *stream_class,
-               struct bt_field_type *event_context_type);
-
-/** @} */
-
-/**
-@name Event class children functions
-@{
-*/
-
-/**
-@brief Returns the number of event classes contained in the
-       CTF IR stream class \p stream_class.
+               struct bt_field_type *field_type);
 
-@param[in] stream_class        Stream class of which to get the number
-                       of children event classes.
-@returns               Number of children event classes
-                       contained in \p stream_class, or
-                       a negative value on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-*/
-extern int64_t bt_stream_class_get_event_class_count(
+extern uint64_t bt_stream_class_get_event_class_count(
                struct bt_stream_class *stream_class);
 
 extern struct bt_event_class *bt_stream_class_borrow_event_class_by_index(
                struct bt_stream_class *stream_class, uint64_t index);
 
-/**
-@brief  Returns the event class at index \p index in the CTF IR stream
-       class \p stream_class.
-
-@param[in] stream_class        Stream class of which to get the event class.
-@param[in] index       Index of the event class to find.
-@returns               Event class at index \p index, or \c NULL
-                       on error.
-
-@prenotnull{stream_class}
-@pre \p index is lesser than the number of event classes contained in the
-       stream class \p stream_class (see
-       bt_stream_class_get_event_class_count()).
-@postrefcountsame{stream_class}
-@postsuccessrefcountretinc
-
-@sa bt_stream_class_get_event_class_by_id(): Finds an event class
-       by ID.
-*/
-static inline
-struct bt_event_class *bt_stream_class_get_event_class_by_index(
-               struct bt_stream_class *stream_class, uint64_t index)
-{
-       return bt_get(bt_stream_class_borrow_event_class_by_index(stream_class,
-               index));
-}
-
 extern struct bt_event_class *bt_stream_class_borrow_event_class_by_id(
                struct bt_stream_class *stream_class, uint64_t id);
 
-/**
-@brief  Returns the event class with ID \c id found in the CTF IR stream
-       class \p stream_class.
-
-@param[in] stream_class        Stream class of which to get the event class.
-@param[in] id          ID of the event class to find.
-@returns               Event class with ID \p id, or \c NULL
-                       on error.
-
-@prenotnull{stream_class}
-@postrefcountsame{stream_class}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_event_class *bt_stream_class_get_event_class_by_id(
-               struct bt_stream_class *stream_class, uint64_t id)
-{
-       return bt_get(bt_stream_class_borrow_event_class_by_id(stream_class,
-               id));
-}
-
-/**
-@brief Adds the CTF IR event class \p event_class to the
-       CTF IR stream class \p stream_class.
-
-On success, \p event_class becomes the child of \p stream_class.
-
-You can only add a given event class to one stream class.
-
-You can call this function even if \p stream_class is frozen. Adding
-event classes is the only operation that is permitted
-on a frozen stream class.
-
-This function tries to resolve the needed
-\link ctfirfieldtypes CTF IR field type\endlink of the dynamic field
-types that are found anywhere in the context or payload field
-types of \p event_class. If any automatic resolving fails:
-
-- If the needed field type should be found in one of the root field
-  types of \p event_class or \p stream_class, this function fails.
-- If \p stream_class is the child of a
-  \link ctfirtraceclass CTF IR trace class\endlink (it was added
-  with bt_trace_add_stream_class()), this function fails.
-- If \p stream_class is not the child of a trace class yet, the
-  automatic resolving is reported to the next call to
-  bt_trace_add_stream_class() with \p stream_class.
-
-@param[in] stream_class        Stream class to which to add \p event_class.
-@param[in] event_class Event class to add to \p stream_class.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{stream_class}
-@prenotnull{event_class}
-@prehot{event_class}
-@postrefcountsame{stream_class}
-@postsuccessrefcountinc{event_class}
-@postsuccessfrozen{event_class}
-*/
-extern int bt_stream_class_add_event_class(
+extern int bt_stream_class_set_default_clock_class(
                struct bt_stream_class *stream_class,
-               struct bt_event_class *event_class);
+               struct bt_clock_class *clock_class);
+
+extern struct bt_clock_class *bt_stream_class_borrow_default_clock_class(
+               struct bt_stream_class *stream_class);
 
-/** @} */
+extern bt_bool bt_stream_class_default_clock_is_always_known(
+               struct bt_stream_class *stream_class);
 
-/**
-@name Misc. function
-@{
-*/
+extern bt_bool bt_stream_class_packets_have_discarded_event_counter_snapshot(
+               struct bt_stream_class *stream_class);
 
-/**
-@brief Accepts the visitor \p visitor to visit the hierarchy of the
-       CTF IR stream class \p stream_class.
+extern int bt_stream_class_set_packets_have_discarded_event_counter_snapshot(
+               struct bt_stream_class *stream_class, bt_bool value);
 
-This function traverses the hierarchy of \p stream_class in pre-order
-and calls \p visitor on each element.
+extern bt_bool bt_stream_class_packets_have_packet_counter_snapshot(
+               struct bt_stream_class *stream_class);
 
-The stream class itself is visited first, and then all its children
-event classes.
+extern int bt_stream_class_set_packets_have_packet_counter_snapshot(
+               struct bt_stream_class *stream_class, bt_bool value);
 
-@param[in] stream_class        Stream class to visit.
-@param[in] visitor     Visiting function.
-@param[in] data                User data.
-@returns               0 on success, or a negative value on error.
+extern bt_bool bt_stream_class_packets_have_default_beginning_clock_value(
+               struct bt_stream_class *stream_class);
 
-@prenotnull{stream_class}
-@prenotnull{visitor}
-*/
-extern int bt_stream_class_visit(struct bt_stream_class *stream_class,
-               bt_visitor visitor, void *data);
+extern int bt_stream_class_set_packets_have_default_beginning_clock_value(
+               struct bt_stream_class *stream_class, bt_bool value);
 
-/** @} */
+extern bt_bool bt_stream_class_packets_have_default_end_clock_value(
+               struct bt_stream_class *stream_class);
 
-/** @} */
+extern int bt_stream_class_set_packets_have_default_end_clock_value(
+               struct bt_stream_class *stream_class, bt_bool value);
 
 #ifdef __cplusplus
 }
index 19cd8c2f8658e92ae80d50577ec2bb6f57c8a99d..0cbd18b561539217621099ac837370d2f625dc74 100644 (file)
@@ -27,8 +27,6 @@
  * SOFTWARE.
  */
 
-#include <babeltrace/assert-pre-internal.h>
-#include <babeltrace/assert-internal.h>
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
 #include <babeltrace/object-internal.h>
@@ -41,12 +39,32 @@ struct bt_stream;
 
 struct bt_stream {
        struct bt_object base;
-       int64_t id;
-       struct bt_stream_class *stream_class;
-       GString *name;
+
+       /* Weak: parent is this class's trace */
+       struct bt_stream_class *class;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       uint64_t id;
 
        /* Pool of `struct bt_packet *` */
        struct bt_object_pool packet_pool;
+
+       bool frozen;
 };
 
+BT_HIDDEN
+void _bt_stream_freeze(struct bt_stream *stream);
+
+#ifdef BT_DEV_MODE
+# define bt_stream_freeze              _bt_stream_freeze
+#else
+# define bt_stream_freeze(_stream)
+#endif
+
 #endif /* BABELTRACE_CTF_IR_STREAM_INTERNAL_H */
index 5f0fd26bfda28c1522f946ce7cec5136032c2fab..69829280c904e5cb4f7b3c65a01e9469853ae4a6 100644 (file)
@@ -30,8 +30,8 @@
  * http://www.efficios.com/ctf
  */
 
-/* For bt_get() */
-#include <babeltrace/ref.h>
+/* For enum bt_property_availability */
+#include <babeltrace/property.h>
 
 #include <stdint.h>
 
 extern "C" {
 #endif
 
-struct bt_stream_class;
-
-/**
-@defgroup ctfirstream CTF IR stream
-@ingroup ctfir
-@brief CTF IR stream.
-
-@code
-#include <babeltrace/ctf-ir/stream.h>
-@endcode
-
-@note
-See \ref ctfwriterstream which documents additional CTF IR stream
-functions exclusive to the CTF writer mode.
-
-A CTF IR <strong><em>stream</em></strong> is an instance of a
-\link ctfirstreamclass CTF IR stream class\endlink.
-
-You can obtain a CTF IR stream object in two different modes:
-
-- <strong>Normal mode</strong>: use bt_stream_create() or
-  bt_stream_create_with_id() with a stream class having a
-  \link ctfirtraceclass CTF IR trace class\endlink parent
-  \em not created by a \link ctfwriter CTF writer\endlink object to
-  create a default stream.
-- <strong>CTF writer mode</strong>: use bt_stream_create() with
-  a stream class having a trace class parent created by a CTF writer
-  object, or use bt_writer_create_stream().
-
-A CTF IR stream object represents a CTF stream, that is, a sequence of
-packets containing events:
-
-@imgtracestructure
-
-A CTF IR stream does not contain, however, actual \link ctfirpacket CTF
-IR packet\endlink objects: it only acts as a common parent to identify
-the original CTF stream of packet objects.
-
-As with any Babeltrace object, CTF IR stream objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-@sa ctfirstreamclass
-@sa ctfirpacket
-@sa ctfwriterstream
-
-@file
-@brief CTF IR stream type and functions.
-@sa ctfirstream
-
-@addtogroup ctfirstream
-@{
-*/
-
-/**
-@struct bt_stream
-@brief A CTF IR stream.
-@sa ctfirstream
-@sa ctfwriterstream
-*/
 struct bt_stream;
-struct bt_event;
-
-/**
-@brief  Creates a default CTF IR stream named \p name with ID \p id
-       from the CTF IR stream class \p stream_class.
-
-\p stream_class \em must have a parent
-\link ctfirtraceclass CTF IR trace class\endlink.
-
-\p id \em must be unique amongst the IDs of all the streams created
-from \p stream_class with bt_stream_create_with_id().
-
-\p name can be \c NULL to create an unnamed stream object.
-
-@param[in] stream_class        CTF IR stream class to use to create the
-                       CTF IR stream.
-@param[in] name                Name of the stream object to create (copied on
-                       success) or \c NULL to create an unnamed stream.
-@param[in] id          ID of the stream object to create.
-@returns               Created stream object, or \c NULL on error.
-
-@prenotnull{stream_class}
-@pre \p id is lesser than or equal to 9223372036854775807 (\c INT64_MAX).
-@pre \p stream_class has a parent trace class.
-@postsuccessrefcountret1
-*/
-extern struct bt_stream *bt_stream_create(struct bt_stream_class *stream_class,
-               const char *name, uint64_t id);
+struct bt_stream_class;
 
-/**
-@brief Returns the name of the CTF IR stream \p stream.
+extern struct bt_stream *bt_stream_create(struct bt_stream_class *stream_class);
 
-On success, \p stream remains the sole owner of the returned string.
+extern struct bt_stream *bt_stream_create_with_id(
+               struct bt_stream_class *stream_class, uint64_t id);
 
-@param[in] stream      Stream object of which to get the name.
-@returns               Name of stream \p stream, or \c NULL if
-                       \p stream is unnamed or on error.
+extern struct bt_stream_class *bt_stream_borrow_class(struct bt_stream *stream);
 
-@prenotnull{stream}
-@postrefcountsame{stream}
-*/
 extern const char *bt_stream_get_name(struct bt_stream *stream);
 
-/**
-@brief Returns the numeric ID of the CTF IR stream \p stream.
-
-@param[in] stream      Stream of which to get the numeric ID.
-@returns               ID of stream \p stream, or a negative value
-                       on error.
-
-@prenotnull{stream}
-@postrefcountsame{stream}
-*/
-extern int64_t bt_stream_get_id(struct bt_stream *stream);
-
-extern struct bt_stream_class *bt_stream_borrow_class(
-               struct bt_stream *stream);
-
-/**
-@brief Returns the parent CTF IR stream class of the CTF IR
-       stream \p stream.
-
-This function returns a reference to the stream class which was used
-to create the stream object in the first place with
-bt_stream_create().
-
-@param[in] stream      Stream of which to get the parent stream class.
-@returns               Parent stream class of \p stream,
-                       or \c NULL on error.
-
-@prenotnull{stream}
-@postrefcountsame{stream}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_stream_class *bt_stream_get_class(
-               struct bt_stream *stream)
-{
-       return bt_get(bt_stream_borrow_class(stream));
-}
+extern int bt_stream_set_name(struct bt_stream *stream, const char *name);
 
-/** @} */
+extern uint64_t bt_stream_get_id(struct bt_stream *stream);
 
 #ifdef __cplusplus
 }
index 8de7885281a5b91edca154005567795d0cddfc47..30b0ba4f697a62d2c0f6aef05e264f10cb13fe80 100644 (file)
@@ -32,7 +32,6 @@
 #include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/field-types.h>
 #include <babeltrace/ctf-ir/fields.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/ctf-ir/attributes-internal.h>
 #include <babeltrace/ctf-ir/clock-class-internal.h>
 #include <babeltrace/object-internal.h>
 
 struct bt_trace {
        struct bt_object base;
-       GString *name;
-       int frozen;
-       unsigned char uuid[BABELTRACE_UUID_LEN];
-       bt_bool uuid_set;
-       enum bt_byte_order native_byte_order;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       struct {
+               uint8_t uuid[BABELTRACE_UUID_LEN];
+
+               /* NULL or `uuid` above */
+               bt_uuid value;
+       } uuid;
+
        struct bt_value *environment;
-       GPtrArray *clock_classes; /* Array of pointers to bt_clock_class */
-       GPtrArray *stream_classes; /* Array of ptrs to bt_stream_class */
-       GPtrArray *streams; /* Array of ptrs to bt_stream */
-       struct bt_field_type *packet_header_field_type;
-       int64_t next_stream_id;
+
+       /* Array of `struct bt_stream_class *` */
+       GPtrArray *stream_classes;
+
+       /* Array of `struct bt_stream *` */
+       GPtrArray *streams;
 
        /*
-        * This flag indicates if the trace is valid. A valid
-        * trace is _always_ frozen.
+        * Stream class (weak) to number of instantiated streams, used
+        * to automatically assign stream IDs per stream class.
         */
-       int valid;
+       GHashTable *stream_classes_stream_count;
+
+       struct bt_field_type *packet_header_ft;
+       bool assigns_automatic_stream_class_id;
 
-       GPtrArray *listeners; /* Array of struct listener_wrapper */
        GArray *is_static_listeners;
-       bt_bool is_static;
-       bt_bool in_remove_listener;
+       bool is_static;
+       bool in_remove_listener;
 
        /* Pool of `struct bt_field_wrapper *` */
        struct bt_object_pool packet_header_field_pool;
-};
 
-BT_HIDDEN
-int bt_trace_object_modification(struct bt_visitor_object *object,
-               void *trace_ptr);
+       bool frozen;
+};
 
 BT_HIDDEN
-bt_bool bt_trace_has_clock_class(struct bt_trace *trace,
-               struct bt_clock_class *clock_class);
-
-/**
-@brief User function type to use with bt_trace_add_listener().
+void _bt_trace_freeze(struct bt_trace *trace);
 
-@param[in] obj New CTF IR object which is part of the trace
-               class hierarchy.
-@param[in] data        User data.
+#ifdef BT_DEV_MODE
+# define bt_trace_freeze               _bt_trace_freeze
+#else
+# define bt_trace_freeze(_trace)
+#endif
 
-@prenotnull{obj}
-*/
-typedef void (*bt_listener_cb)(struct bt_visitor_object *obj, void *data);
-
-/**
-@brief Adds the trace class modification listener \p listener to
-       the CTF IR trace class \p trace_class.
-
-Once you add \p listener to \p trace_class, whenever \p trace_class
-is modified, \p listener is called with the new element and with
-\p data (user data).
-
-@param[in] trace_class Trace class to which to add \p listener.
-@param[in] listener    Modification listener function.
-@param[in] data                User data.
-@returns               0 on success, or a negative value on error.
+BT_HIDDEN
+void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream);
 
-@prenotnull{trace_class}
-@prenotnull{listener}
-@postrefcountsame{trace_class}
-*/
 BT_HIDDEN
-int bt_trace_add_listener(struct bt_trace *trace_class,
-               bt_listener_cb listener, void *data);
-
-static inline
-void bt_trace_freeze(struct bt_trace *trace)
-{
-       int i;
-
-       if (trace->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing trace: addr=%p, name=\"%s\"",
-               trace, bt_trace_get_name(trace));
-       BT_LOGD_STR("Freezing packet header field type.");
-       bt_field_type_freeze(trace->packet_header_field_type);
-       BT_LOGD_STR("Freezing environment attributes.");
-       bt_attributes_freeze(trace->environment);
-
-       if (trace->clock_classes->len > 0) {
-               BT_LOGD_STR("Freezing clock classes.");
-       }
-
-       for (i = 0; i < trace->clock_classes->len; i++) {
-               struct bt_clock_class *clock_class =
-                       g_ptr_array_index(trace->clock_classes, i);
-
-               bt_clock_class_freeze(clock_class);
-       }
-
-       trace->frozen = 1;
-}
+uint64_t bt_trace_get_automatic_stream_id(struct bt_trace *trace,
+               struct bt_stream_class *stream_class);
 
 #endif /* BABELTRACE_CTF_IR_TRACE_INTERNAL_H */
index 949672266188b879f6faabe658d82c1890312a8b..690c88a32680fc12bc4758f15628dc31a7e390f9 100644 (file)
  * http://www.efficios.com/ctf
  */
 
-/* For bt_get() */
-#include <babeltrace/ref.h>
-
-/* For bt_visitor */
-#include <babeltrace/ctf-ir/visitor.h>
-
-/* For bt_bool */
+/* For bt_bool, bt_uuid */
 #include <babeltrace/types.h>
+
 #include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/**
-@defgroup ctfirtraceclass CTF IR trace class
-@ingroup ctfir
-@brief CTF IR trace class.
-
-@code
-#include <babeltrace/ctf-ir/trace.h>
-@endcode
-
-A CTF IR <strong><em>trace class</em></strong> is a descriptor of
-traces.
-
-You can obtain a trace class in two different modes:
-
-- <strong>Normal mode</strong>: use bt_trace_create() to create a
-  default, empty trace class.
-- <strong>CTF writer mode</strong>: use bt_writer_get_trace() to
-  get the trace class created by a given CTF writer object.
-
-A trace class has the following properties:
-
-- A \b name.
-- A <strong>native byte order</strong>: all the
-  \link ctfirfieldtypes field types\endlink eventually part of the trace
-  class with a byte order set to #BT_BYTE_ORDER_NATIVE have this
-  "real" byte order.
-- A \b UUID.
-- An \b environment, which is a custom key-value mapping. Keys are
-  strings and values can be strings or integers.
-
-In the Babeltrace CTF IR system, a trace class contains zero or more
-\link ctfirstreamclass stream classes\endlink, and a stream class
-contains zero or more \link ctfireventclass event classes\endlink. You
-can add an event class to a stream class with
-bt_stream_class_add_event_class(). You can add a stream class to a
-trace class with bt_trace_add_stream_class().
-
-You can access the streams of a trace, that is, the streams which were
-created from the trace's stream classes with bt_stream_create(),
-with bt_trace_get_stream_by_index().
-
-A trace class owns the <strong>trace packet header</strong>
-\link ctfirfieldtypes field type\endlink, which represents the
-\c trace.packet.header CTF scope. This field type describes the
-trace packet header fields of the traces that this trace class
-describes.
-
-The trace packet header field type \em must be a structure field type as
-of Babeltrace \btversion.
-
-As per the CTF specification, the trace packet header field type \em
-must contain a field named \c stream_id if the trace class contains more
-than one stream class.
-
-As a reminder, here's the structure of a CTF packet:
-
-@imgpacketstructure
-
-A trace class also contains zero or more
-\link ctfirclockclass CTF IR clock classes\endlink.
-
-@todo
-Elaborate about clock classes irt clock values.
-
-As with any Babeltrace object, CTF IR trace class objects have
-<a href="https://en.wikipedia.org/wiki/Reference_counting">reference
-counts</a>. See \ref refs to learn more about the reference counting
-management of Babeltrace objects.
-
-The following functions \em freeze their trace class parameter on
-success:
-
-- bt_trace_add_stream_class()
-- bt_writer_create_stream()
-  (\link ctfwriter CTF writer\endlink mode only)
-
-You cannot modify a frozen trace class: it is considered immutable,
-except for:
-
-- Adding a stream class to it with
-  bt_trace_add_stream_class().
-- Adding a CTF IR clock class to it with bt_trace_add_clock_class().
-- \link refs Reference counting\endlink.
-
-@sa ctfirstreamclass
-@sa ctfireventclass
-@sa ctfirclockclass
-
-@file
-@brief CTF IR trace class type and functions.
-@sa ctfirtraceclass
-
-@addtogroup ctfirtraceclass
-@{
-*/
-
-/**
-@struct bt_trace
-@brief A CTF IR trace class.
-@sa ctfirtraceclass
-*/
 struct bt_trace;
 struct bt_stream;
 struct bt_stream_class;
-struct bt_clock_class;
 struct bt_field_type;
 struct bt_value;
 struct bt_packet_header_field;
 
-/**
-@brief User function type to use with
-       bt_trace_add_is_static_listener().
-
-@param[in] trace_class Trace class which is now static.
-@param[in] data                User data as passed to
-                       bt_trace_add_is_static_listener() when
-                       you added the listener.
-
-@prenotnull{trace_class}
-*/
 typedef void (* bt_trace_is_static_listener)(
-       struct bt_trace *trace_class, void *data);
-
-/**
-@brief User function type to use with
-       bt_trace_add_is_static_listener().
+       struct bt_trace *trace, void *data);
 
-@param[in] trace_class Trace class to which the listener was added.
-@param[in] data                User data as passed to
-                       bt_trace_add_is_static_listener() when
-                       you added the listener.
-
-@prenotnull{trace_class}
-*/
 typedef void (* bt_trace_listener_removed)(
-       struct bt_trace *trace_class, void *data);
-
-/**
-@name Creation function
-@{
-*/
-
-/**
-@brief Creates a default CTF IR trace class.
-
-On success, the trace packet header field type of the created trace
-class is an empty structure field type. You can modify this default
-trace packet header field type after the trace class is created with
-bt_trace_get_packet_header_field_type() and
-bt_trace_set_packet_header_field_type().
-
-The created trace class has the following initial properties:
-
-- <strong>Name</strong>: none. You can set a name
-  with bt_trace_set_name().
-- <strong>UUID</strong>: none. You can set a UUID with
-  bt_trace_set_uuid().
-- <strong>Native byte order</strong>: #BT_BYTE_ORDER_UNSPECIFIED.
-  You can set a native byte order with
-  bt_trace_set_native_byte_order().
-- <strong>Environment</strong>: empty. You can add environment entries
-  with bt_trace_set_environment_field(),
-  bt_trace_set_environment_field_integer(), and
-  bt_trace_set_environment_field_string().
+       struct bt_trace *trace, void *data);
 
-@returns       Created trace class, or \c NULL on error.
-
-@postsuccessrefcountret1
-*/
 extern struct bt_trace *bt_trace_create(void);
 
-/** @} */
-
-/**
-@name Properties functions
-@{
-*/
-
-/**
-@brief Returns the name of the CTF IR trace class \p trace_class.
-
-On success, \p trace_class remains the sole owner of the returned
-string. The returned string is valid as long as \p trace_class exists
-and is not modified.
-
-@param[in] trace_class Trace class of which to get the name.
-@returns               Name of trace class \p trace_class, or
-                       \c NULL if \p trace_class is unnamed or
-                       on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-
-@sa bt_trace_set_name(): Sets the name of a given trace class.
-*/
-extern const char *bt_trace_get_name(struct bt_trace *trace_class);
-
-/**
-@brief Sets the name of the CTF IR trace class \p trace_class
-       to \p name.
-
-@param[in] trace_class Trace class of which to set the name.
-@param[in] name                Name of the trace class (copied on success).
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prenotnull{name}
-@prehot{trace_class}
-@postrefcountsame{trace_class}
-
-@sa bt_trace_get_name(): Returns the name of a given trace class.
-*/
-extern int bt_trace_set_name(struct bt_trace *trace_class,
-               const char *name);
-
-/**
-@brief Returns the native byte order of the CTF IR trace class
-       \p trace_class.
-
-@param[in] trace_class Trace class of which to get the default byte
-                       order.
-@returns               Native byte order of \p trace_class,
-                       or #BT_BYTE_ORDER_UNKNOWN on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-
-@sa bt_trace_set_native_byte_order(): Sets the native byte order of
-       a given trace class.
-*/
-extern enum bt_byte_order bt_trace_get_native_byte_order(
-               struct bt_trace *trace_class);
-
-/**
-@brief Sets the native byte order of the CTF IR trace class
-       \p trace_class to \p native_byte_order.
-
-\p native_byte_order \em must be one of:
-
-- #BT_BYTE_ORDER_LITTLE_ENDIAN
-- #BT_BYTE_ORDER_BIG_ENDIAN
-- #BT_BYTE_ORDER_NETWORK
-- <strong>If the trace is not in CTF writer mode<strong>,
-  #BT_BYTE_ORDER_UNSPECIFIED.
-
-@param[in] trace_class         Trace class of which to set the native byte
-                               order.
-@param[in] native_byte_order   Native byte order of the trace class.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prehot{trace_class}
-@pre \p native_byte_order is either #BT_BYTE_ORDER_UNSPECIFIED (if the
-       trace is not in CTF writer mode),
-       #BT_BYTE_ORDER_LITTLE_ENDIAN, #BT_BYTE_ORDER_BIG_ENDIAN, or
-       #BT_BYTE_ORDER_NETWORK.
-@postrefcountsame{trace_class}
-
-@sa bt_trace_get_native_byte_order(): Returns the native byte order of a
-       given trace class.
-*/
-extern int bt_trace_set_native_byte_order(struct bt_trace *trace_class,
-               enum bt_byte_order native_byte_order);
-
-/**
-@brief Returns the UUID of the CTF IR trace class \p trace_class.
-
-On success, the return value is an array of 16 bytes.
-
-@param[in] trace_class Trace class of which to get the UUID.
-@returns               UUID of trace class \p trace_class, or
-                       \c NULL if \p trace_class has no UUID or on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-
-@sa bt_trace_set_uuid(): Sets the UUID of a given trace class.
-*/
-extern const unsigned char *bt_trace_get_uuid(
-               struct bt_trace *trace_class);
-
-/**
-@brief  Sets the UUID of the CTF IR trace class \p trace_class to
-       \p uuid.
-
-\p uuid \em must be an array of 16 bytes.
-
-@param[in] trace_class         Trace class of which to set the UUID.
-@param[in] uuid                        UUID of the \p trace_class (copied on
-                               success).
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prenotnull{uuid}
-@prehot{trace_class}
-@pre \p uuid is an array of 16 bytes.
-@postrefcountsame{trace_class}
-
-@sa bt_trace_get_uuid(): Returns the UUID of a given trace class.
-*/
-extern int bt_trace_set_uuid(struct bt_trace *trace_class,
-               const unsigned char *uuid);
-
-/**
-@brief Returns the number of entries contained in the environment of
-       the CTF IR trace class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the number
-                       of environment entries.
-@returns               Number of environment entries
-                       contained in \p trace_class, or
-                       a negative value on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-*/
-extern int64_t bt_trace_get_environment_field_count(
-               struct bt_trace *trace_class);
-
-/**
-@brief Returns the field name of the environment entry at index
-       \p index in the CTF IR trace class \p trace_class.
-
-On success, the returned string is valid as long as this trace class
-exists and is \em not modified. \p trace_class remains the sole owner of
-the returned string.
-
-@param[in] trace_class Trace class of which to get the name of the
-                       environment entry at index \p index.
-@param[in] index       Index of environment entry to find.
-@returns               Name of the environment entry at index \p index
-                       in \p trace_class, or \c NULL on error.
-
-@prenotnull{trace_class}
-@pre \p index is lesser than the number of environment entries in
-       \p trace_class (see bt_trace_get_environment_field_count()).
-@postrefcountsame{trace_class}
-
-@sa bt_trace_get_environment_field_value_by_index(): Finds a trace class's
-       environment entry by index.
-@sa bt_trace_get_environment_field_value_by_name(): Finds a trace
-       class's environment entry by name.
-@sa bt_trace_set_environment_field(): Sets the value of a trace
-       class's environment entry.
-*/
-extern const char *
-bt_trace_get_environment_field_name_by_index(
-               struct bt_trace *trace_class, uint64_t index);
-
-extern struct bt_value *
-bt_trace_borrow_environment_field_value_by_index(struct bt_trace *trace_class,
-               uint64_t index);
-
-/**
-@brief Returns the value of the environment entry at index
-       \p index in the CTF IR trace class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the value of the
-                       environment entry at index \p index.
-@param[in] index       Index of the environment entry to find.
-@returns               Value of the environment entry at index \p index
-                       in \p trace_class, or \c NULL on error.
-
-@prenotnull{trace_class}
-@pre \p index is lesser than the number of environment entries in
-       \p trace_class (see bt_trace_get_environment_field_count()).
-@postrefcountsame{trace_class}
-@postsuccessrefcountretinc
-
-@sa bt_trace_get_environment_field_value_by_name(): Finds a trace
-       class's environment entry by name.
-@sa bt_trace_set_environment_field(): Sets the value of a trace
-       class's environment entry.
-*/
-static inline
-struct bt_value *bt_trace_get_environment_field_value_by_index(
-               struct bt_trace *trace_class, uint64_t index)
-{
-       return bt_get(bt_trace_borrow_environment_field_value_by_index(
-               trace_class, index));
-}
-
-extern struct bt_value *
-bt_trace_borrow_environment_field_value_by_name(
-               struct bt_trace *trace_class, const char *name);
-
-/**
-@brief Returns the value of the environment entry named \p name
-       in the CTF IR trace class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the value of the
-                       environment entry named \p name.
-@param[in] name                Name of the environment entry to find.
-@returns               Value of the environment entry named \p name
-                       in \p trace_class, or \c NULL if there's no such
-                       entry or on error.
-
-@prenotnull{trace_class}
-@prenotnull{name}
-@postrefcountsame{trace_class}
-@postsuccessrefcountretinc
-
-@sa bt_trace_get_environment_field_value_by_index(): Finds a trace class's
-       environment entry by index.
-@sa bt_trace_set_environment_field(): Sets the value of a trace
-       class's environment entry.
-*/
-static inline
-struct bt_value *
-bt_trace_get_environment_field_value_by_name(
-               struct bt_trace *trace_class, const char *name)
-{
-       return bt_get(
-               bt_trace_borrow_environment_field_value_by_name(
-                       trace_class, name));
-}
-
-/**
-@brief Sets the environment entry named \p name in the
-       CTF IR trace class \p trace_class to \p value.
+extern bt_bool bt_trace_assigns_automatic_stream_class_id(
+               struct bt_trace *trace);
 
-If an environment entry named \p name exists in \p trace_class, its
-value is first put, and then replaced by \p value.
+extern int bt_trace_set_assigns_automatic_stream_class_id(
+               struct bt_trace *trace, bt_bool value);
 
-@param[in] trace_class Trace class of which to set the environment
-                       entry.
-@param[in] name                Name of the environment entry to set (copied
-                       on success).
-@param[in] value       Value of the environment entry named \p name.
-@returns               0 on success, or a negative value on error.
+extern const char *bt_trace_get_name(struct bt_trace *trace);
 
-@prenotnull{trace_class}
-@prenotnull{name}
-@prenotnull{value}
-@prehot{trace_class}
-@pre \p value is an
-       \link bt_value_integer_create() integer value object\endlink
-       or a
-       \link bt_value_string_create() string value object\endlink.
-@postrefcountsame{trace_class}
-@postsuccessrefcountinc{value}
+extern int bt_trace_set_name(struct bt_trace *trace, const char *name);
 
-@sa bt_trace_get_environment_field_value_by_index(): Finds a trace class's
-       environment entry by index.
-@sa bt_trace_get_environment_field_value_by_name(): Finds a trace
-       class's environment entry by name.
-*/
-extern int bt_trace_set_environment_field(
-               struct bt_trace *trace_class, const char *name,
-               struct bt_value *value);
+extern bt_uuid bt_trace_get_uuid(struct bt_trace *trace);
 
-/**
-@brief Sets the environment entry named \p name in the
-       CTF IR trace class \p trace_class to \p value.
+extern int bt_trace_set_uuid(struct bt_trace *trace, bt_uuid uuid);
 
-If an environment entry named \p name exists in \p trace_class, its
-value is first put, and then replaced by a new
-\link bt_value_integer_create() integer value object\endlink
-containing \p value.
+extern uint64_t bt_trace_get_environment_entry_count(struct bt_trace *trace);
 
-@param[in] trace_class Trace class of which to set the environment
-                       entry.
-@param[in] name                Name of the environment entry to set (copied
-                       on success).
-@param[in] value       Value of the environment entry named \p name.
-@returns               0 on success, or a negative value on error.
+extern void bt_trace_borrow_environment_entry_by_index(
+               struct bt_trace *trace, uint64_t index,
+               const char **name, struct bt_value **value);
 
-@prenotnull{trace_class}
-@prenotnull{name}
-@prehot{trace_class}
-@postrefcountsame{trace_class}
+extern struct bt_value *bt_trace_borrow_environment_entry_value_by_name(
+               struct bt_trace *trace, const char *name);
 
-@sa bt_trace_set_environment_field(): Sets the value of a trace
-       class's environment entry.
-*/
-extern int bt_trace_set_environment_field_integer(
-               struct bt_trace *trace_class, const char *name,
+extern int bt_trace_set_environment_entry_integer(
+               struct bt_trace *trace, const char *name,
                int64_t value);
 
-/**
-@brief Sets the environment entry named \p name in the
-       CTF IR trace class \p trace_class to \p value.
-
-If an environment entry named \p name exists in \p trace_class, its
-value is first put, and then replaced by a new
-\link bt_value_string_create() string value object\endlink
-containing \p value.
-
-@param[in] trace_class Trace class of which to set the environment
-                       entry.
-@param[in] name                Name of the environment entry to set (copied
-                       on success).
-@param[in] value       Value of the environment entry named \p name
-                       (copied on success).
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prenotnull{name}
-@prenotnull{value}
-@prehot{trace_class}
-@postrefcountsame{trace_class}
-
-@sa bt_trace_set_environment_field(): Sets the value of a trace
-       class's environment entry.
-*/
-extern int bt_trace_set_environment_field_string(
-               struct bt_trace *trace_class, const char *name,
+extern int bt_trace_set_environment_entry_string(
+               struct bt_trace *trace, const char *name,
                const char *value);
 
-/** @} */
-
-/**
-@name Contained field types functions
-@{
-*/
-
 extern struct bt_field_type *bt_trace_borrow_packet_header_field_type(
-               struct bt_trace *trace_class);
-
-/**
-@brief Returns the packet header field type of the CTF IR trace class
-       \p trace_class.
-
-@param[in] trace_class Trace class of which to get the packet
-                       header field type.
-@returns               Packet header field type of \p trace_class,
-                       or \c NULL if \p trace_class has no packet header field
-                       type or on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-@post <strong>On success, if the return value is a field type</strong>, its
-       reference count is incremented.
-
-@sa bt_trace_set_packet_header_field_type(): Sets the packet
-       header field type of a given trace class.
-*/
-static inline
-struct bt_field_type *bt_trace_get_packet_header_field_type(
-               struct bt_trace *trace_class)
-{
-       return bt_get(bt_trace_borrow_packet_header_field_type(trace_class));
-}
-
-extern struct bt_packet_header_field *bt_trace_create_packet_header_field(
                struct bt_trace *trace);
 
-/**
-@brief Sets the packet header field type of the CTF IR trace class
-       \p trace_class to \p packet_header_type, or unsets the current packet
-       header field type from \p trace_class.
-
-If \p packet_header_type is \c NULL, then this function unsets the current
-packet header field type from \p trace_class, effectively making \p trace_class
-a trace without a packet header field type.
-
-As of Babeltrace \btversion, if \p packet_header_type is not \c NULL,
-\p packet_header_type \em must be a CTF IR structure field type object.
-
-@param[in] trace_class         Trace class of which to set the packet
-                               header field type.
-@param[in] packet_header_type  Packet header field type, or \c NULL to unset
-                               the current packet header field type.
-@returns                       0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prehot{trace_class}
-@pre <strong>\p packet_header_type, if not \c NULL</strong>, is a CTF IR
-       structure field type.
-@postrefcountsame{trace_class}
-@post <strong>On success, if \p packet_header_type is not \c NULL</strong>,
-       the reference count of \p packet_header_type is incremented.
-
-@sa bt_trace_get_packet_header_field_type(): Returns the packet
-       header field type of a given trace class.
-*/
-extern int bt_trace_set_packet_header_field_type(struct bt_trace *trace_class,
+extern int bt_trace_set_packet_header_field_type(struct bt_trace *trace,
                struct bt_field_type *packet_header_type);
 
-/** @} */
-
-/**
-@name Contained clock classes functions
-@{
-*/
-
-/**
-@brief Returns the number of CTF IR clock classes contained in the
-       CTF IR trace class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the number
-                       of contained clock classes.
-@returns               Number of contained clock classes
-                       contained in \p trace_class, or a negative
-                       value on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-*/
-extern int64_t bt_trace_get_clock_class_count(
-               struct bt_trace *trace_class);
-
-extern struct bt_clock_class *bt_trace_borrow_clock_class_by_index(
-               struct bt_trace *trace_class, uint64_t index);
-
-/**
-@brief  Returns the CTF IR clock class at index \p index in the CTF
-       IR trace class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the clock class
-                       contained at index \p index.
-@param[in] index       Index of the clock class to find in
-                       \p trace_class.
-@returns               Clock class at index \p index in \p trace_class,
-                       or \c NULL on error.
-
-@prenotnull{trace_class}
-@pre \p index is lesser than the number of clock classes contained in
-       the trace class \p trace_class (see
-       bt_trace_get_clock_class_count()).
-@postrefcountsame{trace_class}
-@postsuccessrefcountretinc
-
-@sa bt_trace_get_clock_class_by_name(): Finds a clock class by name
-       in a given trace class.
-@sa bt_trace_add_clock_class(): Adds a clock class to a trace class.
-*/
-static inline
-struct bt_clock_class *bt_trace_get_clock_class_by_index(
-               struct bt_trace *trace_class, uint64_t index)
-{
-       return bt_get(bt_trace_borrow_clock_class_by_index(
-               trace_class, index));
-}
-
-extern struct bt_clock_class *bt_trace_borrow_clock_class_by_name(
-               struct bt_trace *trace_class, const char *name);
-
-/**
-@brief  Returns the CTF IR clock class named \c name found in the CTF
-       IR trace class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the clock class
-                       named \p name.
-@param[in] name                Name of the clock class to find in \p trace_class.
-@returns               Clock class named \p name in \p trace_class,
-                       or \c NULL on error.
-
-@prenotnull{trace_class}
-@prenotnull{name}
-@postrefcountsame{trace_class}
-@postsuccessrefcountretinc
-
-@sa bt_trace_get_clock_class_by_index(): Returns the clock class contained
-       in a given trace class at a given index.
-@sa bt_trace_add_clock_class(): Adds a clock class to a trace class.
-*/
-static inline
-struct bt_clock_class *bt_trace_get_clock_class_by_name(
-               struct bt_trace *trace_class, const char *name)
-{
-       return bt_get(bt_trace_borrow_clock_class_by_name(trace_class, name));
-}
-
-/**
-@brief Adds the CTF IR clock class \p clock_class to the CTF IR
-       trace class \p trace_class.
-
-On success, \p trace_class contains \p clock_class.
-
-You can call this function even if \p trace_class or \p clock_class
-are frozen.
-
-@param[in] trace_class Trace class to which to add \p clock_class.
-@param[in] clock_class Clock class to add to \p trace_class.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prenotnull{clock_class}
-@postrefcountsame{trace_class}
-@postsuccessrefcountinc{clock_class}
-@post <strong>On success, if \p trace_class is frozen</strong>,
-       \p clock_class is frozen.
-
-@sa bt_trace_get_clock_class_by_index(): Returns the clock class contained
-       in a given trace class at a given index.
-@sa bt_trace_get_clock_class_by_name(): Finds a clock class by name
-       in a given trace class.
-*/
-extern int bt_trace_add_clock_class(struct bt_trace *trace_class,
-               struct bt_clock_class *clock_class);
-
-/** @} */
-
-/**
-@name Stream class children functions
-@{
-*/
-
-/**
-@brief Returns the number of stream classes contained in the
-       CTF IR trace class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the number
-                       of children stream classes.
-@returns               Number of children stream classes
-                       contained in \p trace_class, or a negative
-                       value on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-*/
-extern int64_t bt_trace_get_stream_class_count(
-               struct bt_trace *trace_class);
+extern uint64_t bt_trace_get_stream_class_count(struct bt_trace *trace);
 
 extern struct bt_stream_class *bt_trace_borrow_stream_class_by_index(
-               struct bt_trace *trace_class, uint64_t index);
-
-/**
-@brief  Returns the stream class at index \p index in the CTF IR trace
-       class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the stream class.
-@param[in] index       Index of the stream class to find.
-@returns               Stream class at index \p index, or \c NULL
-                       on error.
-
-@prenotnull{trace_class}
-@pre \p index is lesser than the number of stream classes contained in
-       the trace class \p trace_class (see
-       bt_trace_get_stream_class_count()).
-@postrefcountsame{trace_class}
-
-@sa bt_trace_get_stream_class_by_id(): Finds a stream class by ID.
-@sa bt_trace_add_stream_class(): Adds a stream class to a trace class.
-*/
-static inline
-struct bt_stream_class *bt_trace_get_stream_class_by_index(
-               struct bt_trace *trace_class, uint64_t index)
-{
-       return bt_get(bt_trace_borrow_stream_class_by_index(
-               trace_class, index));
-}
+               struct bt_trace *trace, uint64_t index);
 
 extern struct bt_stream_class *bt_trace_borrow_stream_class_by_id(
-               struct bt_trace *trace_class, uint64_t id);
-
-/**
-@brief  Returns the stream class with ID \c id found in the CTF IR
-       trace class \p trace_class.
+               struct bt_trace *trace, uint64_t id);
 
-@param[in] trace_class Trace class of which to get the stream class.
-@param[in] id          ID of the stream class to find.
-@returns               Stream class with ID \p id, or \c NULL
-                       on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-@postsuccessrefcountretinc
-
-@sa bt_trace_get_stream_class_by_index(): Returns the stream class contained
-       in a given trace class at a given index.
-@sa bt_trace_add_stream_class(): Adds a stream class to a trace class.
-*/
-static inline
-struct bt_stream_class *bt_trace_get_stream_class_by_id(
-               struct bt_trace *trace_class, uint64_t id)
-{
-       return bt_get(bt_trace_borrow_stream_class_by_id(trace_class, id));
-}
-
-/**
-@brief Adds the CTF IR stream class \p stream_class to the
-       CTF IR trace class \p trace_class.
-
-On success, \p stream_class becomes the child of \p trace_class.
-
-You can only add a given stream class to one trace class.
-
-You can call this function even if \p trace_class is frozen.
-
-This function tries to resolve the needed
-\link ctfirfieldtypes CTF IR field type\endlink of the dynamic field
-types that are found anywhere in the root field types of
-\p stream_class and of all its currently contained
-\link ctfireventclass CTF IR event classes\endlink. If any automatic
-resolving fails, then this function fails.
-
-@param[in] trace_class Trace class to which to add \p stream_class.
-@param[in] stream_class        Stream class to add to \p trace_class.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prenotnull{stream_class}
-@postrefcountsame{trace_class}
-@postsuccessrefcountinc{stream_class}
-@postsuccessfrozen{stream_class}
-
-@sa bt_trace_get_stream_class_by_index(): Returns the stream class contained
-       in a given trace class at a given index.
-@sa bt_trace_get_stream_class_by_id(): Finds a stream class by ID.
-*/
-extern int bt_trace_add_stream_class(struct bt_trace *trace_class,
-               struct bt_stream_class *stream_class);
-
-/** @} */
-
-/**
-@name Stream children functions
-@{
-*/
-
-/**
-@brief  Returns the number of streams contained in the CTF IR trace
-       class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the number
-                       of children streams.
-@returns               Number of children streams
-                       contained in \p trace_class, or a negative
-                       value on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-*/
-extern int64_t bt_trace_get_stream_count(struct bt_trace *trace_class);
+extern uint64_t bt_trace_get_stream_count(struct bt_trace *trace);
 
 extern struct bt_stream *bt_trace_borrow_stream_by_index(
-               struct bt_trace *trace_class, uint64_t index);
-
-/**
-@brief  Returns the stream at index \p index in the CTF IR trace
-       class \p trace_class.
-
-@param[in] trace_class Trace class of which to get the stream.
-@param[in] index       Index of the stream to find.
-@returns               Stream at index \p index, or \c NULL
-                       on error.
-
-@prenotnull{trace_class}
-@pre \p index is lesser than the number of streams contained in
-       the trace class \p trace_class (see
-       bt_trace_get_stream_count()).
-@postrefcountsame{trace_class}
-*/
-static inline
-struct bt_stream *bt_trace_get_stream_by_index(
-               struct bt_trace *trace_class, uint64_t index)
-{
-       return bt_get(bt_trace_borrow_stream_by_index(trace_class, index));
-}
-
-/** @} */
-
-/**
-@name Misc. functions
-@{
-*/
-
-/**
-@brief Returns whether or not the CTF IR trace class \p trace_class
-       is static.
-
-It is guaranteed that a static trace class will never contain new
-streams, stream classes, or clock classes. A static class is always
-frozen.
-
-This function returns #BT_TRUE if bt_trace_set_is_static() was
-previously called on it.
+               struct bt_trace *trace, uint64_t index);
 
-@param[in] trace_class Trace class to check.
-@returns               #BT_TRUE if \p trace_class is static,
+extern struct bt_stream *bt_trace_borrow_stream_by_id(
+               struct bt_trace *trace, uint64_t id);
 
-@sa bt_trace_set_is_static(): Makes a trace class static.
-*/
-extern bt_bool bt_trace_is_static(struct bt_trace *trace_class);
+extern bt_bool bt_trace_is_static(struct bt_trace *trace);
 
-/**
-@brief Makes the CTF IR trace class \p trace_class static.
+extern int bt_trace_make_static(struct bt_trace *trace);
 
-A static trace class is frozen and you cannot call any modifying
-function on it:
-
-- bt_trace_add_stream_class()
-- bt_trace_add_clock_class()
-- bt_trace_set_environment_field()
-- bt_trace_set_environment_field_integer()
-- bt_trace_set_environment_field_string()
-- bt_trace_add_is_static_listener()
-
-You cannot create a stream with bt_stream_create() with any of the
-stream classes of a static trace class.
-
-@param[in] trace_class Trace class to make static.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@postrefcountsame{trace_class}
-@postsuccessfrozen{trace_class}
-
-@sa bt_trace_is_static(): Checks whether or not a given trace class
-       is static.
-@sa bt_trace_add_is_static_listener(): Adds a listener to a trace
-       class which is called when the trace class is made static.
-*/
-extern int bt_trace_set_is_static(struct bt_trace *trace_class);
-
-/**
-@brief  Adds the listener \p listener to the CTF IR trace class
-       \p trace_class which is called when the trace is made static.
-
-\p listener is called with \p data, the user data, the first time
-bt_trace_set_is_static() is called on \p trace_class.
-
-When the trace is destroyed, or when you remove the added listener with
-bt_trace_remove_is_static_listener(), \p listener_removed is called
-if it's not \c NULL. You can use \p listener_removed to free any dynamic
-data which exists only for the added listener. You cannot call
-any function which modifies \p trace_class during the execution of
-\p listener_removed, including bt_trace_remove_is_static_listener().
-
-This function fails if \p trace_class is already static: you need to
-check the condition first with bt_trace_is_static().
-
-On success, this function returns a unique numeric identifier for this
-listener within \p trace. You can use this identifier to remove the
-specific listener you added with
-bt_trace_remove_is_static_listener().
-
-@param[in] trace_class         Trace class to which to add the
-                               listener.
-@param[in] listener            Listener to add to \p trace_class.
-@param[in] listener_removed    Remove listener called when \p listener
-                               is removed from \p trace_class, or
-                               \c NULL if you don't need a remove
-                               listener.
-@param[in] data                        User data passed when \p listener or
-                               \p listener_removed is called.
-@returns                       A unique numeric identifier for this
-                               listener on success (0 or greater), or a
-                               negative value on error.
-
-@prenotnull{trace_class}
-@prenotnull{listener}
-@pre \p trace_class is not static.
-@postrefcountsame{trace_class}
-
-@sa bt_trace_remove_is_static_listener(): Removes a "trace is
-       static" listener from a trace class previously added with this
-       function.
-@sa bt_trace_is_static(): Checks whether or not a given trace class
-       is static.
-@sa bt_trace_set_is_static(): Makes a trace class static.
-*/
 extern int bt_trace_add_is_static_listener(
-               struct bt_trace *trace_class,
+               struct bt_trace *trace,
                bt_trace_is_static_listener listener,
-               bt_trace_listener_removed listener_removed, void *data);
-
-/**
-@brief  Removes the "trace is static" listener identified by
-       \p listener_id from the trace class \p trace_class.
-
-@param[in] trace_class Trace class from which to remove the listener
-                       identified by \p listener_id.
-@param[in] listener_id Identifier of the listener to remove from
-                       \p trace_class.
-@returns               0 if this function removed the listener, or
-                       a negative value on error.
+               bt_trace_listener_removed listener_removed, void *data,
+               uint64_t *listener_id);
 
-@prenotnull{trace_class}
-@pre \p listener_id is the identifier of a listener that you previously
-       added with bt_trace_add_is_static_listener() and did not
-       already remove with this function.
-@postrefcountsame{trace_class}
-
-@sa bt_trace_add_is_static_listener(): Adds a listener to a trace
-       class which is called when the trace class is made static.
-*/
 extern int bt_trace_remove_is_static_listener(
-               struct bt_trace *trace_class, int listener_id);
-
-/**
-@brief Accepts the visitor \p visitor to visit the hierarchy of the
-       CTF IR trace class \p trace_class.
-
-This function traverses the hierarchy of \p trace_class in pre-order
-and calls \p visitor on each element.
-
-The trace class itself is visited first, then, for each children stream
-class, the stream class itself, and all its children event classes.
-
-@param[in] trace_class Trace class to visit.
-@param[in] visitor     Visiting function.
-@param[in] data                User data.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{trace_class}
-@prenotnull{visitor}
-*/
-extern int bt_trace_visit(struct bt_trace *trace_class,
-               bt_visitor visitor, void *data);
-
-/** @} */
-
-/** @} */
+               struct bt_trace *trace, uint64_t listener_id);
 
 #ifdef __cplusplus
 }
index 8aba362e9786663df9d875c4421540ea5bb9f56c..3c539429b3c4a1e2894dd1a05e7c4cc03a205539 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/ctf-ir/field-types.h>
+#include <babeltrace/ctf-ir/clock-class-internal.h>
 #include <stdint.h>
 
 struct search_query {
@@ -32,7 +33,91 @@ struct search_query {
        int found;
 };
 
-BT_HIDDEN
-const char *get_byte_order_string(enum bt_byte_order byte_order);
+static inline
+uint64_t bt_util_ns_from_value(uint64_t frequency, uint64_t value_cycles)
+{
+       uint64_t ns;
+
+       if (frequency == UINT64_C(1000000000)) {
+               ns = value_cycles;
+       } else {
+               double dblres = ((1e9 * (double) value_cycles) / (double) frequency);
+
+               if (dblres >= (double) UINT64_MAX) {
+                       /* Overflows uint64_t */
+                       ns = UINT64_C(-1);
+               } else {
+                       ns = (uint64_t) dblres;
+               }
+       }
+
+       return ns;
+}
+
+static inline
+int bt_util_ns_from_origin(struct bt_clock_class *clock_class, uint64_t value,
+               int64_t *ns_from_origin)
+{
+       int ret = 0;
+       uint64_t value_ns_unsigned;
+       int64_t value_ns_signed;
+
+       if (clock_class->base_offset.overflows) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Initialize to clock class's base offset */
+       *ns_from_origin = clock_class->base_offset.value_ns;
+
+       /* Add given value in cycles */
+       value_ns_unsigned = bt_util_ns_from_value(clock_class->frequency, value);
+       if (value_ns_unsigned >= (uint64_t) INT64_MAX) {
+               /*
+                * FIXME: `value_ns_unsigned` could be greater than
+                * `INT64_MAX` in fact: in this case, we need to
+                * subtract `INT64_MAX` from `value_ns_unsigned`, make
+                * sure that the difference is less than `INT64_MAX`,
+                * and try to add them one after the other to
+                * `*ns_from_origin`.
+                */
+               ret = -1;
+               goto end;
+       }
+
+       value_ns_signed = (int64_t) value_ns_unsigned;
+       BT_ASSERT(value_ns_signed >= 0);
+
+       if (*ns_from_origin <= 0) {
+               goto add_value;
+       }
+
+       if (value_ns_signed > INT64_MAX - *ns_from_origin) {
+               ret = -1;
+               goto end;
+       }
+
+add_value:
+       *ns_from_origin += value_ns_signed;
+
+end:
+       return ret;
+}
+
+static inline
+bool bt_util_value_is_in_range_signed(uint64_t size, int64_t value)
+{
+       int64_t min_value = UINT64_C(-1) << (size - 1);
+       int64_t max_value = (UINT64_C(1) << (size - 1)) - 1;
+       return value >= min_value && value <= max_value;
+}
+
+static inline
+bool bt_util_value_is_in_range_unsigned(unsigned int size, uint64_t value)
+{
+       uint64_t max_value = (size == 64) ? UINT64_MAX :
+               (UINT64_C(1) << size) - 1;
+       return value <= max_value;
+}
 
 #endif /* BABELTRACE_CTF_IR_UTILS_INTERNAL_H */
diff --git a/include/babeltrace/ctf-ir/utils.h b/include/babeltrace/ctf-ir/utils.h
deleted file mode 100644 (file)
index c93b0d8..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef BABELTRACE_CTF_IR_UTILS_H
-#define BABELTRACE_CTF_IR_UTILS_H
-
-/*
- * BabelTrace - CTF IR: Utilities
- *
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-/* For bt_bool */
-#include <babeltrace/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
-@defgroup ctfirutils CTF IR utilities
-@ingroup ctfir
-@brief CTF IR utilities.
-
-@code
-#include <babeltrace/ctf-ir/utils.h>
-@endcode
-
-@file
-@brief CTF IR utilities functions.
-@sa ctfirutils
-
-@addtogroup ctfirutils
-@{
-*/
-
-/**
-@brief Returns whether or not the string \p identifier is a valid
-       identifier according to CTF.
-
-This function returns a negative value if \p identifier is a CTF keyword
-or if it does not meet any other imposed requirement.
-
-@param[in] identifier  String to test.
-@returns               #BT_TRUE if \p identifier is a valid CTF
-                       identifier, or #BT_FALSE otherwise.
-
-@prenotnull{identifier}
-*/
-extern bt_bool bt_identifier_is_valid(const char *identifier);
-
-/** @} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BABELTRACE_CTF_IR_UTILS_H */
diff --git a/include/babeltrace/ctf-ir/validation-internal.h b/include/babeltrace/ctf-ir/validation-internal.h
deleted file mode 100644 (file)
index 2eaa8d6..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H
-#define BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H
-
-/*
- * Babeltrace - CTF IR: Validation of trace, stream class, and event class
- *
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace/values.h>
-#include <babeltrace/babeltrace-internal.h>
-
-struct bt_trace;
-struct bt_stream_class;
-struct bt_event_class;
-struct bt_field_type;
-
-typedef struct bt_field_type *(*bt_validation_flag_copy_field_type_func)(
-               struct bt_field_type *);
-
-enum bt_validation_flag {
-       BT_VALIDATION_FLAG_TRACE        = 1,
-       BT_VALIDATION_FLAG_STREAM       = 2,
-       BT_VALIDATION_FLAG_EVENT        = 4,
-};
-
-/*
- * Validation output structure.
- *
- * This is where the results of the validation function go. The field
- * types are the validated ones which should replace the original field
- * types of a trace, a stream class, and an event class.
- *
- * `valid_flags` contains the results of the validation.
- */
-struct bt_validation_output {
-       struct bt_field_type *packet_header_type;
-       struct bt_field_type *packet_context_type;
-       struct bt_field_type *event_header_type;
-       struct bt_field_type *stream_event_ctx_type;
-       struct bt_field_type *event_context_type;
-       struct bt_field_type *event_payload_type;
-       enum bt_validation_flag valid_flags;
-};
-
-/*
- * This function resolves and validates the field types of an event
- * class, a stream class, and a trace. Copies are created if needed
- * and the resulting field types to use are placed in the `output`
- * validation structure, which also contains the results of the
- * validation. Copies can replace the original field types of a trace,
- * a stream class, and an event class using
- * bt_validation_replace_types().
- *
- * The current known validity of the field types of the trace,
- * stream class, and event class must be indicated with the
- * `trace_valid`, `stream_class_valid`, and `event_class_valid`
- * parameters. If a class is valid, its field types are not copied,
- * validated, or resolved during this call.
- *
- * The validation flags `validate_flags` indicate which classes should
- * have their field types validated.
- *
- * All parameters are owned by the caller.
- */
-BT_HIDDEN
-int bt_validate_class_types(struct bt_value *environment,
-               struct bt_field_type *packet_header_type,
-               struct bt_field_type *packet_context_type,
-               struct bt_field_type *event_header_type,
-               struct bt_field_type *stream_event_ctx_type,
-               struct bt_field_type *event_context_type,
-               struct bt_field_type *event_payload_type,
-               int trace_valid, int stream_class_valid, int event_class_valid,
-               struct bt_validation_output *output,
-               enum bt_validation_flag validate_flags,
-               bt_validation_flag_copy_field_type_func copy_field_type_func);
-
-/*
- * This function replaces the actual field types of a trace, a stream
- * class, and an event class with the appropriate field types contained
- * in a validation output structure.
- *
- * The replace flags `replace_flags` indicate which classes should have
- * their field types replaced.
- *
- * Note that the field types that are not used in the validation output
- * structure are still owned by it at the end of this call.
- * bt_validation_output_put_types() should be called to clean the
- * structure.
- *
- * All parameters are owned by the caller.
- */
-BT_HIDDEN
-void bt_validation_replace_types(struct bt_trace *trace,
-               struct bt_stream_class *stream_class,
-               struct bt_event_class *event_class,
-               struct bt_validation_output *output,
-               enum bt_validation_flag replace_flags);
-
-/*
- * This function puts all the field types contained in a given
- * validation output structure.
- *
- * `output` is owned by the caller and is not freed here.
- */
-BT_HIDDEN
-void bt_validation_output_put_types(
-               struct bt_validation_output *output);
-
-#endif /* BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H */
diff --git a/include/babeltrace/ctf-ir/visitor-internal.h b/include/babeltrace/ctf-ir/visitor-internal.h
deleted file mode 100644 (file)
index 3f8d809..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef BABELTRACE_CTF_IR_VISITOR_INTERNAL_H
-#define BABELTRACE_CTF_IR_VISITOR_INTERNAL_H
-
-/*
- * BabelTrace - CTF IR: Visitor internal
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace/ctf-ir/visitor.h>
-#include <babeltrace/babeltrace-internal.h>
-
-typedef void *(*bt_child_accessor)(void *object, int index);
-typedef int64_t (*bt_child_count_accessor)(void *object);
-typedef int (*bt_child_visitor)(void *object, bt_visitor visitor,
-               void *data);
-
-struct bt_visitor_object {
-       enum bt_visitor_object_type type;
-       void *object;
-};
-
-BT_HIDDEN
-int visitor_helper(struct bt_visitor_object *root,
-               bt_child_count_accessor child_counter,
-               bt_child_accessor child_accessor,
-               bt_child_visitor child_visitor,
-               bt_visitor visitor,
-               void *data);
-
-#endif /* BABELTRACE_CTF_IR_VISITOR_INTERNAL_H */
diff --git a/include/babeltrace/ctf-ir/visitor.h b/include/babeltrace/ctf-ir/visitor.h
deleted file mode 100644 (file)
index 06da7ac..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef BABELTRACE_CTF_IR_VISITOR_H
-#define BABELTRACE_CTF_IR_VISITOR_H
-
-/*
- * BabelTrace - CTF IR: Visitor
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
-@defgroup ctfirvisitor CTF IR visitor
-@ingroup ctfir
-@brief CTF IR visitor.
-
-@code
-#include <babeltrace/ctf-ir/visitor.h>
-@endcode
-
-A CTF IR <strong><em>visitor</em></strong> is a function that you
-can use to visit the hierarchy of a
-\link ctfirtraceclass CTF IR trace class\endlink with
-bt_trace_visit() or of a
-\link ctfirstreamclass CTF IR stream class\endlink with
-bt_stream_class_visit().
-
-The traversal of the object's hierarchy is always done in a
-pre-order fashion.
-
-@sa ctfirstreamclass
-@sa ctfirtraceclass
-
-@file
-@brief CTF IR visitor types and functions.
-@sa ctfirvisitor
-
-@addtogroup ctfirvisitor
-@{
-*/
-
-/**
-@struct bt_object
-@brief A CTF IR object wrapper.
-
-This structure wraps both a CTF IR object and its type
-(see #bt_object_type). It is used in the visiting function.
-
-You can use the bt_object_get_type() and
-bt_object_get_object() accessors to get the type and wrapped
-CTF IR object of a CTF IR object wrapper.
-
-A CTF IR object wrapper has <strong>no reference count</strong>: do \em
-not use bt_put() or bt_get() on it.
-
-@sa ctfirvisitor
-*/
-struct bt_visitor_object;
-
-/**
-@brief CTF IR object wrapper type.
-*/
-enum bt_visitor_object_type {
-       /// Unknown (used for errors).
-       BT_VISITOR_OBJECT_TYPE_UNKNOWN = -1,
-
-       /// \ref ctfirtraceclass.
-       BT_VISITOR_OBJECT_TYPE_TRACE = 0,
-
-       /// \ref ctfirstreamclass.
-       BT_VISITOR_OBJECT_TYPE_STREAM_CLASS = 1,
-
-       /// \ref ctfirstream.
-       BT_VISITOR_OBJECT_TYPE_STREAM = 2,
-
-       /// \ref ctfireventclass.
-       BT_VISITOR_OBJECT_TYPE_EVENT_CLASS = 3,
-
-       /// \ref ctfirevent.
-       BT_VISITOR_OBJECT_TYPE_EVENT = 4,
-
-       /// Number of entries in this enumeration.
-       BT_VISITOR_OBJECT_TYPE_NR,
-};
-
-/**
-@brief Visting function type.
-
-A function of this type is called by bt_trace_visit() or
-bt_stream_class_visit() when visiting the CTF IR object wrapper
-\p object.
-
-\p object has <strong>no reference count</strong>: do \em not use
-bt_put() or bt_get() on it.
-
-@param[in] object      Currently visited CTF IR object wrapper.
-@param[in] data                User data.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{object}
-
-@sa bt_trace_visit(): Accepts a visitor to visit a trace class.
-@sa bt_stream_class_visit(): Accepts a visitor to visit a stream
-       class.
-*/
-typedef int (*bt_visitor)(struct bt_visitor_object *object,
-               void *data);
-
-/**
-@brief Returns the type of the CTF IR object wrapped by the CTF IR
-       object wrapper \p object.
-
-@param[in] object      Object wrapper of which to get the type.
-@returns               Type of \p object.
-
-@prenotnull{object}
-
-@sa bt_visitor_object_get_object(): Returns the object wrapped by a given
-       CTF IR object wrapper.
-*/
-enum bt_visitor_object_type bt_visitor_object_get_type(
-               struct bt_visitor_object *object);
-
-/**
-@brief Returns the CTF IR object wrapped by the CTF IR object
-       wrapper \p object.
-
-The reference count of \p object is \em not incremented by this
-function. On success, you must call bt_get() on the return value to
-have your own reference.
-
-@param[in] object      Object wrapper of which to get the wrapped
-                       CTF IR object.
-@returns               CTF IR object wrapped by \p object.
-
-@prenotnull{object}
-@post The reference count of the returned object is not modified.
-
-@sa bt_visitor_object_get_type(): Returns the type of a given
-       CTF IR object wrapper.
-*/
-void *bt_visitor_object_get_object(struct bt_visitor_object *object);
-
-/** @} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BABELTRACE_CTF_IR_VISITOR_H */
index 7e6073a04a39ee34a2f3dec6cff4f533176c2358..85e2fec348bd96dbdccf139b0279fd42c89d503b 100644 (file)
@@ -34,6 +34,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <babeltrace/align-internal.h>
+#include <babeltrace/endian-internal.h>
 #include <babeltrace/common-internal.h>
 #include <babeltrace/mmap-align-internal.h>
 #include <babeltrace/types.h>
 
 #define PACKET_LEN_INCREMENT   (bt_common_get_page_size() * 8 * CHAR_BIT)
 
+#if (BYTE_ORDER == BIG_ENDIAN)
+# define BT_CTF_MY_BYTE_ORDER  BT_CTF_BYTE_ORDER_BIG_ENDIAN
+#else
+# define BT_CTF_MY_BYTE_ORDER  BT_CTF_BYTE_ORDER_LITTLE_ENDIAN
+#endif
+
 struct bt_ctf_stream_pos {
        int fd;
        int prot;               /* mmap protection */
index a52abafae7eafac8a2c30824f95f8288f3c2cb4a..d5e02863ba56c8873430bef61d1471bee5a4b309 100644 (file)
@@ -41,7 +41,7 @@ struct bt_ctf_visitor_object {
 };
 
 BT_HIDDEN
-int visitor_helper(struct bt_ctf_visitor_object *root,
+int bt_ctf_visitor_helper(struct bt_ctf_visitor_object *root,
                bt_ctf_child_count_accessor child_counter,
                bt_ctf_child_accessor child_accessor,
                bt_ctf_child_visitor child_visitor,
index fdc4f27f52010e5783684b90595cdc8c047af919..db04a9aef5e268c89e66a7e3552a7b691ad529bf 100644 (file)
 #endif /* __FLOAT_WORD_ORDER */
 #endif /* FLOAT_WORD_ORDER */
 
-#if (BYTE_ORDER == BIG_ENDIAN)
-# define BT_MY_BYTE_ORDER      BT_BYTE_ORDER_BIG_ENDIAN
-#else
-# define BT_MY_BYTE_ORDER      BT_BYTE_ORDER_LITTLE_ENDIAN
-#endif
-
 #endif /* _BABELTRACE_ENDIAN_H */
index ccc32965805b1aa401147635cbed5b3a5d79632c..42551c6f09328f38c3d86bfd41f2b292952d9dc8 100644 (file)
  */
 
 #include <glib.h>
-#include <babeltrace/ctf-ir/clock-value-set-internal.h>
+#include <babeltrace/ctf-ir/clock-value-internal.h>
 #include <babeltrace/graph/notification.h>
 
 struct bt_notification_inactivity {
        struct bt_notification parent;
-       struct bt_clock_value_set cv_set;
+       struct bt_clock_value *default_cv;
 };
 
 #endif /* BABELTRACE_GRAPH_NOTIFICATION_INACTIVITY_INTERNAL_H */
index a69d30cd25a28aba300f9a9042cd7bcfb284704b..5de4dd28c609db2afce7943ee04252754987c4dd 100644 (file)
@@ -39,12 +39,11 @@ struct bt_clock_class;
 
 extern
 struct bt_notification *bt_notification_inactivity_create(
-               struct bt_private_connection_private_notification_iterator *notification_iterator);
+               struct bt_private_connection_private_notification_iterator *notification_iterator,
+               struct bt_clock_class *default_clock_class);
 
-extern int bt_notification_inactivity_set_clock_value(
-               struct bt_notification *notif,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default);
+extern int bt_notification_inactivity_set_default_clock_value(
+               struct bt_notification *notif, uint64_t raw_value);
 
 extern struct bt_clock_value *bt_notification_inactivity_borrow_default_clock_value(
                struct bt_notification *notif);
index f34ef5104cf012f2e6478f524bd28cd72d3457ff..15dd084751c405b6752b1d572a9f55f04fa6a6e7 100644 (file)
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/ctf-ir/packet.h>
 #include <babeltrace/graph/notification-internal.h>
-#include <babeltrace/ctf-ir/clock-value-set-internal.h>
+#include <babeltrace/ctf-ir/clock-value-internal.h>
 #include <babeltrace/assert-internal.h>
 
 struct bt_notification_stream_begin {
        struct bt_notification parent;
        struct bt_stream *stream;
-       struct bt_clock_value_set cv_set;
+       struct bt_clock_value *default_cv;
 };
 
 struct bt_notification_stream_end {
        struct bt_notification parent;
        struct bt_stream *stream;
-       struct bt_clock_value_set cv_set;
+       struct bt_clock_value *default_cv;
 };
 
 #endif /* BABELTRACE_GRAPH_NOTIFICATION_STREAM_INTERNAL_H */
index e95c7e5b2007b18dee515014788da6ab92735e28..18b10b9eb7f0d4a6618a52279d22e92cc3b3ddee 100644 (file)
@@ -65,10 +65,8 @@ struct bt_stream *bt_notification_stream_begin_get_stream(
        return bt_get(bt_notification_stream_begin_borrow_stream(notification));
 }
 
-extern int bt_notification_stream_begin_set_clock_value(
-               struct bt_notification *notif,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default);
+extern int bt_notification_stream_begin_set_default_clock_value(
+               struct bt_notification *notif, uint64_t value_cycles);
 
 extern struct bt_clock_value *bt_notification_stream_begin_borrow_default_clock_value(
                struct bt_notification *notif);
@@ -83,10 +81,8 @@ struct bt_stream *bt_notification_stream_end_get_stream(
        return bt_get(bt_notification_stream_end_borrow_stream(notification));
 }
 
-extern int bt_notification_stream_end_set_clock_value(
-               struct bt_notification *notif,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default);
+extern int bt_notification_stream_end_set_default_clock_value(
+               struct bt_notification *notif, uint64_t value_cycles);
 
 extern struct bt_clock_value *bt_notification_stream_end_borrow_default_clock_value(
                struct bt_notification *notif);
index 4373312787e89298b37a1daac096f6b89d4111cf..e2483b29d9a472980c748526d43360dafcafa974 100644 (file)
 #include <babeltrace/babeltrace-internal.h>
 #include <stdarg.h>
 
+#ifndef BT_LOG_TAG
+# error Please define a tag with BT_LOG_TAG before including this file.
+#endif
+
 #define BT_LOG_OUTPUT_LEVEL bt_lib_log_level
 
 #include <babeltrace/logging-internal.h>
@@ -58,7 +62,7 @@ int bt_lib_log_level;
  *   `PRIi64`.
  *
  * The Babeltrace extension conversion specifier is accepted. Its syntax
- * is:
+ * is either `%!u` to format a UUID (`bt_uuid` type) or:
  *
  * 1. Introductory `%!` sequence.
  *
@@ -74,10 +78,6 @@ int bt_lib_log_level;
  *
  * The available format specifiers are:
  *
- *   `r`:
- *       Reference count information. The parameter is any Babeltrace
- *       object.
- *
  *   `F`:
  *       CTF IR field type. The parameter type is `struct bt_field_type *`.
  *
@@ -136,12 +136,15 @@ int bt_lib_log_level;
  *   `g`:
  *       Graph. The parameter type is `struct bt_graph *`.
  *
- *   `u`:
+ *   `l`:
  *       Plugin. The parameter type is `struct bt_plugin *`.
  *
  *   `o`:
  *       Object pool. The parameter type is `struct bt_object_pool *`.
  *
+ *   `O`:
+ *       Object. The parameter type is `struct bt_object *`.
+ *
  * Conversion specifier examples:
  *
  *     %!f
@@ -153,7 +156,7 @@ int bt_lib_log_level;
  * the last one. Therefore you must put this separator in the format
  * string between two Babeltrace objects, e.g.:
  *
- *     BT_LIB_LOGW("Message: count=%u, %!E, %!+C", count, event_class,
+ *     BT_LIB_LOGW("Message: count=%u, %!E, %!+K", count, event_class,
  *                 clock_class);
  *
  * Example with a custom prefix:
diff --git a/include/babeltrace/property-internal.h b/include/babeltrace/property-internal.h
new file mode 100644 (file)
index 0000000..febfc47
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef BABELTRACE_PROPERTY_INTERNAL_H
+#define BABELTRACE_PROPERTY_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/assert-internal.h>
+#include <babeltrace/property.h>
+#include <babeltrace/types.h>
+#include <glib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+struct bt_property {
+       enum bt_property_availability avail;
+};
+
+struct bt_property_uint {
+       struct bt_property base;
+       uint64_t value;
+};
+
+static inline
+void bt_property_uint_set(struct bt_property_uint *prop, uint64_t value)
+{
+       BT_ASSERT(prop);
+       prop->base.avail = BT_PROPERTY_AVAILABILITY_AVAILABLE;
+       prop->value = value;
+}
+
+static inline
+void bt_property_uint_init(struct bt_property_uint *prop,
+               enum bt_property_availability avail, uint64_t value)
+{
+       BT_ASSERT(prop);
+       prop->base.avail = avail;
+       prop->value = value;
+}
+
+#endif /* BABELTRACE_PROPERTY_INTERNAL_H */
diff --git a/include/babeltrace/property.h b/include/babeltrace/property.h
new file mode 100644 (file)
index 0000000..9d79d78
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef BABELTRACE_PROPERTY_H
+#define BABELTRACE_PROPERTY_H
+
+/*
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum bt_property_availability {
+       BT_PROPERTY_AVAILABILITY_AVAILABLE,
+       BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_PROPERTY_H */
index f0bf0f10dd3e447248ac2027e5c198546d8d742a..43575291df542e8f65b8e14718c262a42f5533ae 100644 (file)
@@ -23,6 +23,8 @@
  * SOFTWARE.
  */
 
+#include <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -72,6 +74,8 @@ if (ret) {
 */
 typedef int bt_bool;
 
+typedef const uint8_t *bt_uuid;
+
 /** @} */
 
 #ifdef __cplusplus
index 56075a80e8ecfc56168c96b9b18a6a0cbf7fa536..dda79a6c14f835306040710bb11af8d401cb8436 100644 (file)
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libctf-ir.la
 libctf_ir_la_SOURCES = \
        attributes.c \
        clock-class.c \
+       clock-value.c \
        event.c \
        event-class.c \
        event-header-field.c \
@@ -13,12 +14,10 @@ libctf_ir_la_SOURCES = \
        packet.c \
        packet-context-field.c \
        packet-header-field.c \
+       resolve-field-path.c \
        stream.c \
        stream-class.c \
        trace.c \
-       utils.c \
-       resolve.c \
-       validation.c \
-       visitor.c
+       utils.c
 
 libctf_ir_la_LIBADD = $(UUID_LIBS)
index 88bee77634d121cd2a1d0d42bd2dbf1221dc2b2b..e4d5341925c0fa8e9b0f7dc822f4049affdfe053 100644 (file)
@@ -33,7 +33,7 @@
 #include <babeltrace/compat/uuid-internal.h>
 #include <babeltrace/ctf-ir/clock-class-internal.h>
 #include <babeltrace/ctf-ir/clock-value-internal.h>
-#include <babeltrace/ctf-ir/utils.h>
+#include <babeltrace/ctf-ir/utils-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/types.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/assert-internal.h>
 
-static
-void bt_clock_class_destroy(struct bt_object *obj);
-
-static
-struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class);
+#define BT_ASSERT_PRE_CLOCK_CLASS_HOT(_cc) \
+       BT_ASSERT_PRE_HOT((_cc), "Clock class", ": %!+K", (_cc))
 
 static
-void bt_clock_value_destroy(struct bt_clock_value *clock_value);
-
-BT_HIDDEN
-bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class)
+void destroy_clock_class(struct bt_object *obj)
 {
-       return clock_class && clock_class->name;
-}
+       struct bt_clock_class *clock_class = (void *) obj;
 
-int bt_clock_class_set_name(struct bt_clock_class *clock_class,
-               const char *name)
-{
-       int ret = 0;
+       BT_LIB_LOGD("Destroying clock class: %!+K", clock_class);
 
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
+       if (clock_class->name.str) {
+               g_string_free(clock_class->name.str, TRUE);
        }
 
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_identifier_is_valid(name)) {
-               BT_LOGW("Clock class's name is not a valid CTF identifier: "
-                       "addr=%p, name=\"%s\"",
-                       clock_class, name);
-               ret = -1;
-               goto end;
+       if (clock_class->description.str) {
+               g_string_free(clock_class->description.str, TRUE);
        }
 
-       if (clock_class->name) {
-               g_string_assign(clock_class->name, name);
-       } else {
-               clock_class->name = g_string_new(name);
-               if (!clock_class->name) {
-                       BT_LOGE_STR("Failed to allocate a GString.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Set clock class's name: addr=%p, name=\"%s\"",
-               clock_class, name);
-
-end:
-       return ret;
+       bt_object_pool_finalize(&clock_class->cv_pool);
+       g_free(clock_class);
 }
 
 static
-bool validate_freq(struct bt_clock_class *clock_class,
-               const char *name, uint64_t freq)
+void free_clock_value(struct bt_clock_value *clock_value,
+               struct bt_clock_class *clock_class)
 {
-       bool is_valid = true;
-
-       if (freq == -1ULL || freq == 0) {
-               BT_LOGW("Invalid parameter: frequency is invalid: "
-                       "addr=%p, name=\"%s\", freq=%" PRIu64,
-                       clock_class, name, freq);
-               is_valid = false;
-               goto end;
-       }
-
-end:
-       return is_valid;
+       bt_clock_value_destroy(clock_value);
 }
 
-static
-void bt_clock_class_free_clock_value(struct bt_clock_value *clock_value,
-               struct bt_clock_class *clock_class)
+static inline
+void set_base_offset(struct bt_clock_class *clock_class)
 {
-       bt_clock_value_destroy(clock_value);
+       uint64_t offset_cycles_ns;
+
+       /* Initialize nanosecond timestamp to clock's offset in seconds */
+       if (clock_class->offset_seconds <= (INT64_MIN / INT64_C(1000000000) - 1) ||
+                       clock_class->offset_seconds >= (INT64_MAX / INT64_C(1000000000)) - 1) {
+               /*
+                * Overflow: offset in seconds converted to nanoseconds
+                * is outside the int64_t range. We also subtract 1 here
+                * to leave "space" for the offset in cycles converted
+                * to nanoseconds (which is always less than 1 second by
+                * contract).
+                */
+               clock_class->base_offset.overflows = true;
+               goto end;
+       }
+
+       /* Offset (seconds) to nanoseconds */
+       clock_class->base_offset.value_ns = clock_class->offset_seconds *
+               INT64_C(1000000000);
+
+       /* Add offset in cycles */
+       BT_ASSERT(clock_class->offset_cycles < clock_class->frequency);
+       offset_cycles_ns = bt_util_ns_from_value(clock_class->frequency,
+               clock_class->offset_cycles);
+       BT_ASSERT(offset_cycles_ns < 1000000000);
+       clock_class->base_offset.value_ns += (int64_t) offset_cycles_ns;
+       clock_class->base_offset.overflows = false;
+
+end:
+       return;
 }
 
-struct bt_clock_class *bt_clock_class_create(const char *name,
-               uint64_t freq)
+struct bt_clock_class *bt_clock_class_create(void)
 {
        int ret;
        struct bt_clock_class *clock_class = NULL;
 
-       BT_LOGD("Creating default clock class object: name=\"%s\"",
-               name);
-
-       if (!validate_freq(NULL, name, freq)) {
-               /* validate_freq() logs errors */
-               goto error;
-       }
+       BT_LOGD_STR("Creating default clock class object");
 
        clock_class = g_new0(struct bt_clock_class, 1);
        if (!clock_class) {
@@ -146,22 +119,26 @@ struct bt_clock_class *bt_clock_class_create(const char *name,
                goto error;
        }
 
-       clock_class->precision = 1;
-       clock_class->frequency = freq;
-       bt_object_init_shared(&clock_class->base, bt_clock_class_destroy);
+       bt_object_init_shared(&clock_class->base, destroy_clock_class);
+       clock_class->name.str = g_string_new(NULL);
+       if (!clock_class->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
 
-       if (name) {
-               ret = bt_clock_class_set_name(clock_class, name);
-               if (ret) {
-                       /* bt_clock_class_set_name() logs errors */
-                       goto error;
-               }
+       clock_class->description.str = g_string_new(NULL);
+       if (!clock_class->description.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
        }
 
+       clock_class->frequency = UINT64_C(1000000000);
+       clock_class->is_absolute = BT_TRUE;
+       set_base_offset(clock_class);
        ret = bt_object_pool_initialize(&clock_class->cv_pool,
                (bt_object_pool_new_object_func) bt_clock_value_new,
                (bt_object_pool_destroy_object_func)
-                       bt_clock_class_free_clock_value,
+                       free_clock_value,
                clock_class);
        if (ret) {
                BT_LOGE("Failed to initialize clock value pool: ret=%d",
@@ -169,752 +146,184 @@ struct bt_clock_class *bt_clock_class_create(const char *name,
                goto error;
        }
 
-       BT_LOGD("Created clock class object: addr=%p, name=\"%s\"",
-               clock_class, name);
-       return clock_class;
+       BT_LIB_LOGD("Created clock class object: %!+K", clock_class);
+       goto end;
+
 error:
        BT_PUT(clock_class);
-       return clock_class;
-}
-
-const char *bt_clock_class_get_name(struct bt_clock_class *clock_class)
-{
-       const char *ret = NULL;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       if (clock_class->name) {
-               ret = clock_class->name->str;
-       }
 
 end:
-       return ret;
+       return clock_class;
 }
 
-const char *bt_clock_class_get_description(
+const char *bt_clock_class_get_name(
                struct bt_clock_class *clock_class)
 {
-       const char *ret = NULL;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->name.value;
+}
 
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
+int bt_clock_class_set_name(struct bt_clock_class *clock_class,
+               const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       g_string_assign(clock_class->name.str, name);
+       clock_class->name.value = clock_class->name.str->str;
+       BT_LIB_LOGV("Set clock class's name: %!+K", clock_class);
+       return 0;
+}
 
-       if (clock_class->description) {
-               ret = clock_class->description->str;
-       }
-end:
-       return ret;
+const char *bt_clock_class_get_description(struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->description.value;
 }
 
 int bt_clock_class_set_description(struct bt_clock_class *clock_class,
-               const char *desc)
+               const char *descr)
 {
-       int ret = 0;
-
-       if (!clock_class || !desc) {
-               BT_LOGW("Invalid parameter: clock class or description is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", desc-addr=%p",
-                       clock_class, bt_clock_class_get_name(clock_class),
-                       desc);
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->description = g_string_new(desc);
-       ret = clock_class->description ? 0 : -1;
-       BT_LOGV("Set clock class's description: addr=%p, "
-               "name=\"%s\", desc=\"%s\"",
-               clock_class, bt_clock_class_get_name(clock_class), desc);
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(descr, "Description");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       g_string_assign(clock_class->description.str, descr);
+       clock_class->description.value = clock_class->description.str->str;
+       BT_LIB_LOGV("Set clock class's description: %!+K",
+               clock_class);
+       return 0;
 }
 
-uint64_t bt_clock_class_get_frequency(
-               struct bt_clock_class *clock_class)
+uint64_t bt_clock_class_get_frequency(struct bt_clock_class *clock_class)
 {
-       uint64_t ret = -1ULL;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       ret = clock_class->frequency;
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->frequency;
 }
 
 int bt_clock_class_set_frequency(struct bt_clock_class *clock_class,
-               uint64_t freq)
+               uint64_t frequency)
 {
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW("Invalid parameter: clock class is NULL or frequency is invalid: "
-                       "addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!validate_freq(clock_class, bt_clock_class_get_name(clock_class),
-                       freq)) {
-               /* validate_freq() logs errors */
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->frequency = freq;
-       BT_LOGV("Set clock class's frequency: addr=%p, name=\"%s\", freq=%" PRIu64,
-               clock_class, bt_clock_class_get_name(clock_class), freq);
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       BT_ASSERT_PRE(frequency != UINT64_C(-1) && frequency != 0,
+               "Invalid frequency: %![cc-]+K, new-freq=%" PRIu64,
+               clock_class, frequency);
+       BT_ASSERT_PRE(clock_class->offset_cycles < frequency,
+               "Offset (cycles) is greater than clock class's frequency: "
+               "%![cc-]+K, new-freq=%" PRIu64, clock_class, frequency);
+       clock_class->frequency = frequency;
+       set_base_offset(clock_class);
+       BT_LIB_LOGV("Set clock class's frequency: %!+K", clock_class);
+       return 0;
 }
 
 uint64_t bt_clock_class_get_precision(struct bt_clock_class *clock_class)
 {
-       uint64_t ret = -1ULL;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       ret = clock_class->precision;
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->precision;
 }
 
 int bt_clock_class_set_precision(struct bt_clock_class *clock_class,
                uint64_t precision)
 {
-       int ret = 0;
-
-       if (!clock_class || precision == -1ULL) {
-               BT_LOGW("Invalid parameter: clock class is NULL or precision is invalid: "
-                       "addr=%p, name=\"%s\", precision=%" PRIu64,
-                       clock_class, bt_clock_class_get_name(clock_class),
-                       precision);
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       BT_ASSERT_PRE(precision != UINT64_C(-1),
+               "Invalid precision: %![cc-]+K, new-precision=%" PRIu64,
+               clock_class, precision);
        clock_class->precision = precision;
-       BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64,
-               clock_class, bt_clock_class_get_name(clock_class),
-               precision);
-end:
-       return ret;
+       BT_LIB_LOGV("Set clock class's precision: %!+K", clock_class);
+       return 0;
 }
 
-int bt_clock_class_get_offset_s(struct bt_clock_class *clock_class,
-               int64_t *offset_s)
+void bt_clock_class_get_offset(struct bt_clock_class *clock_class,
+               int64_t *seconds, uint64_t *cycles)
 {
-       int ret = 0;
-
-       if (!clock_class || !offset_s) {
-               BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", offset-addr=%p",
-                       clock_class, bt_clock_class_get_name(clock_class),
-                       offset_s);
-               ret = -1;
-               goto end;
-       }
-
-       *offset_s = clock_class->offset_s;
-end:
-       return ret;
-}
-
-int bt_clock_class_set_offset_s(struct bt_clock_class *clock_class,
-               int64_t offset_s)
-{
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->offset_s = offset_s;
-       BT_LOGV("Set clock class's offset (seconds): "
-               "addr=%p, name=\"%s\", offset-s=%" PRId64,
-               clock_class, bt_clock_class_get_name(clock_class),
-               offset_s);
-end:
-       return ret;
-}
-
-int bt_clock_class_get_offset_cycles(struct bt_clock_class *clock_class,
-               int64_t *offset)
-{
-       int ret = 0;
-
-       if (!clock_class || !offset) {
-               BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", offset-addr=%p",
-                       clock_class, bt_clock_class_get_name(clock_class),
-                       offset);
-               ret = -1;
-               goto end;
-       }
-
-       *offset = clock_class->offset;
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(seconds, "Seconds (output)");
+       BT_ASSERT_PRE_NON_NULL(cycles, "Cycles (output)");
+       *seconds = clock_class->offset_seconds;
+       *cycles = clock_class->offset_cycles;
 }
 
-int bt_clock_class_set_offset_cycles(struct bt_clock_class *clock_class,
-               int64_t offset)
+int bt_clock_class_set_offset(struct bt_clock_class *clock_class,
+               int64_t seconds, uint64_t cycles)
 {
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->offset = offset;
-       BT_LOGV("Set clock class's offset (cycles): addr=%p, name=\"%s\", offset-cycles=%" PRId64,
-               clock_class, bt_clock_class_get_name(clock_class), offset);
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       BT_ASSERT_PRE(cycles < clock_class->frequency,
+               "Offset (cycles) is greater than clock class's frequency: "
+               "%![cc-]+K, new-offset-cycles=%" PRIu64, clock_class, cycles);
+       clock_class->offset_seconds = seconds;
+       clock_class->offset_cycles = cycles;
+       set_base_offset(clock_class);
+       BT_LIB_LOGV("Set clock class's offset: %!+K", clock_class);
+       return 0;
 }
 
 bt_bool bt_clock_class_is_absolute(struct bt_clock_class *clock_class)
 {
-       int ret = -1;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       ret = clock_class->absolute;
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return (bool) clock_class->is_absolute;
 }
 
 int bt_clock_class_set_is_absolute(struct bt_clock_class *clock_class,
                bt_bool is_absolute)
 {
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->absolute = !!is_absolute;
-       BT_LOGV("Set clock class's absolute flag: addr=%p, name=\"%s\", is-absolute=%d",
-               clock_class, bt_clock_class_get_name(clock_class),
-               is_absolute);
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       clock_class->is_absolute = (bool) is_absolute;
+       BT_LIB_LOGV("Set clock class's absolute property: %!+K",
+               clock_class);
+       return 0;
 }
 
-const unsigned char *bt_clock_class_get_uuid(
-               struct bt_clock_class *clock_class)
+bt_uuid bt_clock_class_get_uuid(struct bt_clock_class *clock_class)
 {
-       const unsigned char *ret;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = NULL;
-               goto end;
-       }
-
-       if (!clock_class->uuid_set) {
-               BT_LOGV("Clock class's UUID is not set: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = NULL;
-               goto end;
-       }
-
-       ret = clock_class->uuid;
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->uuid.value;
 }
 
 int bt_clock_class_set_uuid(struct bt_clock_class *clock_class,
-               const unsigned char *uuid)
+               bt_uuid uuid)
 {
-       int ret = 0;
-
-       if (!clock_class || !uuid) {
-               BT_LOGW("Invalid parameter: clock class or UUID is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", uuid-addr=%p",
-                       clock_class, bt_clock_class_get_name(clock_class),
-                       uuid);
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       memcpy(clock_class->uuid, uuid, BABELTRACE_UUID_LEN);
-       clock_class->uuid_set = 1;
-       BT_LOGV("Set clock class's UUID: addr=%p, name=\"%s\", "
-               "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-               clock_class, bt_clock_class_get_name(clock_class),
-               (unsigned int) uuid[0],
-               (unsigned int) uuid[1],
-               (unsigned int) uuid[2],
-               (unsigned int) uuid[3],
-               (unsigned int) uuid[4],
-               (unsigned int) uuid[5],
-               (unsigned int) uuid[6],
-               (unsigned int) uuid[7],
-               (unsigned int) uuid[8],
-               (unsigned int) uuid[9],
-               (unsigned int) uuid[10],
-               (unsigned int) uuid[11],
-               (unsigned int) uuid[12],
-               (unsigned int) uuid[13],
-               (unsigned int) uuid[14],
-               (unsigned int) uuid[15]);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_clock_class_freeze(struct bt_clock_class *clock_class)
-{
-       if (!clock_class || clock_class->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"",
-               clock_class, bt_clock_class_get_name(clock_class));
-       clock_class->frozen = 1;
-}
-
-static
-void bt_clock_class_destroy(struct bt_object *obj)
-{
-       struct bt_clock_class *clock_class;
-
-       clock_class = container_of(obj, struct bt_clock_class, base);
-       BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"",
-               obj, bt_clock_class_get_name(clock_class));
-
-       if (clock_class->name) {
-               g_string_free(clock_class->name, TRUE);
-       }
-
-       if (clock_class->description) {
-               g_string_free(clock_class->description, TRUE);
-       }
-
-       bt_object_pool_finalize(&clock_class->cv_pool);
-       g_free(clock_class);
-}
-
-static
-void bt_clock_value_destroy(struct bt_clock_value *clock_value)
-{
-       BT_LOGD("Destroying clock value: addr=%p, clock-class-addr=%p, "
-               "clock-class-name=\"%s\"", clock_value,
-               clock_value->clock_class,
-               bt_clock_class_get_name(clock_value->clock_class));
-       bt_put(clock_value->clock_class);
-       g_free(clock_value);
-}
-
-static
-struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class)
-{
-       struct bt_clock_value *ret = NULL;
-
-       BT_LOGD("Creating clock value object: clock-class-addr=%p, "
-               "clock-class-name=\"%s\"", clock_class,
-               bt_clock_class_get_name(clock_class));
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       ret = g_new0(struct bt_clock_value, 1);
-       if (!ret) {
-               BT_LOGE_STR("Failed to allocate one clock value.");
-               goto end;
-       }
-
-       bt_object_init_unique(&ret->base);
-       ret->clock_class = bt_get(clock_class);
-       bt_clock_class_freeze(clock_class);
-       BT_LOGD("Created clock value object: clock-value-addr=%p, "
-               "clock-class-addr=%p, clock-class-name=\"%s\", "
-               "ns-from-epoch=%" PRId64 ", ns-from-epoch-overflows=%d",
-               ret, clock_class, bt_clock_class_get_name(clock_class),
-               ret->ns_from_epoch, ret->ns_from_epoch_overflows);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_clock_value *bt_clock_value_create(struct bt_clock_class *clock_class)
-{
-       struct bt_clock_value *clock_value = NULL;
-
-       BT_ASSERT(clock_class);
-       clock_value = bt_object_pool_create_object(&clock_class->cv_pool);
-       if (!clock_value) {
-               BT_LIB_LOGE("Cannot allocate one clock value from clock class's clock value pool: "
-                       "%![cc-]+K", clock_class);
-               goto error;
-       }
-
-       if (!clock_value->clock_class) {
-               clock_value->clock_class = bt_get(clock_class);
-       }
-
-       goto end;
-
-error:
-       if (clock_value) {
-               bt_clock_value_recycle(clock_value);
-               clock_value = NULL;
-       }
-
-end:
-       return clock_value;
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(uuid, "UUID");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       memcpy(clock_class->uuid.uuid, uuid, BABELTRACE_UUID_LEN);
+       clock_class->uuid.value = clock_class->uuid.uuid;
+       BT_LIB_LOGV("Set clock class's UUID: %!+K", clock_class);
+       return 0;
 }
 
 BT_HIDDEN
-void bt_clock_value_recycle(struct bt_clock_value *clock_value)
+void _bt_clock_class_freeze(struct bt_clock_class *clock_class)
 {
-       struct bt_clock_class *clock_class;
-
-       BT_ASSERT(clock_value);
-       BT_LIB_LOGD("Recycling clock value: %!+k", clock_value);
-
-       /*
-        * Those are the important ordered steps:
-        *
-        * 1. Reset the clock value object, but do NOT put its clock
-        *    class's reference. This clock class contains the pool to
-        *    which we're about to recycle this clock value object, so
-        *    we must guarantee its existence thanks to this existing
-        *    reference.
-        *
-        * 2. Move the clock class reference to our `clock_class`
-        *    variable so that we can set the clock value's clock class
-        *    member to NULL before recycling it. We CANNOT do this
-        *    after we put the clock class reference because this
-        *    bt_put() could destroy the clock class, also destroying
-        *    its clock value pool, thus also destroying our clock value
-        *    object (this would result in an invalid write access).
-        *
-        * 3. Recycle the clock value object.
-        *
-        * 4. Put our clock class reference.
-        */
-       bt_clock_value_reset(clock_value);
-       bt_clock_value_set_is_frozen(clock_value, false);
-       clock_class = clock_value->clock_class;
        BT_ASSERT(clock_class);
-       clock_value->clock_class = NULL;
-       bt_object_pool_recycle_object(&clock_class->cv_pool, clock_value);
-       bt_put(clock_class);
-}
-
-int bt_clock_value_get_value(struct bt_clock_value *clock_value,
-               uint64_t *raw_value)
-{
-       int ret = 0;
-
-       if (!clock_value || !raw_value) {
-               BT_LOGW("Invalid parameter: clock value or raw value is NULL: "
-                       "clock-value-addr=%p, raw-value-addr=%p",
-                       clock_value, raw_value);
-               ret = -1;
-               goto end;
-       }
-
-       *raw_value = clock_value->value;
-end:
-       return ret;
-}
-
-int bt_clock_value_get_value_ns_from_epoch(struct bt_clock_value *value,
-               int64_t *ret_value_ns)
-{
-       int ret = 0;
-
-       if (!value || !ret_value_ns) {
-               BT_LOGW("Invalid parameter: clock value or return value pointer is NULL: "
-                       "clock-value-addr=%p, ret-value-addr=%p",
-                       value, ret_value_ns);
-               ret = -1;
-               goto end;
-       }
-
-       if (value->ns_from_epoch_overflows) {
-               BT_LOGW("Clock value converted to nanoseconds from Epoch overflows the signed 64-bit integer range: "
-                       "clock-value-addr=%p, "
-                       "clock-class-offset-s=%" PRId64 ", "
-                       "clock-class-offset-cycles=%" PRId64 ", "
-                       "value=%" PRIu64,
-                       value, value->clock_class->offset_s,
-                       value->clock_class->offset,
-                       value->value);
-               ret = -1;
-               goto end;
-       }
-
-       *ret_value_ns = value->ns_from_epoch;
-
-end:
-       return ret;
-}
-
-struct bt_clock_class *bt_clock_value_borrow_class(
-               struct bt_clock_value *clock_value)
-{
-       struct bt_clock_class *clock_class = NULL;
-
-       if (!clock_value) {
-               BT_LOGW_STR("Invalid parameter: clock value is NULL.");
-               goto end;
-       }
-
-       clock_class = clock_value->clock_class;
 
-end:
-       return clock_class;
-}
-
-BT_HIDDEN
-int bt_clock_class_compare(struct bt_clock_class *clock_class_a,
-               struct bt_clock_class *clock_class_b)
-{
-       int ret = 1;
-       BT_ASSERT(clock_class_a);
-       BT_ASSERT(clock_class_b);
-
-       /* Name */
-       if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) {
-               BT_LOGV("Clock classes differ: different names: "
-                       "cc-a-name=\"%s\", cc-b-name=\"%s\"",
-                       clock_class_a->name->str,
-                       clock_class_b->name->str);
-               goto end;
-       }
-
-       /* Description */
-       if (clock_class_a->description) {
-               if (!clock_class_b->description) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has a "
-                               "description, but clock class B does not.");
-                       goto end;
-               }
-
-               if (strcmp(clock_class_a->name->str, clock_class_b->name->str)
-                               != 0) {
-                       BT_LOGV("Clock classes differ: different descriptions: "
-                               "cc-a-descr=\"%s\", cc-b-descr=\"%s\"",
-                               clock_class_a->description->str,
-                               clock_class_b->description->str);
-                       goto end;
-               }
-       } else {
-               if (clock_class_b->description) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has "
-                               "no description, but clock class B has one.");
-                       goto end;
-               }
-       }
-
-       /* Frequency */
-       if (clock_class_a->frequency != clock_class_b->frequency) {
-               BT_LOGV("Clock classes differ: different frequencies: "
-                       "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
-                       clock_class_a->frequency,
-                       clock_class_b->frequency);
-               goto end;
-       }
-
-       /* Precision */
-       if (clock_class_a->precision != clock_class_b->precision) {
-               BT_LOGV("Clock classes differ: different precisions: "
-                       "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
-                       clock_class_a->precision,
-                       clock_class_b->precision);
-               goto end;
-       }
-
-       /* Offset (seconds) */
-       if (clock_class_a->offset_s != clock_class_b->offset_s) {
-               BT_LOGV("Clock classes differ: different offsets (seconds): "
-                       "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
-                       clock_class_a->offset_s,
-                       clock_class_b->offset_s);
-               goto end;
-       }
-
-       /* Offset (cycles) */
-       if (clock_class_a->offset != clock_class_b->offset) {
-               BT_LOGV("Clock classes differ: different offsets (cycles): "
-                       "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
-                       clock_class_a->offset,
-                       clock_class_b->offset);
-               goto end;
-       }
-
-       /* UUIDs */
-       if (clock_class_a->uuid_set) {
-               if (!clock_class_b->uuid_set) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has a "
-                               "UUID, but clock class B does not.");
-                       goto end;
-               }
-
-               if (memcmp(clock_class_a->uuid, clock_class_b->uuid,
-                               BABELTRACE_UUID_LEN) != 0) {
-                       BT_LOGV("Clock classes differ: different UUIDs: "
-                               "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", "
-                               "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-                               (unsigned int) clock_class_a->uuid[0],
-                               (unsigned int) clock_class_a->uuid[1],
-                               (unsigned int) clock_class_a->uuid[2],
-                               (unsigned int) clock_class_a->uuid[3],
-                               (unsigned int) clock_class_a->uuid[4],
-                               (unsigned int) clock_class_a->uuid[5],
-                               (unsigned int) clock_class_a->uuid[6],
-                               (unsigned int) clock_class_a->uuid[7],
-                               (unsigned int) clock_class_a->uuid[8],
-                               (unsigned int) clock_class_a->uuid[9],
-                               (unsigned int) clock_class_a->uuid[10],
-                               (unsigned int) clock_class_a->uuid[11],
-                               (unsigned int) clock_class_a->uuid[12],
-                               (unsigned int) clock_class_a->uuid[13],
-                               (unsigned int) clock_class_a->uuid[14],
-                               (unsigned int) clock_class_a->uuid[15],
-                               (unsigned int) clock_class_b->uuid[0],
-                               (unsigned int) clock_class_b->uuid[1],
-                               (unsigned int) clock_class_b->uuid[2],
-                               (unsigned int) clock_class_b->uuid[3],
-                               (unsigned int) clock_class_b->uuid[4],
-                               (unsigned int) clock_class_b->uuid[5],
-                               (unsigned int) clock_class_b->uuid[6],
-                               (unsigned int) clock_class_b->uuid[7],
-                               (unsigned int) clock_class_b->uuid[8],
-                               (unsigned int) clock_class_b->uuid[9],
-                               (unsigned int) clock_class_b->uuid[10],
-                               (unsigned int) clock_class_b->uuid[11],
-                               (unsigned int) clock_class_b->uuid[12],
-                               (unsigned int) clock_class_b->uuid[13],
-                               (unsigned int) clock_class_b->uuid[14],
-                               (unsigned int) clock_class_b->uuid[15]);
-                       goto end;
-               }
-       } else {
-               if (clock_class_b->uuid_set) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has "
-                               "no UUID, but clock class B has one.");
-                       goto end;
-               }
-       }
-
-       /* Absolute */
-       if (!!clock_class_a->absolute != !!clock_class_b->absolute) {
-               BT_LOGV("Clock classes differ: one is absolute, the other "
-                       "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d",
-                       !!clock_class_a->absolute,
-                       !!clock_class_b->absolute);
-               goto end;
+       if (clock_class->frozen) {
+               return;
        }
 
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
+       BT_LIB_LOGD("Freezing clock class: %!+K", clock_class);
+       clock_class->frozen = 1;
 }
 
-int bt_clock_class_cycles_to_ns(struct bt_clock_class *clock_class,
+int bt_clock_class_cycles_to_ns_from_origin(struct bt_clock_class *clock_class,
                uint64_t cycles, int64_t *ns)
 {
        int ret;
-       bool overflows;
 
        BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds");
-
-       ret = ns_from_epoch(clock_class, cycles, ns, &overflows);
+       BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds (output)");
+       ret = bt_util_ns_from_origin(clock_class, cycles, ns);
        if (ret) {
-               if (overflows) {
-                       BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
-                               "from Epoch for given clock class: "
-                               "value overflow: %![cc-]+K, cycles=%" PRIu64,
-                               clock_class, cycles);
-               } else {
-                       BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
-                               "from Epoch for given clock class: "
-                               "%![cc-]+K, cycles=%" PRIu64,
-                               clock_class, cycles);
-               }
-
-               goto end;
+               BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
+                       "from origin for given clock class: "
+                       "value overflows the signed 64-bit integer range: "
+                       "%![cc-]+K, cycles=%" PRIu64,
+                       clock_class, cycles);
        }
 
-end:
        return ret;
 }
diff --git a/lib/ctf-ir/clock-value.c b/lib/ctf-ir/clock-value.c
new file mode 100644 (file)
index 0000000..51c89dd
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CLOCK-VALUE"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/compat/uuid-internal.h>
+#include <babeltrace/ctf-ir/clock-class-internal.h>
+#include <babeltrace/ctf-ir/clock-value-internal.h>
+#include <babeltrace/ref.h>
+#include <babeltrace/compiler-internal.h>
+#include <babeltrace/types.h>
+#include <babeltrace/compat/string-internal.h>
+#include <inttypes.h>
+#include <babeltrace/object-internal.h>
+#include <babeltrace/assert-internal.h>
+
+BT_HIDDEN
+void bt_clock_value_destroy(struct bt_clock_value *clock_value)
+{
+       BT_LIB_LOGD("Destroying clock value: %!+k", clock_value);
+       bt_put(clock_value->clock_class);
+       g_free(clock_value);
+}
+
+BT_HIDDEN
+struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class)
+{
+       struct bt_clock_value *ret = NULL;
+
+       BT_ASSERT(clock_class);
+       BT_LIB_LOGD("Creating clock value object: %![cc-]+K=",
+               clock_class);
+       ret = g_new0(struct bt_clock_value, 1);
+       if (!ret) {
+               BT_LOGE_STR("Failed to allocate one clock value.");
+               goto end;
+       }
+
+       bt_object_init_unique(&ret->base);
+       ret->clock_class = bt_get(clock_class);
+       bt_clock_class_freeze(clock_class);
+       BT_LIB_LOGD("Created clock value object: %!+k", ret);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_clock_value *bt_clock_value_create(struct bt_clock_class *clock_class)
+{
+       struct bt_clock_value *clock_value = NULL;
+
+       BT_ASSERT(clock_class);
+       clock_value = bt_object_pool_create_object(&clock_class->cv_pool);
+       if (!clock_value) {
+               BT_LIB_LOGE("Cannot allocate one clock value from clock class's clock value pool: "
+                       "%![cc-]+K", clock_class);
+               goto error;
+       }
+
+       if (likely(!clock_value->clock_class)) {
+               clock_value->clock_class = bt_get(clock_class);
+       }
+
+       goto end;
+
+error:
+       if (clock_value) {
+               bt_clock_value_recycle(clock_value);
+               clock_value = NULL;
+       }
+
+end:
+       return clock_value;
+}
+
+BT_HIDDEN
+void bt_clock_value_recycle(struct bt_clock_value *clock_value)
+{
+       struct bt_clock_class *clock_class;
+
+       BT_ASSERT(clock_value);
+       BT_LIB_LOGD("Recycling clock value: %!+k", clock_value);
+
+       /*
+        * Those are the important ordered steps:
+        *
+        * 1. Reset the clock value object, but do NOT put its clock
+        *    class's reference. This clock class contains the pool to
+        *    which we're about to recycle this clock value object, so
+        *    we must guarantee its existence thanks to this existing
+        *    reference.
+        *
+        * 2. Move the clock class reference to our `clock_class`
+        *    variable so that we can set the clock value's clock class
+        *    member to NULL before recycling it. We CANNOT do this
+        *    after we put the clock class reference because this
+        *    bt_put() could destroy the clock class, also destroying
+        *    its clock value pool, thus also destroying our clock value
+        *    object (this would result in an invalid write access).
+        *
+        * 3. Recycle the clock value object.
+        *
+        * 4. Put our clock class reference.
+        */
+       bt_clock_value_reset(clock_value);
+       clock_class = clock_value->clock_class;
+       BT_ASSERT(clock_class);
+       clock_value->clock_class = NULL;
+       bt_object_pool_recycle_object(&clock_class->cv_pool, clock_value);
+       bt_put(clock_class);
+}
+
+uint64_t bt_clock_value_get_value(struct bt_clock_value *clock_value)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
+       BT_ASSERT_PRE(clock_value->is_set,
+               "Clock value is not set: %!+k", clock_value);
+       return clock_value->value_cycles;
+}
+
+int bt_clock_value_get_ns_from_origin(struct bt_clock_value *clock_value,
+               int64_t *ret_value_ns)
+{
+       int ret = 0;
+       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
+       BT_ASSERT_PRE_NON_NULL(ret_value_ns, "Value (ns) (output)");
+       BT_ASSERT_PRE(clock_value->is_set,
+               "Clock value is not set: %!+k", clock_value);
+
+       if (clock_value->ns_from_origin_overflows) {
+               BT_LIB_LOGD("Clock value, once converted to nanoseconds from origin, "
+                       "overflows the signed 64-bit integer range: "
+                       "%![cv-]+k", clock_value);
+               ret = -1;
+               goto end;
+       }
+
+       *ret_value_ns = clock_value->ns_from_origin;
+
+end:
+       return ret;
+}
+
+struct bt_clock_class *bt_clock_value_borrow_clock_class(
+               struct bt_clock_value *clock_value)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
+       return clock_value->clock_class;
+}
index 61d49fbe08be487b14fa519d0ae8e23962783a50..b8824082c7c62eaadec7fc0ec2c08dd4837f5b9f 100644 (file)
@@ -32,6 +32,7 @@
 #include <babeltrace/assert-pre-internal.h>
 #include <babeltrace/ctf-ir/clock-value-internal.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
+#include <babeltrace/ctf-ir/field-types.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/event-class.h>
 #include <babeltrace/ctf-ir/event-class-internal.h>
@@ -39,9 +40,8 @@
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/trace-internal.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
-#include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
+#include <babeltrace/ctf-ir/resolve-field-path-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/ctf-ir/attributes-internal.h>
 #include <babeltrace/compiler-internal.h>
 #include <inttypes.h>
 #include <stdlib.h>
 
-static inline
-void bt_event_class_finalize(struct bt_object *obj)
+#define BT_ASSERT_PRE_EVENT_CLASS_HOT(_ec) \
+       BT_ASSERT_PRE_HOT((_ec), "Event class", ": %!+E", (_ec))
+
+static
+void destroy_event_class(struct bt_object *obj)
 {
-       struct bt_event_class *event_class;
+       struct bt_event_class *event_class = (void *) obj;
 
-       event_class = container_of(obj, struct bt_event_class, base);
-       BT_LOGD("Finalizing event class: addr=%p, name=\"%s\", id=%" PRId64,
-               event_class, bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class));
+       BT_LIB_LOGD("Destroying event class: %!+E", event_class);
 
-       if (event_class->name) {
-               g_string_free(event_class->name, TRUE);
+       if (event_class->name.str) {
+               g_string_free(event_class->name.str, TRUE);
        }
 
-       if (event_class->emf_uri) {
-               g_string_free(event_class->emf_uri, TRUE);
+       if (event_class->emf_uri.str) {
+               g_string_free(event_class->emf_uri.str, TRUE);
        }
 
        BT_LOGD_STR("Putting context field type.");
-       bt_put(event_class->context_field_type);
+       bt_put(event_class->specific_context_ft);
        BT_LOGD_STR("Putting payload field type.");
-       bt_put(event_class->payload_field_type);
-}
-
-static inline
-int bt_event_class_initialize(struct bt_event_class *event_class,
-               const char *name, bt_object_release_func release_func,
-               bt_field_type_structure_create_func ft_struct_create_func)
-{
-       int ret = 0;
-
-       BT_LOGD("Initializing event class object: name=\"%s\"",
-               name);
-       bt_object_init_shared_with_parent(&event_class->base, release_func);
-       event_class->payload_field_type = ft_struct_create_func();
-       if (!event_class->payload_field_type) {
-               BT_LOGE_STR("Cannot create event class's initial payload field type object.");
-               goto error;
-       }
-
-       event_class->id = -1;
-       event_class->name = g_string_new(name);
-       if (!event_class->name) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       event_class->emf_uri = g_string_new(NULL);
-       if (!event_class->emf_uri) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       event_class->log_level = BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED;
-       BT_LOGD("Initialized event class object: addr=%p, name=\"%s\"",
-               event_class, bt_event_class_get_name(event_class));
-       return ret;
-
-error:
-       ret = -1;
-       return ret;
-}
-
-static
-void bt_event_class_destroy(struct bt_object *obj)
-{
-       struct bt_event_class *event_class = (void *) obj;
-
-       BT_LOGD("Destroying event class: addr=%p", obj);
-       bt_event_class_finalize(obj);
+       bt_put(event_class->payload_ft);
        bt_object_pool_finalize(&event_class->event_pool);
        g_free(obj);
 }
@@ -133,30 +85,63 @@ void free_event(struct bt_event *event,
        bt_event_destroy(event);
 }
 
-struct bt_event_class *bt_event_class_create(const char *name)
+BT_ASSERT_PRE_FUNC
+static
+bool event_class_id_is_unique(struct bt_stream_class *stream_class, uint64_t id)
 {
-       int ret;
-       struct bt_event_class *event_class = NULL;
+       uint64_t i;
+       bool is_unique = true;
 
-       if (!name) {
-               BT_LOGW_STR("Invalid parameter: name is NULL.");
-               goto error;
+       for (i = 0; i < stream_class->event_classes->len; i++) {
+               struct bt_event_class *ec =
+                       stream_class->event_classes->pdata[i];
+
+               if (ec->id == id) {
+                       is_unique = false;
+                       goto end;
+               }
        }
 
-       BT_LOGD("Creating event class object: name=\"%s\"",
-               name);
+end:
+       return is_unique;
+}
+
+static
+struct bt_event_class *create_event_class_with_id(
+               struct bt_stream_class *stream_class, uint64_t id)
+{
+       int ret;
+       struct bt_event_class *event_class;
+
+       BT_ASSERT(stream_class);
+       BT_ASSERT_PRE(event_class_id_is_unique(stream_class, id),
+               "Duplicate event class ID: %![sc-]+S, id=%" PRIu64,
+               stream_class, id);
+       BT_LIB_LOGD("Creating event class object: %![sc-]+S, id=%" PRIu64,
+               stream_class, id);
        event_class = g_new0(struct bt_event_class, 1);
        if (!event_class) {
                BT_LOGE_STR("Failed to allocate one event class.");
                goto error;
        }
 
-       ret = bt_event_class_initialize(event_class,
-               name, bt_event_class_destroy,
-               (bt_field_type_structure_create_func)
-                       bt_field_type_structure_create);
-       if (ret) {
-               goto error;
+       bt_object_init_shared_with_parent(&event_class->base,
+               destroy_event_class);
+       event_class->id = id;
+       bt_property_uint_init(&event_class->log_level,
+                       BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE, 0);
+       event_class->name.str = g_string_new(NULL);
+       if (!event_class->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
+       }
+
+       event_class->emf_uri.str = g_string_new(NULL);
+       if (!event_class->emf_uri.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
        }
 
        ret = bt_object_pool_initialize(&event_class->event_pool,
@@ -169,374 +154,224 @@ struct bt_event_class *bt_event_class_create(const char *name)
                goto error;
        }
 
-       BT_LOGD("Created event class object: addr=%p, name=\"%s\"",
-               event_class, bt_event_class_get_name(event_class));
+       bt_object_set_parent(&event_class->base, &stream_class->base);
+       g_ptr_array_add(stream_class->event_classes, event_class);
+       bt_stream_class_freeze(stream_class);
+       BT_LIB_LOGD("Created event class object: %!+E", event_class);
        goto end;
 
 error:
-       bt_put(event_class);
+       BT_PUT(event_class);
 
 end:
        return event_class;
 }
 
+struct bt_event_class *bt_event_class_create(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(stream_class->assigns_automatic_event_class_id,
+               "Stream class does not automatically assigns event class IDs: "
+               "%![sc-]+S", stream_class);
+       return create_event_class_with_id(stream_class,
+               (uint64_t) stream_class->event_classes->len);
+}
+
+struct bt_event_class *bt_event_class_create_with_id(
+               struct bt_stream_class *stream_class, uint64_t id)
+{
+       BT_ASSERT_PRE(!stream_class->assigns_automatic_event_class_id,
+               "Stream class automatically assigns event class IDs: "
+               "%![sc-]+S", stream_class);
+       return create_event_class_with_id(stream_class, id);
+}
+
 const char *bt_event_class_get_name(struct bt_event_class *event_class)
 {
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT(event_class->name);
-       return event_class->name->str;
+       return event_class->name.value;
 }
 
-int64_t bt_event_class_get_id(struct bt_event_class *event_class)
+int bt_event_class_set_name(struct bt_event_class *event_class,
+               const char *name)
 {
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->id;
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       g_string_assign(event_class->name.str, name);
+       event_class->name.value = event_class->name.str->str;
+       BT_LIB_LOGV("Set event class's name: %!+E", event_class);
+       return 0;
 }
 
-int bt_event_class_set_id(struct bt_event_class *event_class,
-               uint64_t id_param)
+uint64_t bt_event_class_get_id(struct bt_event_class *event_class)
 {
-       int ret = 0;
-       int64_t id = (int64_t) id_param;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class,
-                       bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (id < 0) {
-               BT_LOGW("Invalid parameter: invalid event class's ID: "
-                       "addr=%p, name=\"%s\", id=%" PRIu64,
-                       event_class,
-                       bt_event_class_get_name(event_class),
-                       id_param);
-               ret = -1;
-               goto end;
-       }
-
-       event_class->id = id;
-       BT_LOGV("Set event class's ID: "
-               "addr=%p, name=\"%s\", id=%" PRId64,
-               event_class, bt_event_class_get_name(event_class), id);
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->id;
 }
 
-enum bt_event_class_log_level bt_event_class_get_log_level(
-               struct bt_event_class *event_class)
+enum bt_property_availability bt_event_class_get_log_level(
+               struct bt_event_class *event_class,
+               enum bt_event_class_log_level *log_level)
 {
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->log_level;
+       BT_ASSERT_PRE_NON_NULL(log_level, "Log level (output)");
+       *log_level = (enum bt_event_class_log_level)
+               event_class->log_level.value;
+       return event_class->log_level.base.avail;
 }
 
 int bt_event_class_set_log_level(struct bt_event_class *event_class,
                enum bt_event_class_log_level log_level)
 {
-       int ret = 0;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class,
-                       bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       switch (log_level) {
-       case BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED:
-       case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
-       case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
-       case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
-       case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
-       case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
-       case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
-       case BT_EVENT_CLASS_LOG_LEVEL_INFO:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
-               break;
-       default:
-               BT_LOGW("Invalid parameter: unknown event class log level: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", log-level=%d",
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class), log_level);
-               ret = -1;
-               goto end;
-       }
-
-       event_class->log_level = log_level;
-       BT_LOGV("Set event class's log level: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", log-level=%s",
-               event_class, bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class),
-               bt_common_event_class_log_level_string(log_level));
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       bt_property_uint_set(&event_class->log_level,
+               (uint64_t) log_level);
+       BT_LIB_LOGV("Set event class's log level: %!+E", event_class);
+       return 0;
 }
 
 const char *bt_event_class_get_emf_uri(struct bt_event_class *event_class)
 {
-       const char *emf_uri = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-
-       if (event_class->emf_uri->len > 0) {
-               emf_uri = event_class->emf_uri->str;
-       }
-
-       return emf_uri;
+       return event_class->emf_uri.value;
 }
 
 int bt_event_class_set_emf_uri(struct bt_event_class *event_class,
                const char *emf_uri)
 {
-       int ret = 0;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (emf_uri && strlen(emf_uri) == 0) {
-               BT_LOGW_STR("Invalid parameter: EMF URI is empty.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (emf_uri) {
-               g_string_assign(event_class->emf_uri, emf_uri);
-               BT_LOGV("Set event class's EMF URI: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", emf-uri=\"%s\"",
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class), emf_uri);
-       } else {
-               g_string_assign(event_class->emf_uri, "");
-               BT_LOGV("Reset event class's EMF URI: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class));
-       }
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(emf_uri, "EMF URI");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       g_string_assign(event_class->emf_uri.str, emf_uri);
+       event_class->emf_uri.value = event_class->emf_uri.str->str;
+       BT_LIB_LOGV("Set event class's EMF URI: %!+E", event_class);
+       return 0;
 }
 
 struct bt_stream_class *bt_event_class_borrow_stream_class(
                struct bt_event_class *event_class)
 {
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return (void *) bt_object_borrow_parent(&event_class->base);
+       return bt_event_class_borrow_stream_class_inline(event_class);
 }
 
-struct bt_field_type *bt_event_class_borrow_payload_field_type(
+struct bt_field_type *bt_event_class_borrow_specific_context_field_type(
                struct bt_event_class *event_class)
 {
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->payload_field_type;
+       return event_class->specific_context_ft;
 }
 
-int bt_event_class_set_payload_field_type(struct bt_event_class *event_class,
+int bt_event_class_set_specific_context_field_type(
+               struct bt_event_class *event_class,
                struct bt_field_type *field_type)
 {
-       int ret = 0;
+       int ret;
+       struct bt_stream_class *stream_class;
+       struct bt_trace *trace;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_header = NULL,
+               .packet_context = NULL,
+               .event_header = NULL,
+               .event_common_context = NULL,
+               .event_specific_context = field_type,
+               .event_payload = NULL,
+       };
 
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(field_type, "Field type");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       BT_ASSERT_PRE(bt_field_type_get_type_id(field_type) ==
+               BT_FIELD_TYPE_ID_STRUCTURE,
+               "Specific context field type is not a structure field type: "
+               "%!+F", field_type);
+       stream_class = bt_event_class_borrow_stream_class_inline(
+               event_class);
+       trace = bt_stream_class_borrow_trace_inline(stream_class);
+       resolve_ctx.packet_header = trace->packet_header_ft;
+       resolve_ctx.packet_context = stream_class->packet_context_ft;
+       resolve_ctx.event_header = stream_class->event_header_ft;
+       resolve_ctx.event_common_context =
+               stream_class->event_common_context_ft;
+
+       ret = bt_resolve_field_paths(field_type, &resolve_ctx);
+       if (ret) {
                goto end;
        }
 
-       if (field_type && bt_field_type_get_type_id(field_type) !=
-                       BT_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: event class's payload field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "payload-ft-addr=%p, payload-ft-id=%s",
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class), field_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(field_type)));
-               ret = -1;
-               goto end;
-       }
+       bt_field_type_make_part_of_trace(field_type);
+       bt_put(event_class->specific_context_ft);
+       event_class->specific_context_ft = bt_get(field_type);
+       bt_field_type_freeze(field_type);
+       BT_LIB_LOGV("Set event class's specific context field type: %!+E",
+               event_class);
 
-       bt_put(event_class->payload_field_type);
-       event_class->payload_field_type = bt_get(field_type);
-       BT_LOGV("Set event class's payload field type: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", payload-ft-addr=%p",
-               event_class, bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class), field_type);
 end:
        return ret;
 }
 
-struct bt_field_type *bt_event_class_borrow_context_field_type(
+struct bt_field_type *bt_event_class_borrow_payload_field_type(
                struct bt_event_class *event_class)
 {
-       struct bt_field_type *context_ft = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-
-       if (!event_class->context_field_type) {
-               BT_LOGV("Event class has no context field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class));
-               goto end;
-       }
-
-       context_ft = event_class->context_field_type;
-
-end:
-       return context_ft;
+       return event_class->payload_ft;
 }
 
-int bt_event_class_set_context_field_type(
-               struct bt_event_class *event_class,
+int bt_event_class_set_payload_field_type(struct bt_event_class *event_class,
                struct bt_field_type *field_type)
 {
-       int ret = 0;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
+       int ret;
+       struct bt_stream_class *stream_class;
+       struct bt_trace *trace;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_header = NULL,
+               .packet_context = NULL,
+               .event_header = NULL,
+               .event_common_context = NULL,
+               .event_specific_context = NULL,
+               .event_payload = field_type,
+       };
 
-       if (field_type && bt_field_type_get_type_id(field_type) !=
-                       BT_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: event class's context field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "context-ft-id=%s",
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class),
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(field_type)));
-               ret = -1;
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(field_type, "Field type");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       BT_ASSERT_PRE(bt_field_type_get_type_id(field_type) ==
+               BT_FIELD_TYPE_ID_STRUCTURE,
+               "Payload field type is not a structure field type: %!+F",
+               field_type);
+       stream_class = bt_event_class_borrow_stream_class_inline(
+               event_class);
+       trace = bt_stream_class_borrow_trace_inline(stream_class);
+       resolve_ctx.packet_header = trace->packet_header_ft;
+       resolve_ctx.packet_context = stream_class->packet_context_ft;
+       resolve_ctx.event_header = stream_class->event_header_ft;
+       resolve_ctx.event_common_context =
+               stream_class->event_common_context_ft;
+       resolve_ctx.event_specific_context = event_class->specific_context_ft;
+
+       ret = bt_resolve_field_paths(field_type, &resolve_ctx);
+       if (ret) {
                goto end;
        }
 
-       bt_put(event_class->context_field_type);
-       event_class->context_field_type = bt_get(field_type);
-       BT_LOGV("Set event class's context field type: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", context-ft-addr=%p",
-               event_class, bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class), field_type);
+       bt_field_type_make_part_of_trace(field_type);
+       bt_put(event_class->payload_ft);
+       event_class->payload_ft = bt_get(field_type);
+       bt_field_type_freeze(field_type);
+       BT_LIB_LOGV("Set event class's payload field type: %!+E", event_class);
 
 end:
        return ret;
 }
 
 BT_HIDDEN
-void bt_event_class_freeze(struct bt_event_class *event_class)
-{
-       BT_ASSERT(event_class);
-
-       if (event_class->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing event class: addr=%p, name=\"%s\", id=%" PRId64,
-               event_class, bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class));
-       event_class->frozen = 1;
-       BT_LOGD_STR("Freezing event class's context field type.");
-       bt_field_type_freeze(event_class->context_field_type);
-       BT_LOGD_STR("Freezing event class's payload field type.");
-       bt_field_type_freeze(event_class->payload_field_type);
-}
-
-BT_HIDDEN
-int bt_event_class_validate_single_clock_class(
-               struct bt_event_class *event_class,
-               struct bt_clock_class **expected_clock_class)
+void _bt_event_class_freeze(struct bt_event_class *event_class)
 {
-       int ret = 0;
-
+       /* The field types are already frozen */
        BT_ASSERT(event_class);
-       BT_ASSERT(expected_clock_class);
-       ret = bt_field_type_validate_single_clock_class(
-               event_class->context_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Event class's context field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       event_class,
-                       bt_event_class_get_name(event_class),
-                       event_class->id,
-                       event_class->context_field_type);
-               goto end;
-       }
-
-       ret = bt_field_type_validate_single_clock_class(
-               event_class->payload_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Event class's payload field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       event_class,
-                       bt_event_class_get_name(event_class),
-                       event_class->id,
-                       event_class->payload_field_type);
-               goto end;
-       }
-
-end:
-       return ret;
+       BT_LIB_LOGD("Freezing event class: %!+E", event_class);
+       event_class->frozen = true;
 }
index 40c87497158ced6e76d21568749aafbd78d2e591..dd2b2fffd3a385511c88814c518b65f7e8cb7b93 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <babeltrace/assert-pre-internal.h>
 #include <babeltrace/ctf-ir/event-header-field.h>
+#include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <glib.h>
@@ -35,8 +36,6 @@ struct bt_field *bt_event_header_field_borrow_field(
        struct bt_field_wrapper *field_wrapper = (void *) header_field;
 
        BT_ASSERT_PRE_NON_NULL(field_wrapper, "Event header field");
-       BT_ASSERT_PRE_NON_NULL(field_wrapper->field,
-               "Event header field's field object");
        return (void *) field_wrapper->field;
 }
 
@@ -55,3 +54,37 @@ void bt_event_header_field_release(struct bt_event_header_field *header_field)
         */
        bt_field_wrapper_destroy(field_wrapper);
 }
+
+struct bt_event_header_field *bt_event_header_field_create(
+               struct bt_stream_class *stream_class)
+{
+       struct bt_field_wrapper *field_wrapper;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(bt_stream_class_borrow_trace_inline(stream_class),
+               "Stream class is not part of a trace: %!+S", stream_class);
+       BT_ASSERT_PRE(stream_class->event_header_ft,
+               "Stream class has no event header field type: %!+S",
+               stream_class);
+       field_wrapper = bt_field_wrapper_create(
+               &stream_class->event_header_field_pool,
+               (void *) stream_class->event_header_ft);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one event header field from stream class: "
+                       "%![sc-]+S", stream_class);
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       bt_stream_class_freeze(stream_class);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return (void *) field_wrapper;
+}
index f8ef4e1d7f62201f78b15b978974c02f6a2e174f..91e6ed8fa5ea4ef1523ee0d4e7c6017a1986ef80 100644 (file)
 #include <babeltrace/ctf-ir/packet-internal.h>
 #include <babeltrace/ctf-ir/trace.h>
 #include <babeltrace/ctf-ir/trace-internal.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/ctf-ir/packet-internal.h>
-#include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/ctf-ir/attributes-internal.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/assert-internal.h>
 #include <inttypes.h>
 
-static inline
-int bt_event_validate_types_for_create(
-               struct bt_event_class *event_class,
-               struct bt_validation_output *validation_output,
-               bt_validation_flag_copy_field_type_func copy_field_type_func)
-{
-       int ret;
-       enum bt_validation_flag validation_flags =
-               BT_VALIDATION_FLAG_STREAM |
-               BT_VALIDATION_FLAG_EVENT;
-       struct bt_trace *trace = NULL;
-       struct bt_stream_class *stream_class = NULL;
-       struct bt_field_type *packet_header_type = NULL;
-       struct bt_field_type *packet_context_type = NULL;
-       struct bt_field_type *event_header_type = NULL;
-       struct bt_field_type *stream_event_ctx_type = NULL;
-       struct bt_field_type *event_context_type = NULL;
-       struct bt_field_type *event_payload_type = NULL;
-       int trace_valid = 0;
-       struct bt_value *environment = NULL;
-
-       stream_class = bt_event_class_borrow_stream_class(event_class);
-       BT_ASSERT(stream_class);
-       trace = bt_stream_class_borrow_trace(stream_class);
-       if (trace) {
-               BT_LOGD_STR("Event class is part of a trace.");
-               packet_header_type =
-                       bt_trace_borrow_packet_header_field_type(trace);
-               trace_valid = trace->valid;
-               BT_ASSERT(trace_valid);
-               environment = trace->environment;
-       }
-
-       packet_context_type =
-               bt_stream_class_borrow_packet_context_field_type(
-                       stream_class);
-       event_header_type =
-               bt_stream_class_borrow_event_header_field_type(
-                       stream_class);
-       stream_event_ctx_type =
-               bt_stream_class_borrow_event_context_field_type(
-                       stream_class);
-       event_context_type =
-               bt_event_class_borrow_context_field_type(event_class);
-       event_payload_type =
-               bt_event_class_borrow_payload_field_type(event_class);
-       ret = bt_validate_class_types(environment, packet_header_type,
-               packet_context_type, event_header_type, stream_event_ctx_type,
-               event_context_type, event_payload_type, trace_valid,
-               stream_class->valid, event_class->valid,
-               validation_output, validation_flags, copy_field_type_func);
-       if (ret) {
-               /*
-                * This means something went wrong during the validation
-                * process, not that the objects are invalid.
-                */
-               BT_LOGE("Failed to validate event and parents: ret=%d", ret);
-               goto error;
-       }
-
-       if ((validation_output->valid_flags & validation_flags) !=
-                       validation_flags) {
-               /* Invalid trace/stream class/event class */
-               BT_LOGW("Invalid trace, stream class, or event class: "
-                       "valid-flags=0x%x", validation_output->valid_flags);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       bt_validation_output_put_types(validation_output);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int bt_event_create_fields(
-               struct bt_stream_class *stream_class,
-               struct bt_validation_output *validation_output,
-               create_field_func create_field_func,
-               release_field_func release_field_func,
-               create_header_field_func create_header_field_func,
-               release_header_field_func release_header_field_func,
-               struct bt_field_wrapper **header_field,
-               struct bt_field **stream_event_context_field,
-               struct bt_field **context_field,
-               struct bt_field **payload_field)
-{
-       int ret = 0;
-
-       if (validation_output->event_header_type) {
-               BT_LOGD("Creating initial event header field: ft-addr=%p",
-                       validation_output->event_header_type);
-               *header_field =
-                       create_header_field_func(stream_class,
-                               validation_output->event_header_type);
-               if (!*header_field) {
-                       BT_LOGE_STR("Cannot create initial event header field object.");
-                       goto error;
-               }
-       }
-
-       if (validation_output->stream_event_ctx_type) {
-               BT_LOGD("Creating initial stream event context field: ft-addr=%p",
-                       validation_output->stream_event_ctx_type);
-               *stream_event_context_field = create_field_func(
-                       validation_output->stream_event_ctx_type);
-               if (!*stream_event_context_field) {
-                       BT_LOGE_STR("Cannot create initial stream event context field object.");
-                       goto error;
-               }
-       }
-
-       if (validation_output->event_context_type) {
-               BT_LOGD("Creating initial event context field: ft-addr=%p",
-                       validation_output->event_context_type);
-               *context_field = create_field_func(
-                       validation_output->event_context_type);
-               if (!*context_field) {
-                       BT_LOGE_STR("Cannot create initial event context field object.");
-                       goto error;
-               }
-       }
-
-       if (validation_output->event_payload_type) {
-               BT_LOGD("Creating initial event payload field: ft-addr=%p",
-                       validation_output->event_payload_type);
-               *payload_field = create_field_func(
-                       validation_output->event_payload_type);
-               if (!*payload_field) {
-                       BT_LOGE_STR("Cannot create initial event payload field object.");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       if (*header_field) {
-               release_header_field_func(*header_field, stream_class);
-       }
-
-       if (*stream_event_context_field) {
-               release_field_func(*stream_event_context_field);
-       }
-
-       if (*context_field) {
-               release_field_func(*context_field);
-       }
-
-       if (*payload_field) {
-               release_field_func(*payload_field);
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
 BT_HIDDEN
-int _bt_event_validate(struct bt_event *event)
+void _bt_event_set_is_frozen(struct bt_event *event, bool is_frozen)
 {
-       int ret = 0;
-       struct bt_stream_class *stream_class;
-
        BT_ASSERT(event);
-       if (event->header_field) {
-               ret = bt_field_validate_recursive(
-                       event->header_field->field);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid event's header field: "
-                               "%![event-]+e, %![field-]+f",
-                               event, event->header_field->field);
-                       goto end;
-               }
-       }
-
-       stream_class = bt_event_class_borrow_stream_class(event->class);
-
-       /*
-        * We should not have been able to create the event without associating
-        * the event class to a stream class.
-        */
-       BT_ASSERT(stream_class);
-
-       if (stream_class->event_context_field_type) {
-               ret = bt_field_validate_recursive(
-                       event->stream_event_context_field);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid event's stream event context field: "
-                               "%![event-]+e, %![field-]+f",
-                               event, event->stream_event_context_field);
-                       goto end;
-               }
-       }
-
-       if (event->class->context_field_type) {
-               ret = bt_field_validate_recursive(event->context_field);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid event's payload field: "
-                               "%![event-]+e, %![field-]+f",
-                               event, event->context_field);
-                       goto end;
-               }
-       }
-
-       ret = bt_field_validate_recursive(event->payload_field);
-       if (ret) {
-               BT_ASSERT_PRE_MSG("Invalid event's payload field: "
-                       "%![event-]+e, %![field-]+f",
-                       event, event->payload_field);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void _bt_event_set_is_frozen(struct bt_event *event,
-               bool is_frozen)
-{
-       BT_ASSERT(event);
-       BT_LOGD("Freezing event: addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event, bt_event_class_get_name(event->class),
-               bt_event_class_get_id(event->class));
+       BT_LIB_LOGD("Setting event's frozen state: %!+e, is-frozen=%d",
+               event, is_frozen);
 
        if (event->header_field) {
-               BT_LOGD_STR("Freezing event's header field.");
-               bt_field_set_is_frozen_recursive(
+               BT_LOGD_STR("Setting event's header field's frozen state.");
+               bt_field_set_is_frozen(
                        event->header_field->field, is_frozen);
        }
 
-       if (event->stream_event_context_field) {
-               BT_LOGD_STR("Freezing event's stream event context field.");
-               bt_field_set_is_frozen_recursive(
-                       event->stream_event_context_field, is_frozen);
+       if (event->common_context_field) {
+               BT_LOGD_STR("Setting event's common context field's frozen state.");
+               bt_field_set_is_frozen(
+                       event->common_context_field, is_frozen);
        }
 
-       if (event->context_field) {
-               BT_LOGD_STR("Freezing event's context field.");
-               bt_field_set_is_frozen_recursive(event->context_field,
+       if (event->specific_context_field) {
+               BT_LOGD_STR("Setting event's specific context field's frozen state.");
+               bt_field_set_is_frozen(event->specific_context_field,
                        is_frozen);
        }
 
        if (event->payload_field) {
-               BT_LOGD_STR("Freezing event's payload field.");
-               bt_field_set_is_frozen_recursive(event->payload_field,
+               BT_LOGD_STR("Setting event's payload field's frozen state.");
+               bt_field_set_is_frozen(event->payload_field,
                        is_frozen);
        }
 
        event->frozen = is_frozen;
-       BT_LOGD_STR("Freezing event's packet.");
+       BT_LOGD_STR("Setting event's packet's frozen state.");
        bt_packet_set_is_frozen(event->packet, is_frozen);
 }
 
-static inline
-int bt_event_initialize(struct bt_event *event,
-               struct bt_event_class *event_class,
-               bt_validation_flag_copy_field_type_func field_type_copy_func,
-               create_field_func create_field_func,
-               release_field_func release_field_func,
-               create_header_field_func create_header_field_func,
-               release_header_field_func release_header_field_func)
-{
-       int ret;
-       struct bt_trace *trace = NULL;
-       struct bt_stream_class *stream_class = NULL;
-       struct bt_field_wrapper *event_header = NULL;
-       struct bt_field *stream_event_context = NULL;
-       struct bt_field *event_context = NULL;
-       struct bt_field *event_payload = NULL;
-       struct bt_validation_output validation_output = { 0 };
-       struct bt_clock_class *expected_clock_class = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_LOGD("Initializing event object: event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event_class, bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class));
-
-       stream_class = bt_event_class_borrow_stream_class(event_class);
-       BT_ASSERT_PRE(stream_class,
-               "Event class is not part of a stream class: %!+E", event_class);
-
-       /* The event class was frozen when added to its stream class */
-       BT_ASSERT(event_class->frozen);
-       trace = bt_stream_class_borrow_trace(stream_class);
-       BT_ASSERT_PRE(trace,
-               "Event class's stream class is not part of a trace: "
-               "%![ec-]+E, %![ec-]+S", event_class, stream_class);
-
-       /*
-        * This must be called before anything that can fail because on
-        * failure, the caller releases the reference to `event` to
-        * destroy it.
-        */
-       bt_object_init_unique(&event->base);
-
-       if (!stream_class->frozen) {
-               /*
-                * Because this function freezes the stream class,
-                * validate that this stream class contains at most a
-                * single clock class so that we set its expected clock
-                * class for future checks.
-                */
-               ret = bt_stream_class_validate_single_clock_class(
-                       stream_class, &expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Event class's stream class or one of its event "
-                               "classes contains a field type which is not "
-                               "recursively mapped to the expected "
-                               "clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-id=%" PRId64 ", "
-                               "stream-class-name=\"%s\", "
-                               "expected-clock-class-addr=%p, "
-                               "expected-clock-class-name=\"%s\"",
-                               stream_class,
-                               bt_stream_class_get_id(stream_class),
-                               bt_stream_class_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_clock_class_get_name(expected_clock_class) :
-                                       NULL);
-                       goto error;
-               }
-       }
-
-       /* Validate the trace, the stream class, and the event class */
-       ret = bt_event_validate_types_for_create(
-               event_class, &validation_output, field_type_copy_func);
-       if (ret) {
-               /* bt_event_validate_types_for_create() logs errors */
-               goto error;
-       }
-
-       /*
-        * event does not share a common ancestor with the event class; it has
-        * to guarantee its existence by holding a reference. This reference
-        * shall be released once the event is associated to a stream since,
-        * from that point, the event and its class will share the same
-        * lifetime.
-        *
-        * TODO: Is this still true now that this API and CTF writer are
-        * two different implementations?
-        */
-       event->class = bt_get(event_class);
-       ret = bt_event_create_fields(stream_class,
-               &validation_output,
-               create_field_func, release_field_func,
-               create_header_field_func, release_header_field_func,
-               &event_header, &stream_event_context, &event_context,
-               &event_payload);
-       if (ret) {
-               /* bt_event_create_fields() logs errors */
-               goto error;
-       }
-
-       /*
-        * At this point all the fields are created, potentially from
-        * validated copies of field types, so that the field types and
-        * fields can be replaced in the trace, stream class,
-        * event class, and created event.
-        */
-       bt_validation_replace_types(trace, stream_class, event_class,
-               &validation_output,
-               BT_VALIDATION_FLAG_STREAM | BT_VALIDATION_FLAG_EVENT);
-       event->header_field = event_header;
-       event_header = NULL;
-       event->stream_event_context_field = stream_event_context;
-       stream_event_context = NULL;
-       event->context_field = event_context;
-       event_context = NULL;
-       event->payload_field = event_payload;
-       event_payload = NULL;
-
-       /*
-        * Put what was not moved in bt_validation_replace_types().
-        */
-       bt_validation_output_put_types(&validation_output);
-
-       /*
-        * Freeze the stream class since the event header must not be changed
-        * anymore.
-        */
-       bt_stream_class_freeze(stream_class);
-
-       /*
-        * It is safe to set the stream class's unique clock class
-        * now because the stream class is frozen.
-        */
-       if (expected_clock_class) {
-               BT_MOVE(stream_class->clock_class, expected_clock_class);
-       }
-
-       /*
-        * Mark stream class, and event class as valid since
-        * they're all frozen now.
-        */
-       stream_class->valid = 1;
-       event_class->valid = 1;
-
-       /* Put stuff we borrowed from the event class */
-       BT_LOGD("Initialized event object: addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64,
-               event, bt_event_class_get_name(event->class),
-               bt_event_class_get_id(event->class));
-       goto end;
-
-error:
-       bt_validation_output_put_types(&validation_output);
-       bt_put(expected_clock_class);
-
-       if (event_header) {
-               release_header_field_func(event_header, stream_class);
-       }
-
-       if (stream_event_context) {
-               release_field_func(stream_event_context);
-       }
-
-       if (event_context) {
-               release_field_func(event_context);
-       }
-
-       if (event_payload) {
-               release_field_func(event_payload);
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
 static
-void bt_event_header_field_recycle(struct bt_field_wrapper *field_wrapper,
+void recycle_event_header_field(struct bt_field_wrapper *field_wrapper,
                struct bt_stream_class *stream_class)
 {
        BT_ASSERT(field_wrapper);
@@ -509,15 +102,15 @@ void bt_event_header_field_recycle(struct bt_field_wrapper *field_wrapper,
                field_wrapper);
 }
 
-static
+static inline
 struct bt_field_wrapper *create_event_header_field(
-               struct bt_stream_class *stream_class,
-               struct bt_field_type *ft)
+               struct bt_stream_class *stream_class)
 {
        struct bt_field_wrapper *field_wrapper = NULL;
 
        field_wrapper = bt_field_wrapper_create(
-               &stream_class->event_header_field_pool, (void *) ft);
+               &stream_class->event_header_field_pool,
+               bt_stream_class_borrow_event_header_field_type(stream_class));
        if (!field_wrapper) {
                goto error;
        }
@@ -526,7 +119,7 @@ struct bt_field_wrapper *create_event_header_field(
 
 error:
        if (field_wrapper) {
-               bt_event_header_field_recycle(field_wrapper, stream_class);
+               recycle_event_header_field(field_wrapper, stream_class);
                field_wrapper = NULL;
        }
 
@@ -537,32 +130,64 @@ end:
 BT_HIDDEN
 struct bt_event *bt_event_new(struct bt_event_class *event_class)
 {
-       int ret;
        struct bt_event *event = NULL;
        struct bt_stream_class *stream_class;
+       struct bt_field_type *ft;
 
+       BT_ASSERT(event_class);
        event = g_new0(struct bt_event, 1);
        if (!event) {
                BT_LOGE_STR("Failed to allocate one event.");
                goto error;
        }
 
-       ret = bt_event_initialize(event, event_class,
-               (bt_validation_flag_copy_field_type_func) bt_field_type_copy,
-               (create_field_func) bt_field_create_recursive,
-               (release_field_func) bt_field_destroy_recursive,
-               (create_header_field_func) create_event_header_field,
-               (release_header_field_func) bt_event_header_field_recycle);
-       if (ret) {
-               /* bt_event_initialize() logs errors */
-               goto error;
-       }
-
+       bt_object_init_unique(&event->base);
        stream_class = bt_event_class_borrow_stream_class(event_class);
        BT_ASSERT(stream_class);
-       ret = bt_clock_value_set_initialize(&event->cv_set);
-       if (ret) {
-               goto error;
+
+       if (bt_stream_class_borrow_event_header_field_type(stream_class)) {
+               event->header_field = create_event_header_field(stream_class);
+               if (!event->header_field) {
+                       BT_LOGE_STR("Cannot create event header field.");
+                       goto error;
+               }
+       }
+
+       ft = bt_stream_class_borrow_event_common_context_field_type(
+               stream_class);
+       if (ft) {
+               event->common_context_field = bt_field_create(ft);
+               if (!event->common_context_field) {
+                       /* bt_field_create() logs errors */
+                       goto error;
+               }
+       }
+
+       ft = bt_event_class_borrow_specific_context_field_type(event_class);
+       if (ft) {
+               event->specific_context_field = bt_field_create(ft);
+               if (!event->specific_context_field) {
+                       /* bt_field_create() logs errors */
+                       goto error;
+               }
+       }
+
+       ft = bt_event_class_borrow_payload_field_type(event_class);
+       if (ft) {
+               event->payload_field = bt_field_create(ft);
+               if (!event->payload_field) {
+                       /* bt_field_create() logs errors */
+                       goto error;
+               }
+       }
+
+       if (stream_class->default_clock_class) {
+               event->default_cv = bt_clock_value_create(
+                       stream_class->default_clock_class);
+               if (!event->default_cv) {
+                       /* bt_clock_value_create() logs errors */
+                       goto error;
+               }
        }
 
        goto end;
@@ -589,209 +214,115 @@ struct bt_stream *bt_event_borrow_stream(struct bt_event *event)
        return event->packet ? event->packet->stream : NULL;
 }
 
-struct bt_field *bt_event_borrow_payload(struct bt_event *event)
+struct bt_field *bt_event_borrow_header_field(struct bt_event *event)
 {
-       struct bt_field *payload = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->payload_field) {
-               BT_LOGV("Event has no current payload field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_event_class_get_name(event->class),
-                       bt_event_class_get_id(event->class));
-               goto end;
-       }
-
-       payload = event->payload_field;
-
-end:
-       return payload;
+       return event->header_field ? event->header_field->field : NULL;
 }
 
-struct bt_field *bt_event_borrow_header(struct bt_event *event)
+struct bt_field *bt_event_borrow_common_context_field(struct bt_event *event)
 {
-       struct bt_field *header = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->header_field) {
-               BT_LOGV("Event has no current header field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_event_class_get_name(event->class),
-                       bt_event_class_get_id(event->class));
-               goto end;
-       }
-
-       header = event->header_field->field;
-
-end:
-       return header;
+       return event->common_context_field;
 }
 
-struct bt_field *bt_event_borrow_context(struct bt_event *event)
+struct bt_field *bt_event_borrow_specific_context_field(struct bt_event *event)
 {
-       struct bt_field *context = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->context_field) {
-               BT_LOGV("Event has no current context field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_event_class_get_name(event->class),
-                       bt_event_class_get_id(event->class));
-               goto end;
-       }
-
-       context = event->context_field;
-
-end:
-       return context;
+       return event->specific_context_field;
 }
 
-struct bt_field *bt_event_borrow_stream_event_context(
-               struct bt_event *event)
+struct bt_field *bt_event_borrow_payload_field(struct bt_event *event)
 {
-       struct bt_field *stream_event_context = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->stream_event_context_field) {
-               BT_LOGV("Event has no current stream event context field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_event_class_get_name(event->class),
-                       bt_event_class_get_id(event->class));
-               goto end;
-       }
-
-       stream_event_context = event->stream_event_context_field;
-
-end:
-       return stream_event_context;
+       return event->payload_field;
 }
 
 static
 void release_event_header_field(struct bt_field_wrapper *field_wrapper,
                struct bt_event *event)
 {
-       struct bt_event_class *event_class = bt_event_borrow_class(event);
-
-       if (!event_class) {
+       if (!event->class) {
                bt_field_wrapper_destroy(field_wrapper);
        } else {
                struct bt_stream_class *stream_class =
-                       bt_event_class_borrow_stream_class(event_class);
+                       bt_event_class_borrow_stream_class(event->class);
 
                BT_ASSERT(stream_class);
-               bt_event_header_field_recycle(field_wrapper, stream_class);
+               recycle_event_header_field(field_wrapper, stream_class);
        }
 }
 
-static inline
-void bt_event_finalize(struct bt_object *obj,
-               void (*field_release_func)(void *),
-               void (*header_field_release_func)(void *, struct bt_event *))
+BT_HIDDEN
+void bt_event_destroy(struct bt_event *event)
 {
-       struct bt_event *event = (void *) obj;
-
-       BT_LOGD("Destroying event: addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event,
-               event->class ? bt_event_class_get_name(event->class) : NULL,
-               event->class ? bt_event_class_get_id(event->class) : INT64_C(-1));
+       BT_ASSERT(event);
+       BT_LIB_LOGD("Destroying event: %!+e", event);
 
        if (event->header_field) {
                BT_LOGD_STR("Releasing event's header field.");
-               header_field_release_func(event->header_field, event);
+               release_event_header_field(event->header_field, event);
        }
 
-       if (event->stream_event_context_field) {
-               BT_LOGD_STR("Releasing event's stream event context field.");
-               field_release_func(event->stream_event_context_field);
+       if (event->common_context_field) {
+               BT_LOGD_STR("Destroying event's stream event context field.");
+               bt_field_destroy(event->common_context_field);
        }
 
-       if (event->context_field) {
-               BT_LOGD_STR("Releasing event's context field.");
-               field_release_func(event->context_field);
+       if (event->specific_context_field) {
+               BT_LOGD_STR("Destroying event's context field.");
+               bt_field_destroy(event->specific_context_field);
        }
 
        if (event->payload_field) {
-               BT_LOGD_STR("Releasing event's payload field.");
-               field_release_func(event->payload_field);
+               BT_LOGD_STR("Destroying event's payload field.");
+               bt_field_destroy(event->payload_field);
        }
 
-       /*
-        * Leave this after calling header_field_release_func() because
-        * this function receives the event object and could need its
-        * class to perform some cleanup.
-        */
-       if (!event->base.parent) {
-               /*
-                * Event was keeping a reference to its class since it shared no
-                * common ancestor with it to guarantee they would both have the
-                * same lifetime.
-                */
-               bt_put(event->class);
+       BT_LOGD_STR("Putting event's class.");
+       bt_put(event->class);
+
+       if (event->default_cv) {
+               bt_clock_value_recycle(event->default_cv);
        }
-}
 
-BT_HIDDEN
-void bt_event_destroy(struct bt_event *event)
-{
-       BT_ASSERT(event);
-       bt_event_finalize((void *) event,
-               (void *) bt_field_destroy_recursive,
-               (void *) release_event_header_field);
-       bt_clock_value_set_finalize(&event->cv_set);
        BT_LOGD_STR("Putting event's packet.");
        bt_put(event->packet);
        g_free(event);
 }
 
-int bt_event_set_clock_value(struct bt_event *event,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default)
+int bt_event_set_default_clock_value(struct bt_event *event,
+               uint64_t value_cycles)
 {
+       struct bt_stream_class *sc;
+
        BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_HOT(event, "Event", ": %!+e", event);
-       BT_ASSERT_PRE(is_default,
-               "You can only set a default clock value as of this version.");
-       return bt_clock_value_set_set_clock_value(&event->cv_set, clock_class,
-               raw_value, is_default);
+       BT_ASSERT_PRE_EVENT_HOT(event);
+       sc = bt_event_class_borrow_stream_class_inline(event->class);
+       BT_ASSERT(sc);
+       BT_ASSERT_PRE(sc->default_clock_class,
+               "Event's stream class has no default clock class: "
+               "%![ev-]+e, %![sc-]+S", event, sc);
+       BT_ASSERT(event->default_cv);
+       bt_clock_value_set_value_inline(event->default_cv, value_cycles);
+       BT_LIB_LOGV("Set event's default clock value: %![event-]+e, "
+               "value=%" PRIu64, event, value_cycles);
+       return 0;
 }
 
-struct bt_clock_value *bt_event_borrow_default_clock_value(
-               struct bt_event *event)
+enum bt_clock_value_status bt_event_borrow_default_clock_value(
+               struct bt_event *event, struct bt_clock_value **clock_value)
 {
-       struct bt_clock_value *clock_value = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event, "Event");
-       clock_value = event->cv_set.default_cv;
-       if (!clock_value) {
-               BT_LIB_LOGV("No default clock value: %![event-]+e", event);
-       }
-
-       return clock_value;
+       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value (output)");
+       *clock_value = event->default_cv;
+       return BT_CLOCK_VALUE_STATUS_KNOWN;
 }
 
 struct bt_packet *bt_event_borrow_packet(struct bt_event *event)
 {
-       struct bt_packet *packet = NULL;
-
        BT_ASSERT_PRE_NON_NULL(event, "Event");
-       if (!event->packet) {
-               BT_LOGV("Event has no current packet: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_event_class_get_name(event->class),
-                       bt_event_class_get_id(event->class));
-               goto end;
-       }
-
-       packet = event->packet;
-
-end:
-       return packet;
+       return event->packet;
 }
 
 int bt_event_move_header(struct bt_event *event,
@@ -802,19 +333,17 @@ int bt_event_move_header(struct bt_event *event,
 
        BT_ASSERT_PRE_NON_NULL(event, "Event");
        BT_ASSERT_PRE_NON_NULL(field_wrapper, "Header field");
-       BT_ASSERT_PRE_HOT(event, "Event", ": %!+e", event);
-       stream_class = bt_event_class_borrow_stream_class(
-               bt_event_borrow_class(event));
-       BT_ASSERT_PRE(stream_class->event_header_field_type,
+       BT_ASSERT_PRE_EVENT_HOT(event);
+       stream_class = bt_event_class_borrow_stream_class_inline(event->class);
+       BT_ASSERT_PRE(stream_class->event_header_ft,
                "Stream class has no event header field type: %!+S",
                stream_class);
 
        /* Recycle current header field: always exists */
        BT_ASSERT(event->header_field);
-       bt_event_header_field_recycle(event->header_field,
-               stream_class);
+       recycle_event_header_field(event->header_field, stream_class);
 
        /* Move new field */
-       event->header_field = (void *) field_wrapper;
+       event->header_field = field_wrapper;
        return 0;
 }
index d9893059e4bb8001e3e2ae14269dd71191542f9f..ceb54bf5dc2e2db09d9cc71745bc377b401a66e1 100644 (file)
@@ -28,6 +28,7 @@
 #define BT_LOG_TAG "FIELD-PATH"
 #include <babeltrace/lib-logging-internal.h>
 
+#include <babeltrace/assert-pre-internal.h>
 #include <babeltrace/ctf-ir/field-types.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/field-path-internal.h>
 #include <glib.h>
 
 static
-void field_path_destroy(struct bt_object *obj)
+void destroy_field_path(struct bt_object *obj)
 {
        struct bt_field_path *field_path = (struct bt_field_path *) obj;
 
-       BT_LOGD("Destroying field path: addr=%p", obj);
-
-       if (!field_path) {
-               return;
-       }
-
-       if (field_path->indexes) {
-               g_array_free(field_path->indexes, TRUE);
-       }
+       BT_ASSERT(field_path);
+       BT_LIB_LOGD("Destroying field path: %!+P", field_path);
+       g_array_free(field_path->indexes, TRUE);
        g_free(field_path);
 }
 
@@ -68,106 +63,39 @@ struct bt_field_path *bt_field_path_create(void)
                goto error;
        }
 
-       bt_object_init_shared(&field_path->base, field_path_destroy);
-       field_path->root = BT_SCOPE_UNKNOWN;
-       field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int));
+       bt_object_init_shared(&field_path->base, destroy_field_path);
+       field_path->indexes = g_array_new(FALSE, FALSE, sizeof(uint64_t));
        if (!field_path->indexes) {
                BT_LOGE_STR("Failed to allocate a GArray.");
                goto error;
        }
 
-       BT_LOGD("Created empty field path object: addr=%p", field_path);
-       return field_path;
+       BT_LIB_LOGD("Created empty field path object: %!+P", field_path);
+       goto end;
 
 error:
        BT_PUT(field_path);
-       return NULL;
-}
 
-BT_HIDDEN
-void bt_field_path_clear(struct bt_field_path *field_path)
-{
-       if (field_path->indexes->len > 0) {
-               g_array_remove_range(field_path->indexes, 0,
-                       field_path->indexes->len);
-       }
-}
-
-BT_HIDDEN
-struct bt_field_path *bt_field_path_copy(
-               struct bt_field_path *path)
-{
-       struct bt_field_path *new_path;
-
-       BT_ASSERT(path);
-       BT_LOGD("Copying field path: addr=%p, index-count=%u",
-               path, path->indexes->len);
-       new_path = bt_field_path_create();
-       if (!new_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               goto end;
-       }
-
-       new_path->root = path->root;
-       g_array_insert_vals(new_path->indexes, 0,
-               path->indexes->data, path->indexes->len);
-       BT_LOGD("Copied field path: original-addr=%p, copy-addr=%p",
-               path, new_path);
 end:
-       return new_path;
+       return field_path;
 }
 
-enum bt_scope bt_field_path_get_root_scope(
-               const struct bt_field_path *field_path)
+enum bt_scope bt_field_path_get_root_scope(struct bt_field_path *field_path)
 {
-       enum bt_scope scope = BT_SCOPE_UNKNOWN;
-
-       if (!field_path) {
-               BT_LOGW_STR("Invalid parameter: field path is NULL.");
-               goto end;
-       }
-
-       scope = field_path->root;
-
-end:
-       return scope;
+       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
+       return field_path->root;
 }
 
-int64_t bt_field_path_get_index_count(
-               const struct bt_field_path *field_path)
+uint64_t bt_field_path_get_index_count(struct bt_field_path *field_path)
 {
-       int64_t count = (int64_t) -1;
-
-       if (!field_path) {
-               BT_LOGW_STR("Invalid parameter: field path is NULL.");
-               goto end;
-       }
-
-       count = (int64_t) field_path->indexes->len;
-
-end:
-       return count;
+       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
+       return (uint64_t) field_path->indexes->len;
 }
 
-int bt_field_path_get_index(const struct bt_field_path *field_path,
+uint64_t bt_field_path_get_index_by_index(struct bt_field_path *field_path,
                uint64_t index)
 {
-       int ret = INT_MIN;
-
-       if (!field_path) {
-               BT_LOGW_STR("Invalid parameter: field path is NULL.");
-               goto end;
-       }
-
-       if (index >= field_path->indexes->len) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "addr=%p, index=%" PRIu64 ", count=%u",
-                       field_path, index, field_path->indexes->len);
-               goto end;
-       }
-
-       ret = g_array_index(field_path->indexes, int, index);
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
+       BT_ASSERT_PRE_VALID_INDEX(index, field_path->indexes->len);
+       return bt_field_path_get_index_by_index_inline(field_path, index);
 }
index 5de2978f814c9b93ad66672a2421c51d6572b38f..f71cf29f16d712eefbfe11a7a46611488c4dd202 100644 (file)
@@ -34,7 +34,6 @@
 #include <babeltrace/ctf-ir/field-path-internal.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/fields.h>
-#include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/ctf-ir/clock-class.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/endian-internal.h>
 #include <babeltrace/assert-internal.h>
+#include <babeltrace/compat/glib-internal.h>
 #include <float.h>
 #include <inttypes.h>
 #include <stdlib.h>
 
-static
-struct bt_field_type *bt_field_type_integer_copy(
-               struct bt_field_type *ft);
+enum bt_field_type_id bt_field_type_get_type_id(struct bt_field_type *ft)
+{
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       return ft->id;
+}
 
 static
-struct bt_field_type *bt_field_type_enumeration_copy_recursive(
-               struct bt_field_type *ft);
+void init_field_type(struct bt_field_type *ft, enum bt_field_type_id id,
+               bt_object_release_func release_func)
+{
+       BT_ASSERT(ft);
+       BT_ASSERT(bt_field_type_has_known_id(ft));
+       BT_ASSERT(release_func);
+       bt_object_init_shared(&ft->base, release_func);
+       ft->id = id;
+}
 
 static
-struct bt_field_type *bt_field_type_floating_point_copy(
-               struct bt_field_type *ft);
+void init_integer_field_type(struct bt_field_type_integer *ft, enum bt_field_type_id id,
+               bt_object_release_func release_func)
+{
+       init_field_type((void *) ft, id, release_func);
+       ft->range = 64;
+       ft->base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
+}
 
 static
-struct bt_field_type *bt_field_type_structure_copy_recursive(
-               struct bt_field_type *ft);
+void destroy_integer_field_type(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying integer field type object: %!+F", obj);
+       g_free(obj);
+}
 
-static
-struct bt_field_type *bt_field_type_variant_copy_recursive(
-               struct bt_field_type *ft);
+static inline
+struct bt_field_type *create_integer_field_type(enum bt_field_type_id id)
+{
+       struct bt_field_type_integer *int_ft = NULL;
 
-static
-struct bt_field_type *bt_field_type_array_copy_recursive(
-               struct bt_field_type *ft);
+       BT_LOGD("Creating default integer field type object: id=%s",
+               bt_common_field_type_id_string(id));
+       int_ft = g_new0(struct bt_field_type_integer, 1);
+       if (!int_ft) {
+               BT_LOGE_STR("Failed to allocate one integer field type.");
+               goto error;
+       }
 
-static
-struct bt_field_type *bt_field_type_sequence_copy_recursive(
-               struct bt_field_type *type);
+       init_integer_field_type(int_ft, id, destroy_integer_field_type);
+       BT_LIB_LOGD("Created integer field type object: %!+F", int_ft);
+       goto end;
 
-static
-struct bt_field_type *bt_field_type_string_copy(struct bt_field_type *ft);
+error:
+       BT_PUT(int_ft);
 
-static
-int bt_field_type_integer_validate(struct bt_field_type *ft);
+end:
+       return (void *) int_ft;
+}
 
-static
-int bt_field_type_enumeration_validate_recursive(
-               struct bt_field_type *ft);
-static
-int bt_field_type_sequence_validate_recursive(
-               struct bt_field_type *ft);
-static
-int bt_field_type_array_validate_recursive(
-               struct bt_field_type *ft);
-static
-int bt_field_type_structure_validate_recursive(
-               struct bt_field_type *ft);
-static
-int bt_field_type_variant_validate_recursive(
-               struct bt_field_type *ft);
+struct bt_field_type *bt_field_type_unsigned_integer_create(void)
+{
+       return create_integer_field_type(BT_FIELD_TYPE_ID_UNSIGNED_INTEGER);
+}
 
-static
-void bt_field_type_generic_freeze(struct bt_field_type *ft);
+struct bt_field_type *bt_field_type_signed_integer_create(void)
+{
+       return create_integer_field_type(BT_FIELD_TYPE_ID_SIGNED_INTEGER);
+}
 
-static
-void bt_field_type_enumeration_freeze_recursive(
-               struct bt_field_type *ft);
-static
-void bt_field_type_structure_freeze_recursive(
-               struct bt_field_type *ft);
-static
-void bt_field_type_variant_freeze_recursive(
-               struct bt_field_type *ft);
-static
-void bt_field_type_array_freeze_recursive(
-               struct bt_field_type *ft);
-static
-void bt_field_type_sequence_freeze_recursive(
-               struct bt_field_type *ft);
+uint64_t bt_field_type_integer_get_field_value_range(
+               struct bt_field_type *ft)
+{
+       struct bt_field_type_integer *int_ft = (void *) ft;
 
-static
-void bt_field_type_integer_set_byte_order(
-               struct bt_field_type *ft, enum bt_byte_order byte_order);
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_IS_INT(ft, "Field type");
+       return int_ft->range;
+}
 
+BT_ASSERT_PRE_FUNC
 static
-void bt_field_type_enumeration_set_byte_order_recursive(
-               struct bt_field_type *ft, enum bt_byte_order byte_order);
+bool size_is_valid_for_enumeration_field_type(struct bt_field_type *ft,
+               uint64_t size)
+{
+       // TODO
+       return true;
+}
 
-static
-void bt_field_type_floating_point_set_byte_order(
-               struct bt_field_type *ft, enum bt_byte_order byte_order);
+int bt_field_type_integer_set_field_value_range(
+               struct bt_field_type *ft, uint64_t size)
+{
+       struct bt_field_type_integer *int_ft = (void *) ft;
 
-static
-void bt_field_type_structure_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order);
-static
-void bt_field_type_variant_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order);
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_IS_INT(ft, "Field type");
+       BT_ASSERT_PRE_FT_HOT(ft, "Field type");
+       BT_ASSERT_PRE(size <= 64,
+               "Unsupported size for integer field type's field value range "
+               "(maximum is 64): size=%" PRIu64, size);
+       BT_ASSERT_PRE(int_ft->common.id == BT_FIELD_TYPE_ID_UNSIGNED_INTEGER ||
+               int_ft->common.id == BT_FIELD_TYPE_ID_SIGNED_INTEGER ||
+               size_is_valid_for_enumeration_field_type(ft, size),
+               "Invalid field value range for enumeration field type: "
+               "at least one of the current mapping ranges contains values "
+               "which are outside this range: %!+F, size=%" PRIu64, ft, size);
+       int_ft->range = size;
+       BT_LIB_LOGV("Set integer field type's field value range: %!+F", ft);
+       return 0;
+}
 
-static
-void bt_field_type_array_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order);
+enum bt_field_type_integer_preferred_display_base
+bt_field_type_integer_get_preferred_display_base(struct bt_field_type *ft)
+{
+       struct bt_field_type_integer *int_ft = (void *) ft;
 
-static
-void bt_field_type_sequence_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order);
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_IS_INT(ft, "Field type");
+       return int_ft->base;
+}
 
-static
-int bt_field_type_integer_compare(struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
+int bt_field_type_integer_set_preferred_display_base(struct bt_field_type *ft,
+               enum bt_field_type_integer_preferred_display_base base)
+{
+       struct bt_field_type_integer *int_ft = (void *) ft;
 
-static
-int bt_field_type_floating_point_compare(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_IS_INT(ft, "Field type");
+       BT_ASSERT_PRE_FT_HOT(ft, "Field type");
+       int_ft->base = base;
+       BT_LIB_LOGV("Set integer field type's preferred display base: %!+F", ft);
+       return 0;
+}
 
 static
-int bt_field_type_enumeration_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
+void finalize_enumeration_field_type_mapping(
+               struct bt_field_type_enumeration_mapping *mapping)
+{
+       BT_ASSERT(mapping);
 
-static
-int bt_field_type_string_compare(struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
+       if (mapping->label) {
+               g_string_free(mapping->label, TRUE);
+       }
 
-static
-int bt_field_type_structure_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
+       if (mapping->ranges) {
+               g_array_free(mapping->ranges, TRUE);
+       }
+}
 
 static
-int bt_field_type_variant_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
+void destroy_enumeration_field_type(struct bt_object *obj)
+{
+       struct bt_field_type_enumeration *ft = (void *) obj;
 
-static
-int bt_field_type_array_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
+       BT_ASSERT(ft);
+       BT_LIB_LOGD("Destroying enumeration field type object: %!+F", ft);
 
-static
-int bt_field_type_sequence_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b);
-
-static struct bt_field_type_methods bt_field_type_integer_methods = {
-       .freeze = bt_field_type_generic_freeze,
-       .validate = bt_field_type_integer_validate,
-       .set_byte_order = bt_field_type_integer_set_byte_order,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_integer_copy,
-       .compare = bt_field_type_integer_compare,
-};
-
-static struct bt_field_type_methods bt_field_type_floating_point_methods = {
-       .freeze = bt_field_type_generic_freeze,
-       .validate = NULL,
-       .set_byte_order = bt_field_type_floating_point_set_byte_order,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_floating_point_copy,
-       .compare = bt_field_type_floating_point_compare,
-};
-
-static struct bt_field_type_methods bt_field_type_enumeration_methods = {
-       .freeze = bt_field_type_enumeration_freeze_recursive,
-       .validate = bt_field_type_enumeration_validate_recursive,
-       .set_byte_order = bt_field_type_enumeration_set_byte_order_recursive,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_enumeration_copy_recursive,
-       .compare = bt_field_type_enumeration_compare_recursive,
-};
-
-static struct bt_field_type_methods bt_field_type_string_methods = {
-       .freeze = bt_field_type_generic_freeze,
-       .validate = NULL,
-       .set_byte_order = NULL,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_string_copy,
-       .compare = bt_field_type_string_compare,
-};
-
-static struct bt_field_type_methods bt_field_type_array_methods = {
-       .freeze = bt_field_type_array_freeze_recursive,
-       .validate = bt_field_type_array_validate_recursive,
-       .set_byte_order = bt_field_type_array_set_byte_order_recursive,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_array_copy_recursive,
-       .compare = bt_field_type_array_compare_recursive,
-};
-
-static struct bt_field_type_methods bt_field_type_sequence_methods = {
-       .freeze = bt_field_type_sequence_freeze_recursive,
-       .validate = bt_field_type_sequence_validate_recursive,
-       .set_byte_order = bt_field_type_sequence_set_byte_order_recursive,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_sequence_copy_recursive,
-       .compare = bt_field_type_sequence_compare_recursive,
-};
-
-static struct bt_field_type_methods bt_field_type_structure_methods = {
-       .freeze = bt_field_type_structure_freeze_recursive,
-       .validate = bt_field_type_structure_validate_recursive,
-       .set_byte_order = bt_field_type_structure_set_byte_order_recursive,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_structure_copy_recursive,
-       .compare = bt_field_type_structure_compare_recursive,
-};
-
-static struct bt_field_type_methods bt_field_type_variant_methods = {
-       .freeze = bt_field_type_variant_freeze_recursive,
-       .validate = bt_field_type_variant_validate_recursive,
-       .set_byte_order = bt_field_type_variant_set_byte_order_recursive,
-       .copy = (bt_field_type_method_copy)
-               bt_field_type_variant_copy_recursive,
-       .compare = bt_field_type_variant_compare_recursive,
-};
+       if (ft->mappings) {
+               uint64_t i;
 
-static
-void destroy_enumeration_mapping(struct enumeration_mapping *mapping)
-{
-       g_free(mapping);
+               for (i = 0; i < ft->mappings->len; i++) {
+                       finalize_enumeration_field_type_mapping(
+                               BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(ft, i));
+               }
+
+               g_array_free(ft->mappings, TRUE);
+       }
+
+       if (ft->label_buf) {
+               g_ptr_array_free(ft->label_buf, TRUE);
+       }
+
+       g_free(ft);
 }
 
 static
-void bt_field_type_initialize(struct bt_field_type *ft,
-               bool init_bo, bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+struct bt_field_type *create_enumeration_field_type(enum bt_field_type_id id)
 {
-       BT_ASSERT(ft && (ft->id > BT_FIELD_TYPE_ID_UNKNOWN) &&
-               (ft->id < BT_FIELD_TYPE_ID_NR));
+       struct bt_field_type_enumeration *enum_ft = NULL;
 
-       bt_object_init_shared(&ft->base, release_func);
-       ft->methods = methods;
+       BT_LOGD("Creating default enumeration field type object: id=%s",
+               bt_common_field_type_id_string(id));
+       enum_ft = g_new0(struct bt_field_type_enumeration, 1);
+       if (!enum_ft) {
+               BT_LOGE_STR("Failed to allocate one enumeration field type.");
+               goto error;
+       }
 
-       if (init_bo) {
-               int ret;
-               const enum bt_byte_order bo = BT_BYTE_ORDER_NATIVE;
+       init_integer_field_type((void *) enum_ft, id,
+               destroy_enumeration_field_type);
+       enum_ft->mappings = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_field_type_enumeration_mapping));
+       if (!enum_ft->mappings) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
 
-               BT_LOGD("Setting initial field type's byte order: bo=%s",
-                       bt_common_byte_order_string(bo));
-               ret = bt_field_type_set_byte_order(ft, bo);
-               BT_ASSERT(ret == 0);
+       enum_ft->label_buf = g_ptr_array_new();
+       if (!enum_ft->label_buf) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
        }
 
-       ft->alignment = 1;
+       BT_LIB_LOGD("Created enumeration field type object: %!+F", enum_ft);
+       goto end;
+
+error:
+       BT_PUT(enum_ft);
+
+end:
+       return (void *) enum_ft;
 }
 
-static
-void bt_field_type_integer_initialize(
-               struct bt_field_type *ft,
-               unsigned int size, bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+struct bt_field_type *bt_field_type_unsigned_enumeration_create(void)
 {
-       struct bt_field_type_integer *int_ft = (void *) ft;
-
-       BT_ASSERT(size > 0);
-       BT_LOGD("Initializing integer field type object: size=%u",
-               size);
-       ft->id = BT_FIELD_TYPE_ID_INTEGER;
-       int_ft->size = size;
-       int_ft->base = BT_INTEGER_BASE_DECIMAL;
-       int_ft->encoding = BT_STRING_ENCODING_NONE;
-       bt_field_type_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized integer field type object: addr=%p, size=%u",
-               ft, size);
+       return create_enumeration_field_type(
+               BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION);
 }
 
-static
-void bt_field_type_floating_point_initialize(
-               struct bt_field_type *ft,
-               bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+struct bt_field_type *bt_field_type_signed_enumeration_create(void)
 {
-       struct bt_field_type_floating_point *flt_ft = (void *) ft;
-
-       BT_LOGD_STR("Initializing floating point number field type object.");
-       ft->id = BT_FIELD_TYPE_ID_FLOAT;
-       flt_ft->exp_dig = sizeof(float) * CHAR_BIT - FLT_MANT_DIG;
-       flt_ft->mant_dig = FLT_MANT_DIG;
-       bt_field_type_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized floating point number field type object: addr=%p, "
-               "exp-size=%u, mant-size=%u", ft, flt_ft->exp_dig,
-               flt_ft->mant_dig);
+       return create_enumeration_field_type(
+               BT_FIELD_TYPE_ID_SIGNED_ENUMERATION);
 }
 
-static
-void bt_field_type_enumeration_initialize(
-               struct bt_field_type *ft,
-               struct bt_field_type *container_ft,
-               bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+uint64_t bt_field_type_enumeration_get_mapping_count(struct bt_field_type *ft)
 {
        struct bt_field_type_enumeration *enum_ft = (void *) ft;
 
-       BT_ASSERT(container_ft);
-       BT_LOGD("Initializing enumeration field type object: int-ft-addr=%p",
-               container_ft);
-       ft->id = BT_FIELD_TYPE_ID_ENUM;
-       enum_ft->container_ft = bt_get(container_ft);
-       enum_ft->entries = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) destroy_enumeration_mapping);
-       bt_field_type_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized enumeration field type object: addr=%p, "
-               "int-ft-addr=%p, int-ft-size=%u", ft, container_ft,
-               bt_field_type_integer_get_size(container_ft));
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_IS_ENUM(ft, "Field type");
+       return (uint64_t) enum_ft->mappings->len;
 }
 
-static
-void bt_field_type_string_initialize(
-               struct bt_field_type *ft,
-               bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+void bt_field_type_unsigned_enumeration_borrow_mapping_by_index(
+               struct bt_field_type *ft, uint64_t index,
+               const char **name,
+               struct bt_field_type_unsigned_enumeration_mapping_ranges **ranges)
 {
-       struct bt_field_type_string *string_ft = (void *) ft;
-
-       BT_LOGD_STR("Initializing string field type object.");
-       ft->id = BT_FIELD_TYPE_ID_STRING;
-       bt_field_type_initialize(ft, true, release_func, methods);
-       string_ft->encoding = BT_STRING_ENCODING_UTF8;
-       ft->alignment = CHAR_BIT;
-       BT_LOGD("Initialized string field type object: addr=%p", ft);
+       struct bt_field_type_enumeration *enum_ft = (void *) ft;
+       struct bt_field_type_enumeration_mapping *mapping;
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_NON_NULL(name, "Name (output)");
+       BT_ASSERT_PRE_NON_NULL(ranges, "Ranges (output)");
+       BT_ASSERT_PRE_VALID_INDEX(index, enum_ft->mappings->len);
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION,
+               "Field type");
+       mapping = BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(ft, index);
+       *name = mapping->label->str;
+       *ranges = (void *) mapping;
 }
 
-static
-void bt_field_type_structure_initialize(
-               struct bt_field_type *ft,
-               bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+void bt_field_type_signed_enumeration_borrow_mapping_by_index(
+               struct bt_field_type *ft, uint64_t index,
+               const char **name,
+               struct bt_field_type_signed_enumeration_mapping_ranges **ranges)
 {
-       struct bt_field_type_structure *struct_ft = (void *) ft;
+       struct bt_field_type_enumeration *enum_ft = (void *) ft;
+       struct bt_field_type_enumeration_mapping *mapping;
 
-       BT_LOGD_STR("Initializing structure field type object.");
-       ft->id = BT_FIELD_TYPE_ID_STRUCT;
-       struct_ft->fields = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_field_type_structure_field));
-       struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL);
-       bt_field_type_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized structure field type object: addr=%p", ft);
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_NON_NULL(name, "Name (output)");
+       BT_ASSERT_PRE_NON_NULL(ranges, "Ranges (output)");
+       BT_ASSERT_PRE_VALID_INDEX(index, enum_ft->mappings->len);
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_SIGNED_ENUMERATION,
+               "Field type");
+       mapping = BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(ft, index);
+       *name = mapping->label->str;
+       *ranges = (void *) mapping;
 }
 
-static
-void bt_field_type_array_initialize(
-               struct bt_field_type *ft,
-               struct bt_field_type *element_ft,
-               unsigned int length, bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+static inline
+uint64_t get_enumeration_field_type_mapping_range_count(
+               struct bt_field_type_enumeration_mapping *mapping)
 {
-       struct bt_field_type_array *array_ft = (void *) ft;
-
-       BT_ASSERT(element_ft);
-       BT_LOGD("Initializing array field type object: element-ft-addr=%p, "
-               "length=%u", element_ft, length);
-       ft->id = BT_FIELD_TYPE_ID_ARRAY;
-       array_ft->element_ft = bt_get(element_ft);
-       array_ft->length = length;
-       bt_field_type_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized array field type object: addr=%p, "
-               "element-ft-addr=%p, length=%u", ft, element_ft, length);
+       BT_ASSERT_PRE_NON_NULL(mapping, "Ranges");
+       return (uint64_t) mapping->ranges->len;
 }
 
-static
-void bt_field_type_sequence_initialize(
-               struct bt_field_type *ft,
-               struct bt_field_type *element_ft,
-               const char *length_field_name,
-               bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+uint64_t bt_field_type_unsigned_enumeration_mapping_ranges_get_range_count(
+               struct bt_field_type_unsigned_enumeration_mapping_ranges *ranges)
 {
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-
-       BT_ASSERT(element_ft);
-       BT_ASSERT(length_field_name);
-       BT_ASSERT(bt_identifier_is_valid(length_field_name));
-       BT_LOGD("Initializing sequence field type object: element-ft-addr=%p, "
-               "length-field-name=\"%s\"", element_ft, length_field_name);
-       ft->id = BT_FIELD_TYPE_ID_SEQUENCE;
-       seq_ft->element_ft = bt_get(element_ft);
-       seq_ft->length_field_name = g_string_new(length_field_name);
-       bt_field_type_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized sequence field type object: addr=%p, "
-               "element-ft-addr=%p, length-field-name=\"%s\"",
-               ft, element_ft, length_field_name);
+       return get_enumeration_field_type_mapping_range_count((void *) ranges);
 }
 
-static
-void bt_field_type_variant_initialize(
-               struct bt_field_type *ft,
-               struct bt_field_type *tag_ft,
-               const char *tag_name,
-               bt_object_release_func release_func,
-               struct bt_field_type_methods *methods)
+uint64_t bt_field_type_signed_enumeration_mapping_ranges_get_range_count(
+               struct bt_field_type_signed_enumeration_mapping_ranges *ranges)
 {
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       BT_ASSERT(!tag_name || bt_identifier_is_valid(tag_name));
-       BT_LOGD("Initializing variant field type object: "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               tag_ft, tag_name);
-       ft->id = BT_FIELD_TYPE_ID_VARIANT;
-       var_ft->tag_name = g_string_new(tag_name);
-       var_ft->choice_name_to_index = g_hash_table_new(NULL, NULL);
-       var_ft->choices = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_field_type_variant_choice));
-
-       if (tag_ft) {
-               var_ft->tag_ft = bt_get(tag_ft);
-       }
-
-       bt_field_type_initialize(ft, true, release_func, methods);
-       /* A variant's alignment is undefined */
-       ft->alignment = 0;
-       BT_LOGD("Initialized variant field type object: addr=%p, "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               ft, tag_ft, tag_name);
+       return get_enumeration_field_type_mapping_range_count((void *) ranges);
 }
 
-static
-void bt_field_type_integer_destroy(struct bt_object *obj)
+static inline
+void get_enumeration_field_type_mapping_range_at_index(
+               struct bt_field_type_enumeration_mapping *mapping,
+               uint64_t index, uint64_t *lower, uint64_t *upper)
 {
-       struct bt_field_type_integer *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
+       struct bt_field_type_enumeration_mapping_range *range;
 
-       BT_LOGD("Destroying integer field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting mapped clock class.");
-       bt_put(ft->mapped_clock_class);
-       g_free(ft);
+       BT_ASSERT_PRE_NON_NULL(mapping, "Ranges");
+       BT_ASSERT_PRE_NON_NULL(lower, "Range's lower (output)");
+       BT_ASSERT_PRE_NON_NULL(upper, "Range's upper (output)");
+       BT_ASSERT_PRE_VALID_INDEX(index, mapping->ranges->len);
+       range = BT_FIELD_TYPE_ENUM_MAPPING_RANGE_AT_INDEX(mapping, index);
+       *lower = range->lower.u;
+       *upper = range->upper.u;
 }
 
-static
-void bt_field_type_floating_point_destroy(struct bt_object *obj)
+void bt_field_type_unsigned_enumeration_mapping_ranges_get_range_by_index(
+               struct bt_field_type_unsigned_enumeration_mapping_ranges *ranges,
+               uint64_t index, uint64_t *lower, uint64_t *upper)
 {
-       struct bt_field_type_floating_point *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying floating point number field type object: addr=%p", ft);
-       g_free(ft);
+       get_enumeration_field_type_mapping_range_at_index((void *) ranges,
+               index, lower, upper);
 }
 
-static
-void bt_field_type_enumeration_destroy_recursive(struct bt_object *obj)
+void bt_field_type_signed_enumeration_mapping_ranges_get_range_by_index(
+               struct bt_field_type_unsigned_enumeration_mapping_ranges *ranges,
+               uint64_t index, int64_t *lower, int64_t *upper)
 {
-       struct bt_field_type_enumeration *ft = (void *) obj;
+       get_enumeration_field_type_mapping_range_at_index((void *) ranges,
+               index, (uint64_t *) lower, (uint64_t *) upper);
+}
 
-       if (!ft) {
-               return;
-       }
 
-       BT_LOGD("Destroying enumeration field type object: addr=%p", ft);
-       g_ptr_array_free(ft->entries, TRUE);
-       BT_LOGD_STR("Putting container field type.");
-       bt_put(ft->container_ft);
-       g_free(ft);
-}
 
-static
-void bt_field_type_string_destroy(struct bt_object *obj)
+int bt_field_type_unsigned_enumeration_get_mapping_labels_by_value(
+               struct bt_field_type *ft, uint64_t value,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
 {
-       struct bt_field_type_string *ft = (void *) obj;
+       struct bt_field_type_enumeration *enum_ft = (void *) ft;
+       uint64_t i;
 
-       if (!ft) {
-               return;
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION,
+               "Field type");
+       g_ptr_array_set_size(enum_ft->label_buf, 0);
+
+       for (i = 0; i < enum_ft->mappings->len; i++) {
+               uint64_t j;
+               struct bt_field_type_enumeration_mapping *mapping =
+                       BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(enum_ft, i);
+
+               for (j = 0; j < mapping->ranges->len; j++) {
+                       struct bt_field_type_enumeration_mapping_range *range =
+                               BT_FIELD_TYPE_ENUM_MAPPING_RANGE_AT_INDEX(
+                                       mapping, j);
+
+                       if (value >= range->lower.u &&
+                                       value <= range->upper.u) {
+                               g_ptr_array_add(enum_ft->label_buf,
+                                       mapping->label->str);
+                               break;
+                       }
+               }
        }
 
-       BT_LOGD("Destroying string field type object: addr=%p", ft);
-       g_free(ft);
+       *label_array = (void *) enum_ft->label_buf->pdata;
+       *count = (uint64_t) enum_ft->label_buf->len;
+       return 0;
 }
 
-static
-void bt_field_type_structure_field_finalize(
-               struct bt_field_type_structure_field *field)
+int bt_field_type_signed_enumeration_get_mapping_labels_by_value(
+               struct bt_field_type *ft, int64_t value,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
 {
-       if (!field) {
-               return;
+       struct bt_field_type_enumeration *enum_ft = (void *) ft;
+       uint64_t i;
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_SIGNED_ENUMERATION,
+               "Field type");
+       g_ptr_array_set_size(enum_ft->label_buf, 0);
+
+       for (i = 0; i < enum_ft->mappings->len; i++) {
+               uint64_t j;
+               struct bt_field_type_enumeration_mapping *mapping =
+                       BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(enum_ft, i);
+
+               for (j = 0; j < mapping->ranges->len; j++) {
+                       struct bt_field_type_enumeration_mapping_range *range =
+                               BT_FIELD_TYPE_ENUM_MAPPING_RANGE_AT_INDEX(
+                                       mapping, j);
+
+                       if (value >= range->lower.i &&
+                                       value <= range->upper.i) {
+                               g_ptr_array_add(enum_ft->label_buf,
+                                       mapping->label->str);
+                               break;
+                       }
+               }
        }
 
-       BT_LOGD("Finalizing structure field type's field: "
-               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-               field, field->type, g_quark_to_string(field->name));
-       BT_LOGD_STR("Putting field type.");
-       bt_put(field->type);
+       *label_array = (void *) enum_ft->label_buf->pdata;
+       *count = (uint64_t) enum_ft->label_buf->len;
+       return 0;
 }
 
-static
-void bt_field_type_structure_destroy_recursive(struct bt_object *obj)
+static inline
+int add_mapping_to_enumeration_field_type(struct bt_field_type *ft,
+               const char *label, uint64_t lower, uint64_t upper)
 {
-       struct bt_field_type_structure *ft = (void *) obj;
+       int ret = 0;
        uint64_t i;
+       struct bt_field_type_enumeration *enum_ft = (void *) ft;
+       struct bt_field_type_enumeration_mapping *mapping = NULL;
+       struct bt_field_type_enumeration_mapping_range *range;
 
-       if (!ft) {
-               return;
-       }
+       BT_ASSERT(ft);
+       BT_ASSERT_PRE_NON_NULL(label, "Label");
 
-       BT_LOGD("Destroying structure field type object: addr=%p", ft);
+       /* Find existing mapping identified by this label */
+       for (i = 0; i < enum_ft->mappings->len; i++) {
+               struct bt_field_type_enumeration_mapping *mapping_candidate =
+                       BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(enum_ft, i);
 
-       if (ft->fields) {
-               for (i = 0; i < ft->fields->len; i++) {
-                       bt_field_type_structure_field_finalize(
-                               BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(
-                                       ft, i));
+               if (strcmp(mapping_candidate->label->str, label) == 0) {
+                       mapping = mapping_candidate;
+                       break;
                }
-
-               g_array_free(ft->fields, TRUE);
-       }
-
-       if (ft->field_name_to_index) {
-               g_hash_table_destroy(ft->field_name_to_index);
        }
 
-       g_free(ft);
-}
-
-static
-void bt_field_type_array_destroy_recursive(struct bt_object *obj)
-{
-       struct bt_field_type_array *ft = (void *) obj;
+       if (!mapping) {
+               /* Create new mapping for this label */
+               g_array_set_size(enum_ft->mappings, enum_ft->mappings->len + 1);
+               mapping = BT_FIELD_TYPE_ENUM_MAPPING_AT_INDEX(enum_ft,
+                       enum_ft->mappings->len - 1);
+               mapping->ranges = g_array_new(FALSE, TRUE,
+                       sizeof(struct bt_field_type_enumeration_mapping_range));
+               if (!mapping->ranges) {
+                       finalize_enumeration_field_type_mapping(mapping);
+                       g_array_set_size(enum_ft->mappings,
+                               enum_ft->mappings->len - 1);
+                       ret = -1;
+                       goto end;
+               }
 
-       if (!ft) {
-               return;
+               mapping->label = g_string_new(label);
+               if (!mapping->label) {
+                       finalize_enumeration_field_type_mapping(mapping);
+                       g_array_set_size(enum_ft->mappings,
+                               enum_ft->mappings->len - 1);
+                       ret = -1;
+                       goto end;
+               }
        }
 
-       BT_LOGD("Destroying array field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting element field type.");
-       bt_put(ft->element_ft);
-       g_free(ft);
+       /* Add range */
+       BT_ASSERT(mapping);
+       g_array_set_size(mapping->ranges, mapping->ranges->len + 1);
+       range = BT_FIELD_TYPE_ENUM_MAPPING_RANGE_AT_INDEX(mapping,
+               mapping->ranges->len - 1);
+       range->lower.u = lower;
+       range->upper.u = upper;
+       BT_LIB_LOGV("Added mapping to enumeration field type: "
+               "%![ft-]+F, label=\"%s\", lower-unsigned=%" PRIu64 ", "
+               "upper-unsigned=%" PRIu64, ft, label, lower, upper);
+
+end:
+       return ret;
 }
 
-static
-void bt_field_type_sequence_destroy_recursive(struct bt_object *obj)
+int bt_field_type_unsigned_enumeration_map_range(
+               struct bt_field_type *ft, const char *label,
+               uint64_t range_lower, uint64_t range_upper)
 {
-       struct bt_field_type_sequence *ft = (void *) obj;
+       struct bt_field_type_enumeration *enum_ft = (void *) ft;
 
-       if (!ft) {
-               return;
-       }
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION,
+               "Field type");
+       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_ft->common.range,
+               range_lower),
+               "Range's lower bound is outside the enumeration field type's value range: "
+               "%![ft-]+F, lower=%" PRIu64, ft, range_lower);
+       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(enum_ft->common.range,
+               range_upper),
+               "Range's upper bound is outside the enumeration field type's value range: "
+               "%![ft-]+F, upper=%" PRIu64, ft, range_upper);
+       return add_mapping_to_enumeration_field_type(ft, label, range_lower,
+               range_upper);
+}
+
+int bt_field_type_signed_enumeration_map_range(
+               struct bt_field_type *ft, const char *label,
+               int64_t range_lower, int64_t range_upper)
+{
+       struct bt_field_type_enumeration *enum_ft = (void *) ft;
 
-       BT_LOGD("Destroying sequence field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting element field type.");
-       bt_put(ft->element_ft);
-       g_string_free(ft->length_field_name, TRUE);
-       BT_LOGD_STR("Putting length field path.");
-       bt_put(ft->length_field_path);
-       g_free(ft);
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_SIGNED_ENUMERATION,
+               "Field type");
+       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_ft->common.range,
+               range_lower),
+               "Range's lower bound is outside the enumeration field type's value range: "
+               "%![ft-]+F, lower=%" PRId64, ft, range_lower);
+       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(enum_ft->common.range,
+               range_upper),
+               "Range's upper bound is outside the enumeration field type's value range: "
+               "%![ft-]+F, upper=%" PRId64, ft, range_upper);
+       return add_mapping_to_enumeration_field_type(ft, label, range_lower,
+               range_upper);
 }
 
 static
-void bt_field_type_variant_choice_finalize(
-               struct bt_field_type_variant_choice *choice)
+void destroy_real_field_type(struct bt_object *obj)
 {
-       if (!choice) {
-               return;
-       }
-
-       BT_LOGD("Finalizing variant field type's choice: "
-               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-               choice, choice->type, g_quark_to_string(choice->name));
-       BT_LOGD_STR("Putting field type.");
-       bt_put(choice->type);
-
-       if (choice->ranges) {
-               g_array_free(choice->ranges, TRUE);
-       }
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying real field type object: %!+F", obj);
+       g_free(obj);
 }
 
-static
-void bt_field_type_variant_destroy_recursive(struct bt_object *obj)
+struct bt_field_type *bt_field_type_real_create(void)
 {
-       struct bt_field_type_variant *ft = (void *) obj;
-       uint64_t i;
-
-       if (!ft) {
-               return;
-       }
+       struct bt_field_type_real *real_ft = NULL;
 
-       BT_LOGD("Destroying variant field type object: addr=%p", ft);
-
-       if (ft->choices) {
-               for (i = 0; i < ft->choices->len; i++) {
-                       bt_field_type_variant_choice_finalize(
-                               BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(
-                                       ft, i));
-               }
-
-               g_array_free(ft->choices, TRUE);
+       BT_LOGD_STR("Creating default real field type object.");
+       real_ft = g_new0(struct bt_field_type_real, 1);
+       if (!real_ft) {
+               BT_LOGE_STR("Failed to allocate one real field type.");
+               goto error;
        }
 
-       if (ft->choice_name_to_index) {
-               g_hash_table_destroy(ft->choice_name_to_index);
-       }
+       init_field_type((void *) real_ft, BT_FIELD_TYPE_ID_REAL,
+               destroy_real_field_type);
+       BT_LIB_LOGD("Created real field type object: %!+F", real_ft);
+       goto end;
 
-       if (ft->tag_name) {
-               g_string_free(ft->tag_name, TRUE);
-       }
+error:
+       BT_PUT(real_ft);
 
-       BT_LOGD_STR("Putting tag field type.");
-       bt_put(ft->tag_ft);
-       BT_LOGD_STR("Putting tag field path.");
-       bt_put(ft->tag_field_path);
-       g_free(ft);
+end:
+       return (void *) real_ft;
 }
 
-struct range_overlap_query {
-       union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_start;
-
-       union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_end;
-       int overlaps;
-       GQuark mapping_name;
-};
-
-static
-gint compare_enumeration_mappings_signed(struct enumeration_mapping **a,
-               struct enumeration_mapping **b)
+bt_bool bt_field_type_real_is_single_precision(struct bt_field_type *ft)
 {
-       return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1;
+       struct bt_field_type_real *real_ft = (void *) ft;
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_REAL, "Field type");
+       return real_ft->is_single_precision;
 }
 
-static
-gint compare_enumeration_mappings_unsigned(struct enumeration_mapping **a,
-               struct enumeration_mapping **b)
+int bt_field_type_real_set_is_single_precision(struct bt_field_type *ft,
+               bt_bool is_single_precision)
 {
-       return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1;
+       struct bt_field_type_real *real_ft = (void *) ft;
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_REAL, "Field type");
+       BT_ASSERT_PRE_FT_HOT(ft, "Field type");
+       real_ft->is_single_precision = (bool) is_single_precision;
+       BT_LIB_LOGV("Set real field type's \"is single precision\" property: "
+               "%!+F", ft);
+       return 0;
 }
 
 static
-int add_structure_variant_member(GArray *members,
-               GHashTable *field_name_to_index,
-               struct bt_field_type *field_type, const char *field_name,
-               bool is_variant)
+int init_named_field_types_container(
+               struct bt_field_type_named_field_types_container *ft,
+               enum bt_field_type_id id, bt_object_release_func release_func)
 {
        int ret = 0;
-       GQuark name_quark = g_quark_from_string(field_name);
-       struct bt_field_type **member_ft;
-       GQuark *member_name;
-
-       /* Make sure structure does not contain a field of the same name */
-       if (g_hash_table_lookup_extended(field_name_to_index,
-                       GUINT_TO_POINTER(name_quark), NULL, NULL)) {
-               BT_LOGW("Structure or variant field type already contains a field type with this name: "
-                       "field-name=\"%s\"", field_name);
+
+       init_field_type((void *) ft, id, release_func);
+       ft->named_fts = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_named_field_type));
+       if (!ft->named_fts) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
                ret = -1;
                goto end;
        }
 
-       g_array_set_size(members, members->len + 1);
-
-       if (is_variant) {
-               struct bt_field_type_variant_choice *choice =
-                       &g_array_index(members,
-                               struct bt_field_type_variant_choice,
-                               members->len - 1);
-
-               member_ft = &choice->type;
-               member_name = &choice->name;
-               BT_ASSERT(!choice->ranges);
-               choice->ranges = g_array_new(FALSE, TRUE,
-                       sizeof(struct bt_field_type_variant_choice_range));
-               BT_ASSERT(choice->ranges);
-       } else {
-               struct bt_field_type_structure_field *field =
-                       &g_array_index(members,
-                               struct bt_field_type_structure_field,
-                               members->len - 1);
-
-               member_ft = &field->type;
-               member_name = &field->name;
+       ft->name_to_index = g_hash_table_new(g_str_hash, g_str_equal);
+       if (!ft->name_to_index) {
+               BT_LOGE_STR("Failed to allocate a GHashTable.");
+               ret = -1;
+               goto end;
        }
 
-       *member_name = name_quark;
-       *member_ft = bt_get(field_type);
-       g_hash_table_insert(field_name_to_index,
-               GUINT_TO_POINTER(name_quark),
-               GUINT_TO_POINTER(members->len - 1));
-       BT_LOGV("Added structure/variant field type member: member-ft-addr=%p, "
-               "member-name=\"%s\"", field_type, field_name);
-
 end:
        return ret;
 }
 
 static
-int bt_field_type_integer_validate(struct bt_field_type *ft)
+void finalize_named_field_type(struct bt_named_field_type *named_ft)
 {
-       int ret = 0;
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       BT_ASSERT(named_ft);
+       BT_LIB_LOGD("Finalizing named field type: "
+               "addr=%p, name=\"%s\", %![ft-]+F",
+               named_ft, named_ft->name ? named_ft->name->str : NULL,
+               named_ft->ft);
 
-       if (int_ft->mapped_clock_class && int_ft->is_signed) {
-               BT_LOGW("Invalid integer field type: cannot be signed and have a mapped clock class: "
-                       "ft-addr=%p, clock-class-addr=%p, clock-class-name=\"%s\"",
-                       ft, int_ft->mapped_clock_class,
-                       bt_clock_class_get_name(int_ft->mapped_clock_class));
-               ret = -1;
-               goto end;
+       if (named_ft->name) {
+               g_string_free(named_ft->name, TRUE);
        }
 
-end:
-       return ret;
+       BT_LOGD_STR("Putting named field type's field type.");
+       bt_put(named_ft->ft);
 }
 
 static
-struct enumeration_mapping *bt_field_type_enumeration_get_mapping_by_index(
-               struct bt_field_type *ft, uint64_t index)
+void finalize_named_field_types_container(
+               struct bt_field_type_named_field_types_container *ft)
 {
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-       struct enumeration_mapping *mapping = NULL;
+       uint64_t i;
 
-       if (index >= enum_ft->entries->len) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "addr=%p, index=%" PRIu64 ", count=%u",
-                       ft, index, enum_ft->entries->len);
-               goto end;
-       }
-
-       mapping = g_ptr_array_index(enum_ft->entries, index);
-
-end:
-       return mapping;
-}
+       BT_ASSERT(ft);
 
-/*
- * Note: This algorithm is O(n^2) vs number of enumeration mappings.
- * Only used when freezing an enumeration.
- */
-static
-void bt_field_type_enumeration_set_range_overlap(
-               struct bt_field_type_enumeration *ft)
-{
-       int64_t i, j, len;
-       int is_signed;
-
-       BT_LOGV("Setting enumeration field type's overlap flag: addr=%p",
-               ft);
-       len = ft->entries->len;
-       is_signed = bt_field_type_integer_is_signed((void *) ft->container_ft);
-
-       for (i = 0; i < len; i++) {
-               for (j = i + 1; j < len; j++) {
-                       struct enumeration_mapping *mapping[2];
-
-                       mapping[0] = bt_field_type_enumeration_get_mapping_by_index(
-                               (void *) ft, i);
-                       mapping[1] = bt_field_type_enumeration_get_mapping_by_index(
-                               (void *) ft, j);
-                       if (is_signed) {
-                               if (mapping[0]->range_start._signed
-                                                       <= mapping[1]->range_end._signed
-                                               && mapping[0]->range_end._signed
-                                                       >= mapping[1]->range_start._signed) {
-                                       ft->has_overlapping_ranges = BT_TRUE;
-                                       goto end;
-                               }
-                       } else {
-                               if (mapping[0]->range_start._unsigned
-                                                       <= mapping[1]->range_end._unsigned
-                                               && mapping[0]->range_end._unsigned
-                                                       >= mapping[1]->range_start._unsigned) {
-                                       ft->has_overlapping_ranges = BT_TRUE;
-                                       goto end;
-                               }
-                       }
+       if (ft->named_fts) {
+               for (i = 0; i < ft->named_fts->len; i++) {
+                       finalize_named_field_type(
+                               &g_array_index(ft->named_fts,
+                                       struct bt_named_field_type, i));
                }
+
+               g_array_free(ft->named_fts, TRUE);
        }
 
-end:
-       if (ft->has_overlapping_ranges) {
-               BT_LOGV_STR("Enumeration field type has overlapping ranges.");
-       } else {
-               BT_LOGV_STR("Enumeration field type has no overlapping ranges.");
+       if (ft->name_to_index) {
+               g_hash_table_destroy(ft->name_to_index);
        }
 }
 
 static
-int bt_field_type_enumeration_validate_recursive(
-               struct bt_field_type *ft)
+void destroy_structure_field_type(struct bt_object *obj)
 {
-       int ret = 0;
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying string field type object: %!+F", obj);
+       finalize_named_field_types_container((void *) obj);
+       g_free(obj);
+}
 
-       ret = bt_field_type_integer_validate((void *) enum_ft->container_ft);
-       if (ret) {
-               BT_LOGW("Invalid enumeration field type: container type is invalid: "
-                       "enum-ft-addr=%p, int-ft-addr=%p",
-                       ft, enum_ft->container_ft);
-               goto end;
+struct bt_field_type *bt_field_type_structure_create(void)
+{
+       int ret;
+       struct bt_field_type_structure *struct_ft = NULL;
+
+       BT_LOGD_STR("Creating default structure field type object.");
+       struct_ft = g_new0(struct bt_field_type_structure, 1);
+       if (!struct_ft) {
+               BT_LOGE_STR("Failed to allocate one structure field type.");
+               goto error;
        }
 
-       /* Ensure enum has entries */
-       if (enum_ft->entries->len == 0) {
-               BT_LOGW("Invalid enumeration field type: no entries: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
+       ret = init_named_field_types_container((void *) struct_ft,
+               BT_FIELD_TYPE_ID_STRUCTURE, destroy_structure_field_type);
+       if (ret) {
+               goto error;
        }
 
+       BT_LIB_LOGD("Created structure field type object: %!+F", struct_ft);
+       goto end;
+
+error:
+       BT_PUT(struct_ft);
+
 end:
-       return ret;
+       return (void *) struct_ft;
 }
 
 static
-int bt_field_type_sequence_validate_recursive(
-               struct bt_field_type *ft)
+int append_named_field_type_to_container_field_type(
+               struct bt_field_type_named_field_types_container *container_ft,
+               const char *name, struct bt_field_type *ft)
 {
        int ret = 0;
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
+       struct bt_named_field_type *named_ft;
+       GString *name_str;
 
-       /* Length field name should be set at this point */
-       if (seq_ft->length_field_name->len == 0) {
-               BT_LOGW("Invalid sequence field type: no length field name: "
-                       "addr=%p", ft);
+       BT_ASSERT(container_ft);
+       BT_ASSERT_PRE_FT_HOT(container_ft, "Field type");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE(!bt_g_hash_table_contains(container_ft->name_to_index,
+               name),
+               "Duplicate member/option name in structure/variant field type: "
+               "%![container-ft-]+F, name=\"%s\"", container_ft, name);
+       name_str = g_string_new(name);
+       if (!name_str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
                ret = -1;
                goto end;
        }
 
-       ret = bt_field_type_validate(seq_ft->element_ft);
-       if (ret) {
-               BT_LOGW("Invalid sequence field type: invalid element field type: "
-                       "seq-ft-addr=%p, element-ft-add=%p",
-                       ft, seq_ft->element_ft);
-       }
+       g_array_set_size(container_ft->named_fts,
+               container_ft->named_fts->len + 1);
+       named_ft = &g_array_index(container_ft->named_fts,
+               struct bt_named_field_type, container_ft->named_fts->len - 1);
+       named_ft->name = name_str;
+       named_ft->ft = bt_get(ft);
+       g_hash_table_insert(container_ft->name_to_index, named_ft->name->str,
+               GUINT_TO_POINTER(container_ft->named_fts->len - 1));
+       bt_field_type_freeze(ft);
 
 end:
        return ret;
 }
 
-static
-int bt_field_type_array_validate_recursive(
-               struct bt_field_type *ft)
+int bt_field_type_structure_append_member(struct bt_field_type *ft,
+               const char *name, struct bt_field_type *member_ft)
 {
-       int ret = 0;
-       struct bt_field_type_array *array_ft = (void *) ft;
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCTURE, "Field type");
+       return append_named_field_type_to_container_field_type((void *) ft,
+               name, member_ft);
+}
 
-       ret = bt_field_type_validate(array_ft->element_ft);
-       if (ret) {
-               BT_LOGW("Invalid array field type: invalid element field type: "
-                       "array-ft-addr=%p, element-ft-add=%p",
-                       ft, array_ft->element_ft);
-       }
+uint64_t bt_field_type_structure_get_member_count(struct bt_field_type *ft)
+{
+       struct bt_field_type_structure *struct_ft = (void *) ft;
 
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCTURE, "Field type");
+       return (uint64_t) struct_ft->common.named_fts->len;
 }
 
 static
-int bt_field_type_structure_validate_recursive(
-               struct bt_field_type *ft)
+void borrow_named_field_type_from_container_field_type_at_index(
+               struct bt_field_type_named_field_types_container *ft,
+               uint64_t index, const char **name,
+               struct bt_field_type **out_ft)
 {
-       int ret = 0;
-       struct bt_field_type *child_ft = NULL;
-       int64_t field_count =
-               bt_field_type_structure_get_field_count(ft);
-       int64_t i;
-
-       BT_ASSERT(field_count >= 0);
-
-       for (i = 0; i < field_count; ++i) {
-               const char *field_name;
-
-               ret = bt_field_type_structure_borrow_field_by_index(ft,
-                       &field_name, &child_ft, i);
-               BT_ASSERT(ret == 0);
-               ret = bt_field_type_validate(child_ft);
-               if (ret) {
-                       BT_LOGW("Invalid structure field type: "
-                               "a contained field type is invalid: "
-                               "struct-ft-addr=%p, field-ft-addr=%p, "
-                               "field-name=\"%s\", field-index=%" PRId64,
-                               ft, child_ft, field_name, i);
-                       goto end;
-               }
-       }
+       struct bt_named_field_type *named_ft;
 
-end:
-       return ret;
+       BT_ASSERT(ft);
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(out_ft, "Field type (output)");
+       BT_ASSERT_PRE_VALID_INDEX(index, ft->named_fts->len);
+       named_ft = BT_FIELD_TYPE_NAMED_FT_AT_INDEX(ft, index);
+       *name = named_ft->name->str;
+       *out_ft = named_ft->ft;
 }
 
-static
-bt_bool bt_field_type_enumeration_has_overlapping_ranges(
-               struct bt_field_type_enumeration *enum_ft)
+void bt_field_type_structure_borrow_member_by_index(
+               struct bt_field_type *ft, uint64_t index,
+               const char **name, struct bt_field_type **out_ft)
 {
-       if (!enum_ft->common.frozen) {
-               bt_field_type_enumeration_set_range_overlap(enum_ft);
-       }
-
-       return enum_ft->has_overlapping_ranges;
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCTURE, "Field type");
+       borrow_named_field_type_from_container_field_type_at_index((void *) ft,
+               index, name, out_ft);
 }
 
 static
-int bt_field_type_variant_validate_recursive(
-               struct bt_field_type *ft)
+struct bt_field_type *borrow_field_type_from_container_field_type_by_name(
+               struct bt_field_type_named_field_types_container *ft,
+               const char *name)
 {
-       int ret = 0;
-       int64_t field_count;
-       struct bt_field_type *child_ft = NULL;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       int64_t i;
-
-       if (var_ft->tag_name->len == 0) {
-               BT_LOGW("Invalid variant field type: no tag field name: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (!var_ft->tag_ft) {
-               BT_LOGW("Invalid variant field type: no tag field type: "
-                       "addr=%p, tag-field-name=\"%s\"", var_ft,
-                       var_ft->tag_name->str);
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_field_type_enumeration_has_overlapping_ranges(var_ft->tag_ft)) {
-               BT_LOGW("Invalid variant field type: enumeration tag field type has overlapping ranges: "
-                       "variant-ft-addr=%p, tag-field-name=\"%s\", "
-                       "enum-ft-addr=%p", ft, var_ft->tag_name->str,
-                       var_ft->tag_ft);
-               ret = -1;
-               goto end;
-       }
+       struct bt_field_type *ret_ft = NULL;
+       struct bt_named_field_type *named_ft;
+       gpointer orig_key;
+       gpointer value;
 
-       /*
-        * It is valid to have a variant field type which does not have
-        * the fields corresponding to each label in the associated
-        * enumeration.
-        *
-        * It is also valid to have variant field type fields which
-        * cannot be selected because the variant field type tag has no
-        * mapping named as such. This scenario, while not ideal, cannot
-        * cause any error.
-        *
-        * If a non-existing field happens to be selected by an
-        * enumeration while reading a variant field, an error will be
-        * generated at that point (while reading the stream).
-        */
-       field_count = bt_field_type_variant_get_field_count(ft);
-       if (field_count < 0) {
-               BT_LOGW("Invalid variant field type: no fields: "
-                       "addr=%p, tag-field-name=\"%s\"",
-                       ft, var_ft->tag_name->str);
-               ret = -1;
+       BT_ASSERT(ft);
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       if (!g_hash_table_lookup_extended(ft->name_to_index, name, &orig_key,
+                       &value)) {
                goto end;
        }
 
-       for (i = 0; i < field_count; ++i) {
-               const char *field_name;
-
-               ret = bt_field_type_variant_borrow_field_by_index(ft,
-                       &field_name, &child_ft, i);
-               BT_ASSERT(ret == 0);
-               ret = bt_field_type_validate(child_ft);
-               if (ret) {
-                       BT_LOGW("Invalid variant field type: "
-                               "a contained field type is invalid: "
-                               "variant-ft-addr=%p, tag-field-name=\"%s\", "
-                               "field-ft-addr=%p, field-name=\"%s\", "
-                               "field-index=%" PRId64,
-                               ft, var_ft->tag_name->str, child_ft,
-                               field_name, i);
-                       goto end;
-               }
-       }
+       named_ft = BT_FIELD_TYPE_NAMED_FT_AT_INDEX(ft,
+               GPOINTER_TO_UINT(value));
+       ret_ft = named_ft->ft;
 
 end:
-       return ret;
+       return ret_ft;
 }
 
-/*
- * This function validates a given field type without considering
- * where this field type is located. It only validates the properties
- * of the given field type and the properties of its children if
- * applicable.
- */
-BT_HIDDEN
-int bt_field_type_validate(struct bt_field_type *ft)
+struct bt_field_type *bt_field_type_structure_borrow_member_field_type_by_name(
+               struct bt_field_type *ft, const char *name)
 {
-       int ret = 0;
-
-       BT_ASSERT(ft);
-
-       if (ft->valid) {
-               /* Already marked as valid */
-               goto end;
-       }
-
-       if (ft->methods->validate) {
-               ret = ft->methods->validate(ft);
-       }
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCTURE, "Field type");
+       return borrow_field_type_from_container_field_type_by_name((void *) ft,
+               name);
+}
 
-       if (ret == 0 && ft->frozen) {
-               /* Field type is valid */
-               BT_LOGV("Marking field type as valid: addr=%p", ft);
-               ft->valid = 1;
-       }
+static
+void destroy_variant_field_type(struct bt_object *obj)
+{
+       struct bt_field_type_variant *ft = (void *) obj;
 
-end:
-       return ret;
+       BT_ASSERT(ft);
+       BT_LIB_LOGD("Destroying variant field type object: %!+F", ft);
+       finalize_named_field_types_container((void *) ft);
+       BT_LOGD_STR("Putting selector field path.");
+       bt_put(ft->selector_field_path);
+       g_free(ft);
 }
 
-struct bt_field_type *bt_field_type_integer_create(unsigned int size)
+struct bt_field_type *bt_field_type_variant_create(void)
 {
-       struct bt_field_type_integer *integer = NULL;
-
-       BT_LOGD("Creating integer field type object: size=%u", size);
+       int ret;
+       struct bt_field_type_variant *var_ft = NULL;
 
-       if (size == 0 || size > 64) {
-               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
-                       "size=%u", size);
+       BT_LOGD_STR("Creating default variant field type object.");
+       var_ft = g_new0(struct bt_field_type_variant, 1);
+       if (!var_ft) {
+               BT_LOGE_STR("Failed to allocate one variant field type.");
                goto error;
        }
 
-       integer = g_new0(struct bt_field_type_integer, 1);
-       if (!integer) {
-               BT_LOGE_STR("Failed to allocate one integer field type.");
+       ret = init_named_field_types_container((void *) var_ft,
+               BT_FIELD_TYPE_ID_VARIANT, destroy_variant_field_type);
+       if (ret) {
                goto error;
        }
 
-       bt_field_type_integer_initialize((void *) integer,
-               size, bt_field_type_integer_destroy,
-               &bt_field_type_integer_methods);
-       BT_LOGD("Created integer field type object: addr=%p, size=%u",
-               integer, size);
+       BT_LIB_LOGD("Created variant field type object: %!+F", var_ft);
        goto end;
 
 error:
-       BT_PUT(integer);
+       BT_PUT(var_ft);
 
 end:
-       return (void *) integer;
+       return (void *) var_ft;
 }
 
-
-int bt_field_type_integer_get_size(struct bt_field_type *ft)
+int bt_field_type_variant_set_selector_field_type(
+               struct bt_field_type *ft, struct bt_field_type *selector_ft)
 {
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       struct bt_field_type_variant *var_ft = (void *) ft;
 
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return (int) int_ft->size;
+       BT_ASSERT_PRE_NON_NULL(ft, "Variant field type");
+       BT_ASSERT_PRE_NON_NULL(selector_ft, "Selector field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT, "Field type");
+       BT_ASSERT_PRE_FT_IS_ENUM(selector_ft, "Selector field type");
+       BT_ASSERT_PRE_FT_HOT(ft, "Variant field type");
+       var_ft->selector_ft = selector_ft;
+       bt_field_type_freeze(selector_ft);
+       return 0;
 }
 
-bt_bool bt_field_type_integer_is_signed(struct bt_field_type *ft)
+int bt_field_type_variant_append_option(struct bt_field_type *ft,
+               const char *name, struct bt_field_type *option_ft)
 {
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT, "Field type");
+       return append_named_field_type_to_container_field_type((void *) ft,
+               name, option_ft);
+}
 
+struct bt_field_type *bt_field_type_variant_borrow_option_field_type_by_name(
+               struct bt_field_type *ft, const char *name)
+{
        BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->is_signed;
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT, "Field type");
+       return borrow_field_type_from_container_field_type_by_name((void *) ft,
+               name);
 }
 
-int bt_field_type_integer_set_is_signed(struct bt_field_type *ft,
-               bt_bool is_signed)
+uint64_t bt_field_type_variant_get_option_count(struct bt_field_type *ft)
 {
-       int ret = 0;
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       struct bt_field_type_variant *var_ft = (void *) ft;
 
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT, "Field type");
+       return (uint64_t) var_ft->common.named_fts->len;
+}
 
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
+void bt_field_type_variant_borrow_option_by_index(
+               struct bt_field_type *ft, uint64_t index,
+               const char **name, struct bt_field_type **out_ft)
+{
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT, "Field type");
+       borrow_named_field_type_from_container_field_type_at_index((void *) ft,
+               index, name, out_ft);
+}
 
-       if (ft->id != BT_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
+struct bt_field_path *bt_field_type_variant_borrow_selector_field_path(
+               struct bt_field_type *ft)
+{
+       struct bt_field_type_variant *var_ft = (void *) ft;
 
-       int_ft->is_signed = !!is_signed;
-       BT_LOGV("Set integer field type's signedness: addr=%p, is-signed=%d",
-               ft, is_signed);
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       return var_ft->selector_field_path;
+}
 
-end:
-       return ret;
+static
+void init_array_field_type(struct bt_field_type_array *ft,
+               enum bt_field_type_id id, bt_object_release_func release_func,
+               struct bt_field_type *element_ft)
+{
+       BT_ASSERT(element_ft);
+       init_field_type((void *) ft, id, release_func);
+       ft->element_ft = bt_get(element_ft);
+       bt_field_type_freeze(element_ft);
 }
 
-int bt_field_type_integer_set_size(struct bt_field_type *ft,
-               unsigned int size)
+static
+void finalize_array_field_type(struct bt_field_type_array *array_ft)
 {
-       int ret = 0;
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       BT_ASSERT(array_ft);
+       BT_LOGD_STR("Putting element field type.");
+       bt_put(array_ft->element_ft);
+}
 
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
+static
+void destroy_static_array_field_type(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying static array field type object: %!+F", obj);
+       finalize_array_field_type((void *) obj);
+       g_free(obj);
+}
 
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
+struct bt_field_type *bt_field_type_static_array_create(
+               struct bt_field_type *element_ft, uint64_t length)
+{
+       struct bt_field_type_static_array *array_ft = NULL;
 
-       if (ft->id != BT_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
+       BT_ASSERT_PRE_NON_NULL(element_ft, "Element field type");
+       BT_LOGD_STR("Creating default static array field type object.");
+       array_ft = g_new0(struct bt_field_type_static_array, 1);
+       if (!array_ft) {
+               BT_LOGE_STR("Failed to allocate one static array field type.");
+               goto error;
        }
 
-       if (size == 0 || size > 64) {
-               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
-                       "addr=%p, size=%u", ft, size);
-               ret = -1;
-               goto end;
-       }
+       init_array_field_type((void *) array_ft, BT_FIELD_TYPE_ID_STATIC_ARRAY,
+               destroy_static_array_field_type, element_ft);
+       array_ft->length = length;
+       BT_LIB_LOGD("Created static array field type object: %!+F", array_ft);
+       goto end;
 
-       int_ft->size = size;
-       BT_LOGV("Set integer field type's size: addr=%p, size=%u",
-               ft, size);
+error:
+       BT_PUT(array_ft);
 
 end:
-       return ret;
+       return (void *) array_ft;
 }
 
-enum bt_integer_base bt_field_type_integer_get_base(
+struct bt_field_type *bt_field_type_array_borrow_element_field_type(
                struct bt_field_type *ft)
 {
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       struct bt_field_type_array *array_ft = (void *) ft;
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_IS_ARRAY(ft, "Field type");
+       return array_ft->element_ft;
+}
+
+uint64_t bt_field_type_static_array_get_length(struct bt_field_type *ft)
+{
+       struct bt_field_type_static_array *array_ft = (void *) ft;
 
        BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_INTEGER,
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STATIC_ARRAY,
                "Field type");
-       return int_ft->base;
+       return (uint64_t) array_ft->length;
 }
 
-int bt_field_type_integer_set_base(struct bt_field_type *ft,
-               enum bt_integer_base base)
+static
+void destroy_dynamic_array_field_type(struct bt_object *obj)
 {
-       int ret = 0;
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       struct bt_field_type_dynamic_array *ft = (void *) obj;
 
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
+       BT_ASSERT(ft);
+       BT_LIB_LOGD("Destroying dynamic array field type object: %!+F", ft);
+       finalize_array_field_type((void *) ft);
+       BT_LOGD_STR("Putting length field path.");
+       bt_put(ft->length_field_path);
+       g_free(ft);
+}
 
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
+struct bt_field_type *bt_field_type_dynamic_array_create(
+               struct bt_field_type *element_ft)
+{
+       struct bt_field_type_dynamic_array *array_ft = NULL;
 
-       if (ft->id != BT_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
+       BT_ASSERT_PRE_NON_NULL(element_ft, "Element field type");
+       BT_LOGD_STR("Creating default dynamic array field type object.");
+       array_ft = g_new0(struct bt_field_type_dynamic_array, 1);
+       if (!array_ft) {
+               BT_LOGE_STR("Failed to allocate one dynamic array field type.");
+               goto error;
        }
 
-       switch (base) {
-       case BT_INTEGER_BASE_UNSPECIFIED:
-       case BT_INTEGER_BASE_BINARY:
-       case BT_INTEGER_BASE_OCTAL:
-       case BT_INTEGER_BASE_DECIMAL:
-       case BT_INTEGER_BASE_HEXADECIMAL:
-       {
-               int_ft->base = base;
-               break;
-       }
-       default:
-               BT_LOGW("Invalid parameter: unknown integer field type base: "
-                       "addr=%p, base=%d", ft, base);
-               ret = -1;
-       }
+       init_array_field_type((void *) array_ft, BT_FIELD_TYPE_ID_DYNAMIC_ARRAY,
+               destroy_dynamic_array_field_type, element_ft);
+       BT_LIB_LOGD("Created dynamic array field type object: %!+F", array_ft);
+       goto end;
 
-       BT_LOGV("Set integer field type's base: addr=%p, base=%s",
-               ft, bt_common_integer_base_string(base));
+error:
+       BT_PUT(array_ft);
 
 end:
-       return ret;
+       return (void *) array_ft;
+}
+
+int bt_field_type_dynamic_array_set_length_field_type(struct bt_field_type *ft,
+               struct bt_field_type *length_ft)
+{
+       struct bt_field_type_dynamic_array *array_ft = (void *) ft;
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Dynamic array field type");
+       BT_ASSERT_PRE_NON_NULL(length_ft, "Length field type");
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_DYNAMIC_ARRAY,
+               "Field type");
+       BT_ASSERT_PRE_FT_IS_UNSIGNED_INT(length_ft, "Length field type");
+       BT_ASSERT_PRE_FT_HOT(ft, "Dynamic array field type");
+       array_ft->length_ft = length_ft;
+       bt_field_type_freeze(length_ft);
+       return 0;
 }
 
-enum bt_string_encoding bt_field_type_integer_get_encoding(
+struct bt_field_path *bt_field_type_dynamic_array_borrow_length_field_path(
                struct bt_field_type *ft)
 {
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       struct bt_field_type_dynamic_array *seq_ft = (void *) ft;
 
        BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_INTEGER,
+       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_DYNAMIC_ARRAY,
                "Field type");
-       return int_ft->encoding;
+       return seq_ft->length_field_path;
 }
 
-int bt_field_type_integer_set_encoding(struct bt_field_type *ft,
-               enum bt_string_encoding encoding)
+static
+void destroy_string_field_type(struct bt_object *obj)
 {
-       int ret = 0;
-       struct bt_field_type_integer *int_ft = (void *) ft;
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying string field type object: %!+F", obj);
+       g_free(obj);
+}
 
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
+struct bt_field_type *bt_field_type_string_create(void)
+{
+       struct bt_field_type_string *string_ft = NULL;
 
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
+       BT_LOGD_STR("Creating default string field type object.");
+       string_ft = g_new0(struct bt_field_type_string, 1);
+       if (!string_ft) {
+               BT_LOGE_STR("Failed to allocate one string field type.");
+               goto error;
        }
 
-       if (ft->id != BT_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
+       init_field_type((void *) string_ft, BT_FIELD_TYPE_ID_STRING,
+               destroy_string_field_type);
+       BT_LIB_LOGD("Created string field type object: %!+F", string_ft);
+       goto end;
 
-       if (encoding != BT_STRING_ENCODING_UTF8 &&
-                       encoding != BT_STRING_ENCODING_ASCII &&
-                       encoding != BT_STRING_ENCODING_NONE) {
-               BT_LOGW("Invalid parameter: unknown string encoding: "
-                       "addr=%p, encoding=%d", ft, encoding);
-               ret = -1;
-               goto end;
-       }
-
-       int_ft->encoding = encoding;
-       BT_LOGV("Set integer field type's encoding: addr=%p, encoding=%s",
-               ft, bt_common_string_encoding_string(encoding));
-
-end:
-       return ret;
-}
-
-struct bt_clock_class *bt_field_type_integer_borrow_mapped_clock_class(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_integer *int_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->mapped_clock_class;
-}
-
-static
-int bt_field_type_integer_set_mapped_clock_class_no_check_frozen(
-               struct bt_field_type *ft,
-               struct bt_clock_class *clock_class)
-{
-       struct bt_field_type_integer *int_ft = (void *) ft;
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               goto end;
-       }
-
-       if (!bt_clock_class_is_valid(clock_class)) {
-               BT_LOGW("Invalid parameter: clock class is invalid: ft-addr=%p"
-                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                       ft, clock_class,
-                       bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       bt_put(int_ft->mapped_clock_class);
-       int_ft->mapped_clock_class = bt_get(clock_class);
-       BT_LOGV("Set integer field type's mapped clock class: ft-addr=%p, "
-               "clock-class-addr=%p, clock-class-name=\"%s\"",
-               ft, clock_class, bt_clock_class_get_name(clock_class));
-
-end:
-       return ret;
-}
-
-int bt_field_type_integer_set_mapped_clock_class(struct bt_field_type *ft,
-               struct bt_clock_class *clock_class)
-{
-       int ret = 0;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_field_type_integer_set_mapped_clock_class_no_check_frozen(
-               ft, clock_class);
-
-end:
-       return ret;
-}
-
-static
-void bt_field_type_enum_iter_destroy(struct bt_object *obj)
-{
-       struct bt_field_type_enumeration_mapping_iterator *iter =
-               container_of(obj,
-                       struct bt_field_type_enumeration_mapping_iterator,
-                       base);
-
-       BT_LOGD("Destroying enumeration field type mapping iterator: addr=%p",
-               obj);
-       BT_LOGD_STR("Putting parent enumeration field type.");
-       bt_put(iter->enumeration_ft);
-       g_free(iter);
-}
-
-static
-struct bt_field_type_enumeration_mapping_iterator *
-bt_field_type_enumeration_find_mappings_type(
-               struct bt_field_type *ft,
-               enum bt_field_type_enumeration_mapping_iterator_type iterator_type)
-{
-       struct bt_field_type_enumeration_mapping_iterator *iter = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_ENUM,
-               "Field type");
-       iter = g_new0(struct bt_field_type_enumeration_mapping_iterator, 1);
-       if (!iter) {
-               BT_LOGE_STR("Failed to allocate one enumeration field type mapping.");
-               goto end;
-       }
-
-       bt_object_init_shared(&iter->base, bt_field_type_enum_iter_destroy);
-       iter->enumeration_ft = bt_get(ft);
-       iter->index = -1;
-       iter->type = iterator_type;
-
-end:
-       return iter;
-}
-
-struct bt_field_type_enumeration_mapping_iterator *
-bt_field_type_enumeration_find_mappings_by_name(
-               struct bt_field_type *ft, const char *name)
-{
-       struct bt_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_field_type_enumeration_find_mappings_type(
-                       ft, ITERATOR_BY_NAME);
-       if (!iter) {
-               BT_LOGW("Cannot create enumeration field type mapping iterator: "
-                       "ft-addr=%p, mapping-name=\"%s\"", ft, name);
-               goto error;
-       }
-
-       iter->u.name_quark = g_quark_try_string(name);
-       if (!iter->u.name_quark) {
-               /*
-                * No results are possible, set the iterator's position at the
-                * end.
-                */
-               iter->index = iter->enumeration_ft->entries->len;
-       }
-
-       return iter;
-
-error:
-       bt_put(iter);
-       return NULL;
-}
-
-int bt_field_type_enumeration_mapping_iterator_next(
-               struct bt_field_type_enumeration_mapping_iterator *iter)
-{
-       struct bt_field_type_enumeration *enum_ft = iter->enumeration_ft;
-       int i, ret = 0, len;
-
-       BT_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
-       len = enum_ft->entries->len;
-       for (i = iter->index + 1; i < len; i++) {
-               struct enumeration_mapping *mapping =
-                       bt_field_type_enumeration_get_mapping_by_index(
-                               (void *) enum_ft, i);
-
-               switch (iter->type) {
-               case ITERATOR_BY_NAME:
-                       if (mapping->string == iter->u.name_quark) {
-                               iter->index = i;
-                               goto end;
-                       }
-                       break;
-               case ITERATOR_BY_SIGNED_VALUE:
-               {
-                       int64_t value = iter->u.signed_value;
-
-                       if (value >= mapping->range_start._signed &&
-                                       value <= mapping->range_end._signed) {
-                               iter->index = i;
-                               goto end;
-                       }
-                       break;
-               }
-               case ITERATOR_BY_UNSIGNED_VALUE:
-               {
-                       uint64_t value = iter->u.unsigned_value;
-
-                       if (value >= mapping->range_start._unsigned &&
-                                       value <= mapping->range_end._unsigned) {
-                               iter->index = i;
-                               goto end;
-                       }
-                       break;
-               }
-               default:
-                       BT_LOGF("Invalid enumeration field type mapping iterator type: "
-                               "type=%d", iter->type);
-                       abort();
-               }
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
-struct bt_field_type_enumeration_mapping_iterator *
-bt_field_type_enumeration_signed_find_mappings_by_value(
-               struct bt_field_type *ft, int64_t value)
-{
-       struct bt_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_field_type_enumeration_find_mappings_type(
-                       ft, ITERATOR_BY_SIGNED_VALUE);
-       if (!iter) {
-               BT_LOGW("Cannot create enumeration field type mapping iterator: "
-                       "ft-addr=%p, value=%" PRId64, ft, value);
-               goto error;
-       }
-
-       if (bt_field_type_integer_is_signed(
-                       (void *) iter->enumeration_ft->container_ft) != 1) {
-               BT_LOGW("Invalid parameter: enumeration field type is unsigned: "
-                       "enum-ft-addr=%p, int-ft-addr=%p",
-                       ft, iter->enumeration_ft->container_ft);
-               goto error;
-       }
-
-       iter->u.signed_value = value;
-       return iter;
-
-error:
-       bt_put(iter);
-       return NULL;
-}
-
-struct bt_field_type_enumeration_mapping_iterator *
-bt_field_type_enumeration_unsigned_find_mappings_by_value(
-               struct bt_field_type *ft, uint64_t value)
-{
-       struct bt_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_field_type_enumeration_find_mappings_type(
-                       ft, ITERATOR_BY_UNSIGNED_VALUE);
-       if (!iter) {
-               BT_LOGW("Cannot create enumeration field type mapping iterator: "
-                       "ft-addr=%p, value=%" PRIu64, ft, value);
-               goto error;
-       }
-
-       if (bt_field_type_integer_is_signed(
-                       (void *) iter->enumeration_ft->container_ft) != 0) {
-               BT_LOGW("Invalid parameter: enumeration field type is signed: "
-                       "enum-ft-addr=%p, int-ft-addr=%p",
-                       ft, iter->enumeration_ft->container_ft);
-               goto error;
-       }
-
-       iter->u.unsigned_value = value;
-       return iter;
-
-error:
-       bt_put(iter);
-       return NULL;
-}
-
-int bt_field_type_enumeration_mapping_iterator_signed_get(
-               struct bt_field_type_enumeration_mapping_iterator *iter,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end)
-{
-       BT_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
-       BT_ASSERT_PRE(iter->index != -1,
-               "Invalid enumeration field type mapping iterator access: "
-               "addr=%p, position=-1", iter);
-       return bt_field_type_enumeration_signed_get_mapping_by_index(
-                       (void *) iter->enumeration_ft, iter->index,
-                       mapping_name, range_begin, range_end);
-}
-
-int bt_field_type_enumeration_mapping_iterator_unsigned_get(
-               struct bt_field_type_enumeration_mapping_iterator *iter,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end)
-{
-       BT_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
-       BT_ASSERT_PRE(iter->index != -1,
-               "Invalid enumeration field type mapping iterator access: "
-               "addr=%p, position=-1", iter);
-       return bt_field_type_enumeration_unsigned_get_mapping_by_index(
-                       (void *) iter->enumeration_ft, iter->index,
-                       mapping_name, range_begin, range_end);
-}
-
-int bt_field_type_enumeration_signed_get_mapping_by_index(
-               struct bt_field_type *ft, uint64_t index,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end)
-{
-       int ret = 0;
-       struct enumeration_mapping *mapping;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft,
-               BT_FIELD_TYPE_ID_ENUM, "Field type");
-       mapping = bt_field_type_enumeration_get_mapping_by_index(ft,
-               index);
-       if (!mapping) {
-               /* bt_field_type_enumeration_get_mapping_by_index() logs errors */
-               ret = -1;
-               goto end;
-       }
-
-       if (mapping_name) {
-               *mapping_name = g_quark_to_string(mapping->string);
-               BT_ASSERT(*mapping_name);
-       }
-
-       if (range_begin) {
-               *range_begin = mapping->range_start._signed;
-       }
-
-       if (range_end) {
-               *range_end = mapping->range_end._signed;
-       }
-
-end:
-       return ret;
-}
-
-int bt_field_type_enumeration_unsigned_get_mapping_by_index(
-               struct bt_field_type *ft, uint64_t index,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end)
-{
-       int ret = 0;
-       struct enumeration_mapping *mapping;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_ENUM, "Field type");
-       mapping = bt_field_type_enumeration_get_mapping_by_index(
-               ft, index);
-       if (!mapping) {
-               /* bt_field_type_enumeration_get_mapping_by_index() reports any error */
-               ret = -1;
-               goto end;
-       }
-
-       if (mapping_name) {
-               *mapping_name = g_quark_to_string(mapping->string);
-               BT_ASSERT(*mapping_name);
-       }
-
-       if (range_begin) {
-               *range_begin = mapping->range_start._unsigned;
-       }
-
-       if (range_end) {
-               *range_end = mapping->range_end._unsigned;
-       }
-
-end:
-       return ret;
-}
-
-struct bt_field_type *bt_field_type_enumeration_create(
-               struct bt_field_type *container_ft)
-{
-       struct bt_field_type_enumeration *enumeration = NULL;
-       struct bt_field_type *int_ft = (void *) container_ft;
-
-       BT_LOGD("Creating enumeration field type object: int-ft-addr=%p",
-               container_ft);
-
-       if (!container_ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               goto error;
-       }
-
-       if (int_ft->id != BT_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: container field type is not an integer field type: "
-                       "container-ft-addr=%p, container-ft-id=%s",
-                       container_ft, bt_common_field_type_id_string(int_ft->id));
-               goto error;
-       }
-
-       enumeration = g_new0(struct bt_field_type_enumeration, 1);
-       if (!enumeration) {
-               BT_LOGE_STR("Failed to allocate one enumeration field type.");
-               goto error;
-       }
-
-       bt_field_type_enumeration_initialize((void *) enumeration,
-               int_ft, bt_field_type_enumeration_destroy_recursive,
-               &bt_field_type_enumeration_methods);
-       BT_LOGD("Created enumeration field type object: addr=%p, "
-               "int-ft-addr=%p, int-ft-size=%u",
-               enumeration, container_ft,
-               bt_field_type_integer_get_size(container_ft));
-       goto end;
-
-error:
-       BT_PUT(enumeration);
-
-end:
-       return (void *) enumeration;
-}
-
-struct bt_field_type *bt_field_type_enumeration_borrow_container_field_type(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_ENUM, "Field type");
-       return (void *) enum_ft->container_ft;
-}
-
-int bt_field_type_enumeration_signed_add_mapping(
-               struct bt_field_type *ft, const char *string,
-               int64_t range_start, int64_t range_end)
-{
-       int ret = 0;
-       GQuark mapping_name;
-       struct enumeration_mapping *mapping;
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-       char *escaped_string;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!string) {
-               BT_LOGW_STR("Invalid parameter: string is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (range_end < range_start) {
-               BT_LOGW("Invalid parameter: range's end is lesser than range's start: "
-                       "addr=%p, range-start=%" PRId64 ", range-end=%" PRId64,
-                       ft, range_start, range_end);
-               ret = -1;
-               goto end;
-       }
-
-       if (strlen(string) == 0) {
-               BT_LOGW("Invalid parameter: mapping name is an empty string: "
-                       "enum-ft-addr=%p, mapping-name-addr=%p", ft,
-                       string);
-               ret = -1;
-               goto end;
-       }
-
-       escaped_string = g_strescape(string, NULL);
-       if (!escaped_string) {
-               BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, "
-                       "mapping-name-addr=%p, mapping-name=\"%s\"",
-                       ft, string, string);
-               ret = -1;
-               goto end;
-       }
-
-       mapping = g_new(struct enumeration_mapping, 1);
-       if (!mapping) {
-               BT_LOGE_STR("Failed to allocate one enumeration mapping.");
-               ret = -1;
-               goto error_free;
-       }
-       mapping_name = g_quark_from_string(escaped_string);
-       *mapping = (struct enumeration_mapping) {
-               .range_start._signed = range_start,
-               .range_end._signed = range_end,
-               .string =  mapping_name,
-       };
-       g_ptr_array_add(enum_ft->entries, mapping);
-       g_ptr_array_sort(enum_ft->entries,
-               (GCompareFunc) compare_enumeration_mappings_signed);
-       BT_LOGV("Added mapping to signed enumeration field type: addr=%p, "
-               "name=\"%s\", range-start=%" PRId64 ", "
-               "range-end=%" PRId64,
-               ft, string, range_start, range_end);
-
-error_free:
-       free(escaped_string);
-
-end:
-       return ret;
-}
-
-int bt_field_type_enumeration_unsigned_add_mapping(
-               struct bt_field_type *ft, const char *string,
-               uint64_t range_start, uint64_t range_end)
-{
-       int ret = 0;
-       GQuark mapping_name;
-       struct enumeration_mapping *mapping;
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-       char *escaped_string;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!string) {
-               BT_LOGW_STR("Invalid parameter: string is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (range_end < range_start) {
-               BT_LOGW("Invalid parameter: range's end is lesser than range's start: "
-                       "addr=%p, range-start=%" PRIu64 ", range-end=%" PRIu64,
-                       ft, range_start, range_end);
-               ret = -1;
-               goto end;
-       }
-
-       if (strlen(string) == 0) {
-               BT_LOGW("Invalid parameter: mapping name is an empty string: "
-                       "enum-ft-addr=%p, mapping-name-addr=%p", ft,
-                       string);
-               ret = -1;
-               goto end;
-       }
-
-       escaped_string = g_strescape(string, NULL);
-       if (!escaped_string) {
-               BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, "
-                       "mapping-name-addr=%p, mapping-name=\"%s\"",
-                       ft, string, string);
-               ret = -1;
-               goto end;
-       }
-
-       mapping = g_new(struct enumeration_mapping, 1);
-       if (!mapping) {
-               BT_LOGE_STR("Failed to allocate one enumeration mapping.");
-               ret = -1;
-               goto error_free;
-       }
-       mapping_name = g_quark_from_string(escaped_string);
-       *mapping = (struct enumeration_mapping) {
-               .range_start._unsigned = range_start,
-               .range_end._unsigned = range_end,
-               .string = mapping_name,
-       };
-       g_ptr_array_add(enum_ft->entries, mapping);
-       g_ptr_array_sort(enum_ft->entries,
-               (GCompareFunc) compare_enumeration_mappings_unsigned);
-       BT_LOGV("Added mapping to unsigned enumeration field type: addr=%p, "
-               "name=\"%s\", range-start=%" PRIu64 ", "
-               "range-end=%" PRIu64,
-               ft, string, range_start, range_end);
-
-error_free:
-       free(escaped_string);
-
-end:
-       return ret;
-}
-
-int64_t bt_field_type_enumeration_get_mapping_count(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_ENUM, "Field type");
-       return (int64_t) enum_ft->entries->len;
-}
-
-struct bt_field_type *bt_field_type_floating_point_create(void)
-{
-       struct bt_field_type_floating_point *floating_point =
-               g_new0(struct bt_field_type_floating_point, 1);
-
-       BT_LOGD_STR("Creating floating point number field type object.");
-
-       if (!floating_point) {
-               BT_LOGE_STR("Failed to allocate one floating point number field type.");
-               goto end;
-       }
-
-       bt_field_type_floating_point_initialize(
-               (void *) floating_point,
-               bt_field_type_floating_point_destroy,
-               &bt_field_type_floating_point_methods);
-       BT_LOGD("Created floating point number field type object: addr=%p, "
-               "exp-size=%u, mant-size=%u", floating_point,
-               floating_point->exp_dig, floating_point->mant_dig);
-
-end:
-       return (void *) floating_point;
-}
-
-int bt_field_type_floating_point_get_exponent_digits(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_floating_point *flt_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_FLOAT,
-               "Field type");
-       return (int) flt_ft->exp_dig;
-}
-
-int bt_field_type_floating_point_set_exponent_digits(
-               struct bt_field_type *ft, unsigned int exponent_digits)
-{
-       int ret = 0;
-       struct bt_field_type_floating_point *flt_ft = (void *) ft;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_FLOAT) {
-               BT_LOGW("Invalid parameter: field type is not a floating point number field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) &&
-               (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) &&
-               (exponent_digits !=
-                       sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) {
-               BT_LOGW("Invalid parameter: invalid exponent size: "
-                       "addr=%p, exp-size=%u", ft, exponent_digits);
-               ret = -1;
-               goto end;
-       }
-
-       flt_ft->exp_dig = exponent_digits;
-       BT_LOGV("Set floating point number field type's exponent size: addr=%p, "
-               "exp-size=%u", ft, exponent_digits);
-
-end:
-       return ret;
-}
-
-int bt_field_type_floating_point_get_mantissa_digits(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_floating_point *flt_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_FLOAT,
-               "Field type");
-       return (int) flt_ft->mant_dig;
-}
-
-int bt_field_type_floating_point_set_mantissa_digits(
-               struct bt_field_type *ft, unsigned int mantissa_digits)
-{
-       int ret = 0;
-       struct bt_field_type_floating_point *flt_ft = (void *) ft;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_FLOAT) {
-               BT_LOGW("Invalid parameter: field type is not a floating point number field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if ((mantissa_digits != FLT_MANT_DIG) &&
-               (mantissa_digits != DBL_MANT_DIG) &&
-               (mantissa_digits != LDBL_MANT_DIG)) {
-               BT_LOGW("Invalid parameter: invalid mantissa size: "
-                       "addr=%p, mant-size=%u", ft, mantissa_digits);
-               ret = -1;
-               goto end;
-       }
-
-       flt_ft->mant_dig = mantissa_digits;
-       BT_LOGV("Set floating point number field type's mantissa size: addr=%p, "
-               "mant-size=%u", ft, mantissa_digits);
-
-end:
-       return ret;
-}
-
-struct bt_field_type *bt_field_type_structure_create(void)
-{
-       struct bt_field_type_structure *structure =
-               g_new0(struct bt_field_type_structure, 1);
-
-       BT_LOGD_STR("Creating structure field type object.");
-
-       if (!structure) {
-               BT_LOGE_STR("Failed to allocate one structure field type.");
-               goto error;
-       }
-
-       bt_field_type_structure_initialize((void *) structure,
-               bt_field_type_structure_destroy_recursive,
-               &bt_field_type_structure_methods);
-       BT_LOGD("Created structure field type object: addr=%p",
-               structure);
-       goto end;
-
-error:
-       BT_PUT(structure);
-
-end:
-       return (void *) structure;
-}
-
-int bt_field_type_structure_add_field(struct bt_field_type *ft,
-               struct bt_field_type *field_type,
-               const char *field_name)
-{
-       int ret = 0;
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-
-       /*
-        * TODO: check that `field_type` does not contain `type`,
-        *       recursively.
-        */
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!field_name) {
-               BT_LOGW_STR("Invalid parameter: field name is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: field type is not a structure field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (ft == field_type) {
-               BT_LOGW("Invalid parameter: structure field type and field type to add are the same: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (add_structure_variant_member(struct_ft->fields,
-                       struct_ft->field_name_to_index, field_type, field_name,
-                       false)) {
-               BT_LOGW("Cannot add field to structure field type: "
-                       "struct-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-                       ft, field_type, field_name);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Added structure field type field: struct-ft-addr=%p, "
-               "field-ft-addr=%p, field-name=\"%s\"", ft,
-               field_type, field_name);
-
-end:
-       return ret;
-}
-
-int64_t bt_field_type_structure_get_field_count(struct bt_field_type *ft)
-{
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       return (int64_t) struct_ft->fields->len;
-}
-
-int bt_field_type_structure_borrow_field_by_index(
-               struct bt_field_type *ft,
-               const char **field_name,
-               struct bt_field_type **field_type, uint64_t index)
-{
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-       struct bt_field_type_structure_field *field;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       BT_ASSERT_PRE(index < struct_ft->fields->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u, %![ft-]+F",
-               index, struct_ft->fields->len, ft);
-       field = BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(struct_ft, index);
-
-       if (field_type) {
-               *field_type = field->type;
-       }
-
-       if (field_name) {
-               *field_name = g_quark_to_string(field->name);
-               BT_ASSERT(*field_name);
-       }
-
-       return 0;
-}
-
-struct bt_field_type *bt_field_type_structure_borrow_field_type_by_name(
-               struct bt_field_type *ft, const char *name)
-{
-       size_t index;
-       GQuark name_quark;
-       struct bt_field_type_structure_field *field;
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-       struct bt_field_type *field_type = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index,
-                       GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               goto end;
-       }
-
-       field = BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(ft, index);
-       field_type = field->type;
-
-end:
-       return field_type;
-}
-
-struct bt_field_type *bt_field_type_variant_create(
-       struct bt_field_type *tag_ft, const char *tag_name)
-{
-       struct bt_field_type_variant *var_ft = NULL;
-
-       BT_LOGD("Creating variant field type object: "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               tag_ft, tag_name);
-
-       if (tag_name && !bt_identifier_is_valid(tag_name)) {
-               BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: "
-                       "tag-ft-addr=%p, tag-field-name=\"%s\"",
-                       tag_ft, tag_name);
-               goto error;
-       }
-
-       var_ft = g_new0(struct bt_field_type_variant, 1);
-       if (!var_ft) {
-               BT_LOGE_STR("Failed to allocate one variant field type.");
-               goto error;
-       }
-
-       bt_field_type_variant_initialize((void *) var_ft,
-               (void *) tag_ft, tag_name,
-               bt_field_type_variant_destroy_recursive,
-               &bt_field_type_variant_methods);
-       BT_LOGD("Created variant field type object: addr=%p, "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               var_ft, tag_ft, tag_name);
-       goto end;
-
-error:
-       BT_PUT(var_ft);
-
-end:
-       return (void *) var_ft;
-}
-
-struct bt_field_type *bt_field_type_variant_borrow_tag_field_type(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       struct bt_field_type *tag_ft = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-
-       if (!var_ft->tag_ft) {
-               BT_LOGV("Variant field type has no tag field type: "
-                       "addr=%p", ft);
-               goto end;
-       }
-
-       tag_ft = (void *) var_ft->tag_ft;
-
-end:
-       return tag_ft;
-}
-
-const char *bt_field_type_variant_get_tag_name(struct bt_field_type *ft)
-{
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       const char *tag_name = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-
-       if (var_ft->tag_name->len == 0) {
-               BT_LOGV("Variant field type has no tag field name: "
-                       "addr=%p", ft);
-               goto end;
-       }
-
-       tag_name = var_ft->tag_name->str;
-
-end:
-       return tag_name;
-}
-
-int bt_field_type_variant_set_tag_name(
-               struct bt_field_type *ft, const char *name)
-{
-       int ret = 0;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft, bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_identifier_is_valid(name)) {
-               BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: "
-                       "variant-ft-addr=%p, tag-field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       g_string_assign(var_ft->tag_name, name);
-       BT_LOGV("Set variant field type's tag field name: addr=%p, "
-               "tag-field-name=\"%s\"", ft, name);
-
-end:
-       return ret;
-}
-
-int bt_field_type_variant_add_field(struct bt_field_type *ft,
-               struct bt_field_type *field_type,
-               const char *field_name)
-{
-       size_t i;
-       int ret = 0;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       GQuark field_name_quark = g_quark_from_string(field_name);
-
-       /*
-        * TODO: check that `field_type` does not contain `type`,
-        *       recursively.
-        */
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (ft == field_type) {
-               BT_LOGW("Invalid parameter: variant field type and field type to add are the same: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       /* The user has explicitly provided a tag; validate against it. */
-       if (var_ft->tag_ft) {
-               int name_found = 0;
-
-               /* Make sure this name is present in the enum tag */
-               for (i = 0; i < var_ft->tag_ft->entries->len; i++) {
-                       struct enumeration_mapping *mapping =
-                               g_ptr_array_index(var_ft->tag_ft->entries, i);
-
-                       if (mapping->string == field_name_quark) {
-                               name_found = 1;
-                               break;
-                       }
-               }
-
-               if (!name_found) {
-                       /* Validation failed */
-                       BT_LOGW("Invalid parameter: field name does not name a tag field type's mapping: "
-                               "variant-ft-addr=%p, tag-ft-addr=%p, "
-                               "tag-field-name=\"%s\""
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               ft, var_ft->tag_ft, var_ft->tag_name->str,
-                               field_type, field_name);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       if (add_structure_variant_member(var_ft->choices,
-                       var_ft->choice_name_to_index, field_type,
-                       field_name, true)) {
-               BT_LOGW("Cannot add field to variant field type: "
-                       "variant-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-                       ft, field_type, field_name);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Added variant field type field: variant-ft-addr=%p, "
-               "field-ft-addr=%p, field-name=\"%s\"", ft,
-               field_type, field_name);
-
-end:
-       return ret;
-}
-
-struct bt_field_type *bt_field_type_variant_borrow_field_type_by_name(
-               struct bt_field_type *ft,
-               const char *field_name)
-{
-       size_t index;
-       GQuark name_quark;
-       struct bt_field_type_variant_choice *choice;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       struct bt_field_type *field_type = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(field_name, "Name");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       name_quark = g_quark_try_string(field_name);
-       if (!name_quark) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, field_name);
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-                       GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, field_name);
-               goto end;
-       }
-
-       choice = BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(ft, index);
-       field_type = choice->type;
-
-end:
-       return field_type;
-}
-
-int64_t bt_field_type_variant_get_field_count(struct bt_field_type *ft)
-{
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Variant field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       return (int64_t) var_ft->choices->len;
-}
-
-int bt_field_type_variant_borrow_field_by_index(struct bt_field_type *ft,
-               const char **field_name, struct bt_field_type **field_type,
-               uint64_t index)
-{
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       struct bt_field_type_variant_choice *choice;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       BT_ASSERT_PRE(index < var_ft->choices->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u, %![ft-]+F",
-               index, var_ft->choices->len, ft);
-       choice = BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(ft, index);
-
-       if (field_type) {
-               *field_type = choice->type;
-       }
-
-       if (field_name) {
-               *field_name = g_quark_to_string(choice->name);
-               BT_ASSERT(*field_name);
-       }
-
-       return 0;
-}
-
-BT_HIDDEN
-int64_t bt_field_type_variant_find_choice_index(
-               struct bt_field_type *ft, uint64_t uval,
-               bool is_signed)
-{
-       int64_t ret;
-       uint64_t i;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       BT_ASSERT(ft);
-       BT_ASSERT(ft->id == BT_FIELD_TYPE_ID_VARIANT);
-
-       if (bt_field_type_variant_update_choices(ft)) {
-               ret = INT64_C(-1);
-               goto end;
-       }
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               uint64_t range_i;
-               struct bt_field_type_variant_choice *choice =
-                       BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(
-                               var_ft, i);
-
-               for (range_i = 0; range_i < choice->ranges->len; range_i++) {
-                       struct bt_field_type_variant_choice_range *range =
-                               &g_array_index(
-                                       choice->ranges,
-                                       struct bt_field_type_variant_choice_range,
-                                       range_i);
-
-                       if (is_signed) {
-                               int64_t tag_ival = (int64_t) uval;
-
-                               if (tag_ival >= range->lower.i &&
-                                               tag_ival <= range->upper.i) {
-                                       goto found;
-                               }
-                       } else {
-                               if (uval >= range->lower.u &&
-                                               uval <= range->upper.u) {
-                                       goto found;
-                               }
-                       }
-               }
-       }
-
-       /* Range not found */
-       ret = INT64_C(-1);
-       goto end;
-
-found:
-       ret = (int64_t) i;
-
-end:
-       return ret;
-}
-
-struct bt_field_type *bt_field_type_array_create(
-               struct bt_field_type *element_ft, unsigned int length)
-{
-       struct bt_field_type_array *array = NULL;
-
-       BT_LOGD("Creating array field type object: element-ft-addr=%p, "
-               "length=%u", element_ft, length);
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               goto error;
-       }
-
-       if (length == 0) {
-               BT_LOGW_STR("Invalid parameter: length is zero.");
-               goto error;
-       }
-
-       array = g_new0(struct bt_field_type_array, 1);
-       if (!array) {
-               BT_LOGE_STR("Failed to allocate one array field type.");
-               goto error;
-       }
-
-       bt_field_type_array_initialize((void *) array,
-               (void *) element_ft, length,
-               bt_field_type_array_destroy_recursive,
-               &bt_field_type_array_methods);
-       BT_LOGD("Created array field type object: addr=%p, "
-               "element-ft-addr=%p, length=%u",
-               array, element_ft, length);
-       goto end;
-
-error:
-       BT_PUT(array);
-
-end:
-       return (void *) array;
-}
-
-struct bt_field_type *bt_field_type_array_borrow_element_field_type(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_array *array_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_ARRAY,
-               "Field type");
-       BT_ASSERT(array_ft && array_ft->element_ft);
-       return array_ft->element_ft;
-}
-
-int64_t bt_field_type_array_get_length(struct bt_field_type *ft)
-{
-       struct bt_field_type_array *array_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_ARRAY,
-               "Field type");
-       return (int64_t) array_ft->length;
-}
-
-struct bt_field_type *bt_field_type_sequence_create(
-               struct bt_field_type *element_ft,
-               const char *length_field_name)
-{
-       struct bt_field_type_sequence *sequence = NULL;
-
-       BT_LOGD("Creating sequence field type object: element-ft-addr=%p, "
-               "length-field-name=\"%s\"", element_ft, length_field_name);
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               goto error;
-       }
-
-       if (!bt_identifier_is_valid(length_field_name)) {
-               BT_LOGW("Invalid parameter: length field name is not a valid CTF identifier: "
-                       "length-field-name=\"%s\"", length_field_name);
-               goto error;
-       }
-
-       sequence = g_new0(struct bt_field_type_sequence, 1);
-       if (!sequence) {
-               BT_LOGE_STR("Failed to allocate one sequence field type.");
-               goto error;
-       }
-
-       bt_field_type_sequence_initialize((void *) sequence,
-               (void *) element_ft, length_field_name,
-               bt_field_type_sequence_destroy_recursive,
-               &bt_field_type_sequence_methods);
-       BT_LOGD("Created sequence field type object: addr=%p, "
-               "element-ft-addr=%p, length-field-name=\"%s\"",
-               sequence, element_ft, length_field_name);
-       goto end;
-
-error:
-       BT_PUT(sequence);
-
-end:
-       return (void *) sequence;
-}
-
-struct bt_field_type *bt_field_type_sequence_borrow_element_field_type(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->element_ft;
-}
-
-const char *bt_field_type_sequence_get_length_field_name(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->length_field_name ?
-               seq_ft->length_field_name->str : NULL;
-}
-
-struct bt_field_type *bt_field_type_string_create(void)
-{
-       struct bt_field_type_string *string =
-               g_new0(struct bt_field_type_string, 1);
-
-       BT_LOGD_STR("Creating string field type object.");
-
-       if (!string) {
-               BT_LOGE_STR("Failed to allocate one string field type.");
-               return NULL;
-       }
-
-       bt_field_type_string_initialize((void *) string,
-               bt_field_type_string_destroy,
-               &bt_field_type_string_methods);
-       BT_LOGD("Created string field type object: addr=%p", string);
-       return (void *) string;
-}
-
-enum bt_string_encoding bt_field_type_string_get_encoding(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_string *string_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRING,
-               "Field type");
-       return string_ft->encoding;
-}
-
-int bt_field_type_string_set_encoding(struct bt_field_type *ft,
-               enum bt_string_encoding encoding)
-{
-       int ret = 0;
-       struct bt_field_type_string *string_ft = (void *) ft;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_STRING) {
-               BT_LOGW("Invalid parameter: field type is not a string field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (encoding != BT_STRING_ENCODING_UTF8 &&
-                       encoding != BT_STRING_ENCODING_ASCII) {
-               BT_LOGW("Invalid parameter: unknown string encoding: "
-                       "addr=%p, encoding=%d", ft, encoding);
-               ret = -1;
-               goto end;
-       }
-
-       string_ft->encoding = encoding;
-       BT_LOGV("Set string field type's encoding: addr=%p, encoding=%s",
-               ft, bt_common_string_encoding_string(encoding));
-
-end:
-       return ret;
-}
-
-int bt_field_type_get_alignment(struct bt_field_type *ft)
-{
-       int ret;
-       enum bt_field_type_id type_id;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-
-       if (ft->frozen) {
-               ret = (int) ft->alignment;
-               goto end;
-       }
-
-       type_id = bt_field_type_get_type_id(ft);
-       switch (type_id) {
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-       {
-               struct bt_field_type *element_ft =
-                       bt_field_type_sequence_borrow_element_field_type(ft);
-
-               BT_ASSERT(element_ft);
-               ret = bt_field_type_get_alignment(element_ft);
-               break;
-       }
-       case BT_FIELD_TYPE_ID_ARRAY:
-       {
-               struct bt_field_type *element_ft =
-                       bt_field_type_array_borrow_element_field_type(ft);
-
-               BT_ASSERT(element_ft);
-               ret = bt_field_type_get_alignment(element_ft);
-               break;
-       }
-       case BT_FIELD_TYPE_ID_STRUCT:
-       {
-               int64_t i, element_count;
-
-               element_count = bt_field_type_structure_get_field_count(
-                       ft);
-               BT_ASSERT(element_count >= 0);
-
-               for (i = 0; i < element_count; i++) {
-                       struct bt_field_type *field = NULL;
-                       int field_alignment;
-
-                       ret = bt_field_type_structure_borrow_field_by_index(
-                               ft, NULL, &field, i);
-                       BT_ASSERT(ret == 0);
-                       BT_ASSERT(field);
-                       field_alignment = bt_field_type_get_alignment(
-                               field);
-                       if (field_alignment < 0) {
-                               ret = field_alignment;
-                               goto end;
-                       }
-
-                       ft->alignment = MAX(field_alignment, ft->alignment);
-               }
-               ret = (int) ft->alignment;
-               break;
-       }
-       case BT_FIELD_TYPE_ID_UNKNOWN:
-               BT_LOGW("Invalid parameter: unknown field type ID: "
-                       "addr=%p, ft-id=%d", ft, type_id);
-               ret = -1;
-               break;
-       default:
-               ret = (int) ft->alignment;
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int is_power_of_two(unsigned int value)
-{
-       return ((value & (value - 1)) == 0) && value > 0;
-}
-
-int bt_field_type_set_alignment(struct bt_field_type *ft,
-               unsigned int alignment)
-{
-       int ret = 0;
-       enum bt_field_type_id type_id;
-
-       /* Alignment must be a power of two */
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (!is_power_of_two(alignment)) {
-               BT_LOGW("Invalid parameter: alignment is not a power of two: "
-                       "addr=%p, align=%u", ft, alignment);
-               ret = -1;
-               goto end;
-       }
-
-       type_id = bt_field_type_get_type_id(ft);
-       if (type_id == BT_FIELD_TYPE_ID_UNKNOWN) {
-               BT_LOGW("Invalid parameter: unknown field type ID: "
-                       "addr=%p, ft-id=%d", ft, type_id);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id == BT_FIELD_TYPE_ID_STRING && alignment != CHAR_BIT) {
-               BT_LOGW("Invalid parameter: alignment must be %u for a string field type: "
-                       "addr=%p, align=%u", CHAR_BIT, ft, alignment);
-               ret = -1;
-               goto end;
-       }
-
-       if (type_id == BT_FIELD_TYPE_ID_VARIANT ||
-                       type_id == BT_FIELD_TYPE_ID_SEQUENCE ||
-                       type_id == BT_FIELD_TYPE_ID_ARRAY) {
-               /* Setting an alignment on these types makes no sense */
-               BT_LOGW("Invalid parameter: cannot set the alignment of this field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       ft->alignment = alignment;
-       ret = 0;
-       BT_LOGV("Set field type's alignment: addr=%p, align=%u",
-               ft, alignment);
-
-end:
-       return ret;
-}
-
-enum bt_byte_order bt_field_type_get_byte_order(struct bt_field_type *ft)
-{
-       enum bt_byte_order ret = BT_BYTE_ORDER_UNKNOWN;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-
-       switch (ft->id) {
-       case BT_FIELD_TYPE_ID_INTEGER:
-       {
-               struct bt_field_type_integer *integer = (void *) ft;
-
-               ret = integer->user_byte_order;
-               break;
-       }
-       case BT_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_field_type_enumeration *enum_ft = (void *) ft;
-
-               ret = bt_field_type_get_byte_order(
-                       (void *) enum_ft->container_ft);
-               break;
-       }
-       case BT_FIELD_TYPE_ID_FLOAT:
-       {
-               struct bt_field_type_floating_point *floating_point = (void *) ft;
-               ret = floating_point->user_byte_order;
-               break;
-       }
-       default:
-               BT_LOGW("Invalid parameter: cannot get the byte order of this field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               goto end;
-       }
-
-       BT_ASSERT(ret == BT_BYTE_ORDER_NATIVE ||
-               ret == BT_BYTE_ORDER_LITTLE_ENDIAN ||
-               ret == BT_BYTE_ORDER_BIG_ENDIAN ||
-               ret == BT_BYTE_ORDER_NETWORK);
-
-end:
-       return ret;
-}
-
-int bt_field_type_set_byte_order(struct bt_field_type *ft,
-               enum bt_byte_order byte_order)
-{
-       int ret = 0;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order != BT_BYTE_ORDER_NATIVE &&
-                       byte_order != BT_BYTE_ORDER_LITTLE_ENDIAN &&
-                       byte_order != BT_BYTE_ORDER_BIG_ENDIAN &&
-                       byte_order != BT_BYTE_ORDER_NETWORK) {
-               BT_LOGW("Invalid parameter: invalid byte order: "
-                       "addr=%p, bo=%s", ft,
-                       bt_common_byte_order_string(byte_order));
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->methods->set_byte_order) {
-               ft->methods->set_byte_order(ft, byte_order);
-       }
-
-       BT_LOGV("Set field type's byte order: addr=%p, bo=%s",
-               ft, bt_common_byte_order_string(byte_order));
-
-end:
-       return ret;
-}
-
-enum bt_field_type_id bt_field_type_get_type_id(struct bt_field_type *ft)
-{
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       return ft->id;
-}
-
-BT_HIDDEN
-void bt_field_type_freeze(struct bt_field_type *ft)
-{
-       if (!ft || ft->frozen) {
-               return;
-       }
-
-       BT_ASSERT(ft->methods->freeze);
-       ft->methods->freeze(ft);
-}
-
-struct bt_field_type *bt_field_type_copy(struct bt_field_type *ft)
-{
-       struct bt_field_type *ft_copy = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT(ft->methods->copy);
-       ft_copy = ft->methods->copy(ft);
-       if (!ft_copy) {
-               BT_LOGE_STR("Cannot copy field type.");
-               goto end;
-       }
-
-       ft_copy->alignment = ft->alignment;
-
-end:
-       return ft_copy;
-}
-
-static inline
-int bt_field_type_structure_get_field_name_index(
-               struct bt_field_type *ft, const char *name)
-{
-       int ret;
-       size_t index;
-       GQuark name_quark;
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index,
-                       GUINT_TO_POINTER(name_quark),
-                       NULL, (gpointer *) &index)) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       ret = (int) index;
-
-end:
-       return ret;
-}
-
-static inline
-int bt_field_type_variant_get_field_name_index(
-               struct bt_field_type *ft, const char *name)
-{
-       int ret;
-       size_t index;
-       GQuark name_quark;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-                       GUINT_TO_POINTER(name_quark),
-                       NULL, (gpointer *) &index)) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       ret = (int) index;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_field_type_sequence_set_length_field_path(
-               struct bt_field_type *ft, struct bt_field_path *path)
-{
-       int ret = 0;
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_SEQUENCE) {
-               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_get(path);
-       BT_MOVE(seq_ft->length_field_path, path);
-       BT_LOGV("Set sequence field type's length field path: ft-addr=%p, "
-               "field-path-addr=%p", ft, path);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_field_type_variant_set_tag_field_path(
-               struct bt_field_type *ft,
-               struct bt_field_path *path)
-{
-       int ret = 0;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_common_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_get(path);
-       BT_MOVE(var_ft->tag_field_path, path);
-       BT_LOGV("Set variant field type's tag field path: ft-addr=%p, "
-               "field-path-addr=%p", ft, path);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_field_type_variant_set_tag_field_type(
-               struct bt_field_type *ft,
-               struct bt_field_type *tag_ft)
-{
-       int ret = 0;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: variant field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!tag_ft) {
-               BT_LOGW_STR("Invalid parameter: tag field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (tag_ft->id != BT_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: tag field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", tag_ft,
-                       bt_common_field_type_id_string(tag_ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_put(var_ft->tag_ft);
-       var_ft->tag_ft = bt_get(tag_ft);
-       BT_LOGV("Set variant field type's tag field type: variant-ft-addr=%p, "
-               "tag-ft-addr=%p", ft, tag_ft);
-
-end:
-       return ret;
-}
-
-static
-void bt_field_type_generic_freeze(struct bt_field_type *ft)
-{
-       ft->frozen = 1;
-}
-
-static
-void bt_field_type_enumeration_freeze_recursive(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-
-       BT_LOGD("Freezing enumeration field type object: addr=%p", ft);
-       bt_field_type_enumeration_set_range_overlap(enum_ft);
-       bt_field_type_generic_freeze(ft);
-       BT_LOGD("Freezing enumeration field type object's container field type: int-ft-addr=%p",
-               enum_ft->container_ft);
-       bt_field_type_freeze((void *) enum_ft->container_ft);
-}
-
-static
-void bt_field_type_structure_freeze_recursive(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-       uint64_t i;
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing structure field type object: addr=%p", ft);
-       ft->alignment = bt_field_type_get_alignment(ft);
-       bt_field_type_generic_freeze(ft);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_field_type_structure_field *field =
-                       BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(ft, i);
-
-               BT_LOGD("Freezing structure field type field: "
-                       "ft-addr=%p, name=\"%s\"",
-                       field->type, g_quark_to_string(field->name));
-               bt_field_type_freeze(field->type);
-       }
-}
-
-BT_HIDDEN
-int bt_field_type_variant_update_choices(struct bt_field_type *ft)
-{
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       uint64_t i;
-       int ret = 0;
-       bool is_signed;
-
-       if (ft->frozen && var_ft->choices_up_to_date) {
-               goto end;
-       }
-
-       BT_ASSERT(var_ft->tag_ft);
-       is_signed = !!var_ft->tag_ft->container_ft->is_signed;
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_field_type_variant_choice *choice =
-                       BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(ft, i);
-               const char *choice_name = g_quark_to_string(choice->name);
-               struct bt_field_type_enumeration_mapping_iterator *iter =
-                       bt_field_type_enumeration_find_mappings_by_name(
-                               (void *) var_ft->tag_ft, choice_name);
-
-               if (!iter) {
-                       ret = -1;
-                       goto end;
-               }
-
-               BT_ASSERT(choice->ranges);
-               g_array_set_size(choice->ranges, 0);
-
-               while (bt_field_type_enumeration_mapping_iterator_next(iter) == 0) {
-                       struct bt_field_type_variant_choice_range range;
-
-                       if (is_signed) {
-                               ret = bt_field_type_enumeration_mapping_iterator_signed_get(
-                                       iter, NULL,
-                                       &range.lower.i, &range.upper.i);
-                       } else {
-                               ret = bt_field_type_enumeration_mapping_iterator_unsigned_get(
-                                       iter, NULL,
-                                       &range.lower.u, &range.upper.u);
-                       }
-
-                       BT_ASSERT(ret == 0);
-                       g_array_append_val(choice->ranges, range);
-               }
-
-               bt_put(iter);
-       }
-
-       var_ft->choices_up_to_date = true;
-
-end:
-       return ret;
-}
-
-static
-void bt_field_type_variant_freeze_recursive(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       uint64_t i;
-
-       BT_LOGD("Freezing variant field type object: addr=%p", ft);
-       bt_field_type_generic_freeze(ft);
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_field_type_variant_choice *choice =
-                       BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(ft, i);
-
-               BT_LOGD("Freezing variant field type member: "
-                       "ft-addr=%p, name=\"%s\"",
-                       choice->type, g_quark_to_string(choice->name));
-               bt_field_type_freeze(choice->type);
-       }
-}
-
-static
-void bt_field_type_array_freeze_recursive(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_array *array_ft = (void *) ft;
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing array field type object: addr=%p", ft);
-       ft->alignment = bt_field_type_get_alignment(ft);
-       bt_field_type_generic_freeze(ft);
-       BT_LOGD("Freezing array field type object's element field type: element-ft-addr=%p",
-               array_ft->element_ft);
-       bt_field_type_freeze(array_ft->element_ft);
-}
-
-static
-void bt_field_type_sequence_freeze_recursive(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing sequence field type object: addr=%p", ft);
-       ft->alignment = bt_field_type_get_alignment(ft);
-       bt_field_type_generic_freeze(ft);
-       BT_LOGD("Freezing sequence field type object's element field type: element-ft-addr=%p",
-               seq_ft->element_ft);
-       bt_field_type_freeze(seq_ft->element_ft);
-}
-
-static
-void bt_field_type_integer_set_byte_order(
-               struct bt_field_type *ft, enum bt_byte_order byte_order)
-{
-       struct bt_field_type_integer *int_ft = (void *) ft;
-
-       int_ft->user_byte_order = byte_order;
-}
-
-static
-void bt_field_type_enumeration_set_byte_order_recursive(
-               struct bt_field_type *ft, enum bt_byte_order byte_order)
-{
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-
-       bt_field_type_set_byte_order((void *) enum_ft->container_ft,
-               byte_order);
-}
-
-static
-void bt_field_type_floating_point_set_byte_order(
-               struct bt_field_type *ft, enum bt_byte_order byte_order)
-{
-       struct bt_field_type_floating_point *flt_ft = (void *) ft;
-
-       flt_ft->user_byte_order = byte_order;
-}
-
-static
-void bt_field_type_structure_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order)
-{
-       int i;
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_field_type_structure_field *field =
-                       BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft, i);
-               struct bt_field_type *field_type = field->type;
-
-               bt_field_type_set_byte_order(field_type, byte_order);
-       }
-}
-
-static
-void bt_field_type_variant_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order)
-{
-       int i;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_field_type_variant_choice *choice =
-                       BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(
-                               var_ft, i);
-               struct bt_field_type *field_type = choice->type;
-
-               bt_field_type_set_byte_order(field_type, byte_order);
-       }
-}
-
-static
-void bt_field_type_array_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order)
-{
-       struct bt_field_type_array *array_ft = (void *) ft;
-
-       bt_field_type_set_byte_order(array_ft->element_ft, byte_order);
-}
-
-static
-void bt_field_type_sequence_set_byte_order_recursive(
-               struct bt_field_type *ft,
-               enum bt_byte_order byte_order)
-{
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-
-       bt_field_type_set_byte_order(seq_ft->element_ft, byte_order);
-}
-
-
-static
-int bt_field_type_integer_compare(struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-       struct bt_field_type_integer *int_ft_a = (void *) ft_a;
-       struct bt_field_type_integer *int_ft_b = (void *) ft_b;
-
-       /* Length */
-       if (int_ft_a->size != int_ft_b->size) {
-               BT_LOGV("Integer field types differ: different sizes: "
-                       "ft-a-size=%u, ft-b-size=%u",
-                       int_ft_a->size, int_ft_b->size);
-               goto end;
-       }
-
-       /* Byte order */
-       if (int_ft_a->user_byte_order != int_ft_b->user_byte_order) {
-               BT_LOGV("Integer field types differ: different byte orders: "
-                       "ft-a-bo=%s, ft-b-bo=%s",
-                       bt_common_byte_order_string(int_ft_a->user_byte_order),
-                       bt_common_byte_order_string(int_ft_b->user_byte_order));
-               goto end;
-       }
-
-       /* Signedness */
-       if (int_ft_a->is_signed != int_ft_b->is_signed) {
-               BT_LOGV("Integer field types differ: different signedness: "
-                       "ft-a-is-signed=%d, ft-b-is-signed=%d",
-                       int_ft_a->is_signed,
-                       int_ft_b->is_signed);
-               goto end;
-       }
-
-       /* Base */
-       if (int_ft_a->base != int_ft_b->base) {
-               BT_LOGV("Integer field types differ: different bases: "
-                       "ft-a-base=%s, ft-b-base=%s",
-                       bt_common_integer_base_string(int_ft_a->base),
-                       bt_common_integer_base_string(int_ft_b->base));
-               goto end;
-       }
-
-       /* Encoding */
-       if (int_ft_a->encoding != int_ft_b->encoding) {
-               BT_LOGV("Integer field types differ: different encodings: "
-                       "ft-a-encoding=%s, ft-b-encoding=%s",
-                       bt_common_string_encoding_string(int_ft_a->encoding),
-                       bt_common_string_encoding_string(int_ft_b->encoding));
-               goto end;
-       }
-
-       /* Mapped clock class */
-       if (int_ft_a->mapped_clock_class) {
-               if (!int_ft_b->mapped_clock_class) {
-                       BT_LOGV_STR("Integer field types differ: field type A "
-                               "has a mapped clock class, but field type B "
-                               "does not.");
-                       goto end;
-               }
-
-               if (bt_clock_class_compare(int_ft_a->mapped_clock_class,
-                               int_ft_b->mapped_clock_class) != 0) {
-                       BT_LOGV_STR("Integer field types differ: different "
-                               "mapped clock classes.");
-               }
-       } else {
-               if (int_ft_b->mapped_clock_class) {
-                       BT_LOGV_STR("Integer field types differ: field type A "
-                               "has no description, but field type B has one.");
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int bt_field_type_floating_point_compare(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-       struct bt_field_type_floating_point *flt_ft_a = (void *) ft_a;
-       struct bt_field_type_floating_point *flt_ft_b = (void *) ft_b;
-
-       /* Byte order */
-       if (flt_ft_a->user_byte_order != flt_ft_b->user_byte_order) {
-               BT_LOGV("Floating point number field types differ: different byte orders: "
-                       "ft-a-bo=%s, ft-b-bo=%s",
-                       bt_common_byte_order_string(flt_ft_a->user_byte_order),
-                       bt_common_byte_order_string(flt_ft_b->user_byte_order));
-               goto end;
-       }
-
-       /* Exponent length */
-       if (flt_ft_a->exp_dig != flt_ft_b->exp_dig) {
-               BT_LOGV("Floating point number field types differ: different exponent sizes: "
-                       "ft-a-exp-size=%u, ft-b-exp-size=%u",
-                       flt_ft_a->exp_dig, flt_ft_b->exp_dig);
-               goto end;
-       }
-
-       /* Mantissa length */
-       if (flt_ft_a->mant_dig != flt_ft_b->mant_dig) {
-               BT_LOGV("Floating point number field types differ: different mantissa sizes: "
-                       "ft-a-mant-size=%u, ft-b-mant-size=%u",
-                       flt_ft_a->mant_dig, flt_ft_b->mant_dig);
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int compare_enumeration_mappings(struct enumeration_mapping *mapping_a,
-               struct enumeration_mapping *mapping_b)
-{
-       int ret = 1;
-
-       /* Label */
-       if (mapping_a->string != mapping_b->string) {
-               BT_LOGV("Enumeration field type mappings differ: different names: "
-                       "mapping-a-name=\"%s\", mapping-b-name=\"%s\"",
-                       g_quark_to_string(mapping_a->string),
-                       g_quark_to_string(mapping_b->string));
-               goto end;
-       }
-
-       /* Range start */
-       if (mapping_a->range_start._unsigned !=
-                       mapping_b->range_start._unsigned) {
-               BT_LOGV("Enumeration field type mappings differ: different starts of range: "
-                       "mapping-a-range-start-unsigned=%" PRIu64 ", "
-                       "mapping-b-range-start-unsigned=%" PRIu64,
-                       mapping_a->range_start._unsigned,
-                       mapping_b->range_start._unsigned);
-               goto end;
-       }
-
-       /* Range end */
-       if (mapping_a->range_end._unsigned !=
-                       mapping_b->range_end._unsigned) {
-               BT_LOGV("Enumeration field type mappings differ: different ends of range: "
-                       "mapping-a-range-end-unsigned=%" PRIu64 ", "
-                       "mapping-b-range-end-unsigned=%" PRIu64,
-                       mapping_a->range_end._unsigned,
-                       mapping_b->range_end._unsigned);
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int bt_field_type_enumeration_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_field_type_enumeration *enum_ft_a = (void *) ft_a;
-       struct bt_field_type_enumeration *enum_ft_b = (void *) ft_b;
-
-       /* Container field type */
-       ret = bt_field_type_compare((void *) enum_ft_a->container_ft,
-               (void *) enum_ft_b->container_ft);
-       if (ret) {
-               BT_LOGV("Enumeration field types differ: different container field types: "
-                       "ft-a-container-ft-addr=%p, ft-b-container-ft-addr=%p",
-                       enum_ft_a->container_ft, enum_ft_b->container_ft);
-               goto end;
-       }
-
-       ret = 1;
-
-       /* Entries */
-       if (enum_ft_a->entries->len != enum_ft_b->entries->len) {
-               goto end;
-       }
-
-       for (i = 0; i < enum_ft_a->entries->len; ++i) {
-               struct enumeration_mapping *mapping_a =
-                       g_ptr_array_index(enum_ft_a->entries, i);
-               struct enumeration_mapping *mapping_b =
-                       g_ptr_array_index(enum_ft_b->entries, i);
-
-               if (compare_enumeration_mappings(mapping_a, mapping_b)) {
-                       BT_LOGV("Enumeration field types differ: different mappings: "
-                               "ft-a-mapping-addr=%p, ft-b-mapping-addr=%p, "
-                               "ft-a-mapping-name=\"%s\", ft-b-mapping-name=\"%s\"",
-                               mapping_a, mapping_b,
-                               g_quark_to_string(mapping_a->string),
-                               g_quark_to_string(mapping_b->string));
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int bt_field_type_string_compare(struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-       struct bt_field_type_string *string_ft_a = (void *) ft_a;
-       struct bt_field_type_string *string_ft_b = (void *) ft_b;
-
-       /* Encoding */
-       if (string_ft_a->encoding != string_ft_b->encoding) {
-               BT_LOGV("String field types differ: different encodings: "
-                       "ft-a-encoding=%s, ft-b-encoding=%s",
-                       bt_common_string_encoding_string(string_ft_a->encoding),
-                       bt_common_string_encoding_string(string_ft_b->encoding));
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int compare_structure_variant_members(
-               struct bt_field_type *member_a_ft,
-               struct bt_field_type *member_b_ft,
-               GQuark member_a_name, GQuark member_b_name)
-{
-       int ret = 1;
-
-       /* Label */
-       if (member_a_name != member_b_name) {
-               BT_LOGV("Structure/variant field type fields differ: different names: "
-                       "field-a-name=%s, field-b-name=%s",
-                       g_quark_to_string(member_a_name),
-                       g_quark_to_string(member_b_name));
-               goto end;
-       }
-
-       /* Type */
-       ret = bt_field_type_compare(member_a_ft, member_b_ft);
-       if (ret == 1) {
-               BT_LOGV("Structure/variant field type fields differ: different field types: "
-                       "field-name=\"%s\", field-a-ft-addr=%p, field-b-ft-addr=%p",
-                       g_quark_to_string(member_a_name),
-                       member_a_ft, member_b_ft);
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_field_type_structure_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_field_type_structure *struct_ft_a = (void *) ft_a;
-       struct bt_field_type_structure *struct_ft_b = (void *) ft_b;
-
-       /* Alignment */
-       if (bt_field_type_get_alignment(ft_a) !=
-                       bt_field_type_get_alignment(ft_b)) {
-               BT_LOGV("Structure field types differ: different alignments: "
-                       "ft-a-align=%u, ft-b-align=%u",
-                       bt_field_type_get_alignment(ft_a),
-                       bt_field_type_get_alignment(ft_b));
-               goto end;
-       }
-
-       /* Fields */
-       if (struct_ft_a->fields->len != struct_ft_b->fields->len) {
-               BT_LOGV("Structure field types differ: different field counts: "
-                       "ft-a-field-count=%u, ft-b-field-count=%u",
-                       struct_ft_a->fields->len, struct_ft_b->fields->len);
-               goto end;
-       }
-
-       for (i = 0; i < struct_ft_a->fields->len; ++i) {
-               struct bt_field_type_structure_field *field_a =
-                       BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft_a, i);
-               struct bt_field_type_structure_field *field_b =
-                       BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft_b, i);
-
-               ret = compare_structure_variant_members(field_a->type,
-                       field_b->type, field_a->name, field_b->name);
-               if (ret) {
-                       /* compare_structure_variant_members() logs what differs */
-                       BT_LOGV_STR("Structure field types differ: different fields.");
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int bt_field_type_variant_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_field_type_variant *var_ft_a = (void *) ft_a;
-       struct bt_field_type_variant *var_ft_b = (void *) ft_b;
-
-       /* Tag name */
-       if (strcmp(var_ft_a->tag_name->str, var_ft_b->tag_name->str)) {
-               BT_LOGV("Variant field types differ: different tag field names: "
-                       "ft-a-tag-field-name=\"%s\", ft-b-tag-field-name=\"%s\"",
-                       var_ft_a->tag_name->str, var_ft_b->tag_name->str);
-               goto end;
-       }
-
-       /* Tag type */
-       ret = bt_field_type_compare((void *) var_ft_a->tag_ft,
-               (void *) var_ft_b->tag_ft);
-       if (ret) {
-               BT_LOGV("Variant field types differ: different tag field types: "
-                       "ft-a-tag-ft-addr=%p, ft-b-tag-ft-addr=%p",
-                       var_ft_a->tag_ft, var_ft_b->tag_ft);
-               goto end;
-       }
-
-       ret = 1;
-
-       /* Fields */
-       if (var_ft_a->choices->len != var_ft_b->choices->len) {
-               BT_LOGV("Variant field types differ: different field counts: "
-                       "ft-a-field-count=%u, ft-b-field-count=%u",
-                       var_ft_a->choices->len, var_ft_b->choices->len);
-               goto end;
-       }
-
-       for (i = 0; i < var_ft_a->choices->len; ++i) {
-               struct bt_field_type_variant_choice *choice_a =
-                       BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(
-                               var_ft_a, i);
-               struct bt_field_type_variant_choice *choice_b =
-                       BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(
-                               var_ft_b, i);
-
-               ret = compare_structure_variant_members(choice_a->type,
-                       choice_b->type, choice_a->name, choice_b->name);
-               if (ret) {
-                       /* compare_structure_variant_members() logs what differs */
-                       BT_LOGV_STR("Variant field types differ: different fields.");
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int bt_field_type_array_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-       struct bt_field_type_array *array_ft_a = (void *) ft_a;
-       struct bt_field_type_array *array_ft_b = (void *) ft_b;
-
-       /* Length */
-       if (array_ft_a->length != array_ft_b->length) {
-               BT_LOGV("Structure field types differ: different lengths: "
-                       "ft-a-length=%u, ft-b-length=%u",
-                       array_ft_a->length, array_ft_b->length);
-               goto end;
-       }
-
-       /* Element type */
-       ret = bt_field_type_compare(array_ft_a->element_ft,
-               array_ft_b->element_ft);
-       if (ret == 1) {
-               BT_LOGV("Array field types differ: different element field types: "
-                       "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p",
-                       array_ft_a->element_ft, array_ft_b->element_ft);
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_field_type_sequence_compare_recursive(
-               struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = -1;
-       struct bt_field_type_sequence *seq_ft_a = (void *) ft_a;
-       struct bt_field_type_sequence *seq_ft_b = (void *) ft_b;
-
-       /* Length name */
-       if (strcmp(seq_ft_a->length_field_name->str,
-                       seq_ft_b->length_field_name->str)) {
-               BT_LOGV("Sequence field types differ: different length field names: "
-                       "ft-a-length-field-name=\"%s\", "
-                       "ft-b-length-field-name=\"%s\"",
-                       seq_ft_a->length_field_name->str,
-                       seq_ft_b->length_field_name->str);
-               goto end;
-       }
-
-       /* Element type */
-       ret = bt_field_type_compare(seq_ft_a->element_ft,
-                       seq_ft_b->element_ft);
-       if (ret == 1) {
-               BT_LOGV("Sequence field types differ: different element field types: "
-                       "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p",
-                       seq_ft_a->element_ft, seq_ft_b->element_ft);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_field_type_compare(struct bt_field_type *ft_a,
-               struct bt_field_type *ft_b)
-{
-       int ret = 1;
-
-       BT_ASSERT_PRE_NON_NULL(ft_a, "Field type A");
-       BT_ASSERT_PRE_NON_NULL(ft_b, "Field type B");
-
-       if (ft_a == ft_b) {
-               /* Same reference: equal (even if both are NULL) */
-               ret = 0;
-               goto end;
-       }
-
-       if (!ft_a) {
-               BT_LOGW_STR("Invalid parameter: field type A is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!ft_b) {
-               BT_LOGW_STR("Invalid parameter: field type B is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft_a->id != ft_b->id) {
-               /* Different type IDs */
-               BT_LOGV("Field types differ: different IDs: "
-                       "ft-a-addr=%p, ft-b-addr=%p, "
-                       "ft-a-id=%s, ft-b-id=%s",
-                       ft_a, ft_b,
-                       bt_common_field_type_id_string(ft_a->id),
-                       bt_common_field_type_id_string(ft_b->id));
-               goto end;
-       }
-
-       if (ft_a->id == BT_FIELD_TYPE_ID_UNKNOWN) {
-               /* Both have unknown type IDs */
-               BT_LOGW_STR("Invalid parameter: field type IDs are unknown.");
-               goto end;
-       }
-
-       BT_ASSERT(ft_a->methods->compare);
-       ret = ft_a->methods->compare(ft_a, ft_b);
-       if (ret == 1) {
-               BT_LOGV("Field types differ: ft-a-addr=%p, ft-b-addr=%p",
-                       ft_a, ft_b);
-       }
+error:
+       BT_PUT(string_ft);
 
 end:
-       return ret;
-}
-
-BT_HIDDEN
-int64_t bt_field_type_get_field_count(struct bt_field_type *ft)
-{
-       int64_t field_count = -1;
-
-       switch (ft->id) {
-       case BT_FIELD_TYPE_ID_STRUCT:
-               field_count =
-                       bt_field_type_structure_get_field_count(ft);
-               break;
-       case BT_FIELD_TYPE_ID_VARIANT:
-               field_count =
-                       bt_field_type_variant_get_field_count(ft);
-               break;
-       case BT_FIELD_TYPE_ID_ARRAY:
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               /*
-                * Array and sequence types always contain a single member
-                * (the element type).
-                */
-               field_count = 1;
-               break;
-       default:
-               break;
-       }
-
-       return field_count;
+       return (void *) string_ft;
 }
 
 BT_HIDDEN
-struct bt_field_type *bt_field_type_borrow_field_at_index(
-               struct bt_field_type *ft, int index)
+void _bt_field_type_freeze(struct bt_field_type *ft)
 {
-       struct bt_field_type *field_type = NULL;
-
-       switch (ft->id) {
-       case BT_FIELD_TYPE_ID_STRUCT:
-       {
-               int ret = bt_field_type_structure_borrow_field_by_index(
-                       ft, NULL, &field_type, index);
-               if (ret) {
-                       field_type = NULL;
-                       goto end;
-               }
-               break;
-       }
-       case BT_FIELD_TYPE_ID_VARIANT:
-       {
-               int ret = bt_field_type_variant_borrow_field_by_index(
-                       ft, NULL, &field_type, index);
-               if (ret) {
-                       field_type = NULL;
-                       goto end;
-               }
-               break;
-       }
-       case BT_FIELD_TYPE_ID_ARRAY:
-               field_type =
-                       bt_field_type_array_borrow_element_field_type(ft);
-               break;
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               field_type =
-                       bt_field_type_sequence_borrow_element_field_type(ft);
-               break;
-       default:
-               break;
-       }
-
-end:
-       return field_type;
+       /*
+        * Element/member/option field types are frozen when added to
+        * their owner.
+        */
+       BT_ASSERT(ft);
+       ft->frozen = true;
 }
 
 BT_HIDDEN
-int bt_field_type_get_field_index(struct bt_field_type *ft,
-               const char *name)
+void _bt_field_type_make_part_of_trace(struct bt_field_type *ft)
 {
-       int field_index = -1;
+       BT_ASSERT(ft);
+       BT_ASSERT_PRE(!ft->part_of_trace,
+               "Field type is already part of a trace: %!+F", ft);
+       ft->part_of_trace = true;
 
        switch (ft->id) {
-       case BT_FIELD_TYPE_ID_STRUCT:
-               field_index = bt_field_type_structure_get_field_name_index(
-                       ft, name);
-               break;
+       case BT_FIELD_TYPE_ID_STRUCTURE:
        case BT_FIELD_TYPE_ID_VARIANT:
-               field_index = bt_field_type_variant_get_field_name_index(
-                       ft, name);
-               break;
-       default:
-               break;
-       }
-
-       return field_index;
-}
-
-struct bt_field_path *bt_field_type_variant_borrow_tag_field_path(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_variant *var_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       return var_ft->tag_field_path;
-}
-
-struct bt_field_path *bt_field_type_sequence_borrow_length_field_path(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_FT_HAS_ID(ft, BT_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->length_field_path;
-}
-
-BT_HIDDEN
-int bt_field_type_validate_single_clock_class(
-               struct bt_field_type *ft,
-               struct bt_clock_class **expected_clock_class)
-{
-       int ret = 0;
-
-       if (!ft) {
-               goto end;
-       }
-
-       BT_ASSERT(expected_clock_class);
-
-       switch (ft->id) {
-       case BT_FIELD_TYPE_ID_INTEGER:
        {
-               struct bt_clock_class *mapped_clock_class =
-                       bt_field_type_integer_borrow_mapped_clock_class(ft);
+               struct bt_field_type_named_field_types_container *container_ft =
+                       (void *) ft;
+               uint64_t i;
 
-               if (!mapped_clock_class) {
-                       goto end;
-               }
+               for (i = 0; i < container_ft->named_fts->len; i++) {
+                       struct bt_named_field_type *named_ft =
+                               BT_FIELD_TYPE_NAMED_FT_AT_INDEX(
+                                       container_ft, i);
 
-               if (!*expected_clock_class) {
-                       /* Move reference to output parameter */
-                       *expected_clock_class = bt_get(mapped_clock_class);
-                       mapped_clock_class = NULL;
-                       BT_LOGV("Setting expected clock class: "
-                               "expected-clock-class-addr=%p",
-                               *expected_clock_class);
-               } else {
-                       if (mapped_clock_class != *expected_clock_class) {
-                               BT_LOGW("Integer field type is not mapped to "
-                                       "the expected clock class: "
-                                       "mapped-clock-class-addr=%p, "
-                                       "mapped-clock-class-name=\"%s\", "
-                                       "expected-clock-class-addr=%p, "
-                                       "expected-clock-class-name=\"%s\"",
-                                       mapped_clock_class,
-                                       bt_clock_class_get_name(mapped_clock_class),
-                                       *expected_clock_class,
-                                       bt_clock_class_get_name(*expected_clock_class));
-                               bt_put(mapped_clock_class);
-                               ret = -1;
-                               goto end;
-                       }
+                       bt_field_type_make_part_of_trace(named_ft->ft);
                }
 
                break;
        }
-       case BT_FIELD_TYPE_ID_ENUM:
-       case BT_FIELD_TYPE_ID_ARRAY:
-       case BT_FIELD_TYPE_ID_SEQUENCE:
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
        {
-               struct bt_field_type *sub_ft = NULL;
-
-               switch (ft->id) {
-               case BT_FIELD_TYPE_ID_ENUM:
-                       sub_ft = bt_field_type_enumeration_borrow_container_field_type(
-                               ft);
-                       break;
-               case BT_FIELD_TYPE_ID_ARRAY:
-                       sub_ft = bt_field_type_array_borrow_element_field_type(
-                               ft);
-                       break;
-               case BT_FIELD_TYPE_ID_SEQUENCE:
-                       sub_ft = bt_field_type_sequence_borrow_element_field_type(
-                               ft);
-                       break;
-               default:
-                       BT_LOGF("Unexpected field type ID: id=%d", ft->id);
-                       abort();
-               }
+               struct bt_field_type_array *array_ft = (void *) ft;
 
-               BT_ASSERT(sub_ft);
-               ret = bt_field_type_validate_single_clock_class(sub_ft,
-                       expected_clock_class);
-               break;
-       }
-       case BT_FIELD_TYPE_ID_STRUCT:
-       {
-               uint64_t i;
-               int64_t count = bt_field_type_structure_get_field_count(
-                       ft);
-
-               for (i = 0; i < count; i++) {
-                       const char *name;
-                       struct bt_field_type *member_type;
-
-                       ret = bt_field_type_structure_borrow_field_by_index(
-                               ft, &name, &member_type, i);
-                       BT_ASSERT(ret == 0);
-                       ret = bt_field_type_validate_single_clock_class(
-                               member_type, expected_clock_class);
-                       if (ret) {
-                               BT_LOGW("Structure field type's field's type "
-                                       "is not recursively mapped to the "
-                                       "expected clock class: "
-                                       "field-ft-addr=%p, field-name=\"%s\"",
-                                       member_type, name);
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_FIELD_TYPE_ID_VARIANT:
-       {
-               uint64_t i;
-               int64_t count = bt_field_type_variant_get_field_count(
-                       ft);
-
-               for (i = 0; i < count; i++) {
-                       const char *name;
-                       struct bt_field_type *member_type;
-
-                       ret = bt_field_type_variant_borrow_field_by_index(
-                               ft, &name, &member_type, i);
-                       BT_ASSERT(ret == 0);
-                       ret = bt_field_type_validate_single_clock_class(
-                               member_type, expected_clock_class);
-                       if (ret) {
-                               BT_LOGW("Variant field type's field's type "
-                                       "is not recursively mapped to the "
-                                       "expected clock class: "
-                                       "field-ft-addr=%p, field-name=\"%s\"",
-                                       member_type, name);
-                               goto end;
-                       }
-               }
+               bt_field_type_make_part_of_trace(array_ft->element_ft);
                break;
        }
        default:
                break;
        }
-
-end:
-       return ret;
-}
-
-static
-struct bt_field_type *bt_field_type_integer_copy(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_integer *int_ft = (void *) ft;
-       struct bt_field_type_integer *copy_ft;
-
-       BT_LOGD("Copying integer field type's: addr=%p", ft);
-       copy_ft = (void *) bt_field_type_integer_create(int_ft->size);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create integer field type.");
-               goto end;
-       }
-
-       copy_ft->mapped_clock_class = bt_get(int_ft->mapped_clock_class);
-       copy_ft->user_byte_order = int_ft->user_byte_order;
-       copy_ft->is_signed = int_ft->is_signed;
-       copy_ft->size = int_ft->size;
-       copy_ft->base = int_ft->base;
-       copy_ft->encoding = int_ft->encoding;
-       BT_LOGD("Copied integer field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
-
-static
-struct bt_field_type *bt_field_type_enumeration_copy_recursive(
-               struct bt_field_type *ft)
-{
-       size_t i;
-       struct bt_field_type_enumeration *enum_ft = (void *) ft;
-       struct bt_field_type_enumeration *copy_ft = NULL;
-       struct bt_field_type_enumeration *container_copy_ft;
-
-       BT_LOGD("Copying enumeration field type's: addr=%p", ft);
-
-       /* Copy the source enumeration's container */
-       BT_LOGD_STR("Copying enumeration field type's container field type.");
-       container_copy_ft =
-               (void *) bt_field_type_copy((void *) enum_ft->container_ft);
-       if (!container_copy_ft) {
-               BT_LOGE_STR("Cannot copy enumeration field type's container field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_field_type_enumeration_create(
-               (void *) container_copy_ft);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create enumeration field type.");
-               goto end;
-       }
-
-       /* Copy all enumaration entries */
-       for (i = 0; i < enum_ft->entries->len; i++) {
-               struct enumeration_mapping *mapping = g_ptr_array_index(
-                       enum_ft->entries, i);
-               struct enumeration_mapping *copy_mapping = g_new0(
-                       struct enumeration_mapping, 1);
-
-               if (!copy_mapping) {
-                       BT_LOGE_STR("Failed to allocate one enumeration mapping.");
-                       goto error;
-               }
-
-               *copy_mapping = *mapping;
-               g_ptr_array_add(copy_ft->entries, copy_mapping);
-       }
-
-       BT_LOGD("Copied enumeration field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_put(container_copy_ft);
-       return (void *) copy_ft;
-
-error:
-       bt_put(container_copy_ft);
-        BT_PUT(copy_ft);
-       return (void *) copy_ft;
-}
-
-static
-struct bt_field_type *bt_field_type_floating_point_copy(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type_floating_point *flt_ft = (void *) ft;
-       struct bt_field_type_floating_point *copy_ft;
-
-       BT_LOGD("Copying floating point number field type's: addr=%p", ft);
-       copy_ft = (void *) bt_field_type_floating_point_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create floating point number field type.");
-               goto end;
-       }
-
-       copy_ft->user_byte_order = flt_ft->user_byte_order;
-       copy_ft->exp_dig = flt_ft->exp_dig;
-       copy_ft->mant_dig = flt_ft->mant_dig;
-       BT_LOGD("Copied floating point number field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
-
-static
-struct bt_field_type *bt_field_type_structure_copy_recursive(
-               struct bt_field_type *ft)
-{
-       int64_t i;
-       GHashTableIter iter;
-       gpointer key, value;
-       struct bt_field_type_structure *struct_ft = (void *) ft;
-       struct bt_field_type_structure *copy_ft;
-
-       BT_LOGD("Copying structure field type's: addr=%p", ft);
-       copy_ft = (void *) bt_field_type_structure_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create structure field type.");
-               goto end;
-       }
-
-       /* Copy field_name_to_index */
-       g_hash_table_iter_init(&iter, struct_ft->field_name_to_index);
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               g_hash_table_insert(copy_ft->field_name_to_index,
-                       key, value);
-       }
-
-       g_array_set_size(copy_ft->fields, struct_ft->fields->len);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_field_type_structure_field *entry, *copy_entry;
-               struct bt_field_type *field_ft_copy;
-
-               entry = BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(
-                       struct_ft, i);
-               copy_entry = BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(
-                       copy_ft, i);
-               BT_LOGD("Copying structure field type's field: "
-                       "index=%" PRId64 ", "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, entry, g_quark_to_string(entry->name));
-
-               field_ft_copy = (void *) bt_field_type_copy(
-                       (void *) entry->type);
-               if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy structure field type's field: "
-                               "index=%" PRId64 ", "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, entry, g_quark_to_string(entry->name));
-                       goto error;
-               }
-
-               copy_entry->name = entry->name;
-               copy_entry->type = field_ft_copy;
-       }
-
-       BT_LOGD("Copied structure field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-
-error:
-        BT_PUT(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_field_type *bt_field_type_variant_copy_recursive(
-               struct bt_field_type *ft)
-{
-       int64_t i;
-       GHashTableIter iter;
-       gpointer key, value;
-       struct bt_field_type *tag_ft_copy = NULL;
-       struct bt_field_type_variant *var_ft = (void *) ft;
-       struct bt_field_type_variant *copy_ft = NULL;
-
-       BT_LOGD("Copying variant field type's: addr=%p", ft);
-       if (var_ft->tag_ft) {
-               BT_LOGD_STR("Copying variant field type's tag field type.");
-               tag_ft_copy = bt_field_type_copy((void *) var_ft->tag_ft);
-               if (!tag_ft_copy) {
-                       BT_LOGE_STR("Cannot copy variant field type's tag field type.");
-                       goto end;
-               }
-       }
-
-       copy_ft = (void *) bt_field_type_variant_create(
-               (void *) tag_ft_copy,
-               var_ft->tag_name->len ? var_ft->tag_name->str : NULL);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create variant field type.");
-               goto end;
-       }
-
-       /* Copy field_name_to_index */
-       g_hash_table_iter_init(&iter, var_ft->choice_name_to_index);
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               g_hash_table_insert(copy_ft->choice_name_to_index,
-                       key, value);
-       }
-
-       g_array_set_size(copy_ft->choices, var_ft->choices->len);
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_field_type_variant_choice *entry, *copy_entry;
-               struct bt_field_type *field_ft_copy;
-               uint64_t range_i;
-
-               entry = BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(var_ft, i);
-               copy_entry = BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(
-                       copy_ft, i);
-               BT_LOGD("Copying variant field type's field: "
-                       "index=%" PRId64 ", "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, entry, g_quark_to_string(entry->name));
-
-               field_ft_copy = (void *) bt_field_type_copy(
-                       (void *) entry->type);
-               if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy variant field type's field: "
-                               "index=%" PRId64 ", "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, entry, g_quark_to_string(entry->name));
-                       g_free(copy_entry);
-                       goto error;
-               }
-
-               copy_entry->name = entry->name;
-               copy_entry->type = field_ft_copy;
-
-               /* Copy ranges */
-               copy_entry->ranges = g_array_new(FALSE, TRUE,
-                       sizeof(struct bt_field_type_variant_choice_range));
-               BT_ASSERT(copy_entry->ranges);
-               g_array_set_size(copy_entry->ranges, entry->ranges->len);
-
-               for (range_i = 0; range_i < entry->ranges->len; range_i++) {
-                       copy_entry->ranges[range_i] = entry->ranges[range_i];
-               }
-       }
-
-       if (var_ft->tag_field_path) {
-               BT_LOGD_STR("Copying variant field type's tag field path.");
-               copy_ft->tag_field_path = bt_field_path_copy(
-                       var_ft->tag_field_path);
-               if (!copy_ft->tag_field_path) {
-                       BT_LOGE_STR("Cannot copy variant field type's tag field path.");
-                       goto error;
-               }
-       }
-
-       copy_ft->choices_up_to_date = var_ft->choices_up_to_date;
-       BT_LOGD("Copied variant field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_put(tag_ft_copy);
-       return (void *) copy_ft;
-
-error:
-       bt_put(tag_ft_copy);
-        BT_PUT(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_field_type *bt_field_type_array_copy_recursive(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type *container_ft_copy = NULL;
-       struct bt_field_type_array *array_ft = (void *) ft;
-       struct bt_field_type_array *copy_ft = NULL;
-
-       BT_LOGD("Copying array field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying array field type's element field type.");
-       container_ft_copy = bt_field_type_copy(array_ft->element_ft);
-       if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy array field type's element field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_field_type_array_create(
-               (void *) container_ft_copy, array_ft->length);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create array field type.");
-               goto end;
-       }
-
-       BT_LOGD("Copied array field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_put(container_ft_copy);
-       return (void *) copy_ft;
-}
-
-static
-struct bt_field_type *bt_field_type_sequence_copy_recursive(
-               struct bt_field_type *ft)
-{
-       struct bt_field_type *container_ft_copy = NULL;
-       struct bt_field_type_sequence *seq_ft = (void *) ft;
-       struct bt_field_type_sequence *copy_ft = NULL;
-
-       BT_LOGD("Copying sequence field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying sequence field type's element field type.");
-       container_ft_copy = bt_field_type_copy(seq_ft->element_ft);
-       if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy sequence field type's element field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_field_type_sequence_create(
-               (void *) container_ft_copy,
-               seq_ft->length_field_name->len ?
-                       seq_ft->length_field_name->str : NULL);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create sequence field type.");
-               goto end;
-       }
-
-       if (seq_ft->length_field_path) {
-               BT_LOGD_STR("Copying sequence field type's length field path.");
-               copy_ft->length_field_path = bt_field_path_copy(
-                       seq_ft->length_field_path);
-               if (!copy_ft->length_field_path) {
-                       BT_LOGE_STR("Cannot copy sequence field type's length field path.");
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied sequence field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_put(container_ft_copy);
-       return (void *) copy_ft;
-error:
-       bt_put(container_ft_copy);
-       BT_PUT(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_field_type *bt_field_type_string_copy(struct bt_field_type *ft)
-{
-       struct bt_field_type_string *string_ft = (void *) ft;
-       struct bt_field_type_string *copy_ft = NULL;
-
-       BT_LOGD("Copying string field type's: addr=%p", ft);
-       copy_ft = (void *) bt_field_type_string_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create string field type.");
-               goto end;
-       }
-
-       copy_ft->encoding = string_ft->encoding;
-       BT_LOGD("Copied string field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
 }
index 054d80a3837408fbc006742bac2c70d3bb3ff935..ee28705f682e40a07fab62da10f4e0d8a6e3e44f 100644 (file)
@@ -57,7 +57,7 @@ void bt_field_wrapper_destroy(struct bt_field_wrapper *field_wrapper)
 
        if (field_wrapper->field) {
                BT_LOGD_STR("Destroying field.");
-               bt_field_destroy_recursive((void *) field_wrapper->field);
+               bt_field_destroy((void *) field_wrapper->field);
        }
 
        BT_LOGD_STR("Putting stream class.");
@@ -80,7 +80,7 @@ struct bt_field_wrapper *bt_field_wrapper_create(
        }
 
        if (!field_wrapper->field) {
-               field_wrapper->field = (void *) bt_field_create_recursive(ft);
+               field_wrapper->field = (void *) bt_field_create(ft);
                if (!field_wrapper->field) {
                        BT_LIB_LOGE("Cannot create field wrapper from field type: "
                                "%![ft-]+F", ft);
index 3ebe6ebf18b25805bf9bf23393e63e599b8c5f00..c0bd86b06a21e0c1254069e360e41390fc7239d6 100644 (file)
 #include <babeltrace/assert-internal.h>
 #include <inttypes.h>
 
-#define BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(_field, _name)              \
-       BT_ASSERT_PRE((_field)->type->id == BT_FIELD_TYPE_ID_INTEGER || \
-               (_field)->type->id == BT_FIELD_TYPE_ID_ENUM,            \
-               _name " is not an integer or an enumeration field: "    \
-               "%!+f", (_field))
-
-static
-int bt_field_generic_validate(struct bt_field *field);
-
-static
-int bt_field_structure_validate_recursive(struct bt_field *field);
-
-static
-int bt_field_variant_validate_recursive(struct bt_field *field);
-
-static
-int bt_field_array_validate_recursive(struct bt_field *field);
-
-static
-int bt_field_sequence_validate_recursive(struct bt_field *field);
-
-static
-void bt_field_generic_reset(struct bt_field *field);
-
-static
-void bt_field_structure_reset_recursive(struct bt_field *field);
-
 static
-void bt_field_variant_reset_recursive(struct bt_field *field);
+void reset_single_field(struct bt_field *field);
 
 static
-void bt_field_array_reset_recursive(struct bt_field *field);
+void reset_array_field(struct bt_field *field);
 
 static
-void bt_field_sequence_reset_recursive(struct bt_field *field);
+void reset_structure_field(struct bt_field *field);
 
 static
-void bt_field_generic_set_is_frozen(struct bt_field *field,
-               bool is_frozen);
+void reset_variant_field(struct bt_field *field);
 
 static
-void bt_field_structure_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen);
+void set_single_field_is_frozen(struct bt_field *field, bool is_frozen);
 
 static
-void bt_field_variant_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen);
+void set_array_field_is_frozen(struct bt_field *field, bool is_frozen);
 
 static
-void bt_field_array_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen);
+void set_structure_field_is_frozen(struct bt_field *field, bool is_frozen);
 
 static
-void bt_field_sequence_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen);
+void set_variant_field_is_frozen(struct bt_field *field, bool is_frozen);
 
 static
-bt_bool bt_field_generic_is_set(struct bt_field *field);
+bool single_field_is_set(struct bt_field *field);
 
 static
-bt_bool bt_field_structure_is_set_recursive(
-               struct bt_field *field);
+bool array_field_is_set(struct bt_field *field);
 
 static
-bt_bool bt_field_variant_is_set_recursive(struct bt_field *field);
+bool structure_field_is_set(struct bt_field *field);
 
 static
-bt_bool bt_field_array_is_set_recursive(struct bt_field *field);
+bool variant_field_is_set(struct bt_field *field);
 
 static
-bt_bool bt_field_sequence_is_set_recursive(struct bt_field *field);
-
-static struct bt_field_methods bt_field_integer_methods = {
-       .set_is_frozen = bt_field_generic_set_is_frozen,
-       .validate = bt_field_generic_validate,
-       .is_set = bt_field_generic_is_set,
-       .reset = bt_field_generic_reset,
+struct bt_field_methods integer_field_methods = {
+       .set_is_frozen = set_single_field_is_frozen,
+       .is_set = single_field_is_set,
+       .reset = reset_single_field,
 };
 
-static struct bt_field_methods bt_field_floating_point_methods = {
-       .set_is_frozen = bt_field_generic_set_is_frozen,
-       .validate = bt_field_generic_validate,
-       .is_set = bt_field_generic_is_set,
-       .reset = bt_field_generic_reset,
-};
-
-static struct bt_field_methods bt_field_enumeration_methods = {
-       .set_is_frozen = bt_field_generic_set_is_frozen,
-       .validate = bt_field_generic_validate,
-       .is_set = bt_field_generic_is_set,
-       .reset = bt_field_generic_reset,
-};
-
-static struct bt_field_methods bt_field_string_methods = {
-       .set_is_frozen = bt_field_generic_set_is_frozen,
-       .validate = bt_field_generic_validate,
-       .is_set = bt_field_generic_is_set,
-       .reset = bt_field_generic_reset,
-};
-
-static struct bt_field_methods bt_field_structure_methods = {
-       .set_is_frozen = bt_field_structure_set_is_frozen_recursive,
-       .validate = bt_field_structure_validate_recursive,
-       .is_set = bt_field_structure_is_set_recursive,
-       .reset = bt_field_structure_reset_recursive,
+static
+struct bt_field_methods real_field_methods = {
+       .set_is_frozen = set_single_field_is_frozen,
+       .is_set = single_field_is_set,
+       .reset = reset_single_field,
 };
 
-static struct bt_field_methods bt_field_sequence_methods = {
-       .set_is_frozen = bt_field_sequence_set_is_frozen_recursive,
-       .validate = bt_field_sequence_validate_recursive,
-       .is_set = bt_field_sequence_is_set_recursive,
-       .reset = bt_field_sequence_reset_recursive,
+static
+struct bt_field_methods string_field_methods = {
+       .set_is_frozen = set_single_field_is_frozen,
+       .is_set = single_field_is_set,
+       .reset = reset_single_field,
 };
 
-static struct bt_field_methods bt_field_array_methods = {
-       .set_is_frozen = bt_field_array_set_is_frozen_recursive,
-       .validate = bt_field_array_validate_recursive,
-       .is_set = bt_field_array_is_set_recursive,
-       .reset = bt_field_array_reset_recursive,
+static
+struct bt_field_methods structure_field_methods = {
+       .set_is_frozen = set_structure_field_is_frozen,
+       .is_set = structure_field_is_set,
+       .reset = reset_structure_field,
 };
 
-static struct bt_field_methods bt_field_variant_methods = {
-       .set_is_frozen = bt_field_variant_set_is_frozen_recursive,
-       .validate = bt_field_variant_validate_recursive,
-       .is_set = bt_field_variant_is_set_recursive,
-       .reset = bt_field_variant_reset_recursive,
+static
+struct bt_field_methods array_field_methods = {
+       .set_is_frozen = set_array_field_is_frozen,
+       .is_set = array_field_is_set,
+       .reset = reset_array_field,
 };
 
 static
-struct bt_field *bt_field_integer_create(struct bt_field_type *);
+struct bt_field_methods variant_field_methods = {
+       .set_is_frozen = set_variant_field_is_frozen,
+       .is_set = variant_field_is_set,
+       .reset = reset_variant_field,
+};
 
 static
-struct bt_field *bt_field_enumeration_create(struct bt_field_type *);
+struct bt_field *create_integer_field(struct bt_field_type *);
 
 static
-struct bt_field *bt_field_floating_point_create(struct bt_field_type *);
+struct bt_field *create_real_field(struct bt_field_type *);
 
 static
-struct bt_field *bt_field_structure_create(struct bt_field_type *);
+struct bt_field *create_string_field(struct bt_field_type *);
 
 static
-struct bt_field *bt_field_variant_create(struct bt_field_type *);
+struct bt_field *create_structure_field(struct bt_field_type *);
 
 static
-struct bt_field *bt_field_array_create(struct bt_field_type *);
+struct bt_field *create_static_array_field(struct bt_field_type *);
 
 static
-struct bt_field *bt_field_sequence_create(struct bt_field_type *);
+struct bt_field *create_dynamic_array_field(struct bt_field_type *);
 
 static
-struct bt_field *bt_field_string_create(struct bt_field_type *);
+struct bt_field *create_variant_field(struct bt_field_type *);
 
 static
 struct bt_field *(* const field_create_funcs[])(struct bt_field_type *) = {
-       [BT_FIELD_TYPE_ID_INTEGER] =    bt_field_integer_create,
-       [BT_FIELD_TYPE_ID_ENUM] =       bt_field_enumeration_create,
-       [BT_FIELD_TYPE_ID_FLOAT] =      bt_field_floating_point_create,
-       [BT_FIELD_TYPE_ID_STRUCT] =     bt_field_structure_create,
-       [BT_FIELD_TYPE_ID_VARIANT] =    bt_field_variant_create,
-       [BT_FIELD_TYPE_ID_ARRAY] =      bt_field_array_create,
-       [BT_FIELD_TYPE_ID_SEQUENCE] =   bt_field_sequence_create,
-       [BT_FIELD_TYPE_ID_STRING] =     bt_field_string_create,
+       [BT_FIELD_TYPE_ID_UNSIGNED_INTEGER]     = create_integer_field,
+       [BT_FIELD_TYPE_ID_SIGNED_INTEGER]       = create_integer_field,
+       [BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION] = create_integer_field,
+       [BT_FIELD_TYPE_ID_SIGNED_ENUMERATION]   = create_integer_field,
+       [BT_FIELD_TYPE_ID_REAL]                 = create_real_field,
+       [BT_FIELD_TYPE_ID_STRING]               = create_string_field,
+       [BT_FIELD_TYPE_ID_STRUCTURE]            = create_structure_field,
+       [BT_FIELD_TYPE_ID_STATIC_ARRAY]         = create_static_array_field,
+       [BT_FIELD_TYPE_ID_DYNAMIC_ARRAY]        = create_dynamic_array_field,
+       [BT_FIELD_TYPE_ID_VARIANT]              = create_variant_field,
 };
 
 static
-void bt_field_integer_destroy(struct bt_field *field);
-
-static
-void bt_field_enumeration_destroy(struct bt_field *field);
-
-static
-void bt_field_floating_point_destroy(struct bt_field *field);
+void destroy_integer_field(struct bt_field *field);
 
 static
-void bt_field_structure_destroy_recursive(struct bt_field *field);
+void destroy_real_field(struct bt_field *field);
 
 static
-void bt_field_variant_destroy_recursive(struct bt_field *field);
+void destroy_string_field(struct bt_field *field);
 
 static
-void bt_field_array_destroy_recursive(struct bt_field *field);
+void destroy_structure_field(struct bt_field *field);
 
 static
-void bt_field_sequence_destroy_recursive(struct bt_field *field);
+void destroy_array_field(struct bt_field *field);
 
 static
-void bt_field_string_destroy(struct bt_field *field);
+void destroy_variant_field(struct bt_field *field);
 
 static
 void (* const field_destroy_funcs[])(struct bt_field *) = {
-       [BT_FIELD_TYPE_ID_INTEGER] =    bt_field_integer_destroy,
-       [BT_FIELD_TYPE_ID_ENUM] =       bt_field_enumeration_destroy,
-       [BT_FIELD_TYPE_ID_FLOAT] =      bt_field_floating_point_destroy,
-       [BT_FIELD_TYPE_ID_STRUCT] =     bt_field_structure_destroy_recursive,
-       [BT_FIELD_TYPE_ID_VARIANT] =    bt_field_variant_destroy_recursive,
-       [BT_FIELD_TYPE_ID_ARRAY] =      bt_field_array_destroy_recursive,
-       [BT_FIELD_TYPE_ID_SEQUENCE] =   bt_field_sequence_destroy_recursive,
-       [BT_FIELD_TYPE_ID_STRING] =     bt_field_string_destroy,
+       [BT_FIELD_TYPE_ID_UNSIGNED_INTEGER]     = destroy_integer_field,
+       [BT_FIELD_TYPE_ID_SIGNED_INTEGER]       = destroy_integer_field,
+       [BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION] = destroy_integer_field,
+       [BT_FIELD_TYPE_ID_SIGNED_ENUMERATION]   = destroy_integer_field,
+       [BT_FIELD_TYPE_ID_REAL]                 = destroy_real_field,
+       [BT_FIELD_TYPE_ID_STRING]               = destroy_string_field,
+       [BT_FIELD_TYPE_ID_STRUCTURE]            = destroy_structure_field,
+       [BT_FIELD_TYPE_ID_STATIC_ARRAY]         = destroy_array_field,
+       [BT_FIELD_TYPE_ID_DYNAMIC_ARRAY]        = destroy_array_field,
+       [BT_FIELD_TYPE_ID_VARIANT]              = destroy_variant_field,
 };
 
-BT_ASSERT_PRE_FUNC
-static inline bool value_is_in_range_signed(unsigned int size, int64_t value)
+struct bt_field_type *bt_field_borrow_type(struct bt_field *field)
 {
-       bool ret = true;
-       int64_t min_value, max_value;
-
-       min_value = -(1ULL << (size - 1));
-       max_value = (1ULL << (size - 1)) - 1;
-       if (value < min_value || value > max_value) {
-               BT_LOGF("Value is out of bounds: value=%" PRId64 ", "
-                       "min-value=%" PRId64 ", max-value=%" PRId64,
-                       value, min_value, max_value);
-               ret = false;
-       }
-
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       return field->type;
 }
 
-BT_ASSERT_PRE_FUNC
-static inline bool value_is_in_range_unsigned(unsigned int size, uint64_t value)
+enum bt_field_type_id bt_field_get_type_id(struct bt_field *field)
 {
-       bool ret = true;
-       int64_t max_value;
-
-       max_value = (size == 64) ? UINT64_MAX : ((uint64_t) 1 << size) - 1;
-       if (value > max_value) {
-               BT_LOGF("Value is out of bounds: value=%" PRIu64 ", "
-                       "max-value=%" PRIu64,
-                       value, max_value);
-               ret = false;
-       }
-
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       return field->type->id;
 }
 
 BT_HIDDEN
-struct bt_field *bt_field_create_recursive(struct bt_field_type *type)
+struct bt_field *bt_field_create(struct bt_field_type *ft)
 {
        struct bt_field *field = NULL;
-       enum bt_field_type_id type_id;
-
-       BT_ASSERT_PRE_NON_NULL(type, "Field type");
-       BT_ASSERT(bt_field_type_has_known_id((void *) type));
-       BT_ASSERT_PRE(bt_field_type_validate((void *) type) == 0,
-               "Field type is invalid: %!+F", type);
-       type_id = bt_field_type_get_type_id(type);
-       field = field_create_funcs[type_id](type);
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT(bt_field_type_has_known_id(ft));
+       field = field_create_funcs[ft->id](ft);
        if (!field) {
+               BT_LIB_LOGE("Cannot create field object from field type: "
+                       "%![ft-]+F", ft);
                goto end;
        }
 
-       bt_field_type_freeze(type);
-
 end:
        return field;
 }
 
-struct bt_field_type *bt_field_borrow_type(struct bt_field *field)
+static inline
+void init_field(struct bt_field *field, struct bt_field_type *ft,
+               struct bt_field_methods *methods)
 {
-       struct bt_field_type *ret = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       ret = field->type;
-       return ret;
+       BT_ASSERT(field);
+       BT_ASSERT(ft);
+       bt_object_init_unique(&field->base);
+       field->methods = methods;
+       field->type = bt_get(ft);
 }
 
-enum bt_field_type_id bt_field_get_type_id(struct bt_field *field)
+static
+struct bt_field *create_integer_field(struct bt_field_type *ft)
 {
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       return field->type->id;
+       struct bt_field_integer *int_field;
+
+       BT_LIB_LOGD("Creating integer field object: %![ft-]+F", ft);
+       int_field = g_new0(struct bt_field_integer, 1);
+       if (!int_field) {
+               BT_LOGE_STR("Failed to allocate one integer field.");
+               goto end;
+       }
+
+       init_field((void *) int_field, ft, &integer_field_methods);
+       BT_LIB_LOGD("Created integer field object: %!+f", int_field);
+
+end:
+       return (void *) int_field;
 }
 
-int64_t bt_field_sequence_get_length(struct bt_field *field)
+static
+struct bt_field *create_real_field(struct bt_field_type *ft)
 {
-       struct bt_field_sequence *sequence = (void *) field;
+       struct bt_field_real *real_field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_SEQUENCE,
-               "Field");
-       return (int64_t) sequence->length;
+       BT_LIB_LOGD("Creating real field object: %![ft-]+F", ft);
+       real_field = g_new0(struct bt_field_real, 1);
+       if (!real_field) {
+               BT_LOGE_STR("Failed to allocate one real field.");
+               goto end;
+       }
+
+       init_field((void *) real_field, ft, &real_field_methods);
+       BT_LIB_LOGD("Created real field object: %!+f", real_field);
+
+end:
+       return (void *) real_field;
 }
 
-int bt_field_sequence_set_length(struct bt_field *field, uint64_t length)
+static
+struct bt_field *create_string_field(struct bt_field_type *ft)
 {
-       int ret = 0;
-       struct bt_field_sequence *sequence = (void *) field;
+       struct bt_field_string *string_field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_ASSERT_PRE(((int64_t) length) >= 0,
-               "Invalid sequence length (too large): length=%" PRId64,
-               length);
-       BT_ASSERT_PRE_FIELD_HOT(field, "Sequence field");
+       BT_LIB_LOGD("Creating string field object: %![ft-]+F", ft);
+       string_field = g_new0(struct bt_field_string, 1);
+       if (!string_field) {
+               BT_LOGE_STR("Failed to allocate one string field.");
+               goto end;
+       }
 
-       if (unlikely(length > sequence->elements->len)) {
-               /* Make more room */
-               struct bt_field_type_sequence *sequence_ft;
-               uint64_t cur_len = sequence->elements->len;
-               uint64_t i;
+       init_field((void *) string_field, ft, &string_field_methods);
+       string_field->buf = g_array_sized_new(FALSE, FALSE,
+               sizeof(char), 1);
+       if (!string_field->buf) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               BT_PUT(string_field);
+               goto end;
+       }
 
-               g_ptr_array_set_size(sequence->elements, length);
-               sequence_ft = (void *) sequence->common.type;
+       g_array_index(string_field->buf, char, 0) = '\0';
+       BT_LIB_LOGD("Created string field object: %!+f", string_field);
 
-               for (i = cur_len; i < sequence->elements->len; i++) {
-                       struct bt_field *elem_field =
-                               bt_field_create_recursive(
-                                       sequence_ft->element_ft);
+end:
+       return (void *) string_field;
+}
 
-                       if (!elem_field) {
-                               ret = -1;
-                               goto end;
-                       }
+static inline
+int create_fields_from_named_field_types(
+               struct bt_field_type_named_field_types_container *ft,
+               GPtrArray **fields)
+{
+       int ret = 0;
+       uint64_t i;
 
-                       BT_ASSERT(!sequence->elements->pdata[i]);
-                       sequence->elements->pdata[i] = elem_field;
-               }
+       *fields = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_field_destroy);
+       if (!*fields) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               ret = -1;
+               goto end;
        }
 
-       sequence->length = length;
+       g_ptr_array_set_size(*fields, ft->named_fts->len);
+
+       for (i = 0; i < ft->named_fts->len; i++) {
+               struct bt_field *field;
+               struct bt_named_field_type *named_ft =
+                       BT_FIELD_TYPE_NAMED_FT_AT_INDEX(ft, i);
+
+               field = bt_field_create(named_ft->ft);
+               if (!field) {
+                       BT_LIB_LOGE("Failed to create structure member or variant option field: "
+                               "name=\"%s\", %![ft-]+F",
+                               named_ft->name->str, named_ft->ft);
+                       ret = -1;
+                       goto end;
+               }
+
+               g_ptr_array_index(*fields, i) = field;
+       }
 
 end:
        return ret;
 }
 
-struct bt_field *bt_field_structure_borrow_field_by_index(
-               struct bt_field *field, uint64_t index)
+static
+struct bt_field *create_structure_field(struct bt_field_type *ft)
 {
-       struct bt_field_structure *structure = (void *) field;
+       struct bt_field_structure *struct_field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Structure field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_STRUCT, "Field");
-       BT_ASSERT_PRE(index < structure->fields->len,
-               "Index is out of bound: %![struct-field-]+f, "
-               "index=%" PRIu64 ", count=%u", field, index,
-               structure->fields->len);
-       return structure->fields->pdata[index];
-}
+       BT_LIB_LOGD("Creating structure field object: %![ft-]+F", ft);
+       struct_field = g_new0(struct bt_field_structure, 1);
+       if (!struct_field) {
+               BT_LOGE_STR("Failed to allocate one structure field.");
+               goto end;
+       }
 
-struct bt_field *bt_field_structure_borrow_field_by_name(
-               struct bt_field *field, const char *name)
-{
-       struct bt_field *ret = NULL;
-       GQuark field_quark;
-       struct bt_field_type_structure *structure_ft;
-       struct bt_field_structure *structure = (void *) field;
-       size_t index;
-       GHashTable *field_name_to_index;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Structure field");
-       BT_ASSERT_PRE_NON_NULL(name, "Field name");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_STRUCT, "Field");
-       structure_ft = (void *) field->type;
-       field_name_to_index = structure_ft->field_name_to_index;
-       field_quark = g_quark_from_string(name);
-       if (!g_hash_table_lookup_extended(field_name_to_index,
-                       GUINT_TO_POINTER(field_quark),
-                       NULL, (gpointer *) &index)) {
-               BT_LOGV("Invalid parameter: no such field in structure field's type: "
-                       "struct-field-addr=%p, struct-ft-addr=%p, name=\"%s\"",
-                       field, field->type, name);
-               goto error;
+       init_field((void *) struct_field, ft, &structure_field_methods);
+
+       if (create_fields_from_named_field_types((void *) ft,
+                       &struct_field->fields)) {
+               BT_LIB_LOGE("Cannot create structure member fields: "
+                       "%![ft-]+F", ft);
+               BT_PUT(struct_field);
+               goto end;
        }
 
-       ret = structure->fields->pdata[index];
-       BT_ASSERT(ret);
+       BT_LIB_LOGD("Created structure field object: %!+f", struct_field);
 
-error:
-       return ret;
+end:
+       return (void *) struct_field;
 }
 
-struct bt_field *bt_field_array_borrow_field(
-               struct bt_field *field, uint64_t index)
+static
+struct bt_field *create_variant_field(struct bt_field_type *ft)
 {
-       struct bt_field_array *array = (void *) field;
+       struct bt_field_variant *var_field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Array field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_ARRAY,
-               "Field");
-       BT_ASSERT_PRE(index < array->elements->len,
-               "Index is out of bound: %![array-field-]+f, "
-               "index=%" PRIu64 ", count=%u", field,
-               index, array->elements->len);
-       return array->elements->pdata[(size_t) index];
-}
+       BT_LIB_LOGD("Creating variant field object: %![ft-]+F", ft);
+       var_field = g_new0(struct bt_field_variant, 1);
+       if (!var_field) {
+               BT_LOGE_STR("Failed to allocate one variant field.");
+               goto end;
+       }
 
-struct bt_field *bt_field_sequence_borrow_field(
-               struct bt_field *field, uint64_t index)
-{
-       struct bt_field_sequence *sequence = (void *) field;
+       init_field((void *) var_field, ft, &variant_field_methods);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_SEQUENCE,
-               "Field");
-       BT_ASSERT_PRE(index < sequence->length,
-               "Index is out of bound: %![seq-field-]+f, "
-               "index=%" PRIu64 ", count=%u", field, index,
-               sequence->elements->len);
-       return sequence->elements->pdata[(size_t) index];
-}
+       if (create_fields_from_named_field_types((void *) ft,
+                       &var_field->fields)) {
+               BT_LIB_LOGE("Cannot create variant member fields: "
+                       "%![ft-]+F", ft);
+               BT_PUT(var_field);
+               goto end;
+       }
 
-struct bt_field *bt_field_variant_borrow_current_field(
-               struct bt_field *field)
-{
-       struct bt_field_variant *variant = (void *) field;
+       BT_LIB_LOGD("Created variant field object: %!+f", var_field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Variant field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_ASSERT_PRE(variant->current_field,
-               "Variant field has no current field: %!+f", field);
-       return variant->current_field;
+end:
+       return (void *) var_field;
 }
 
 static inline
-int bt_field_variant_set_tag(struct bt_field *field,
-               uint64_t tag_uval, bool is_signed)
+int init_array_field_fields(struct bt_field_array *array_field)
 {
        int ret = 0;
-       int64_t choice_index;
-       struct bt_field_variant *variant = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Variant field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_VARIANT, "Field");
+       uint64_t i;
+       struct bt_field_type_array *array_ft;
 
-       /* Find matching index in variant field's type */
-       choice_index = bt_field_type_variant_find_choice_index(
-               field->type, tag_uval, is_signed);
-       if (choice_index < 0) {
+       BT_ASSERT(array_field);
+       array_ft = (void *) array_field->common.type;
+       array_field->fields = g_ptr_array_sized_new(array_field->length);
+       if (!array_field->fields) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
                ret = -1;
                goto end;
        }
 
-       /* Select corresponding field */
-       BT_ASSERT(choice_index < variant->fields->len);
-       variant->current_field = variant->fields->pdata[choice_index];
-       variant->tag_value.u = tag_uval;
+       g_ptr_array_set_free_func(array_field->fields,
+               (GDestroyNotify) bt_field_destroy);
+       g_ptr_array_set_size(array_field->fields, array_field->length);
+
+       for (i = 0; i < array_field->length; i++) {
+               array_field->fields->pdata[i] = bt_field_create(
+                       array_ft->element_ft);
+               if (!array_field->fields->pdata[i]) {
+                       BT_LIB_LOGE("Cannot create array field's element field: "
+                               "index=%" PRIu64 ", %![ft-]+F", i, array_ft);
+                       ret = -1;
+                       goto end;
+               }
+       }
 
 end:
        return ret;
 }
 
-int bt_field_variant_set_tag_signed(struct bt_field *variant_field,
-               int64_t tag)
+static
+struct bt_field *create_static_array_field(struct bt_field_type *ft)
 {
-       return bt_field_variant_set_tag((void *) variant_field,
-               (uint64_t) tag, true);
-}
+       struct bt_field_type_static_array *array_ft = (void *) ft;
+       struct bt_field_array *array_field;
 
-int bt_field_variant_set_tag_unsigned(struct bt_field *variant_field,
-               uint64_t tag)
-{
-       return bt_field_variant_set_tag((void *) variant_field,
-               (uint64_t) tag, false);
-}
+       BT_LIB_LOGD("Creating static array field object: %![ft-]+F", ft);
+       array_field = g_new0(struct bt_field_array, 1);
+       if (!array_field) {
+               BT_LOGE_STR("Failed to allocate one static array field.");
+               goto end;
+       }
 
-int bt_field_variant_get_tag_signed(struct bt_field *field,
-               int64_t *tag)
-{
-       struct bt_field_variant *variant = (void *) field;
+       init_field((void *) array_field, ft, &array_field_methods);
+       array_field->length = array_ft->length;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Variant field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_ASSERT_PRE(variant->current_field,
-               "Variant field has no current field: %!+f", field);
-       *tag = variant->tag_value.i;
-       return 0;
-}
+       if (init_array_field_fields(array_field)) {
+               BT_LIB_LOGE("Cannot create static array fields: "
+                       "%![ft-]+F", ft);
+               BT_PUT(array_field);
+               goto end;
+       }
 
-int bt_field_variant_get_tag_unsigned(struct bt_field *field,
-               uint64_t *tag)
-{
-       struct bt_field_variant *variant = (void *) field;
+       BT_LIB_LOGD("Created static array field object: %!+f", array_field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Variant field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_ASSERT_PRE(variant->current_field,
-               "Variant field has no current field: %!+f", field);
-       *tag = variant->tag_value.u;
-       return 0;
+end:
+       return (void *) array_field;
 }
 
-struct bt_field_type_enumeration_mapping_iterator *
-bt_field_enumeration_get_mappings(struct bt_field *field)
+static
+struct bt_field *create_dynamic_array_field(struct bt_field_type *ft)
 {
-       struct bt_field_enumeration *enum_field = (void *) field;
-       struct bt_field_type_enumeration *enum_type = NULL;
-       struct bt_field_type_integer *integer_type = NULL;
-       struct bt_field_type_enumeration_mapping_iterator *iter = NULL;
+       struct bt_field_array *array_field;
 
-       BT_ASSERT(field);
-       BT_ASSERT(field->type->id == BT_FIELD_TYPE_ID_ENUM);
-       BT_ASSERT(field->payload_set);
-       BT_ASSERT_PRE_NON_NULL(field, "Enumeration field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID((struct bt_field *) field,
-               BT_FIELD_TYPE_ID_ENUM, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SET((struct bt_field *) field,
-               "Enumeration field");
-       enum_type = (void *) field->type;
-       integer_type = enum_type->container_ft;
-
-       if (!integer_type->is_signed) {
-               iter = bt_field_type_enumeration_unsigned_find_mappings_by_value(
-                               field->type,
-                               enum_field->common.payload.unsignd);
-       } else {
-               iter = bt_field_type_enumeration_signed_find_mappings_by_value(
-                               field->type,
-                               enum_field->common.payload.signd);
+       BT_LIB_LOGD("Creating dynamic array field object: %![ft-]+F", ft);
+       array_field = g_new0(struct bt_field_array, 1);
+       if (!array_field) {
+               BT_LOGE_STR("Failed to allocate one dynamic array field.");
+               goto end;
+       }
+
+       init_field((void *) array_field, ft, &array_field_methods);
+
+       if (init_array_field_fields(array_field)) {
+               BT_LIB_LOGE("Cannot create dynamic array fields: "
+                       "%![ft-]+F", ft);
+               BT_PUT(array_field);
+               goto end;
        }
 
-       return iter;
+       BT_LIB_LOGD("Created dynamic array field object: %!+f", array_field);
+
+end:
+       return (void *) array_field;
 }
 
-BT_ASSERT_PRE_FUNC
-static inline
-struct bt_field_type_integer *get_int_enum_int_ft(
-               struct bt_field *field)
+int64_t bt_field_signed_integer_get_value(struct bt_field *field)
 {
        struct bt_field_integer *int_field = (void *) field;
-       struct bt_field_type_integer *int_ft = NULL;
-
-       if (int_field->common.type->id == BT_FIELD_TYPE_ID_INTEGER) {
-               int_ft = (void *) int_field->common.type;
-       } else if (int_field->common.type->id == BT_FIELD_TYPE_ID_ENUM) {
-               struct bt_field_type_enumeration *enum_ft =
-                       (void *) int_field->common.type;
-               int_ft = enum_ft->container_ft;
-       } else {
-               abort();
-       }
 
-       BT_ASSERT(int_ft);
-       return int_ft;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(field, "Field");
+       return int_field->value.i;
 }
 
-int bt_field_integer_signed_get_value(struct bt_field *field, int64_t *value)
+void bt_field_signed_integer_set_value(struct bt_field *field, int64_t value)
 {
-       struct bt_field_integer *integer = (void *) field;
+       struct bt_field_integer *int_field = (void *) field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Integer/enumeration field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_IS_SET(field,
-               "Integer/enumeration field");
-       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(field, "Field");
-       BT_ASSERT_PRE(bt_field_type_integer_is_signed(
-               (void *) get_int_enum_int_ft(field)),
-               "Field's type is unsigned: %!+f", field);
-       *value = integer->payload.signd;
-       return 0;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(
+               ((struct bt_field_type_integer *) field->type)->range, value),
+               "Value is out of bounds: value=%" PRId64 ", %![field-]+f, "
+               "%![ft-]+F", value, field, field->type);
+       int_field->value.i = value;
+       bt_field_set_single(field, true);
 }
 
-int bt_field_integer_signed_set_value(struct bt_field *field, int64_t value)
+uint64_t bt_field_unsigned_integer_get_value(struct bt_field *field)
 {
-       int ret = 0;
-       struct bt_field_integer *integer = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(field, "Field");
-       BT_ASSERT_PRE(bt_field_type_integer_is_signed(
-               (void *) get_int_enum_int_ft(field)),
-               "Field's type is unsigned: %!+f", field);
-       BT_ASSERT_PRE(value_is_in_range_signed(
-               get_int_enum_int_ft(field)->size, value),
-               "Value is out of bounds: value=%" PRId64 ", %![field-]+f",
-               value, field);
-       integer->payload.signd = value;
-       bt_field_set(field, true);
-       return ret;
+       struct bt_field_integer *int_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(field, "Field");
+       return int_field->value.u;
 }
 
-int bt_field_integer_unsigned_get_value(struct bt_field *field, uint64_t *value)
+void bt_field_unsigned_integer_set_value(struct bt_field *field,
+               uint64_t value)
 {
-       struct bt_field_integer *integer = (void *) field;
+       struct bt_field_integer *int_field = (void *) field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(field, "Field");
-       BT_ASSERT_PRE(!bt_field_type_integer_is_signed(
-               (void *) get_int_enum_int_ft(field)),
-               "Field's type is signed: %!+f", field);
-       *value = integer->payload.unsignd;
-       return 0;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(
+               ((struct bt_field_type_integer *) field->type)->range, value),
+               "Value is out of bounds: value=%" PRIu64 ", %![field-]+f, "
+               "%![ft-]+F", value, field, field->type);
+       int_field->value.u = value;
+       bt_field_set_single(field, true);
 }
 
-int bt_field_integer_unsigned_set_value(struct bt_field *field,
-               uint64_t value)
+double bt_field_real_get_value(struct bt_field *field)
 {
-       struct bt_field_integer *integer = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(field, "Field");
-       BT_ASSERT_PRE(!bt_field_type_integer_is_signed(
-               (void *) get_int_enum_int_ft(field)),
-               "Field's type is signed: %!+f", field);
-       BT_ASSERT_PRE(value_is_in_range_unsigned(
-               get_int_enum_int_ft(field)->size, value),
-               "Value is out of bounds: value=%" PRIu64 ", %![field-]+f",
-               value, field);
-       integer->payload.unsignd = value;
-       bt_field_set(field, true);
-       return 0;
+       struct bt_field_real *real_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_REAL, "Field");
+       return real_field->value;
 }
 
-int bt_field_floating_point_get_value(struct bt_field *field,
-               double *value)
+void bt_field_real_set_value(struct bt_field *field, double value)
 {
-       struct bt_field_floating_point *floating_point = (void *) field;
+       struct bt_field_real *real_field = (void *) field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Floating point number field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Floating point number field");
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_REAL, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE(
+               !((struct bt_field_type_real *) field->type)->is_single_precision ||
+               (double) (float) value == value,
+               "Invalid value for a single-precision real number: value=%f, "
+               "%![ft-]+F", value, field->type);
+       real_field->value = value;
+       bt_field_set_single(field, true);
+}
+
+int bt_field_unsigned_enumeration_get_mapping_labels(struct bt_field *field,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
+{
+       struct bt_field_integer *int_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Count (output)");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
        BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_FLOAT, "Field");
-       *value = floating_point->payload;
-       return 0;
+               BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION, "Field");
+       return bt_field_type_unsigned_enumeration_get_mapping_labels_by_value(
+               field->type, int_field->value.u, label_array, count);
 }
 
-int bt_field_floating_point_set_value(struct bt_field *field,
-               double value)
+int bt_field_signed_enumeration_get_mapping_labels(struct bt_field *field,
+               bt_field_type_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
 {
-       struct bt_field_floating_point *floating_point = (void *) field;
+       struct bt_field_integer *int_field = (void *) field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Floating point number field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Floating point number field");
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Count (output)");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
        BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_FLOAT, "Field");
-       floating_point->payload = value;
-       bt_field_set(field, true);
-       return 0;
+               BT_FIELD_TYPE_ID_SIGNED_ENUMERATION, "Field");
+       return bt_field_type_signed_enumeration_get_mapping_labels_by_value(
+               field->type, int_field->value.i, label_array, count);
 }
 
 const char *bt_field_string_get_value(struct bt_field *field)
 {
-       struct bt_field_string *string = (void *) field;
+       struct bt_field_string *string_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_STRING,
+               "Field");
+       return (const char *) string_field->buf->data;
+}
+
+uint64_t bt_field_string_get_length(struct bt_field *field)
+{
+       struct bt_field_string *string_field = (void *) field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "String field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_STRING, "Field");
-       return (const char *) string->buf->data;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_STRING,
+               "Field");
+       return string_field->length;
 }
 
 int bt_field_string_set_value(struct bt_field *field, const char *value)
 {
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
        BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_HOT(field, "String field");
-       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_STRING, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_STRING,
+               "Field");
        bt_field_string_clear(field);
-       return bt_field_string_append_len(field,
-               value, strlen(value));
+       return bt_field_string_append_with_length(field, value,
+               (uint64_t) strlen(value));
 }
 
 int bt_field_string_append(struct bt_field *field, const char *value)
 {
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       return bt_field_string_append_len(field, value,
-               strlen(value));
+       return bt_field_string_append_with_length(field, value,
+               (uint64_t) strlen(value));
 }
 
-int bt_field_string_append_len(struct bt_field *field,
-               const char *value, unsigned int length)
+int bt_field_string_append_with_length(struct bt_field *field,
+               const char *value, uint64_t length)
 {
        struct bt_field_string *string_field = (void *) field;
        char *data;
-       size_t new_size;
+       uint64_t new_length;
 
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
        BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_HOT(field, "String field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
        BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
                BT_FIELD_TYPE_ID_STRING, "Field");
 
        /* Make sure no null bytes are appended */
        BT_ASSERT_PRE(memchr(value, '\0', length) == NULL,
                "String value to append contains a null character: "
-               "partial-value=\"%.32s\", length=%u", value, length);
+               "partial-value=\"%.32s\", length=%" PRIu64, value, length);
 
-       new_size = string_field->size + length;
+       new_length = length + string_field->length;
 
-       if (unlikely(new_size + 1 > string_field->buf->len)) {
-               g_array_set_size(string_field->buf, new_size + 1);
+       if (unlikely(new_length + 1 > string_field->buf->len)) {
+               g_array_set_size(string_field->buf, new_length + 1);
        }
 
        data = string_field->buf->data;
-       memcpy(data + string_field->size, value, length);
-       ((char *) string_field->buf->data)[new_size] = '\0';
-       string_field->size = new_size;
-       bt_field_set(field, true);
+       memcpy(data + string_field->length, value, length);
+       ((char *) string_field->buf->data)[new_length] = '\0';
+       string_field->length = new_length;
+       bt_field_set_single(field, true);
        return 0;
 }
 
@@ -745,851 +664,401 @@ int bt_field_string_clear(struct bt_field *field)
 {
        struct bt_field_string *string_field = (void *) field;
 
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "String field");
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
        BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
                BT_FIELD_TYPE_ID_STRING, "Field");
-       string_field->size = 0;
-       bt_field_set(field, true);
+       string_field->length = 0;
+       bt_field_set_single(field, true);
        return 0;
 }
 
-static inline
-void bt_field_finalize(struct bt_field *field)
+uint64_t bt_field_array_get_length(struct bt_field *field)
 {
-       BT_ASSERT(field);
-       BT_LOGD_STR("Putting field's type.");
-       bt_put(field->type);
-}
+       struct bt_field_array *array_field = (void *) field;
 
-static
-void bt_field_integer_destroy(struct bt_field *field)
-{
-       BT_ASSERT(field);
-       BT_LOGD("Destroying integer field object: addr=%p", field);
-       bt_field_finalize(field);
-       g_free(field);
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_ARRAY(field, "Field");
+       return array_field->length;
 }
 
-static
-void bt_field_floating_point_destroy(struct bt_field *field)
+int bt_field_dynamic_array_set_length(struct bt_field *field,
+               uint64_t length)
 {
-       BT_ASSERT(field);
-       BT_LOGD("Destroying floating point field object: addr=%p", field);
-       bt_field_finalize(field);
-       g_free(field);
-}
+       int ret = 0;
+       struct bt_field_array *array_field = (void *) field;
 
-static
-void bt_field_enumeration_destroy(struct bt_field *field)
-{
-       BT_LOGD("Destroying enumeration field object: addr=%p", field);
-       bt_field_finalize((void *) field);
-       g_free(field);
-}
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
+               BT_FIELD_TYPE_ID_DYNAMIC_ARRAY, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
 
-static
-void bt_field_structure_destroy_recursive(struct bt_field *field)
-{
-       struct bt_field_structure *structure = (void *) field;
+       if (unlikely(length > array_field->fields->len)) {
+               /* Make more room */
+               struct bt_field_type_array *array_ft;
+               uint64_t cur_len = array_field->fields->len;
+               uint64_t i;
 
-       BT_ASSERT(field);
-       BT_LOGD("Destroying structure field object: addr=%p", field);
-       bt_field_finalize(field);
-
-       if (structure->fields) {
-               g_ptr_array_free(structure->fields, TRUE);
-       }
-
-       g_free(field);
-}
-
-static
-void bt_field_variant_destroy_recursive(struct bt_field *field)
-{
-       struct bt_field_variant *variant = (void *) field;
-
-       BT_ASSERT(field);
-       BT_LOGD("Destroying variant field object: addr=%p", field);
-       bt_field_finalize(field);
-
-       if (variant->fields) {
-               g_ptr_array_free(variant->fields, TRUE);
-       }
-
-       g_free(field);
-}
-
-static
-void bt_field_array_destroy_recursive(struct bt_field *field)
-{
-       struct bt_field_array *array = (void *) field;
-
-       BT_ASSERT(field);
-       BT_LOGD("Destroying array field object: addr=%p", field);
-       bt_field_finalize(field);
-
-       if (array->elements) {
-               g_ptr_array_free(array->elements, TRUE);
-       }
-
-       g_free(field);
-}
-
-static
-void bt_field_sequence_destroy_recursive(struct bt_field *field)
-{
-       struct bt_field_sequence *sequence = (void *) field;
-
-       BT_ASSERT(field);
-       BT_LOGD("Destroying sequence field object: addr=%p", field);
-       bt_field_finalize(field);
-
-       if (sequence->elements) {
-               g_ptr_array_free(sequence->elements, TRUE);
-       }
-       g_free(field);
-}
-
-static
-void bt_field_string_destroy(struct bt_field *field)
-{
-       struct bt_field_string *string = (void *) field;
-
-       BT_LOGD("Destroying string field object: addr=%p", field);
-       BT_ASSERT(field);
-       bt_field_finalize(field);
-
-       if (string->buf) {
-               g_array_free(string->buf, TRUE);
-       }
+               g_ptr_array_set_size(array_field->fields, length);
+               array_ft = (void *) field->type;
 
-       g_free(field);
-}
-
-BT_HIDDEN
-void bt_field_destroy_recursive(struct bt_field *field)
-{
-       if (!field) {
-               return;
-       }
-
-       BT_ASSERT(bt_field_type_has_known_id((void *) field->type));
-       field_destroy_funcs[field->type->id](field);
-}
-
-static inline
-void bt_field_initialize(struct bt_field *field,
-               struct bt_field_type *ft,
-               struct bt_field_methods *methods)
-{
-       BT_ASSERT(field);
-       BT_ASSERT(ft);
-       bt_object_init_unique(&field->base);
-       field->methods = methods;
-       field->type = bt_get(ft);
-}
-
-static
-struct bt_field *bt_field_integer_create(struct bt_field_type *type)
-{
-       struct bt_field_integer *integer =
-               g_new0(struct bt_field_integer, 1);
-
-       BT_LOGD("Creating integer field object: ft-addr=%p", type);
-
-       if (integer) {
-               bt_field_initialize((void *) integer, (void *) type,
-                       &bt_field_integer_methods);
-               BT_LOGD("Created integer field object: addr=%p, ft-addr=%p",
-                       integer, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one integer field.");
-       }
-
-       return (void *) integer;
-}
-
-static
-struct bt_field *bt_field_enumeration_create(struct bt_field_type *type)
-{
-       struct bt_field_enumeration *enumeration = g_new0(
-               struct bt_field_enumeration, 1);
-
-       BT_LOGD("Creating enumeration field object: ft-addr=%p", type);
-
-       if (enumeration) {
-               bt_field_initialize((void *) enumeration,
-                       (void *) type, &bt_field_enumeration_methods);
-               BT_LOGD("Created enumeration field object: addr=%p, ft-addr=%p",
-                       enumeration, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one enumeration field.");
-       }
-
-       return (void *) enumeration;
-}
+               for (i = cur_len; i < array_field->fields->len; i++) {
+                       struct bt_field *elem_field = bt_field_create(
+                               array_ft->element_ft);
 
-static
-struct bt_field *bt_field_floating_point_create(struct bt_field_type *type)
-{
-       struct bt_field_floating_point *floating_point;
-
-       BT_LOGD("Creating floating point number field object: ft-addr=%p", type);
-       floating_point = g_new0(struct bt_field_floating_point, 1);
-
-       if (floating_point) {
-               bt_field_initialize((void *) floating_point,
-                       (void *) type, &bt_field_floating_point_methods);
-               BT_LOGD("Created floating point number field object: addr=%p, ft-addr=%p",
-                       floating_point, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one floating point number field.");
-       }
-
-       return (void *) floating_point;
-}
-
-static inline
-int bt_field_structure_initialize(struct bt_field *field,
-               struct bt_field_type *type,
-               struct bt_field_methods *methods,
-               bt_field_create_func field_create_func,
-               GDestroyNotify field_release_func)
-{
-       int ret = 0;
-       struct bt_field_type_structure *structure_type = (void *) type;
-       struct bt_field_structure *structure = (void *) field;
-       size_t i;
-
-       BT_LOGD("Initializing structure field object: ft-addr=%p", type);
-       bt_field_initialize(field, type, methods);
-       structure->fields = g_ptr_array_new_with_free_func(field_release_func);
-       g_ptr_array_set_size(structure->fields, structure_type->fields->len);
+                       if (!elem_field) {
+                               BT_LIB_LOGE("Cannot create element field for "
+                                       "dynamic array field: "
+                                       "index=%" PRIu64 ", "
+                                       "%![array-field-]+f", i, field);
+                               ret = -1;
+                               goto end;
+                       }
 
-       /* Create all fields contained in the structure field. */
-       for (i = 0; i < structure_type->fields->len; i++) {
-               struct bt_field *field;
-               struct bt_field_type_structure_field *struct_field =
-                       BT_FIELD_TYPE_STRUCTURE_FIELD_AT_INDEX(
-                               structure_type, i);
-               field = field_create_func(struct_field->type);
-               if (!field) {
-                       BT_LOGE("Failed to create structure field's member: name=\"%s\", index=%zu",
-                               g_quark_to_string(struct_field->name), i);
-                       ret = -1;
-                       goto end;
+                       BT_ASSERT(!array_field->fields->pdata[i]);
+                       array_field->fields->pdata[i] = elem_field;
                }
-
-               g_ptr_array_index(structure->fields, i) = field;
        }
 
-       BT_LOGD("Initialized structure field object: addr=%p, ft-addr=%p",
-               field, type);
+       array_field->length = length;
 
 end:
        return ret;
 }
 
-static
-struct bt_field *bt_field_structure_create(struct bt_field_type *type)
-{
-       struct bt_field_structure *structure = g_new0(
-               struct bt_field_structure, 1);
-       int iret;
-
-       BT_LOGD("Creating structure field object: ft-addr=%p", type);
-
-       if (!structure) {
-               BT_LOGE_STR("Failed to allocate one structure field.");
-               goto end;
-       }
-
-       iret = bt_field_structure_initialize((void *) structure,
-               (void *) type, &bt_field_structure_methods,
-               (bt_field_create_func) bt_field_create_recursive,
-               (GDestroyNotify) bt_field_destroy_recursive);
-       if (iret) {
-               BT_PUT(structure);
-               goto end;
-       }
-
-       BT_LOGD("Created structure field object: addr=%p, ft-addr=%p",
-               structure, type);
-
-end:
-       return (void *) structure;
-}
-
-static inline
-int bt_field_variant_initialize(struct bt_field *field,
-               struct bt_field_type *type,
-               struct bt_field_methods *methods,
-               bt_field_create_func field_create_func,
-               GDestroyNotify field_release_func)
+struct bt_field *bt_field_array_borrow_element_field_by_index(
+               struct bt_field *field, uint64_t index)
 {
-       int ret = 0;
-       struct bt_field_type_variant *variant_type = (void *) type;
-       struct bt_field_variant *variant = (void *) field;
-       size_t i;
-
-       BT_LOGD("Initializing variant field object: ft-addr=%p", type);
-       bt_field_initialize(field, type, methods);
-       ret = bt_field_type_variant_update_choices(type);
-       if (ret) {
-               BT_LOGE("Cannot update variant field type choices: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       variant->fields = g_ptr_array_new_with_free_func(field_release_func);
-       g_ptr_array_set_size(variant->fields, variant_type->choices->len);
-
-       /* Create all fields contained in the variant field. */
-       for (i = 0; i < variant_type->choices->len; i++) {
-               struct bt_field *field;
-               struct bt_field_type_variant_choice *var_choice =
-                       BT_FIELD_TYPE_VARIANT_CHOICE_AT_INDEX(
-                               variant_type, i);
-
-               field = field_create_func(var_choice->type);
-               if (!field) {
-                       BT_LOGE("Failed to create variant field's member: name=\"%s\", index=%zu",
-                               g_quark_to_string(var_choice->name), i);
-                       ret = -1;
-                       goto end;
-               }
-
-               g_ptr_array_index(variant->fields, i) = field;
-       }
-
-       BT_LOGD("Initialized variant field object: addr=%p, ft-addr=%p",
-               field, type);
+       struct bt_field_array *array_field = (void *) field;
 
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_ARRAY(field, "Field");
+       BT_ASSERT_PRE_VALID_INDEX(index, array_field->length);
+       return array_field->fields->pdata[index];
 }
 
-static inline
-int bt_field_string_initialize(struct bt_field *field,
-               struct bt_field_type *type,
-               struct bt_field_methods *methods)
+struct bt_field *bt_field_structure_borrow_member_field_by_index(
+               struct bt_field *field, uint64_t index)
 {
-       int ret = 0;
-       struct bt_field_string *string = (void *) field;
-
-       BT_LOGD("Initializing string field object: ft-addr=%p", type);
-       bt_field_initialize(field, type, methods);
-       string->buf = g_array_sized_new(FALSE, FALSE, sizeof(char), 1);
-       if (!string->buf) {
-               ret = -1;
-               goto end;
-       }
-
-       g_array_index(string->buf, char, 0) = '\0';
-       BT_LOGD("Initialized string field object: addr=%p, ft-addr=%p",
-               field, type);
+       struct bt_field_structure *struct_field = (void *) field;
 
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
+               BT_FIELD_TYPE_ID_STRUCTURE, "Field");
+       BT_ASSERT_PRE_VALID_INDEX(index, struct_field->fields->len);
+       return struct_field->fields->pdata[index];
 }
 
-static
-struct bt_field *bt_field_variant_create(struct bt_field_type *type)
+struct bt_field *bt_field_structure_borrow_member_field_by_name(
+               struct bt_field *field, const char *name)
 {
-       struct bt_field_variant *variant = g_new0(
-               struct bt_field_variant, 1);
-       int iret;
+       struct bt_field *ret_field = NULL;
+       struct bt_field_type_structure *struct_ft;
+       struct bt_field_structure *struct_field = (void *) field;
+       gpointer orig_key;
+       gpointer index;
 
-       BT_LOGD("Creating variant field object: ft-addr=%p", type);
-
-       if (!variant) {
-               BT_LOGE_STR("Failed to allocate one variant field.");
-               goto end;
-       }
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(name, "Field name");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
+               BT_FIELD_TYPE_ID_STRUCTURE, "Field");
+       struct_ft = (void *) field->type;
 
-       iret = bt_field_variant_initialize((void *) variant,
-               (void *) type, &bt_field_variant_methods,
-               (bt_field_create_func) bt_field_create_recursive,
-               (GDestroyNotify) bt_field_destroy_recursive);
-       if (iret) {
-               BT_PUT(variant);
+       if (!g_hash_table_lookup_extended(struct_ft->common.name_to_index, name,
+                       &orig_key, &index)) {
                goto end;
        }
 
-       BT_LOGD("Created variant field object: addr=%p, ft-addr=%p",
-               variant, type);
+       ret_field = struct_field->fields->pdata[GPOINTER_TO_UINT(index)];
+       BT_ASSERT(ret_field);
 
 end:
-       return (void *) variant;
+       return ret_field;
 }
 
-static inline
-int bt_field_array_initialize(struct bt_field *field,
-               struct bt_field_type *type,
-               struct bt_field_methods *methods,
-               bt_field_create_func field_create_func,
-               GDestroyNotify field_destroy_func)
+struct bt_field *bt_field_variant_borrow_selected_option_field(
+               struct bt_field *field)
 {
-       struct bt_field_type_array *array_type = (void *) type;
-       struct bt_field_array *array = (void *) field;
-       unsigned int array_length;
-       int ret = 0;
-       uint64_t i;
-
-       BT_LOGD("Initializing array field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-       bt_field_initialize(field, type, methods);
-       array_length = array_type->length;
-       array->elements = g_ptr_array_sized_new(array_length);
-       if (!array->elements) {
-               ret = -1;
-               goto end;
-       }
+       struct bt_field_variant *var_field = (void *) field;
 
-       g_ptr_array_set_free_func(array->elements, field_destroy_func);
-       g_ptr_array_set_size(array->elements, array_length);
-
-       for (i = 0; i < array_length; i++) {
-               array->elements->pdata[i] = field_create_func(
-                       array_type->element_ft);
-               if (!array->elements->pdata[i]) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       BT_LOGD("Initialized array field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
+               BT_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_ASSERT_PRE(var_field->selected_field,
+               "Variant field has no selected field: %!+f", field);
+       return var_field->selected_field;
 }
 
-static
-struct bt_field *bt_field_array_create(struct bt_field_type *type)
+int bt_field_variant_select_option_field(struct bt_field *field,
+               uint64_t index)
 {
-       struct bt_field_array *array =
-               g_new0(struct bt_field_array, 1);
-       int ret;
+       struct bt_field_variant *var_field = (void *) field;
 
-       BT_LOGD("Creating array field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-
-       if (!array) {
-               BT_LOGE_STR("Failed to allocate one array field.");
-               goto end;
-       }
-
-       ret = bt_field_array_initialize((void *) array,
-               (void *) type, &bt_field_array_methods,
-               (bt_field_create_func) bt_field_create_recursive,
-               (GDestroyNotify) bt_field_destroy_recursive);
-       if (ret) {
-               BT_PUT(array);
-               goto end;
-       }
-
-       BT_LOGD("Created array field object: addr=%p, ft-addr=%p",
-               array, type);
-
-end:
-       return (void *) array;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
+               BT_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE_VALID_INDEX(index, var_field->fields->len);
+       var_field->selected_field = var_field->fields->pdata[index];
+       var_field->selected_index = index;
+       return 0;
 }
 
-static inline
-int bt_field_sequence_initialize(struct bt_field *field,
-               struct bt_field_type *type,
-               struct bt_field_methods *methods,
-               GDestroyNotify field_destroy_func)
+uint64_t bt_field_variant_get_selected_option_field_index(
+               struct bt_field *field)
 {
-       struct bt_field_sequence *sequence = (void *) field;
-       int ret = 0;
-
-       BT_LOGD("Initializing sequence field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-       bt_field_initialize(field, type, methods);
-       sequence->elements = g_ptr_array_new();
-       if (!sequence->elements) {
-               ret = -1;
-               goto end;
-       }
+       struct bt_field_variant *var_field = (void *) field;
 
-       g_ptr_array_set_free_func(sequence->elements, field_destroy_func);
-       BT_LOGD("Initialized sequence field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_TYPE_ID(field,
+               BT_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_ASSERT_PRE(var_field->selected_field,
+               "Variant field has no selected field: %!+f", field);
+       return var_field->selected_index;
 }
 
-static
-struct bt_field *bt_field_sequence_create(struct bt_field_type *type)
+static inline
+void bt_field_finalize(struct bt_field *field)
 {
-       struct bt_field_sequence *sequence =
-               g_new0(struct bt_field_sequence, 1);
-       int ret;
-
-       BT_LOGD("Creating sequence field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-
-       if (!sequence) {
-               BT_LOGE_STR("Failed to allocate one sequence field.");
-               goto end;
-       }
-
-       ret = bt_field_sequence_initialize((void *) sequence,
-               (void *) type, &bt_field_sequence_methods,
-               (GDestroyNotify) bt_field_destroy_recursive);
-       if (ret) {
-               BT_PUT(sequence);
-               goto end;
-       }
-
-       BT_LOGD("Created sequence field object: addr=%p, ft-addr=%p",
-               sequence, type);
-
-end:
-       return (void *) sequence;
+       BT_ASSERT(field);
+       BT_LOGD_STR("Putting field's type.");
+       bt_put(field->type);
 }
 
 static
-struct bt_field *bt_field_string_create(struct bt_field_type *type)
+void destroy_integer_field(struct bt_field *field)
 {
-       struct bt_field_string *string = g_new0(
-               struct bt_field_string, 1);
-
-       BT_LOGD("Creating string field object: ft-addr=%p", type);
-
-       if (string) {
-               bt_field_string_initialize((void *) string,
-                       (void *) type, &bt_field_string_methods);
-               BT_LOGD("Created string field object: addr=%p, ft-addr=%p",
-                       string, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one string field.");
-       }
-
-       return (void *) string;
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying integer field object: %!+f", field);
+       bt_field_finalize(field);
+       g_free(field);
 }
 
 static
-int bt_field_generic_validate(struct bt_field *field)
+void destroy_real_field(struct bt_field *field)
 {
-       return (field && field->payload_set) ? 0 : -1;
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying real field object: %!+f", field);
+       bt_field_finalize(field);
+       g_free(field);
 }
 
 static
-int bt_field_structure_validate_recursive(struct bt_field *field)
+void destroy_structure_field(struct bt_field *field)
 {
-       int64_t i;
-       int ret = 0;
-       struct bt_field_structure *structure = (void *) field;
+       struct bt_field_structure *struct_field = (void *) field;
 
        BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying structure field object: %!+f", field);
+       bt_field_finalize(field);
 
-       for (i = 0; i < structure->fields->len; i++) {
-               ret = bt_field_validate_recursive(
-                       (void *) structure->fields->pdata[i]);
-
-               if (ret) {
-                       int this_ret;
-                       const char *name;
-
-                       this_ret = bt_field_type_structure_borrow_field_by_index(
-                               field->type, &name, NULL, i);
-                       BT_ASSERT(this_ret == 0);
-                       BT_ASSERT_PRE_MSG("Invalid structure field's field: "
-                               "%![struct-field-]+f, field-name=\"%s\", "
-                               "index=%" PRId64 ", %![field-]+f",
-                               field, name, i, structure->fields->pdata[i]);
-                       goto end;
-               }
+       if (struct_field->fields) {
+               g_ptr_array_free(struct_field->fields, TRUE);
        }
 
-end:
-       return ret;
+       g_free(field);
 }
 
 static
-int bt_field_variant_validate_recursive(struct bt_field *field)
+void destroy_variant_field(struct bt_field *field)
 {
-       int ret = 0;
-       struct bt_field_variant *variant = (void *) field;
+       struct bt_field_variant *var_field = (void *) field;
 
        BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying variant field object: %!+f", field);
+       bt_field_finalize(field);
 
-       if (!variant->current_field) {
-               ret = -1;
-               goto end;
+       if (var_field->fields) {
+               g_ptr_array_free(var_field->fields, TRUE);
        }
 
-       ret = bt_field_validate_recursive(variant->current_field);
-
-end:
-       return ret;
+       g_free(field);
 }
 
 static
-int bt_field_array_validate_recursive(struct bt_field *field)
+void destroy_array_field(struct bt_field *field)
 {
-       int64_t i;
-       int ret = 0;
-       struct bt_field_array *array = (void *) field;
+       struct bt_field_array *array_field = (void *) field;
 
        BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying array field object: %!+f", field);
+       bt_field_finalize(field);
 
-       for (i = 0; i < array->elements->len; i++) {
-               ret = bt_field_validate_recursive((void *) array->elements->pdata[i]);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid array field's element field: "
-                               "%![array-field-]+f, " PRId64 ", "
-                               "%![elem-field-]+f",
-                               field, i, array->elements->pdata[i]);
-                       goto end;
-               }
+       if (array_field->fields) {
+               g_ptr_array_free(array_field->fields, TRUE);
        }
 
-end:
-       return ret;
+       g_free(field);
 }
 
 static
-int bt_field_sequence_validate_recursive(struct bt_field *field)
+void destroy_string_field(struct bt_field *field)
 {
-       size_t i;
-       int ret = 0;
-       struct bt_field_sequence *sequence = (void *) field;
+       struct bt_field_string *string_field = (void *) field;
 
        BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying string field object: %!+f", field);
+       bt_field_finalize(field);
 
-       for (i = 0; i < sequence->elements->len; i++) {
-               ret = bt_field_validate_recursive(
-                       (void *) sequence->elements->pdata[i]);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid sequence field's element field: "
-                               "%![seq-field-]+f, " PRId64 ", "
-                               "%![elem-field-]+f",
-                               field, i, sequence->elements->pdata[i]);
-                       goto end;
-               }
+       if (string_field->buf) {
+               g_array_free(string_field->buf, TRUE);
        }
-end:
-       return ret;
+
+       g_free(field);
 }
 
-static
-void bt_field_generic_reset(struct bt_field *field)
+BT_HIDDEN
+void bt_field_destroy(struct bt_field *field)
 {
        BT_ASSERT(field);
-       field->payload_set = false;
+       BT_ASSERT(bt_field_type_has_known_id(field->type));
+       field_destroy_funcs[field->type->id](field);
 }
 
 static
-void bt_field_structure_reset_recursive(struct bt_field *field)
+void reset_single_field(struct bt_field *field)
 {
-       int64_t i;
-       struct bt_field_structure *structure = (void *) field;
-
        BT_ASSERT(field);
-
-       for (i = 0; i < structure->fields->len; i++) {
-               struct bt_field *member = structure->fields->pdata[i];
-
-               if (!member) {
-                       /*
-                        * Structure members are lazily initialized;
-                        * skip if this member has not been allocated
-                        * yet.
-                        */
-                       continue;
-               }
-
-               bt_field_reset_recursive(member);
-       }
+       field->is_set = false;
 }
 
 static
-void bt_field_variant_reset_recursive(struct bt_field *field)
+void reset_structure_field(struct bt_field *field)
 {
-       struct bt_field_variant *variant = (void *) field;
+       uint64_t i;
+       struct bt_field_structure *struct_field = (void *) field;
 
        BT_ASSERT(field);
-       variant->current_field = NULL;
+
+       for (i = 0; i < struct_field->fields->len; i++) {
+               bt_field_reset(struct_field->fields->pdata[i]);
+       }
 }
 
 static
-void bt_field_array_reset_recursive(struct bt_field *field)
+void reset_variant_field(struct bt_field *field)
 {
-       size_t i;
-       struct bt_field_array *array = (void *) field;
+       uint64_t i;
+       struct bt_field_variant *var_field = (void *) field;
 
        BT_ASSERT(field);
 
-       for (i = 0; i < array->elements->len; i++) {
-               struct bt_field *member = array->elements->pdata[i];
-
-               if (!member) {
-                       /*
-                        * Array elements are lazily initialized; skip
-                        * if this member has not been allocated yet.
-                        */
-                       continue;
-               }
-
-               bt_field_reset_recursive(member);
+       for (i = 0; i < var_field->fields->len; i++) {
+               bt_field_reset(var_field->fields->pdata[i]);
        }
 }
 
 static
-void bt_field_sequence_reset_recursive(struct bt_field *field)
+void reset_array_field(struct bt_field *field)
 {
-       struct bt_field_sequence *sequence = (void *) field;
        uint64_t i;
+       struct bt_field_array *array_field = (void *) field;
 
        BT_ASSERT(field);
 
-       for (i = 0; i < sequence->elements->len; i++) {
-               if (sequence->elements->pdata[i]) {
-                       bt_field_reset_recursive(
-                               sequence->elements->pdata[i]);
-               }
+       for (i = 0; i < array_field->fields->len; i++) {
+               bt_field_reset(array_field->fields->pdata[i]);
        }
-
-       sequence->length = 0;
 }
 
 static
-void bt_field_generic_set_is_frozen(struct bt_field *field,
-               bool is_frozen)
+void set_single_field_is_frozen(struct bt_field *field, bool is_frozen)
 {
        field->frozen = is_frozen;
 }
 
 static
-void bt_field_structure_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen)
+void set_structure_field_is_frozen(struct bt_field *field, bool is_frozen)
 {
        uint64_t i;
-       struct bt_field_structure *structure_field = (void *) field;
+       struct bt_field_structure *struct_field = (void *) field;
 
-       BT_LOGD("Freezing structure field object: addr=%p", field);
+       BT_LIB_LOGD("Setting structure field's frozen state: "
+               "%![field-]+f, is-frozen=%d", field, is_frozen);
 
-       for (i = 0; i < structure_field->fields->len; i++) {
-               struct bt_field *struct_field =
-                       g_ptr_array_index(structure_field->fields, i);
+       for (i = 0; i < struct_field->fields->len; i++) {
+               struct bt_field *member_field = struct_field->fields->pdata[i];
 
-               BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64,
-                       struct_field, i);
-               bt_field_set_is_frozen_recursive(struct_field,
-                       is_frozen);
+               BT_LIB_LOGD("Setting structure field's member field's "
+                       "frozen state: %![field-]+f, index=%" PRIu64,
+                       member_field, i);
+               bt_field_set_is_frozen(member_field, is_frozen);
        }
 
-       bt_field_generic_set_is_frozen(field, is_frozen);
+       set_single_field_is_frozen(field, is_frozen);
 }
 
 static
-void bt_field_variant_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen)
+void set_variant_field_is_frozen(struct bt_field *field, bool is_frozen)
 {
        uint64_t i;
-       struct bt_field_variant *variant_field = (void *) field;
+       struct bt_field_variant *var_field = (void *) field;
 
-       BT_LOGD("Freezing variant field object: addr=%p", field);
+       BT_LIB_LOGD("Setting variant field's frozen state: "
+               "%![field-]+f, is-frozen=%d", field, is_frozen);
 
-       for (i = 0; i < variant_field->fields->len; i++) {
-               struct bt_field *var_field =
-                       g_ptr_array_index(variant_field->fields, i);
+       for (i = 0; i < var_field->fields->len; i++) {
+               struct bt_field *option_field = var_field->fields->pdata[i];
 
-               BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64,
-                       var_field, i);
-               bt_field_set_is_frozen_recursive(var_field, is_frozen);
+               BT_LIB_LOGD("Setting variant field's option field's "
+                       "frozen state: %![field-]+f, index=%" PRIu64,
+                       option_field, i);
+               bt_field_set_is_frozen(option_field, is_frozen);
        }
 
-       bt_field_generic_set_is_frozen(field, is_frozen);
+       set_single_field_is_frozen(field, is_frozen);
 }
 
 static
-void bt_field_array_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen)
+void set_array_field_is_frozen(struct bt_field *field, bool is_frozen)
 {
-       int64_t i;
+       uint64_t i;
        struct bt_field_array *array_field = (void *) field;
 
-       BT_LOGD("Freezing array field object: addr=%p", field);
+       BT_LIB_LOGD("Setting array field's frozen state: "
+               "%![field-]+f, is-frozen=%d", field, is_frozen);
 
-       for (i = 0; i < array_field->elements->len; i++) {
-               struct bt_field *elem_field =
-                       g_ptr_array_index(array_field->elements, i);
+       for (i = 0; i < array_field->fields->len; i++) {
+               struct bt_field *elem_field = array_field->fields->pdata[i];
 
-               BT_LOGD("Freezing array field object's element field: "
-                       "element-field-addr=%p, index=%" PRId64,
+               BT_LIB_LOGD("Setting array field's element field's "
+                       "frozen state: %![field-]+f, index=%" PRIu64,
                        elem_field, i);
-               bt_field_set_is_frozen_recursive(elem_field, is_frozen);
+               bt_field_set_is_frozen(elem_field, is_frozen);
        }
 
-       bt_field_generic_set_is_frozen(field, is_frozen);
-}
-
-static
-void bt_field_sequence_set_is_frozen_recursive(
-               struct bt_field *field, bool is_frozen)
-{
-       int64_t i;
-       struct bt_field_sequence *sequence_field = (void *) field;
-
-       BT_LOGD("Freezing sequence field object: addr=%p", field);
-
-       for (i = 0; i < sequence_field->length; i++) {
-               struct bt_field *elem_field =
-                       g_ptr_array_index(sequence_field->elements, i);
-
-               BT_LOGD("Freezing sequence field object's element field: "
-                       "element-field-addr=%p, index=%" PRId64,
-                       elem_field, i);
-               bt_field_set_is_frozen_recursive(elem_field, is_frozen);
-       }
-
-       bt_field_generic_set_is_frozen(field, is_frozen);
+       set_single_field_is_frozen(field, is_frozen);
 }
 
 BT_HIDDEN
-void _bt_field_set_is_frozen_recursive(struct bt_field *field,
+void _bt_field_set_is_frozen(struct bt_field *field,
                bool is_frozen)
 {
-       if (!field) {
-               goto end;
-       }
-
-       BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d",
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Setting field object's frozen state: %!+f, is-frozen=%d",
                field, is_frozen);
-       BT_ASSERT(bt_field_type_has_known_id(field->type));
        BT_ASSERT(field->methods->set_is_frozen);
        field->methods->set_is_frozen(field, is_frozen);
-
-end:
-       return;
 }
 
 static
-bt_bool bt_field_generic_is_set(struct bt_field *field)
+bool single_field_is_set(struct bt_field *field)
 {
-       return field && field->payload_set;
+       BT_ASSERT(field);
+       return field->is_set;
 }
 
 static
-bt_bool bt_field_structure_is_set_recursive(
-               struct bt_field *field)
+bool structure_field_is_set(struct bt_field *field)
 {
-       bt_bool is_set = BT_FALSE;
-       size_t i;
-       struct bt_field_structure *structure = (void *) field;
+       bool is_set = true;
+       uint64_t i;
+       struct bt_field_structure *struct_field = (void *) field;
 
        BT_ASSERT(field);
 
-       for (i = 0; i < structure->fields->len; i++) {
-               is_set = bt_field_is_set_recursive(
-                       structure->fields->pdata[i]);
+       for (i = 0; i < struct_field->fields->len; i++) {
+               is_set = bt_field_is_set(struct_field->fields->pdata[i]);
                if (!is_set) {
                        goto end;
                }
@@ -1600,57 +1069,31 @@ end:
 }
 
 static
-bt_bool bt_field_variant_is_set_recursive(struct bt_field *field)
-{
-       struct bt_field_variant *variant = (void *) field;
-       bt_bool is_set = BT_FALSE;
-
-       BT_ASSERT(field);
-
-       if (variant->current_field) {
-               is_set = bt_field_is_set_recursive(
-                       variant->current_field);
-       }
-
-       return is_set;
-}
-
-static
-bt_bool bt_field_array_is_set_recursive(struct bt_field *field)
+bool variant_field_is_set(struct bt_field *field)
 {
-       size_t i;
-       bt_bool is_set = BT_FALSE;
-       struct bt_field_array *array = (void *) field;
+       struct bt_field_variant *var_field = (void *) field;
+       bool is_set = false;
 
        BT_ASSERT(field);
 
-       for (i = 0; i < array->elements->len; i++) {
-               is_set = bt_field_is_set_recursive(array->elements->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
+       if (var_field->selected_field) {
+               is_set = bt_field_is_set(var_field->selected_field);
        }
 
-end:
        return is_set;
 }
 
 static
-bt_bool bt_field_sequence_is_set_recursive(struct bt_field *field)
+bool array_field_is_set(struct bt_field *field)
 {
-       size_t i;
-       bt_bool is_set = BT_FALSE;
-       struct bt_field_sequence *sequence = (void *) field;
+       bool is_set = true;
+       uint64_t i;
+       struct bt_field_array *array_field = (void *) field;
 
        BT_ASSERT(field);
 
-       if (!sequence->elements) {
-               goto end;
-       }
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               is_set = bt_field_is_set_recursive(
-                       sequence->elements->pdata[i]);
+       for (i = 0; i < array_field->length; i++) {
+               is_set = bt_field_is_set(array_field->fields->pdata[i]);
                if (!is_set) {
                        goto end;
                }
index 598f1cf2928799f493c006da2d5836b9a62ee22c..55fdb7f4462e59d5663320646d076bf4c085525a 100644 (file)
@@ -24,6 +24,7 @@
 #include <babeltrace/lib-logging-internal.h>
 
 #include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/packet-context-field.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
@@ -35,9 +36,7 @@ struct bt_field *bt_packet_context_field_borrow_field(
        struct bt_field_wrapper *field_wrapper = (void *) context_field;
 
        BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet context field");
-       BT_ASSERT_PRE_NON_NULL(field_wrapper->field,
-               "Packet context field's field object");
-       return (void *) field_wrapper->field;
+       return field_wrapper->field;
 }
 
 void bt_packet_context_field_release(struct bt_packet_context_field *context_field)
@@ -50,8 +49,42 @@ void bt_packet_context_field_release(struct bt_packet_context_field *context_fie
         * Do not recycle because the pool could be destroyed at this
         * point. This function is only called when there's an error
         * anyway because the goal of a packet context field wrapper is
-        * to eventually move it to a packet with bt_packet_move_context()
-        * after creating it.
+        * to eventually move it to a packet with
+        * bt_packet_move_context() after creating it.
         */
        bt_field_wrapper_destroy(field_wrapper);
 }
+
+struct bt_packet_context_field *bt_packet_context_field_create(
+               struct bt_stream_class *stream_class)
+{
+       struct bt_field_wrapper *field_wrapper;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(stream_class->frozen,
+               "Stream class is not part of a trace: %!+S", stream_class);
+       BT_ASSERT_PRE(stream_class->packet_context_ft,
+               "Stream class has no packet context field type: %!+S",
+               stream_class);
+       field_wrapper = bt_field_wrapper_create(
+               &stream_class->packet_context_field_pool,
+               (void *) stream_class->packet_context_ft);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one packet context field from stream class: "
+                       "%![sc-]+S", stream_class);
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       bt_stream_class_freeze(stream_class);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return (void *) field_wrapper;
+}
index 58d2716b3b9fc5ba81bdba186acc00cb2f1e98e1..17d88ad09cdcf40f55b1d8cee095ea6cc3bc4a3e 100644 (file)
@@ -24,6 +24,7 @@
 #include <babeltrace/lib-logging-internal.h>
 
 #include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/ctf-ir/trace-internal.h>
 #include <babeltrace/ctf-ir/packet-header-field.h>
 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
@@ -34,9 +35,7 @@ struct bt_field *bt_packet_header_field_borrow_field(
 {
        struct bt_field_wrapper *field_wrapper = (void *) header_field;
 
-       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Event header field");
-       BT_ASSERT_PRE_NON_NULL(field_wrapper->field,
-               "Event header field's field object");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet header field");
        return (void *) field_wrapper->field;
 }
 
@@ -44,7 +43,7 @@ void bt_packet_header_field_release(struct bt_packet_header_field *header_field)
 {
        struct bt_field_wrapper *field_wrapper = (void *) header_field;
 
-       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Event header field");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet header field");
 
        /*
         * Do not recycle because the pool could be destroyed at this
@@ -55,3 +54,34 @@ void bt_packet_header_field_release(struct bt_packet_header_field *header_field)
         */
        bt_field_wrapper_destroy(field_wrapper);
 }
+
+struct bt_packet_header_field *bt_packet_header_field_create(
+               struct bt_trace *trace)
+{
+       struct bt_field_wrapper *field_wrapper;
+
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(trace->packet_header_ft,
+               "Trace has no packet header field type: %!+t", trace);
+       field_wrapper = bt_field_wrapper_create(
+               &trace->packet_header_field_pool,
+               (void *) trace->packet_header_ft);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one packet header field from trace: "
+                       "%![trace-]+t", trace);
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       bt_trace_freeze(trace);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return (void *) field_wrapper;
+}
index 43506ef8c1bc54404c5e67e178ed611b2771cfeb..d3fce47af34e1a872c653609ce9114f5aa5d7cc8 100644 (file)
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/stream-internal.h>
+#include <babeltrace/ctf-ir/clock-value-internal.h>
 #include <babeltrace/ctf-ir/trace-internal.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/assert-internal.h>
 #include <inttypes.h>
 
+#define BT_ASSERT_PRE_PACKET_HOT(_packet) \
+       BT_ASSERT_PRE_HOT((_packet), "Packet", ": %!+a", (_packet))
+
 struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
        return packet->stream;
 }
 
-struct bt_field *bt_packet_borrow_header(struct bt_packet *packet)
+struct bt_field *bt_packet_borrow_header_field(struct bt_packet *packet)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       return packet->header ? (void *) packet->header->field : NULL;
+       return packet->header_field ? packet->header_field->field : NULL;
 }
 
-struct bt_field *bt_packet_borrow_context(struct bt_packet *packet)
+struct bt_field *bt_packet_borrow_context_field(struct bt_packet *packet)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       return packet->context ? (void *) packet->context->field : NULL;
+       return packet->context_field ? packet->context_field->field : NULL;
 }
 
 BT_HIDDEN
@@ -68,20 +72,18 @@ void _bt_packet_set_is_frozen(struct bt_packet *packet, bool is_frozen)
                return;
        }
 
-       BT_LOGD("Setting packet's frozen state: addr=%p, frozen=%d",
-               packet, is_frozen);
+       BT_LIB_LOGD("Setting packet's frozen state: %![packet-]+a, "
+               "is-frozen=%d", packet, is_frozen);
 
-       if (packet->header) {
-               BT_LOGD("Setting packet's header field's frozen state: "
-                       "frozen=%d", is_frozen);
-               bt_field_set_is_frozen_recursive((void *) packet->header->field,
+       if (packet->header_field) {
+               BT_LOGD_STR("Setting packet's header field's frozen state.");
+               bt_field_set_is_frozen(packet->header_field->field,
                        is_frozen);
        }
 
-       if (packet->context) {
-               BT_LOGD("Setting packet's context field's frozen state: "
-                       "frozen=%d", is_frozen);
-               bt_field_set_is_frozen_recursive((void *) packet->context->field,
+       if (packet->context_field) {
+               BT_LOGD_STR("Setting packet's context field's frozen state.");
+               bt_field_set_is_frozen(packet->context_field->field,
                        is_frozen);
        }
 
@@ -89,62 +91,44 @@ void _bt_packet_set_is_frozen(struct bt_packet *packet, bool is_frozen)
 }
 
 static inline
-void bt_packet_reset_avail(struct bt_packet *packet)
+void reset_counter_snapshots(struct bt_packet *packet)
 {
-       /* Previous packet */
-       packet->prev_packet_info.avail =
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NOT_AVAILABLE;
-       packet->prev_packet_info.discarded_event_counter.avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-       packet->prev_packet_info.seq_num.avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-       packet->prev_packet_info.default_end_cv.avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-
-       /* Current packet */
-       packet->discarded_event_counter.avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-       packet->seq_num.avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-
-       /* Computed */
-       packet->discarded_event_count.avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-       packet->discarded_packet_count.avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
+       packet->discarded_event_counter_snapshot.base.avail =
+               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
+       packet->packet_counter_snapshot.base.avail =
+               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
 }
 
 static inline
-void bt_packet_reset(struct bt_packet *packet)
+void reset_packet(struct bt_packet *packet)
 {
        BT_ASSERT(packet);
+       BT_LIB_LOGD("Resetting packet: %!+a", packet);
        bt_packet_set_is_frozen(packet, false);
 
-       if (packet->header) {
-               bt_field_set_is_frozen_recursive(
-                       (void *) packet->header->field, false);
-               bt_field_reset_recursive((void *) packet->header->field);
+       if (packet->header_field) {
+               bt_field_set_is_frozen(packet->header_field->field, false);
+               bt_field_reset(packet->header_field->field);
        }
 
-       if (packet->context) {
-               bt_field_set_is_frozen_recursive(
-                       (void *) packet->context->field, false);
-               bt_field_reset_recursive((void *) packet->context->field);
+       if (packet->context_field) {
+               bt_field_set_is_frozen(packet->context_field->field, false);
+               bt_field_reset(packet->context_field->field);
        }
 
-       bt_clock_value_set_reset(&packet->begin_cv_set);
-       bt_clock_value_set_reset(&packet->end_cv_set);
-       bt_packet_reset_avail(packet);
-       bt_packet_invalidate_properties(packet);
+       if (packet->default_beginning_cv) {
+               bt_clock_value_reset(packet->default_beginning_cv);
+       }
 
-       if (packet->prev_packet_info.default_end_cv.cv) {
-               bt_clock_value_recycle(packet->prev_packet_info.default_end_cv.cv);
-               packet->prev_packet_info.default_end_cv.cv = NULL;
+       if (packet->default_end_cv) {
+               bt_clock_value_reset(packet->default_end_cv);
        }
+
+       reset_counter_snapshots(packet);
 }
 
 static
-void bt_packet_header_field_recycle(struct bt_field_wrapper *header_field,
+void recycle_header_field(struct bt_field_wrapper *header_field,
                struct bt_trace *trace)
 {
        BT_ASSERT(header_field);
@@ -156,7 +140,7 @@ void bt_packet_header_field_recycle(struct bt_field_wrapper *header_field,
 }
 
 static
-void bt_packet_context_field_recycle(struct bt_field_wrapper *context_field,
+void recycle_context_field(struct bt_field_wrapper *context_field,
                struct bt_stream_class *stream_class)
 {
        BT_ASSERT(context_field);
@@ -197,7 +181,7 @@ void bt_packet_recycle(struct bt_packet *packet)
         *
         * 4. Put our stream reference.
         */
-       bt_packet_reset(packet);
+       reset_packet(packet);
        stream = packet->stream;
        BT_ASSERT(stream);
        packet->stream = NULL;
@@ -208,32 +192,39 @@ void bt_packet_recycle(struct bt_packet *packet)
 BT_HIDDEN
 void bt_packet_destroy(struct bt_packet *packet)
 {
-       BT_LOGD("Destroying packet: addr=%p", packet);
-       BT_LOGD_STR("Destroying packet's header field.");
+       BT_LIB_LOGD("Destroying packet: %!+a", packet);
 
-       if (packet->header) {
+       if (packet->header_field) {
                if (packet->stream) {
                        BT_LOGD_STR("Recycling packet's header field.");
-                       bt_packet_header_field_recycle(packet->header,
-                               bt_stream_class_borrow_trace(
-                                       bt_stream_borrow_class(packet->stream)));
+                       recycle_header_field(packet->header_field,
+                               bt_stream_class_borrow_trace_inline(
+                                       packet->stream->class));
                } else {
-                       bt_field_wrapper_destroy(packet->header);
+                       bt_field_wrapper_destroy(packet->header_field);
                }
        }
 
-       if (packet->context) {
+       if (packet->context_field) {
                if (packet->stream) {
                        BT_LOGD_STR("Recycling packet's context field.");
-                       bt_packet_context_field_recycle(packet->context,
-                               bt_stream_borrow_class(packet->stream));
+                       recycle_context_field(packet->context_field,
+                               packet->stream->class);
                } else {
-                       bt_field_wrapper_destroy(packet->context);
+                       bt_field_wrapper_destroy(packet->context_field);
                }
        }
 
-       bt_clock_value_set_finalize(&packet->begin_cv_set);
-       bt_clock_value_set_finalize(&packet->end_cv_set);
+       if (packet->default_beginning_cv) {
+               BT_LOGD_STR("Recycling beginning clock value.");
+               bt_clock_value_recycle(packet->default_beginning_cv);
+       }
+
+       if (packet->default_end_cv) {
+               BT_LOGD_STR("Recycling end clock value.");
+               bt_clock_value_recycle(packet->default_end_cv);
+       }
+
        BT_LOGD_STR("Putting packet's stream.");
        bt_put(packet->stream);
        g_free(packet);
@@ -243,281 +234,80 @@ BT_HIDDEN
 struct bt_packet *bt_packet_new(struct bt_stream *stream)
 {
        struct bt_packet *packet = NULL;
-       struct bt_stream_class *stream_class = NULL;
        struct bt_trace *trace = NULL;
 
        BT_ASSERT(stream);
-       BT_LOGD("Creating packet object: stream-addr=%p, "
-               "stream-name=\"%s\", stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-class-id=%" PRId64,
-               stream, bt_stream_get_name(stream),
-               stream->stream_class,
-               bt_stream_class_get_name(stream->stream_class),
-               bt_stream_class_get_id(stream->stream_class));
-       stream_class = bt_stream_borrow_class(stream);
-       BT_ASSERT(stream_class);
-       trace = bt_stream_class_borrow_trace(stream_class);
-       BT_ASSERT(trace);
+       BT_LIB_LOGD("Creating packet object: %![stream-]+s", stream);
        packet = g_new0(struct bt_packet, 1);
        if (!packet) {
                BT_LOGE_STR("Failed to allocate one packet object.");
-               goto end;
+               goto error;
        }
 
        bt_object_init_shared(&packet->base,
                (bt_object_release_func) bt_packet_recycle);
        packet->stream = bt_get(stream);
+       trace = bt_stream_class_borrow_trace_inline(stream->class);
+       BT_ASSERT(trace);
 
-       if (trace->packet_header_field_type) {
-               BT_LOGD("Creating initial packet header field: ft-addr=%p",
-                       trace->packet_header_field_type);
-               packet->header = bt_field_wrapper_create(
+       if (trace->packet_header_ft) {
+               BT_LOGD_STR("Creating initial packet header field.");
+               packet->header_field = bt_field_wrapper_create(
                        &trace->packet_header_field_pool,
-                       (void *) trace->packet_header_field_type);
-               if (!packet->header) {
-                       BT_LOGE("Cannot create packet header field wrapper.");
-                       BT_PUT(packet);
-                       goto end;
+                       trace->packet_header_ft);
+               if (!packet->header_field) {
+                       BT_LOGE_STR("Cannot create packet header field wrapper.");
+                       goto error;
                }
        }
 
-       if (stream->stream_class->packet_context_field_type) {
-               BT_LOGD("Creating initial packet context field: ft-addr=%p",
-                       stream->stream_class->packet_context_field_type);
-               packet->context = bt_field_wrapper_create(
-                       &stream_class->packet_context_field_pool,
-                       (void *) stream->stream_class->packet_context_field_type);
-               if (!packet->context) {
-                       BT_LOGE("Cannot create packet context field wrapper.");
-                       BT_PUT(packet);
-                       goto end;
+       if (stream->class->packet_context_ft) {
+               BT_LOGD_STR("Creating initial packet context field.");
+               packet->context_field = bt_field_wrapper_create(
+                       &stream->class->packet_context_field_pool,
+                       stream->class->packet_context_ft);
+               if (!packet->context_field) {
+                       BT_LOGE_STR("Cannot create packet context field wrapper.");
+                       goto error;
                }
        }
 
-       if (bt_clock_value_set_initialize(&packet->begin_cv_set)) {
-               BT_PUT(packet);
-               goto end;
-       }
-
-       if (bt_clock_value_set_initialize(&packet->end_cv_set)) {
-               BT_PUT(packet);
-               goto end;
-       }
-
-       bt_packet_reset_avail(packet);
-       BT_LOGD("Created packet object: addr=%p", packet);
-
-end:
-       return packet;
-}
-
-static inline
-uint64_t get_uint_field_value(struct bt_field *parent_field, const char *name)
-{
-       uint64_t val = UINT64_C(-1);
-       struct bt_field *field = bt_field_structure_borrow_field_by_name(
-               parent_field, name);
-       int ret;
-
-       if (!field) {
-               goto end;
-       }
-
-       BT_ASSERT(bt_field_is_integer(field));
-       BT_ASSERT(!bt_field_type_integer_is_signed(
-               bt_field_borrow_type(field)));
-       ret = bt_field_integer_unsigned_get_value(field, &val);
-       BT_ASSERT(ret == 0);
-
-end:
-       return val;
-}
-
-static inline
-void set_packet_prop_uint64(struct bt_packet_prop_uint64 *prop, uint64_t val)
-{
-       BT_ASSERT(prop);
-       prop->value = val;
-       prop->avail = BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE;
-}
-
-static inline
-int set_packet_default_clock_value(struct bt_field *pkt_ctx_field,
-               const char *field_name, struct bt_clock_value_set *cv_set)
-{
-       int ret = 0;
-       uint64_t val = UINT64_C(-1);
-       struct bt_field *field = bt_field_structure_borrow_field_by_name(
-               pkt_ctx_field, field_name);
-       struct bt_clock_class *clock_class;
-
-       if (!field) {
-               goto end;
-       }
-
-       BT_ASSERT(bt_field_is_integer(field));
-       BT_ASSERT(!bt_field_type_integer_is_signed(
-               bt_field_borrow_type(field)));
-       clock_class = bt_field_type_integer_borrow_mapped_clock_class(
-               bt_field_borrow_type(field));
-       if (!clock_class) {
-               goto end;
-       }
-
-       ret = bt_field_integer_unsigned_get_value(field, &val);
-       BT_ASSERT(ret == 0);
-       ret = bt_clock_value_set_set_clock_value(cv_set, clock_class,
-               val, true);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_packet_set_properties(struct bt_packet *packet)
-{
-       struct bt_field *pkt_context_field;
-       uint64_t val;
-       int ret = 0;
-
-       BT_ASSERT(!packet->props_are_set);
-
-       pkt_context_field = bt_packet_borrow_context(packet);
-       if (!pkt_context_field) {
-               goto end;
-       }
-
-       /* Discarded event counter */
-       val = get_uint_field_value(pkt_context_field, "events_discarded");
-       if (val != UINT64_C(-1)) {
-               set_packet_prop_uint64(&packet->discarded_event_counter, val);
-       }
-
-       /* Sequence number */
-       val = get_uint_field_value(pkt_context_field, "packet_seq_num");
-       if (val != UINT64_C(-1)) {
-               set_packet_prop_uint64(&packet->seq_num, val);
-       }
-
-       /* Beginning and end times */
-       ret = set_packet_default_clock_value(pkt_context_field,
-               "timestamp_begin", &packet->begin_cv_set);
-       if (ret) {
-               goto end;
-       }
-
-       ret = set_packet_default_clock_value(pkt_context_field,
-               "timestamp_end", &packet->end_cv_set);
-       if (ret) {
-               goto end;
-       }
-
-       /* Information from previous packet */
-       if (packet->prev_packet_info.avail ==
-                       BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_AVAILABLE) {
-               /* Discarded event count */
-               if (packet->prev_packet_info.discarded_event_counter.avail ==
-                               BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE) {
-                       BT_ASSERT(packet->discarded_event_counter.avail ==
-                               BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE);
-                       set_packet_prop_uint64(&packet->discarded_event_count,
-                               packet->discarded_event_counter.value -
-                               packet->prev_packet_info.discarded_event_counter.value);
+       if (stream->class->default_clock_class) {
+               if (stream->class->packets_have_default_beginning_cv) {
+                       packet->default_beginning_cv = bt_clock_value_create(
+                               stream->class->default_clock_class);
+                       if (!packet->default_beginning_cv) {
+                               /* bt_clock_value_create() logs errors */
+                               goto error;
+                       }
                }
 
-               /* Discarded packet count */
-               if (packet->prev_packet_info.seq_num.avail ==
-                               BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE) {
-                       BT_ASSERT(packet->seq_num.avail ==
-                               BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE);
-                       set_packet_prop_uint64(&packet->discarded_packet_count,
-                               packet->seq_num.value -
-                               packet->prev_packet_info.seq_num.value - 1);
+               if (stream->class->packets_have_default_end_cv) {
+                       packet->default_end_cv = bt_clock_value_create(
+                               stream->class->default_clock_class);
+                       if (!packet->default_end_cv) {
+                               /* bt_clock_value_create() logs errors */
+                               goto error;
+                       }
                }
        }
 
-end:
-       return ret;
-}
-
-static
-int snapshot_prev_packet_properties(struct bt_packet *packet,
-               enum bt_packet_previous_packet_availability prev_packet_avail,
-               struct bt_packet *prev_packet)
-{
-       int ret = 0;
-       struct bt_clock_value *prev_packet_default_end_cv;
-
-       if (!prev_packet) {
-               goto end;
-       }
-
-       if (!prev_packet->props_are_set) {
-               ret = bt_packet_set_properties(prev_packet);
-               if (ret) {
-                       BT_LIB_LOGE("Cannot update previous packet's properties: "
-                               "%![prev-packet-]+a", prev_packet);
-                       goto end;
-               }
-       }
-
-       packet->prev_packet_info.avail = prev_packet_avail;
-       prev_packet_default_end_cv = prev_packet->end_cv_set.default_cv;
-
-       /* End time */
-       if (prev_packet_default_end_cv) {
-               /* Copy clock value */
-               packet->prev_packet_info.default_end_cv.cv =
-                       bt_clock_value_create(
-                               prev_packet_default_end_cv->clock_class);
-               if (!packet->prev_packet_info.default_end_cv.cv) {
-                       BT_LIB_LOGE("Cannot create a clock value from a clock class: "
-                               "%![cc-]+K",
-                               prev_packet_default_end_cv->clock_class);
-                       ret = -1;
-                       goto end;
-               }
-
-               bt_clock_value_set_raw_value(
-                       packet->prev_packet_info.default_end_cv.cv,
-                       prev_packet_default_end_cv->value);
-               packet->prev_packet_info.default_end_cv.avail =
-                       BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE;
-       }
-
-       /* Discarded event counter */
-       packet->prev_packet_info.discarded_event_counter =
-               prev_packet->discarded_event_counter;
+       reset_counter_snapshots(packet);
+       BT_LIB_LOGD("Created packet object: %!+a", packet);
+       goto end;
 
-       /* Sequence number */
-       packet->prev_packet_info.seq_num = prev_packet->seq_num;
+error:
+       BT_PUT(packet);
 
 end:
-       return ret;
+       return packet;
 }
 
-struct bt_packet *bt_packet_create(struct bt_stream *stream,
-               enum bt_packet_previous_packet_availability prev_packet_avail,
-               struct bt_packet *prev_packet)
+struct bt_packet *bt_packet_create(struct bt_stream *stream)
 {
        struct bt_packet *packet = NULL;
-       int ret;
 
        BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       BT_ASSERT_PRE(!prev_packet || prev_packet->stream == stream,
-               "New packet's and previous packet's stream are not the same: "
-               "%![new-packet-stream-]+s, %![prev-packet]+a, "
-               "%![prev-packet-stream]+s", stream, prev_packet,
-               prev_packet->stream);
-       BT_ASSERT_PRE(
-               prev_packet_avail == BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_AVAILABLE ||
-               prev_packet_avail == BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NOT_AVAILABLE ||
-               prev_packet_avail == BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE,
-               "Invalid previous packet availability value: val=%d",
-               prev_packet_avail);
-       BT_ASSERT_PRE(!prev_packet ||
-               prev_packet_avail == BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_AVAILABLE,
-               "Previous packet is available, but previous packet is NULL.");
        packet = bt_object_pool_create_object(&stream->packet_pool);
        if (unlikely(!packet)) {
                BT_LIB_LOGE("Cannot allocate one packet from stream's packet pool: "
@@ -525,166 +315,174 @@ struct bt_packet *bt_packet_create(struct bt_stream *stream,
                goto end;
        }
 
-       if (unlikely(!packet->stream)) {
+       if (likely(!packet->stream)) {
                packet->stream = stream;
                bt_object_get_no_null_check_no_parent_check(
                        &packet->stream->base);
        }
 
-       ret = snapshot_prev_packet_properties(packet, prev_packet_avail,
-               prev_packet);
-       if (ret) {
-               /* Recycle */
-               BT_PUT(packet);
-               goto end;
-       }
-
-       if (prev_packet) {
-               bt_packet_validate_properties(prev_packet);
-               bt_packet_set_is_frozen(prev_packet, true);
-       }
-
-       goto end;
-
 end:
        return packet;
 }
 
-int bt_packet_move_header(struct bt_packet *packet,
+int bt_packet_move_header_field(struct bt_packet *packet,
                struct bt_packet_header_field *header_field)
 {
        struct bt_trace *trace;
        struct bt_field_wrapper *field_wrapper = (void *) header_field;
 
-       BT_ASSERT_PRE_NON_NULL(packet, "Event");
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
        BT_ASSERT_PRE_NON_NULL(field_wrapper, "Header field");
-       BT_ASSERT_PRE_HOT(packet, "Packet", ": %!+a", packet);
-       trace = bt_stream_class_borrow_trace(
-               bt_stream_borrow_class(packet->stream));
-       BT_ASSERT_PRE(trace->packet_header_field_type,
+       BT_ASSERT_PRE_PACKET_HOT(packet);
+       trace = bt_stream_class_borrow_trace_inline(packet->stream->class);
+       BT_ASSERT_PRE(trace->packet_header_ft,
                "Trace has no packet header field type: %!+t",
                trace);
-
-       /* TODO: compare field types (precondition) */
+       BT_ASSERT_PRE(field_wrapper->field->type ==
+               trace->packet_header_ft,
+               "Unexpected packet header field's type: "
+               "%![ft-]+F, %![expected-ft-]+F", field_wrapper->field->type,
+               trace->packet_header_ft);
 
        /* Recycle current header field: always exists */
-       BT_ASSERT(packet->header);
-       bt_packet_header_field_recycle(packet->header, trace);
+       BT_ASSERT(packet->header_field);
+       recycle_header_field(packet->header_field, trace);
 
        /* Move new field */
-       packet->header = field_wrapper;
+       packet->header_field = field_wrapper;
        return 0;
 }
 
-int bt_packet_move_context(struct bt_packet *packet,
+int bt_packet_move_context_field(struct bt_packet *packet,
                struct bt_packet_context_field *context_field)
 {
        struct bt_stream_class *stream_class;
        struct bt_field_wrapper *field_wrapper = (void *) context_field;
 
-       BT_ASSERT_PRE_NON_NULL(packet, "Event");
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
        BT_ASSERT_PRE_NON_NULL(field_wrapper, "Context field");
        BT_ASSERT_PRE_HOT(packet, "Packet", ": %!+a", packet);
-       stream_class = bt_stream_borrow_class(packet->stream);
-       BT_ASSERT_PRE(stream_class->packet_context_field_type,
+       stream_class = packet->stream->class;
+       BT_ASSERT_PRE(stream_class->packet_context_ft,
                "Stream class has no packet context field type: %!+S",
                stream_class);
-
-       /* TODO: compare field types (precondition) */
+       BT_ASSERT_PRE(field_wrapper->field->type ==
+               stream_class->packet_context_ft,
+               "Unexpected packet header field's type: "
+               "%![ft-]+F, %![expected-ft-]+F", field_wrapper->field->type,
+               stream_class->packet_context_ft);
 
        /* Recycle current context field: always exists */
-       BT_ASSERT(packet->context);
-       bt_packet_context_field_recycle(packet->context, stream_class);
+       BT_ASSERT(packet->context_field);
+       recycle_context_field(packet->context_field, stream_class);
 
        /* Move new field */
-       packet->context = field_wrapper;
+       packet->context_field = field_wrapper;
        return 0;
 }
 
-enum bt_packet_property_availability
-bt_packet_borrow_default_beginning_clock_value(struct bt_packet *packet,
-               struct bt_clock_value **clock_value)
+int bt_packet_set_default_beginning_clock_value(struct bt_packet *packet,
+               uint64_t value_cycles)
 {
-       enum bt_packet_property_availability avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE;
+       struct bt_stream_class *sc;
 
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
-       *clock_value = packet->begin_cv_set.default_cv;
-       if (!*clock_value) {
-               avail = BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-       }
-
-       return avail;
+       BT_ASSERT_PRE_PACKET_HOT(packet);
+       sc = packet->stream->class;
+       BT_ASSERT(sc);
+       BT_ASSERT_PRE(sc->default_clock_class,
+               "Packet's stream class has no default clock class: "
+               "%![packet-]+a, %![sc-]+S", packet, sc);
+       BT_ASSERT_PRE(sc->packets_have_default_beginning_cv,
+               "Packet's stream class indicates that its packets have "
+               "no default beginning clock value: %![packet-]+a, %![sc-]+S",
+               packet, sc);
+       BT_ASSERT(packet->default_beginning_cv);
+       bt_clock_value_set_value_inline(packet->default_beginning_cv, value_cycles);
+       BT_LIB_LOGV("Set packet's default beginning clock value: "
+               "%![packet-]+a, value=%" PRIu64, value_cycles);
+       return 0;
 }
 
-enum bt_packet_property_availability
-bt_packet_borrow_default_end_clock_value(struct bt_packet *packet,
-               struct bt_clock_value **clock_value)
+enum bt_clock_value_status bt_packet_borrow_default_beginning_clock_value(
+               struct bt_packet *packet, struct bt_clock_value **clock_value)
 {
-       enum bt_packet_property_availability avail =
-               BT_PACKET_PROPERTY_AVAILABILITY_AVAILABLE;
-
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
-       *clock_value = packet->end_cv_set.default_cv;
-       if (!*clock_value) {
-               avail = BT_PACKET_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-       }
-
-       return avail;
+       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value (output)");
+       *clock_value = packet->default_beginning_cv;
+       return BT_CLOCK_VALUE_STATUS_KNOWN;
 }
 
-enum bt_packet_previous_packet_availability
-bt_packet_get_previous_packet_availability(struct bt_packet *packet)
+int bt_packet_set_default_end_clock_value(struct bt_packet *packet,
+               uint64_t value_cycles)
 {
+       struct bt_stream_class *sc;
+
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       return packet->prev_packet_info.avail;
+       BT_ASSERT_PRE_PACKET_HOT(packet);
+       sc = packet->stream->class;
+       BT_ASSERT(sc);
+       BT_ASSERT_PRE(sc->default_clock_class,
+               "Packet's stream class has no default clock class: "
+               "%![packet-]+a, %![sc-]+S", packet, sc);
+       BT_ASSERT_PRE(sc->packets_have_default_end_cv,
+               "Packet's stream class indicates that its packets have "
+               "no default end clock value: %![packet-]+a, %![sc-]+S",
+               packet, sc);
+       BT_ASSERT(packet->default_end_cv);
+       bt_clock_value_set_value_inline(packet->default_end_cv, value_cycles);
+       BT_LIB_LOGV("Set packet's default end clock value: "
+               "%![packet-]+a, value=%" PRIu64, value_cycles);
+       return 0;
 }
 
-enum bt_packet_property_availability
-bt_packet_borrow_previous_packet_default_end_clock_value(
+enum bt_clock_value_status bt_packet_borrow_default_end_clock_value(
                struct bt_packet *packet, struct bt_clock_value **clock_value)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
-       *clock_value = packet->prev_packet_info.default_end_cv.cv;
-       return packet->prev_packet_info.default_end_cv.avail;
+       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value (output)");
+       *clock_value = packet->default_end_cv;
+       return BT_CLOCK_VALUE_STATUS_KNOWN;
 }
 
-enum bt_packet_property_availability bt_packet_get_discarded_event_counter(
-               struct bt_packet *packet, uint64_t *counter)
+enum bt_property_availability bt_packet_get_discarded_event_counter_snapshot(
+               struct bt_packet *packet, uint64_t *value)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(counter, "Counter");
-       *counter = packet->discarded_event_counter.value;
-       return packet->discarded_event_counter.avail;
+       BT_ASSERT_PRE_NON_NULL(value, "Value (output)");
+       *value = packet->discarded_event_counter_snapshot.value;
+       return packet->discarded_event_counter_snapshot.base.avail;
 }
 
-enum bt_packet_property_availability bt_packet_get_sequence_number(
-               struct bt_packet *packet, uint64_t *sequence_number)
+int bt_packet_set_discarded_event_counter_snapshot(struct bt_packet *packet,
+               uint64_t value)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(sequence_number, "Sequence number");
-       *sequence_number = packet->seq_num.value;
-       return packet->seq_num.avail;
+       BT_ASSERT_PRE_PACKET_HOT(packet);
+       BT_ASSERT_PRE(packet->stream->class->packets_have_discarded_event_counter_snapshot,
+               "Packet's stream's discarded event counter is not enabled: "
+               "%![packet-]+a", packet);
+       bt_property_uint_set(&packet->discarded_event_counter_snapshot, value);
+       return 0;
 }
 
-enum bt_packet_property_availability bt_packet_get_discarded_event_count(
-               struct bt_packet *packet, uint64_t *count)
+enum bt_property_availability bt_packet_get_packet_counter_snapshot(
+               struct bt_packet *packet, uint64_t *value)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(count, "Count");
-       *count = packet->discarded_event_count.value;
-       return packet->discarded_event_count.avail;
+       BT_ASSERT_PRE_NON_NULL(value, "Value (output)");
+       *value = packet->packet_counter_snapshot.value;
+       return packet->packet_counter_snapshot.base.avail;
 }
 
-enum bt_packet_property_availability bt_packet_get_discarded_packet_count(
-               struct bt_packet *packet, uint64_t *count)
+int bt_packet_set_packet_counter_snapshot(struct bt_packet *packet,
+               uint64_t value)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(count, "Count");
-       *count = packet->discarded_packet_count.value;
-       return packet->discarded_packet_count.avail;
+       BT_ASSERT_PRE_PACKET_HOT(packet);
+       BT_ASSERT_PRE(packet->stream->class->packets_have_packet_counter_snapshot,
+               "Packet's stream's packet counter is not enabled: "
+               "%![packet-]+a", packet);
+       bt_property_uint_set(&packet->packet_counter_snapshot, value);
+       return 0;
 }
-
diff --git a/lib/ctf-ir/resolve-field-path.c b/lib/ctf-ir/resolve-field-path.c
new file mode 100644 (file)
index 0000000..6036758
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "RESOLVE-FIELD-PATH"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <babeltrace/ctf-ir/field-types-internal.h>
+#include <babeltrace/ctf-ir/field-path-internal.h>
+#include <babeltrace/ctf-ir/field-path.h>
+#include <babeltrace/ctf-ir/resolve-field-path-internal.h>
+#include <limits.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <glib.h>
+
+static
+bool find_field_type_recursive(struct bt_field_type *ft,
+               struct bt_field_type *tgt_ft, struct bt_field_path *field_path)
+{
+       bool found = false;
+
+       if (tgt_ft == ft) {
+               found = true;
+               goto end;
+       }
+
+       switch (ft->id) {
+       case BT_FIELD_TYPE_ID_STRUCTURE:
+       case BT_FIELD_TYPE_ID_VARIANT:
+       {
+               struct bt_field_type_named_field_types_container *container_ft =
+                       (void *) ft;
+               uint64_t i;
+
+               for (i = 0; i < container_ft->named_fts->len; i++) {
+                       struct bt_named_field_type *named_ft =
+                               BT_FIELD_TYPE_NAMED_FT_AT_INDEX(
+                                       container_ft, i);
+
+                       g_array_append_val(field_path->indexes, i);
+                       found = find_field_type_recursive(named_ft->ft,
+                               tgt_ft, field_path);
+                       if (found) {
+                               goto end;
+                       }
+
+                       g_array_set_size(field_path->indexes,
+                               field_path->indexes->len - 1);
+               }
+
+               break;
+       }
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
+       {
+               struct bt_field_type_array *array_ft = (void *) ft;
+
+               found = find_field_type_recursive(array_ft->element_ft,
+                       tgt_ft, field_path);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return found;
+}
+
+static
+int find_field_type(struct bt_field_type *root_ft,
+               enum bt_scope root_scope, struct bt_field_type *tgt_ft,
+               struct bt_field_path **ret_field_path)
+{
+       int ret = 0;
+       struct bt_field_path *field_path = NULL;
+
+       if (!root_ft) {
+               goto end;
+       }
+
+       field_path = bt_field_path_create();
+       if (!field_path) {
+               ret = -1;
+               goto end;
+       }
+
+       field_path->root = root_scope;
+       if (!find_field_type_recursive(root_ft, tgt_ft, field_path)) {
+               /* Not found here */
+               BT_PUT(field_path);
+       }
+
+end:
+       *ret_field_path = field_path;
+       return ret;
+}
+
+static
+struct bt_field_path *find_field_type_in_ctx(struct bt_field_type *ft,
+               struct bt_resolve_field_path_context *ctx)
+{
+       struct bt_field_path *field_path = NULL;
+       int ret;
+
+       ret = find_field_type(ctx->packet_header, BT_SCOPE_PACKET_HEADER,
+               ft, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_type(ctx->packet_context, BT_SCOPE_PACKET_CONTEXT,
+               ft, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_type(ctx->event_header, BT_SCOPE_EVENT_HEADER,
+               ft, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_type(ctx->event_common_context,
+               BT_SCOPE_EVENT_COMMON_CONTEXT, ft, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_type(ctx->event_specific_context,
+               BT_SCOPE_EVENT_SPECIFIC_CONTEXT, ft, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_type(ctx->event_payload, BT_SCOPE_EVENT_PAYLOAD,
+               ft, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+end:
+       return field_path;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool target_is_before_source(struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path)
+{
+       bool is_valid = true;
+       uint64_t src_i = 0, tgt_i = 0;
+
+       if (tgt_field_path->root < src_field_path->root) {
+               goto end;
+       }
+
+       if (tgt_field_path->root > src_field_path->root) {
+               is_valid = false;
+               goto end;
+       }
+
+       BT_ASSERT(tgt_field_path->root == src_field_path->root);
+
+       while (src_i < src_field_path->indexes->len &&
+                       tgt_i < tgt_field_path->indexes->len) {
+               uint64_t src_index = bt_field_path_get_index_by_index_inline(
+                       src_field_path, src_i);
+               uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
+                       tgt_field_path, tgt_i);
+
+               if (tgt_index > src_index) {
+                       is_valid = false;
+                       goto end;
+               }
+
+               src_i++;
+               tgt_i++;
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+struct bt_field_type *borrow_root_field_type(
+               struct bt_resolve_field_path_context *ctx, enum bt_scope scope)
+{
+       switch (scope) {
+       case BT_SCOPE_PACKET_HEADER:
+               return ctx->packet_header;
+       case BT_SCOPE_PACKET_CONTEXT:
+               return ctx->packet_context;
+       case BT_SCOPE_EVENT_HEADER:
+               return ctx->event_header;
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               return ctx->event_common_context;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               return ctx->event_specific_context;
+       case BT_SCOPE_EVENT_PAYLOAD:
+               return ctx->event_payload;
+       default:
+               abort();
+       }
+
+       return NULL;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+struct bt_field_type *borrow_child_field_type(struct bt_field_type *parent_ft,
+               uint64_t index, bool *advance)
+{
+       struct bt_field_type *child_ft = NULL;
+
+       switch (parent_ft->id) {
+       case BT_FIELD_TYPE_ID_STRUCTURE:
+       case BT_FIELD_TYPE_ID_VARIANT:
+       {
+               struct bt_named_field_type *named_ft =
+                       BT_FIELD_TYPE_NAMED_FT_AT_INDEX(parent_ft, index);
+
+               child_ft = named_ft->ft;
+               *advance = true;
+               break;
+       }
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
+       {
+               struct bt_field_type_array *array_ft = (void *) parent_ft;
+
+               child_ft = array_ft->element_ft;
+               *advance = false;
+               break;
+       }
+       default:
+               break;
+       }
+
+       return child_ft;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool target_field_path_in_different_scope_has_struct_ft_only(
+               struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       uint64_t i = 0;
+       struct bt_field_type *ft;
+
+       if (src_field_path->root == tgt_field_path->root) {
+               goto end;
+       }
+
+       ft = borrow_root_field_type(ctx, tgt_field_path->root);
+
+       while (i < tgt_field_path->indexes->len) {
+               uint64_t index = bt_field_path_get_index_by_index_inline(
+                       tgt_field_path, i);
+               bool advance;
+
+               if (ft->id == BT_FIELD_TYPE_ID_STATIC_ARRAY ||
+                               ft->id == BT_FIELD_TYPE_ID_DYNAMIC_ARRAY ||
+                               ft->id == BT_FIELD_TYPE_ID_VARIANT) {
+                       is_valid = false;
+                       goto end;
+               }
+
+               ft = borrow_child_field_type(ft, index, &advance);
+
+               if (advance) {
+                       i++;
+               }
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool lca_is_structure_field_type(struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       struct bt_field_type *src_ft;
+       struct bt_field_type *tgt_ft;
+       struct bt_field_type *prev_ft = NULL;
+       uint64_t src_i = 0, tgt_i = 0;
+
+       if (src_field_path->root != tgt_field_path->root) {
+               goto end;
+       }
+
+       src_ft = borrow_root_field_type(ctx, src_field_path->root);
+       tgt_ft = borrow_root_field_type(ctx, tgt_field_path->root);
+       BT_ASSERT(src_ft);
+       BT_ASSERT(tgt_ft);
+
+       while (src_i < src_field_path->indexes->len &&
+                       tgt_i < tgt_field_path->indexes->len) {
+               bool advance;
+               uint64_t src_index = bt_field_path_get_index_by_index_inline(
+                       src_field_path, src_i);
+               uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
+                       tgt_field_path, tgt_i);
+
+               if (src_ft != tgt_ft) {
+                       if (!prev_ft) {
+                               /*
+                                * This is correct: the LCA is the root
+                                * scope field type, which must be a
+                                * structure field type.
+                                */
+                               break;
+                       }
+
+                       if (prev_ft->id != BT_FIELD_TYPE_ID_STRUCTURE) {
+                               is_valid = false;
+                       }
+
+                       break;
+               }
+
+               prev_ft = src_ft;
+               src_ft = borrow_child_field_type(src_ft, src_index, &advance);
+
+               if (advance) {
+                       src_i++;
+               }
+
+               tgt_ft = borrow_child_field_type(tgt_ft, tgt_index, &advance);
+
+               if (advance) {
+                       tgt_i++;
+               }
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool lca_to_target_has_struct_ft_only(struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       struct bt_field_type *src_ft;
+       struct bt_field_type *tgt_ft;
+       uint64_t src_i = 0, tgt_i = 0;
+
+       if (src_field_path->root != tgt_field_path->root) {
+               goto end;
+       }
+
+       src_ft = borrow_root_field_type(ctx, src_field_path->root);
+       tgt_ft = borrow_root_field_type(ctx, tgt_field_path->root);
+       BT_ASSERT(src_ft);
+       BT_ASSERT(tgt_ft);
+       BT_ASSERT(src_ft == tgt_ft);
+
+       /* Find LCA */
+       while (src_i < src_field_path->indexes->len &&
+                       tgt_i < tgt_field_path->indexes->len) {
+               bool advance;
+               uint64_t src_index = bt_field_path_get_index_by_index_inline(
+                       src_field_path, src_i);
+               uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
+                       tgt_field_path, tgt_i);
+
+               if (src_i != tgt_i) {
+                       /* Next FT is different: LCA is `tgt_ft` */
+                       break;
+               }
+
+               src_ft = borrow_child_field_type(src_ft, src_index, &advance);
+
+               if (advance) {
+                       src_i++;
+               }
+
+               tgt_ft = borrow_child_field_type(tgt_ft, tgt_index, &advance);
+
+               if (advance) {
+                       tgt_i++;
+               }
+       }
+
+       /* Only structure field types to the target */
+       while (tgt_i < tgt_field_path->indexes->len) {
+               bool advance;
+               uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
+                       tgt_field_path, tgt_i);
+
+               if (tgt_ft->id == BT_FIELD_TYPE_ID_STATIC_ARRAY ||
+                               tgt_ft->id == BT_FIELD_TYPE_ID_DYNAMIC_ARRAY ||
+                               tgt_ft->id == BT_FIELD_TYPE_ID_VARIANT) {
+                       is_valid = false;
+                       goto end;
+               }
+
+               tgt_ft = borrow_child_field_type(tgt_ft, tgt_index, &advance);
+
+               if (advance) {
+                       tgt_i++;
+               }
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool field_path_is_valid(struct bt_field_type *src_ft,
+               struct bt_field_type *tgt_ft,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       struct bt_field_path *src_field_path = find_field_type_in_ctx(
+               src_ft, ctx);
+       struct bt_field_path *tgt_field_path = find_field_type_in_ctx(
+               tgt_ft, ctx);
+
+       if (!src_field_path) {
+               BT_ASSERT_PRE_MSG("Cannot find requesting field type in "
+                       "resolving context: %!+F", src_ft);
+               is_valid = false;
+               goto end;
+       }
+
+       if (!tgt_field_path) {
+               BT_ASSERT_PRE_MSG("Cannot find target field type in "
+                       "resolving context: %!+F", tgt_ft);
+               is_valid = false;
+               goto end;
+       }
+
+       /* Target must be before source */
+       if (!target_is_before_source(src_field_path, tgt_field_path)) {
+               BT_ASSERT_PRE_MSG("Target field type is located after "
+                       "requesting field type: %![req-ft-]+F, %![tgt-ft-]+F",
+                       src_ft, tgt_ft);
+               is_valid = false;
+               goto end;
+       }
+
+       /*
+        * If target is in a different scope than source, there are no
+        * array or variant field types on the way to the target.
+        */
+       if (!target_field_path_in_different_scope_has_struct_ft_only(
+                       src_field_path, tgt_field_path, ctx)) {
+               BT_ASSERT_PRE_MSG("Target field type is located in a "
+                       "different scope than requesting field type, "
+                       "but within an array or a variant field type: "
+                       "%![req-ft-]+F, %![tgt-ft-]+F",
+                       src_ft, tgt_ft);
+               is_valid = false;
+               goto end;
+       }
+
+       /* Same scope: LCA must be a structure field type */
+       if (!lca_is_structure_field_type(src_field_path, tgt_field_path, ctx)) {
+               BT_ASSERT_PRE_MSG("Lowest common ancestor of target and "
+                       "requesting field types is not a structure field type: "
+                       "%![req-ft-]+F, %![tgt-ft-]+F",
+                       src_ft, tgt_ft);
+               is_valid = false;
+               goto end;
+       }
+
+       /* Same scope: path from LCA to target has no array/variant FTs */
+       if (!lca_to_target_has_struct_ft_only(src_field_path, tgt_field_path,
+                       ctx)) {
+               BT_ASSERT_PRE_MSG("Path from lowest common ancestor of target "
+                       "and requesting field types to target field type "
+                       "contains an array or a variant field type: "
+                       "%![req-ft-]+F, %![tgt-ft-]+F", src_ft, tgt_ft);
+               is_valid = false;
+               goto end;
+       }
+
+end:
+       bt_put(src_field_path);
+       bt_put(tgt_field_path);
+       return is_valid;
+}
+
+static
+struct bt_field_path *resolve_field_path(struct bt_field_type *src_ft,
+               struct bt_field_type *tgt_ft,
+               struct bt_resolve_field_path_context *ctx)
+{
+       BT_ASSERT_PRE(field_path_is_valid(src_ft, tgt_ft, ctx),
+               "Invalid target field type: %![req-ft-]+F, %![tgt-ft-]+F",
+               src_ft, tgt_ft);
+       return find_field_type_in_ctx(tgt_ft, ctx);
+}
+
+BT_HIDDEN
+int bt_resolve_field_paths(struct bt_field_type *ft,
+               struct bt_resolve_field_path_context *ctx)
+{
+       int ret = 0;
+
+       BT_ASSERT(ft);
+
+       /* Resolving part for dynamic array and variant field types */
+       switch (ft->id) {
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
+       {
+               struct bt_field_type_dynamic_array *dyn_array_ft = (void *) ft;
+
+               if (dyn_array_ft->length_ft) {
+                       BT_ASSERT(!dyn_array_ft->length_field_path);
+                       dyn_array_ft->length_field_path = resolve_field_path(
+                               ft, dyn_array_ft->length_ft, ctx);
+                       if (!dyn_array_ft->length_field_path) {
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case BT_FIELD_TYPE_ID_VARIANT:
+       {
+               struct bt_field_type_variant *var_ft = (void *) ft;
+
+               if (var_ft->selector_ft) {
+                       BT_ASSERT(!var_ft->selector_field_path);
+                       var_ft->selector_field_path =
+                               resolve_field_path(ft,
+                                       var_ft->selector_ft, ctx);
+                       if (!var_ft->selector_field_path) {
+                               ret = -1;
+                               goto end;
+                       }
+               }
+       }
+       default:
+               break;
+       }
+
+       /* Recursive part */
+       switch (ft->id) {
+       case BT_FIELD_TYPE_ID_STRUCTURE:
+       case BT_FIELD_TYPE_ID_VARIANT:
+       {
+               struct bt_field_type_named_field_types_container *container_ft =
+                       (void *) ft;
+               uint64_t i;
+
+               for (i = 0; i < container_ft->named_fts->len; i++) {
+                       struct bt_named_field_type *named_ft =
+                               BT_FIELD_TYPE_NAMED_FT_AT_INDEX(
+                                       container_ft, i);
+
+                       ret = bt_resolve_field_paths(named_ft->ft, ctx);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
+       {
+               struct bt_field_type_array *array_ft = (void *) ft;
+
+               ret = bt_resolve_field_paths(array_ft->element_ft, ctx);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
diff --git a/lib/ctf-ir/resolve.c b/lib/ctf-ir/resolve.c
deleted file mode 100644 (file)
index c4bf310..0000000
+++ /dev/null
@@ -1,1338 +0,0 @@
-/*
- * resolve.c
- *
- * Babeltrace - CTF IR: Type resolving internal
- *
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *          Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "RESOLVE"
-#include <babeltrace/lib-logging-internal.h>
-
-#include <babeltrace/ctf-ir/stream-class.h>
-#include <babeltrace/ctf-ir/resolve-internal.h>
-#include <babeltrace/ctf-ir/field-types.h>
-#include <babeltrace/ctf-ir/field-path.h>
-#include <babeltrace/ctf-ir/field-path-internal.h>
-#include <babeltrace/ref.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/values.h>
-#include <babeltrace/types.h>
-#include <babeltrace/assert-internal.h>
-#include <limits.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <glib.h>
-
-typedef GPtrArray type_stack;
-
-/*
- * A stack frame.
- *
- * `type` contains a compound field type (structure, variant, array,
- * or sequence) and `index` indicates the index of the field type in
- * the upper frame (-1 for array and sequence field types).
- *
- * `type` is owned by the stack frame.
- */
-struct type_stack_frame {
-       struct bt_field_type *type;
-       int index;
-};
-
-/*
- * The current context of the resolving engine.
- *
- * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2)
- * in the following order:
- *
- *   * Packet header
- *   * Packet context
- *   * Event header
- *   * Stream event context
- *   * Event context
- *   * Event payload
- */
-struct resolve_context {
-       struct bt_value *environment;
-       struct bt_field_type *scopes[6];
-
-       /* Root scope being visited */
-       enum bt_scope root_scope;
-       type_stack *type_stack;
-       struct bt_field_type *cur_field_type;
-};
-
-/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
-static const char * const absolute_path_prefixes[] = {
-       [BT_SCOPE_ENV]                          = "env.",
-       [BT_SCOPE_TRACE_PACKET_HEADER]          = "trace.packet.header.",
-       [BT_SCOPE_STREAM_PACKET_CONTEXT]        = "stream.packet.context.",
-       [BT_SCOPE_STREAM_EVENT_HEADER]          = "stream.event.header.",
-       [BT_SCOPE_STREAM_EVENT_CONTEXT]         = "stream.event.context.",
-       [BT_SCOPE_EVENT_CONTEXT]                = "event.context.",
-       [BT_SCOPE_EVENT_FIELDS]                 = "event.fields.",
-};
-
-/* Number of path tokens used for the absolute prefixes */
-static const int absolute_path_prefix_ptoken_counts[] = {
-       [BT_SCOPE_ENV]                  = 1,
-       [BT_SCOPE_TRACE_PACKET_HEADER]  = 3,
-       [BT_SCOPE_STREAM_PACKET_CONTEXT]        = 3,
-       [BT_SCOPE_STREAM_EVENT_HEADER]  = 3,
-       [BT_SCOPE_STREAM_EVENT_CONTEXT] = 3,
-       [BT_SCOPE_EVENT_CONTEXT]                = 2,
-       [BT_SCOPE_EVENT_FIELDS]         = 2,
-};
-
-/*
- * Destroys a type stack frame.
- */
-static
-void type_stack_destroy_notify(gpointer data)
-{
-       struct type_stack_frame *frame = data;
-
-       BT_PUT(frame->type);
-       g_free(frame);
-}
-
-/*
- * Creates a type stack.
- *
- * Return value is owned by the caller.
- */
-static
-type_stack *type_stack_create(void)
-{
-       return g_ptr_array_new_with_free_func(type_stack_destroy_notify);
-}
-
-/*
- * Destroys a type stack.
- */
-static
-void type_stack_destroy(type_stack *stack)
-{
-       g_ptr_array_free(stack, TRUE);
-}
-
-/*
- * Pushes a field type onto a type stack.
- *
- * `type` is owned by the caller (stack frame gets a new reference).
- */
-static
-int type_stack_push(type_stack *stack, struct bt_field_type *type)
-{
-       int ret = 0;
-       struct type_stack_frame *frame = NULL;
-
-       if (!stack || !type) {
-               BT_LOGW("Invalid parameter: stack or type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       frame = g_new0(struct type_stack_frame, 1);
-       if (!frame) {
-               BT_LOGE_STR("Failed to allocate one field type stack frame.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Pushing field type on context's stack: "
-               "ft-addr=%p, stack-size-before=%u", type, stack->len);
-       frame->type = bt_get(type);
-       g_ptr_array_add(stack, frame);
-
-end:
-       return ret;
-}
-
-/*
- * Checks whether or not `stack` is empty.
- */
-static
-bt_bool type_stack_empty(type_stack *stack)
-{
-       return stack->len == 0;
-}
-
-/*
- * Returns the number of frames in `stack`.
- */
-static
-size_t type_stack_size(type_stack *stack)
-{
-       return stack->len;
-}
-
-/*
- * Returns the top frame of `stack`.
- *
- * Return value is owned by `stack`.
- */
-static
-struct type_stack_frame *type_stack_peek(type_stack *stack)
-{
-       struct type_stack_frame *entry = NULL;
-
-       if (!stack || type_stack_empty(stack)) {
-               goto end;
-       }
-
-       entry = g_ptr_array_index(stack, stack->len - 1);
-end:
-       return entry;
-}
-
-/*
- * Returns the frame at index `index` in `stack`.
- *
- * Return value is owned by `stack`.
- */
-static
-struct type_stack_frame *type_stack_at(type_stack *stack,
-               size_t index)
-{
-       struct type_stack_frame *entry = NULL;
-
-       if (!stack || index >= stack->len) {
-               goto end;
-       }
-
-       entry = g_ptr_array_index(stack, index);
-
-end:
-       return entry;
-}
-
-/*
- * Removes the top frame of `stack`.
- */
-static
-void type_stack_pop(type_stack *stack)
-{
-       if (!type_stack_empty(stack)) {
-               /*
-                * This will call the frame's destructor and free it, as
-                * well as put its contained field type.
-                */
-               BT_LOGV("Popping context's stack: stack-size-before=%u",
-                       stack->len);
-               g_ptr_array_set_size(stack, stack->len - 1);
-       }
-}
-
-/*
- * Returns the scope field type of `scope` in the context `ctx`.
- *
- * Return value is owned by `ctx` on success.
- */
-static
-struct bt_field_type *get_type_from_ctx(struct resolve_context *ctx,
-               enum bt_scope scope)
-{
-       BT_ASSERT(scope >= BT_SCOPE_TRACE_PACKET_HEADER &&
-               scope <= BT_SCOPE_EVENT_FIELDS);
-
-       return ctx->scopes[scope - BT_SCOPE_TRACE_PACKET_HEADER];
-}
-
-/*
- * Returns the CTF scope from a path string. May return
- * CTF_NODE_UNKNOWN if the path is found to be relative.
- */
-static
-enum bt_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
-{
-       enum bt_scope scope;
-       enum bt_scope ret = BT_SCOPE_UNKNOWN;
-       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
-               sizeof(*absolute_path_prefixes);
-
-       for (scope = BT_SCOPE_ENV; scope < BT_SCOPE_ENV +
-                       prefixes_count; scope++) {
-               /*
-                * Chech if path string starts with a known absolute
-                * path prefix.
-                *
-                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
-                */
-               if (strncmp(pathstr, absolute_path_prefixes[scope],
-                               strlen(absolute_path_prefixes[scope]))) {
-                       /* Prefix does not match: try the next one */
-                       BT_LOGV("Prefix does not match: trying the next one: "
-                               "path=\"%s\", path-prefix=\"%s\", scope=%s",
-                               pathstr, absolute_path_prefixes[scope],
-                               bt_common_scope_string(scope));
-                       continue;
-               }
-
-               /* Found it! */
-               ret = scope;
-               BT_LOGV("Found root scope from absolute path: "
-                       "path=\"%s\", scope=%s", pathstr,
-                       bt_common_scope_string(scope));
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Destroys a path token.
- */
-static
-void ptokens_destroy_func(gpointer ptoken, gpointer data)
-{
-       g_string_free(ptoken, TRUE);
-}
-
-/*
- * Destroys a path token list.
- */
-static
-void ptokens_destroy(GList *ptokens)
-{
-       if (!ptokens) {
-               return;
-       }
-
-       g_list_foreach(ptokens, ptokens_destroy_func, NULL);
-       g_list_free(ptokens);
-}
-
-/*
- * Returns the string contained in a path token.
- */
-static
-const char *ptoken_get_string(GList *ptoken)
-{
-       GString *tokenstr = (GString *) ptoken->data;
-
-       return tokenstr->str;
-}
-
-/*
- * Converts a path string to a path token list, that is, splits the
- * individual words of a path string into a list of individual
- * strings.
- *
- * Return value is owned by the caller on success.
- */
-static
-GList *pathstr_to_ptokens(const char *pathstr)
-{
-       const char *at = pathstr;
-       const char *last = at;
-       GList *ptokens = NULL;
-
-       for (;;) {
-               if (*at == '.' || *at == '\0') {
-                       GString *tokenstr;
-
-                       if (at == last) {
-                               /* Error: empty token */
-                               BT_LOGW("Empty path token: path=\"%s\", pos=%u",
-                                       pathstr, (int) (at - pathstr));
-                               goto error;
-                       }
-
-                       tokenstr = g_string_new(NULL);
-                       g_string_append_len(tokenstr, last, at - last);
-                       ptokens = g_list_append(ptokens, tokenstr);
-                       last = at + 1;
-               }
-
-               if (*at == '\0') {
-                       break;
-               }
-
-               at++;
-       }
-
-       return ptokens;
-
-error:
-       ptokens_destroy(ptokens);
-       return NULL;
-}
-
-/*
- * Converts a path token list to a field path object. The path token
- * list is relative from `type`. The index of the source looking for
- * its target within `type` is indicated by `src_index`. This can be
- * `INT_MAX` if the source is contained in `type`.
- *
- * `ptokens` is owned by the caller. `field_path` is an output parameter
- * owned by the caller that must be filled here. `type` is owned by the
- * caller.
- */
-static
-int ptokens_to_field_path(GList *ptokens, struct bt_field_path *field_path,
-               struct bt_field_type *type, int src_index)
-{
-       int ret = 0;
-       GList *cur_ptoken = ptokens;
-       bt_bool first_level_done = BT_FALSE;
-
-       /* Get our own reference */
-       bt_get(type);
-
-       /* Locate target */
-       while (cur_ptoken) {
-               int child_index;
-               struct bt_field_type *child_type;
-               const char *field_name = ptoken_get_string(cur_ptoken);
-               enum bt_field_type_id type_id =
-                       bt_field_type_get_type_id(type);
-
-               BT_LOGV("Current path token: token=\"%s\"", field_name);
-
-               /* Find to which index corresponds the current path token */
-               if (type_id == BT_FIELD_TYPE_ID_ARRAY ||
-                               type_id == BT_FIELD_TYPE_ID_SEQUENCE) {
-                       child_index = -1;
-               } else {
-                       child_index = bt_field_type_get_field_index(type,
-                               field_name);
-                       if (child_index < 0) {
-                               /*
-                                * Error: field name does not exist or
-                                * wrong current type.
-                                */
-                               BT_LOGW("Cannot get index of field type: "
-                                       "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
-                                       field_name, src_index, child_index, first_level_done);
-                               ret = -1;
-                               goto end;
-                       } else if (child_index > src_index &&
-                                       !first_level_done) {
-                               BT_LOGW("Child field type is located after source field type: "
-                                       "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
-                                       field_name, src_index, child_index, first_level_done);
-                               ret = -1;
-                               goto end;
-                       }
-
-                       /* Next path token */
-                       cur_ptoken = g_list_next(cur_ptoken);
-                       first_level_done = BT_TRUE;
-               }
-
-               /* Create new field path entry */
-               g_array_append_val(field_path->indexes, child_index);
-
-               /* Get child field type */
-               child_type = bt_field_type_borrow_field_at_index(type,
-                       child_index);
-               if (!child_type) {
-                       BT_LOGW("Cannot get child field type: "
-                               "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
-                               field_name, src_index, child_index, first_level_done);
-                       ret = -1;
-                       goto end;
-               }
-
-               /* Move child type to current type */
-               bt_get(child_type);
-               BT_MOVE(type, child_type);
-       }
-
-end:
-       bt_put(type);
-       return ret;
-}
-
-/*
- * Converts a known absolute path token list to a field path object
- * within the resolving context `ctx`.
- *
- * `ptokens` is owned by the caller. `field_path` is an output parameter
- * owned by the caller that must be filled here.
- */
-static
-int absolute_ptokens_to_field_path(GList *ptokens,
-               struct bt_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       GList *cur_ptoken;
-       struct bt_field_type *type;
-
-       /* Skip absolute path tokens */
-       cur_ptoken = g_list_nth(ptokens,
-               absolute_path_prefix_ptoken_counts[field_path->root]);
-
-       /* Start with root type */
-       type = get_type_from_ctx(ctx, field_path->root);
-       if (!type) {
-               /* Error: root type is not available */
-               BT_LOGW("Root field type is not available: "
-                       "root-scope=%s",
-                       bt_common_scope_string(field_path->root));
-               ret = -1;
-               goto end;
-       }
-
-       /* Locate target */
-       ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX);
-
-end:
-       return ret;
-}
-
-/*
- * Converts a known relative path token list to a field path object
- * within the resolving context `ctx`.
- *
- * `ptokens` is owned by the caller. `field_path` is an output parameter
- * owned by the caller that must be filled here.
- */
-static
-int relative_ptokens_to_field_path(GList *ptokens,
-               struct bt_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       int parent_pos_in_stack;
-       struct bt_field_path *tail_field_path = bt_field_path_create();
-
-       if (!tail_field_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               ret = -1;
-               goto end;
-       }
-
-       parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1;
-
-       while (parent_pos_in_stack >= 0) {
-               struct bt_field_type *parent_type =
-                       type_stack_at(ctx->type_stack,
-                               parent_pos_in_stack)->type;
-               int cur_index = type_stack_at(ctx->type_stack,
-                       parent_pos_in_stack)->index;
-
-               BT_LOGV("Locating target field type from current parent field type: "
-                       "parent-pos=%d, parent-ft-addr=%p, cur-index=%d",
-                       parent_pos_in_stack, parent_type, cur_index);
-
-               /* Locate target from current parent type */
-               ret = ptokens_to_field_path(ptokens, tail_field_path,
-                       parent_type, cur_index);
-               if (ret) {
-                       /* Not found... yet */
-                       BT_LOGV_STR("Not found at this point.");
-                       bt_field_path_clear(tail_field_path);
-               } else {
-                       /* Found: stitch tail field path to head field path */
-                       int i = 0;
-                       int tail_field_path_len =
-                               tail_field_path->indexes->len;
-
-                       while (BT_TRUE) {
-                               struct bt_field_type *cur_type =
-                                       type_stack_at(ctx->type_stack, i)->type;
-                               int index = type_stack_at(
-                                       ctx->type_stack, i)->index;
-
-                               if (cur_type == parent_type) {
-                                       break;
-                               }
-
-                               g_array_append_val(field_path->indexes,
-                                       index);
-                               i++;
-                       }
-
-                       for (i = 0; i < tail_field_path_len; i++) {
-                               int index = g_array_index(
-                                       tail_field_path->indexes,
-                                       int, i);
-
-                               g_array_append_val(field_path->indexes,
-                                       index);
-                       }
-                       break;
-               }
-
-               parent_pos_in_stack--;
-       }
-
-       if (parent_pos_in_stack < 0) {
-               /* Not found: look in previous scopes */
-               field_path->root--;
-
-               while (field_path->root >= BT_SCOPE_TRACE_PACKET_HEADER) {
-                       struct bt_field_type *root_type;
-                       bt_field_path_clear(field_path);
-
-                       BT_LOGV("Looking into potential root scope: scope=%s",
-                               bt_common_scope_string(field_path->root));
-                       root_type = get_type_from_ctx(ctx, field_path->root);
-                       if (!root_type) {
-                               field_path->root--;
-                               continue;
-                       }
-
-                       /* Locate target in previous scope */
-                       ret = ptokens_to_field_path(ptokens, field_path,
-                               root_type, INT_MAX);
-                       if (ret) {
-                               /* Not found yet */
-                               BT_LOGV_STR("Not found in this scope.");
-                               field_path->root--;
-                               continue;
-                       }
-
-                       /* Found */
-                       BT_LOGV_STR("Found in this scope.");
-                       break;
-               }
-       }
-
-end:
-       BT_PUT(tail_field_path);
-       return ret;
-}
-
-/*
- * Converts a path string to a field path object within the resolving
- * context `ctx`.
- *
- * Return value is owned by the caller on success.
- */
-static
-struct bt_field_path *pathstr_to_field_path(const char *pathstr,
-               struct resolve_context *ctx)
-{
-       int ret;
-       enum bt_scope root_scope;
-       GList *ptokens = NULL;
-       struct bt_field_path *field_path = NULL;
-
-       /* Create field path */
-       field_path = bt_field_path_create();
-       if (!field_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Convert path string to path tokens */
-       ptokens = pathstr_to_ptokens(pathstr);
-       if (!ptokens) {
-               BT_LOGW("Cannot convert path string to path tokens: "
-                       "path=\"%s\"", pathstr);
-               ret = -1;
-               goto end;
-       }
-
-       /* Absolute or relative path? */
-       root_scope = get_root_scope_from_absolute_pathstr(pathstr);
-
-       if (root_scope == BT_SCOPE_UNKNOWN) {
-               /* Relative path: start with current root scope */
-               field_path->root = ctx->root_scope;
-               BT_LOGV("Detected relative path: starting with current root scope: "
-                       "scope=%s", bt_common_scope_string(field_path->root));
-               ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
-               if (ret) {
-                       BT_LOGW("Cannot get relative field path of path string: "
-                               "path=\"%s\", start-scope=%s, end-scope=%s",
-                               pathstr, bt_common_scope_string(ctx->root_scope),
-                               bt_common_scope_string(field_path->root));
-                       goto end;
-               }
-       } else if (root_scope == BT_SCOPE_ENV) {
-               BT_LOGW("Sequence field types referring the trace environment are not supported as of this version: "
-                       "path=\"%s\"", pathstr);
-               ret = -1;
-               goto end;
-       } else {
-               /* Absolute path: use found root scope */
-               field_path->root = root_scope;
-               BT_LOGV("Detected absolute path: using root scope: "
-                       "scope=%s", bt_common_scope_string(field_path->root));
-               ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
-               if (ret) {
-                       BT_LOGW("Cannot get absolute field path of path string: "
-                               "path=\"%s\", root-scope=%s",
-                               pathstr, bt_common_scope_string(root_scope));
-                       goto end;
-               }
-       }
-
-       if (ret == 0) {
-               GString *field_path_pretty =
-                       bt_field_path_string(field_path);
-               const char *field_path_pretty_str =
-                       field_path_pretty ? field_path_pretty->str : NULL;
-
-               BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"",
-                       pathstr, field_path_pretty_str);
-
-               if (field_path_pretty) {
-                       g_string_free(field_path_pretty, TRUE);
-               }
-       }
-
-end:
-       if (ret) {
-               BT_PUT(field_path);
-       }
-
-       ptokens_destroy(ptokens);
-       return field_path;
-}
-
-/*
- * Retrieves a field type by following the field path `field_path` in
- * the resolving context `ctx`.
- *
- * Return value is owned by the caller on success.
- */
-static
-struct bt_field_type *field_path_to_field_type(
-               struct bt_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int i;
-       struct bt_field_type *type;
-
-       /* Start with root type */
-       type = get_type_from_ctx(ctx, field_path->root);
-       bt_get(type);
-       if (!type) {
-               /* Error: root type is not available */
-               BT_LOGW("Root field type is not available: root-scope=%s",
-                       bt_common_scope_string(field_path->root));
-               goto error;
-       }
-
-       /* Locate target */
-       for (i = 0; i < field_path->indexes->len; i++) {
-               struct bt_field_type *child_type;
-               int child_index =
-                       g_array_index(field_path->indexes, int, i);
-
-               /* Get child field type */
-               child_type = bt_field_type_borrow_field_at_index(type,
-                       child_index);
-               if (!child_type) {
-                       BT_LOGW("Cannot get field type: "
-                               "parent-ft-addr=%p, index=%d", type, i);
-                       goto error;
-               }
-
-               /* Move child type to current type */
-               bt_get(child_type);
-               BT_MOVE(type, child_type);
-       }
-
-       return type;
-
-error:
-       BT_PUT(type);
-       return type;
-}
-
-/*
- * Returns the equivalent field path object of the context type stack.
- *
- * Return value is owned by the caller on success.
- */
-static
-struct bt_field_path *get_ctx_stack_field_path(struct resolve_context *ctx)
-{
-       int i;
-       struct bt_field_path *field_path;
-
-       /* Create field path */
-       field_path = bt_field_path_create();
-       if (!field_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               goto error;
-       }
-
-       field_path->root = ctx->root_scope;
-
-       for (i = 0; i < type_stack_size(ctx->type_stack); i++) {
-               struct type_stack_frame *frame;
-
-               frame = type_stack_at(ctx->type_stack, i);
-               g_array_append_val(field_path->indexes, frame->index);
-       }
-
-       return field_path;
-
-error:
-       BT_PUT(field_path);
-       return field_path;
-}
-
-/*
- * Returns the lowest common ancestor of two field path objects
- * having the same root scope.
- *
- * `field_path1` and `field_path2` are owned by the caller.
- */
-int get_field_paths_lca_index(struct bt_field_path *field_path1,
-               struct bt_field_path *field_path2)
-{
-       int lca_index = 0;
-       int field_path1_len, field_path2_len;
-
-       if (BT_LOG_ON_VERBOSE) {
-               GString *field_path1_pretty =
-                       bt_field_path_string(field_path1);
-               GString *field_path2_pretty =
-                       bt_field_path_string(field_path2);
-               const char *field_path1_pretty_str =
-                       field_path1_pretty ? field_path1_pretty->str : NULL;
-               const char *field_path2_pretty_str =
-                       field_path2_pretty ? field_path2_pretty->str : NULL;
-
-               BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: "
-                       "field-path-1=\"%s\", field-path-2=\"%s\"",
-                       field_path1_pretty_str, field_path2_pretty_str);
-
-               if (field_path1_pretty) {
-                       g_string_free(field_path1_pretty, TRUE);
-               }
-
-               if (field_path2_pretty) {
-                       g_string_free(field_path2_pretty, TRUE);
-               }
-       }
-
-       /*
-        * Start from both roots and find the first mismatch.
-        */
-       BT_ASSERT(field_path1->root == field_path2->root);
-       field_path1_len = field_path1->indexes->len;
-       field_path2_len = field_path2->indexes->len;
-
-       while (BT_TRUE) {
-               int target_index, ctx_index;
-
-               if (lca_index == field_path2_len ||
-                               lca_index == field_path1_len) {
-                       /*
-                        * This means that both field paths never split.
-                        * This is invalid because the target cannot be
-                        * an ancestor of the source.
-                        */
-                       BT_LOGW("Source field type is an ancestor of target field type or vice versa: "
-                               "lca-index=%d, field-path-1-len=%d, "
-                               "field-path-2-len=%d",
-                               lca_index, field_path1_len, field_path2_len);
-                       lca_index = -1;
-                       break;
-               }
-
-               target_index = g_array_index(field_path1->indexes, int,
-                       lca_index);
-               ctx_index = g_array_index(field_path2->indexes, int,
-                       lca_index);
-
-               if (target_index != ctx_index) {
-                       /* LCA index is the previous */
-                       break;
-               }
-
-               lca_index++;
-       }
-
-       BT_LOGV("Found LCA: lca-index=%d", lca_index);
-       return lca_index;
-}
-
-/*
- * Validates a target field path.
- *
- * `target_field_path` and `target_type` are owned by the caller.
- */
-static
-int validate_target_field_path(struct bt_field_path *target_field_path,
-               struct bt_field_type *target_type,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       struct bt_field_path *ctx_field_path;
-       int target_field_path_len = target_field_path->indexes->len;
-       int lca_index;
-       enum bt_field_type_id ctx_cur_field_type_id;
-       enum bt_field_type_id target_type_id;
-
-       /* Get context field path */
-       ctx_field_path = get_ctx_stack_field_path(ctx);
-       if (!ctx_field_path) {
-               BT_LOGW_STR("Cannot get field path from context's stack.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Make sure the target is not a root.
-        */
-       if (target_field_path_len == 0) {
-               BT_LOGW_STR("Target field path's length is 0 (targeting the root).");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Make sure the root of the target field path is not located
-        * after the context field path's root.
-        */
-       if (target_field_path->root > ctx_field_path->root) {
-               BT_LOGW("Target field type is located after source field type: "
-                       "target-root=%s, source-root=%s",
-                       bt_common_scope_string(target_field_path->root),
-                       bt_common_scope_string(ctx_field_path->root));
-               ret = -1;
-               goto end;
-       }
-
-       if (target_field_path->root == ctx_field_path->root) {
-               int target_index, ctx_index;
-
-               /*
-                * Find the index of the lowest common ancestor of both field
-                * paths.
-                */
-               lca_index = get_field_paths_lca_index(target_field_path,
-                       ctx_field_path);
-               if (lca_index < 0) {
-                       BT_LOGW_STR("Cannot get least common ancestor.");
-                       ret = -1;
-                       goto end;
-               }
-
-               /*
-                * Make sure the target field path is located before the
-                * context field path.
-                */
-               target_index = g_array_index(target_field_path->indexes,
-                       int, lca_index);
-               ctx_index = g_array_index(ctx_field_path->indexes,
-                       int, lca_index);
-
-               if (target_index >= ctx_index) {
-                       BT_LOGW("Target field type's index is greater than or equal to source field type's index in LCA: "
-                               "lca-index=%d, target-index=%d, source-index=%d",
-                               lca_index, target_index, ctx_index);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * Make sure the target type has the right type and properties.
-        */
-       ctx_cur_field_type_id = bt_field_type_get_type_id(
-               ctx->cur_field_type);
-       target_type_id = bt_field_type_get_type_id(target_type);
-
-       switch (ctx_cur_field_type_id) {
-       case BT_FIELD_TYPE_ID_VARIANT:
-               if (target_type_id != BT_FIELD_TYPE_ID_ENUM) {
-                       BT_LOGW("Variant field type's tag field type is not an enumeration field type: "
-                               "tag-ft-addr=%p, tag-ft-id=%s",
-                               target_type,
-                               bt_common_field_type_id_string(target_type_id));
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               if (target_type_id != BT_FIELD_TYPE_ID_INTEGER ||
-                               bt_field_type_integer_is_signed(target_type)) {
-                       BT_LOGW("Sequence field type's length field type is not an unsigned integer field type: "
-                               "length-ft-addr=%p, length-ft-id=%s",
-                               target_type,
-                               bt_common_field_type_id_string(target_type_id));
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       default:
-               abort();
-       }
-
-end:
-       BT_PUT(ctx_field_path);
-       return ret;
-}
-
-/*
- * Resolves a variant or sequence field type `type`.
- *
- * `type` is owned by the caller.
- */
-static
-int resolve_sequence_or_variant_type(struct bt_field_type *type,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       const char *pathstr;
-       enum bt_field_type_id type_id = bt_field_type_get_type_id(type);
-       struct bt_field_path *target_field_path = NULL;
-       struct bt_field_type *target_type = NULL;
-       GString *target_field_path_pretty = NULL;
-       const char *target_field_path_pretty_str;
-
-
-       /* Get path string */
-       switch (type_id) {
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               pathstr =
-                       bt_field_type_sequence_get_length_field_name(type);
-               break;
-       case BT_FIELD_TYPE_ID_VARIANT:
-               pathstr =
-                       bt_field_type_variant_get_tag_name(type);
-               break;
-       default:
-               abort();
-       }
-
-       if (!pathstr) {
-               BT_LOGW_STR("Cannot get path string.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Get target field path out of path string */
-       target_field_path = pathstr_to_field_path(pathstr, ctx);
-       if (!target_field_path) {
-               BT_LOGW("Cannot get target field path for path string: "
-                       "path=\"%s\"", pathstr);
-               ret = -1;
-               goto end;
-       }
-
-       target_field_path_pretty = bt_field_path_string(target_field_path);
-       target_field_path_pretty_str =
-               target_field_path_pretty ? target_field_path_pretty->str : NULL;
-
-       /* Get target field type */
-       target_type = field_path_to_field_type(target_field_path, ctx);
-       if (!target_type) {
-               BT_LOGW("Cannot get target field type for path string: "
-                       "path=\"%s\", target-field-path=\"%s\"",
-                       pathstr, target_field_path_pretty_str);
-               ret = -1;
-               goto end;
-       }
-
-       ret = validate_target_field_path(target_field_path, target_type, ctx);
-       if (ret) {
-               BT_LOGW("Invalid target field path for path string: "
-                       "path=\"%s\", target-field-path=\"%s\"",
-                       pathstr, target_field_path_pretty_str);
-               goto end;
-       }
-
-       /* Set target field path and target field type */
-       switch (type_id) {
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               ret = bt_field_type_sequence_set_length_field_path(
-                       type, target_field_path);
-               if (ret) {
-                       BT_LOGW("Cannot set sequence field type's length field path: "
-                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
-                               ret, type, pathstr,
-                               target_field_path_pretty_str);
-                       goto end;
-               }
-               break;
-       case BT_FIELD_TYPE_ID_VARIANT:
-               ret = bt_field_type_variant_set_tag_field_path(
-                       type, target_field_path);
-               if (ret) {
-                       BT_LOGW("Cannot set varaint field type's tag field path: "
-                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
-                               ret, type, pathstr,
-                               target_field_path_pretty_str);
-                       goto end;
-               }
-
-               ret = bt_field_type_variant_set_tag_field_type(
-                       type, target_type);
-               if (ret) {
-                       BT_LOGW("Cannot set varaint field type's tag field type: "
-                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
-                               ret, type, pathstr,
-                               target_field_path_pretty_str);
-                       goto end;
-               }
-               break;
-       default:
-               abort();
-       }
-
-end:
-       if (target_field_path_pretty) {
-               g_string_free(target_field_path_pretty, TRUE);
-       }
-
-       BT_PUT(target_field_path);
-       BT_PUT(target_type);
-       return ret;
-}
-
-/*
- * Resolves a field type `type`.
- *
- * `type` is owned by the caller.
- */
-static
-int resolve_type(struct bt_field_type *type, struct resolve_context *ctx)
-{
-       int ret = 0;
-       enum bt_field_type_id type_id;
-
-       if (!type) {
-               /* Type is not available; still valid */
-               goto end;
-       }
-
-       type_id = bt_field_type_get_type_id(type);
-       ctx->cur_field_type = type;
-
-       /* Resolve sequence/variant field type */
-       switch (type_id) {
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-       case BT_FIELD_TYPE_ID_VARIANT:
-               ret = resolve_sequence_or_variant_type(type, ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve sequence field type's length or variant field type's tag: "
-                               "ret=%d, ft-addr=%p", ret, type);
-                       goto end;
-               }
-               break;
-       default:
-               break;
-       }
-
-       /* Recurse into compound types */
-       switch (type_id) {
-       case BT_FIELD_TYPE_ID_STRUCT:
-       case BT_FIELD_TYPE_ID_VARIANT:
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-       case BT_FIELD_TYPE_ID_ARRAY:
-       {
-               int64_t field_count, f_index;
-
-               ret = type_stack_push(ctx->type_stack, type);
-               if (ret) {
-                       BT_LOGW("Cannot push field type on context's stack: "
-                               "ft-addr=%p", type);
-                       goto end;
-               }
-
-               field_count = bt_field_type_get_field_count(type);
-               if (field_count < 0) {
-                       BT_LOGW("Cannot get field type's field count: "
-                               "ret=%" PRId64 ", ft-addr=%p",
-                               field_count, type);
-                       ret = field_count;
-                       goto end;
-               }
-
-               for (f_index = 0; f_index < field_count; f_index++) {
-                       struct bt_field_type *child_type =
-                               bt_field_type_borrow_field_at_index(type,
-                                       f_index);
-
-                       if (!child_type) {
-                               BT_LOGW("Cannot get field type's child field: "
-                                       "ft-addr=%p, index=%" PRId64 ", "
-                                       "count=%" PRId64, type, f_index,
-                                       field_count);
-                               ret = -1;
-                               goto end;
-                       }
-
-                       if (type_id == BT_FIELD_TYPE_ID_ARRAY||
-                                       type_id == BT_FIELD_TYPE_ID_SEQUENCE) {
-                               type_stack_peek(ctx->type_stack)->index = -1;
-                       } else {
-                               type_stack_peek(ctx->type_stack)->index =
-                                       f_index;
-                       }
-
-                       BT_LOGV("Resolving field type's child field type: "
-                               "parent-ft-addr=%p, child-ft-addr=%p, "
-                               "index=%" PRId64 ", count=%" PRId64,
-                               type, child_type, f_index, field_count);
-                       ret = resolve_type(child_type, ctx);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               type_stack_pop(ctx->type_stack);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Resolves the root field type corresponding to the scope `root_scope`.
- */
-static
-int resolve_root_type(enum bt_scope root_scope, struct resolve_context *ctx)
-{
-       int ret;
-
-       BT_ASSERT(type_stack_size(ctx->type_stack) == 0);
-       ctx->root_scope = root_scope;
-       ret = resolve_type(get_type_from_ctx(ctx, root_scope), ctx);
-       ctx->root_scope = BT_SCOPE_UNKNOWN;
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_resolve_types(
-               struct bt_value *environment,
-               struct bt_field_type *packet_header_type,
-               struct bt_field_type *packet_context_type,
-               struct bt_field_type *event_header_type,
-               struct bt_field_type *stream_event_ctx_type,
-               struct bt_field_type *event_context_type,
-               struct bt_field_type *event_payload_type,
-               enum bt_resolve_flag flags)
-{
-       int ret = 0;
-       struct resolve_context ctx = {
-               .environment = environment,
-               .scopes = {
-                       packet_header_type,
-                       packet_context_type,
-                       event_header_type,
-                       stream_event_ctx_type,
-                       event_context_type,
-                       event_payload_type,
-               },
-               .root_scope = BT_SCOPE_UNKNOWN,
-       };
-
-       BT_LOGV("Resolving field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p, "
-               "event-context-ft-addr=%p, "
-               "event-payload-ft-addr=%p",
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type, event_context_type, event_payload_type);
-
-       /* Initialize type stack */
-       ctx.type_stack = type_stack_create();
-       if (!ctx.type_stack) {
-               BT_LOGE_STR("Cannot create field type stack.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Resolve packet header type */
-       if (flags & BT_RESOLVE_FLAG_PACKET_HEADER) {
-               ret = resolve_root_type(BT_SCOPE_TRACE_PACKET_HEADER, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve trace packet header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve packet context type */
-       if (flags & BT_RESOLVE_FLAG_PACKET_CONTEXT) {
-               ret = resolve_root_type(BT_SCOPE_STREAM_PACKET_CONTEXT, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve stream packet context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve event header type */
-       if (flags & BT_RESOLVE_FLAG_EVENT_HEADER) {
-               ret = resolve_root_type(BT_SCOPE_STREAM_EVENT_HEADER, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve stream event header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve stream event context type */
-       if (flags & BT_RESOLVE_FLAG_STREAM_EVENT_CTX) {
-               ret = resolve_root_type(BT_SCOPE_STREAM_EVENT_CONTEXT, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve stream event context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve event context type */
-       if (flags & BT_RESOLVE_FLAG_EVENT_CONTEXT) {
-               ret = resolve_root_type(BT_SCOPE_EVENT_CONTEXT, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve event context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve event payload type */
-       if (flags & BT_RESOLVE_FLAG_EVENT_PAYLOAD) {
-               ret = resolve_root_type(BT_SCOPE_EVENT_FIELDS, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve event payload field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       BT_LOGV_STR("Resolved field types.");
-
-end:
-       type_stack_destroy(ctx.type_stack);
-
-       return ret;
-}
index 24cb870b36461596f179cdc08e683997bac023bb..69b9d5c312a56009b6f09a0da01e9d73473e06f6 100644 (file)
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
-#include <babeltrace/ctf-ir/visitor-internal.h>
-#include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
+#include <babeltrace/ctf-ir/resolve-field-path-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/align-internal.h>
 #include <babeltrace/endian-internal.h>
 #include <babeltrace/assert-internal.h>
+#include <babeltrace/property-internal.h>
 #include <inttypes.h>
 #include <stdint.h>
 #include <stdbool.h>
 
-static inline
-int bt_stream_class_initialize(struct bt_stream_class *stream_class,
-               const char *name, bt_object_release_func release_func)
-{
-       BT_LOGD("Initializing stream class object: name=\"%s\"", name);
-
-       bt_object_init_shared_with_parent(&stream_class->base, release_func);
-       stream_class->name = g_string_new(name);
-       stream_class->event_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!stream_class->event_classes) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash,
-                       g_int64_equal, g_free, NULL);
-       if (!stream_class->event_classes_ht) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               goto error;
-       }
-
-       BT_LOGD("Initialized stream class object: addr=%p, name=\"%s\"",
-               stream_class, name);
-       return 0;
-
-error:
-       return -1;
-}
+#define BT_ASSERT_PRE_STREAM_CLASS_HOT(_sc) \
+       BT_ASSERT_PRE_HOT((_sc), "Stream class", ": %!+S", (_sc))
 
 static
-void bt_stream_class_destroy(struct bt_object *obj)
+void destroy_stream_class(struct bt_object *obj)
 {
        struct bt_stream_class *stream_class = (void *) obj;
 
-       BT_LOGD("Destroying stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class));
-       bt_put(stream_class->clock_class);
+       BT_LIB_LOGD("Destroying stream class: %!+S", stream_class);
+       BT_LOGD_STR("Putting default clock class.");
+       bt_put(stream_class->default_clock_class);
 
-       if (stream_class->event_classes_ht) {
-               g_hash_table_destroy(stream_class->event_classes_ht);
-       }
        if (stream_class->event_classes) {
                BT_LOGD_STR("Destroying event classes.");
                g_ptr_array_free(stream_class->event_classes, TRUE);
        }
 
-       if (stream_class->name) {
-               g_string_free(stream_class->name, TRUE);
+       if (stream_class->name.str) {
+               g_string_free(stream_class->name.str, TRUE);
        }
 
        BT_LOGD_STR("Putting event header field type.");
-       bt_put(stream_class->event_header_field_type);
+       bt_put(stream_class->event_header_ft);
        BT_LOGD_STR("Putting packet context field type.");
-       bt_put(stream_class->packet_context_field_type);
-       BT_LOGD_STR("Putting event context field type.");
-       bt_put(stream_class->event_context_field_type);
+       bt_put(stream_class->packet_context_ft);
+       BT_LOGD_STR("Putting event common context field type.");
+       bt_put(stream_class->event_common_context_ft);
        bt_object_pool_finalize(&stream_class->event_header_field_pool);
        bt_object_pool_finalize(&stream_class->packet_context_field_pool);
        g_free(stream_class);
@@ -119,22 +87,63 @@ void free_field_wrapper(struct bt_field_wrapper *field_wrapper,
        bt_field_wrapper_destroy((void *) field_wrapper);
 }
 
-struct bt_stream_class *bt_stream_class_create(const char *name)
+BT_ASSERT_PRE_FUNC
+static
+bool stream_class_id_is_unique(struct bt_trace *trace, uint64_t id)
+{
+       uint64_t i;
+       bool is_unique = true;
+
+       for (i = 0; i < trace->stream_classes->len; i++) {
+               struct bt_stream_class *sc =
+                       trace->stream_classes->pdata[i];
+
+               if (sc->id == id) {
+                       is_unique = false;
+                       goto end;
+               }
+       }
+
+end:
+       return is_unique;
+}
+
+static
+struct bt_stream_class *create_stream_class_with_id(struct bt_trace *trace,
+               uint64_t id)
 {
        struct bt_stream_class *stream_class = NULL;
        int ret;
 
-       BT_LOGD("Creating stream class object: name=\"%s\"", name);
+       BT_ASSERT(trace);
+       BT_ASSERT_PRE(stream_class_id_is_unique(trace, id),
+               "Duplicate stream class ID: %![trace-]+t, id=%" PRIu64,
+               trace, id);
+       BT_LIB_LOGD("Creating stream class object: %![trace-]+t, id=%" PRIu64,
+               trace, id);
        stream_class = g_new0(struct bt_stream_class, 1);
        if (!stream_class) {
                BT_LOGE_STR("Failed to allocate one stream class.");
                goto error;
        }
 
-       ret = bt_stream_class_initialize(stream_class, name,
-               bt_stream_class_destroy);
-       if (ret) {
-               /* bt_stream_class_initialize() logs errors */
+       bt_object_init_shared_with_parent(&stream_class->base,
+               destroy_stream_class);
+
+       stream_class->name.str = g_string_new(NULL);
+       if (!stream_class->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
+       }
+
+       stream_class->id = id;
+       stream_class->assigns_automatic_event_class_id = true;
+       stream_class->assigns_automatic_stream_id = true;
+       stream_class->event_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!stream_class->event_classes) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
                goto error;
        }
 
@@ -158,595 +167,147 @@ struct bt_stream_class *bt_stream_class_create(const char *name)
                goto error;
        }
 
-       BT_LOGD("Created stream class object: addr=%p, name=\"%s\"",
-               stream_class, name);
-       return stream_class;
-
-error:
-       bt_put(stream_class);
-       return NULL;
-}
-
-struct bt_event_header_field *bt_stream_class_create_event_header_field(
-               struct bt_stream_class *stream_class)
-{
-       struct bt_field_wrapper *field_wrapper;
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(stream_class->frozen,
-               "Stream class is not part of a trace: %!+S", stream_class);
-       BT_ASSERT_PRE(stream_class->event_header_field_type,
-               "Stream class has no event header field type: %!+S",
-               stream_class);
-       field_wrapper = bt_field_wrapper_create(
-               &stream_class->event_header_field_pool,
-               (void *) stream_class->event_header_field_type);
-       if (!field_wrapper) {
-               BT_LIB_LOGE("Cannot allocate one event header field from stream class: "
-                       "%![sc-]+S", stream_class);
-               goto error;
-       }
-
-       BT_ASSERT(field_wrapper->field);
+       bt_object_set_parent(&stream_class->base, &trace->base);
+       g_ptr_array_add(trace->stream_classes, stream_class);
+       bt_trace_freeze(trace);
+       BT_LIB_LOGD("Created stream class object: %!+S", stream_class);
        goto end;
 
 error:
-       if (field_wrapper) {
-               bt_field_wrapper_destroy(field_wrapper);
-               field_wrapper = NULL;
-       }
+       BT_PUT(stream_class);
 
 end:
-       return (void *) field_wrapper;
+       return stream_class;
 }
 
-struct bt_packet_context_field *bt_stream_class_create_packet_context_field(
-               struct bt_stream_class *stream_class)
+struct bt_stream_class *bt_stream_class_create(struct bt_trace *trace)
 {
-       struct bt_field_wrapper *field_wrapper;
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(stream_class->frozen,
-               "Stream class is not part of a trace: %!+S", stream_class);
-       BT_ASSERT_PRE(stream_class->packet_context_field_type,
-               "Stream class has no packet context field type: %!+S",
-               stream_class);
-       field_wrapper = bt_field_wrapper_create(
-               &stream_class->packet_context_field_pool,
-               (void *) stream_class->packet_context_field_type);
-       if (!field_wrapper) {
-               BT_LIB_LOGE("Cannot allocate one packet context field from stream class: "
-                       "%![sc-]+S", stream_class);
-               goto error;
-       }
-
-       BT_ASSERT(field_wrapper->field);
-       goto end;
-
-error:
-       if (field_wrapper) {
-               bt_field_wrapper_destroy(field_wrapper);
-               field_wrapper = NULL;
-       }
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(trace->assigns_automatic_stream_class_id,
+               "Trace does not automatically assigns stream class IDs: "
+               "%![sc-]+t", trace);
+       return create_stream_class_with_id(trace,
+               (uint64_t) trace->stream_classes->len);
+}
 
-end:
-       return (void *) field_wrapper;
+struct bt_stream_class *bt_stream_class_create_with_id(
+               struct bt_trace *trace, uint64_t id)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(!trace->assigns_automatic_stream_class_id,
+               "Trace automatically assigns stream class IDs: "
+               "%![sc-]+t", trace);
+       return create_stream_class_with_id(trace, id);
 }
 
 struct bt_trace *bt_stream_class_borrow_trace(struct bt_stream_class *stream_class)
 {
-       BT_ASSERT(stream_class);
-       return (void *) bt_object_borrow_parent(&stream_class->base);
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return bt_stream_class_borrow_trace_inline(stream_class);
 }
 
 const char *bt_stream_class_get_name(struct bt_stream_class *stream_class)
 {
        BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->name->len > 0 ? stream_class->name->str : NULL;
+       return stream_class->name.value;
 }
 
 int bt_stream_class_set_name(struct bt_stream_class *stream_class,
                const char *name)
 {
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!name) {
-               g_string_assign(stream_class->name, "");
-       } else {
-               if (strlen(name) == 0) {
-                       BT_LOGW("Invalid parameter: name is empty.");
-                       ret = -1;
-                       goto end;
-               }
-
-               g_string_assign(stream_class->name, name);
-       }
-
-       BT_LOGV("Set stream class's name: "
-               "addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class));
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       g_string_assign(stream_class->name.str, name);
+       stream_class->name.value = stream_class->name.str->str;
+       BT_LIB_LOGV("Set stream class's name: %!+S", stream_class);
+       return 0;
 }
 
-int64_t bt_stream_class_get_id(struct bt_stream_class *stream_class)
+uint64_t bt_stream_class_get_id(struct bt_stream_class *stream_class)
 {
-       int64_t ret;
-
        BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-
-       if (!stream_class->id_set) {
-               BT_LOGV("Stream class's ID is not set: addr=%p, name=\"%s\"",
-                       stream_class,
-                       bt_stream_class_get_name(stream_class));
-               ret = (int64_t) -1;
-               goto end;
-       }
-
-       ret = stream_class->id;
-
-end:
-       return ret;
+       return stream_class->id;
 }
 
-int bt_stream_class_set_id(struct bt_stream_class *stream_class,
-               uint64_t id_param)
+uint64_t bt_stream_class_get_event_class_count(
+               struct bt_stream_class *stream_class)
 {
-       int ret = 0;
-       int64_t id = (int64_t) id_param;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (id < 0) {
-               BT_LOGW("Invalid parameter: invalid stream class's ID: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", id=%" PRIu64,
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class),
-                       id_param);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_stream_class_set_id_no_check(stream_class, id);
-       if (ret == 0) {
-               BT_LOGV("Set stream class's ID: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class));
-       }
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (uint64_t) stream_class->event_classes->len;
 }
 
-static
-void event_class_exists(gpointer element, gpointer query)
+struct bt_event_class *bt_stream_class_borrow_event_class_by_index(
+               struct bt_stream_class *stream_class, uint64_t index)
 {
-       struct bt_event_class *event_class_a = element;
-       struct search_query *search_query = query;
-       struct bt_event_class *event_class_b = search_query->value;
-       int64_t id_a, id_b;
-
-       if (search_query->value == element) {
-               search_query->found = 1;
-               goto end;
-       }
-
-       /*
-        * Two event classes cannot share the same ID in a given
-        * stream class.
-        */
-       id_a = bt_event_class_get_id(event_class_a);
-       id_b = bt_event_class_get_id(event_class_b);
-
-       if (id_a < 0 || id_b < 0) {
-               /* at least one ID is not set: will be automatically set later */
-               goto end;
-       }
-
-       if (id_a == id_b) {
-               BT_LOGW("Event class with this ID already exists in the stream class: "
-                       "id=%" PRId64 ", name=\"%s\"",
-                       id_a, bt_event_class_get_name(event_class_a));
-               search_query->found = 1;
-               goto end;
-       }
-
-end:
-       return;
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_VALID_INDEX(index, stream_class->event_classes->len);
+       return g_ptr_array_index(stream_class->event_classes, index);
 }
 
-int bt_stream_class_add_event_class(struct bt_stream_class *stream_class,
-               struct bt_event_class *event_class)
+struct bt_event_class *bt_stream_class_borrow_event_class_by_id(
+               struct bt_stream_class *trace, uint64_t id)
 {
-       int ret = 0;
-       int64_t *event_id = NULL;
-       struct bt_trace *trace = NULL;
-       struct bt_stream_class *old_stream_class = NULL;
-       struct bt_validation_output validation_output = { 0 };
-       struct bt_field_type *packet_header_type = NULL;
-       struct bt_field_type *packet_context_type = NULL;
-       struct bt_field_type *event_header_type = NULL;
-       struct bt_field_type *stream_event_ctx_type = NULL;
-       struct bt_field_type *event_context_type = NULL;
-       struct bt_field_type *event_payload_type = NULL;
-       const enum bt_validation_flag validation_flags =
-               BT_VALIDATION_FLAG_EVENT;
-       struct bt_clock_class *expected_clock_class = NULL;
-
-       if (!stream_class) {
-               BT_LOGW("Invalid parameter: stream class is NULL: "
-                       "stream-class-addr=%p", stream_class);
-               ret = -1;
-               goto end;
-       }
-
-       trace = bt_stream_class_borrow_trace(stream_class);
-       if (trace && trace->is_static) {
-               BT_LOGW("Invalid parameter: stream class's trace is static: "
-                       "trace-addr=%p, trace-name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       if (!stream_class || !event_class) {
-               BT_LOGW("Invalid parameter: stream class or event class is NULL: "
-                       "stream-class-addr=%p, event-class-addr=%p",
-                       stream_class, event_class);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGD("Adding event class to stream class: "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64 ", event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class),
-               event_class,
-               bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class));
-       trace = bt_stream_class_borrow_trace(stream_class);
-
-       if (stream_class->frozen) {
-               /*
-                * We only check that the event class to be added has a
-                * single class which matches the stream class's
-                * expected clock class if the stream class is frozen.
-                * If it's not, then this event class is added "as is"
-                * and the validation will be performed when calling
-                * either bt_trace_add_stream_class() or
-                * bt_event_create(). This is because the stream class's
-                * field types (packet context, event header, event
-                * context) could change before the next call to one of
-                * those two functions.
-                */
-               expected_clock_class = bt_get(stream_class->clock_class);
-
-               /*
-                * At this point, `expected_clock_class` can be NULL,
-                * and bt_event_class_validate_single_clock_class()
-                * below can set it.
-                */
-               ret = bt_event_class_validate_single_clock_class(
-                       event_class, &expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Event class contains a field type which is not "
-                               "recursively mapped to its stream class's "
-                               "expected clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-id=%" PRId64 ", "
-                               "stream-class-name=\"%s\", "
-                               "expected-clock-class-addr=%p, "
-                               "expected-clock-class-name=\"%s\"",
-                               stream_class,
-                               bt_stream_class_get_id(stream_class),
-                               bt_stream_class_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_clock_class_get_name(expected_clock_class) :
-                                       NULL);
-                       goto end;
-               }
-       }
-
-       event_id = g_new(int64_t, 1);
-       if (!event_id) {
-               BT_LOGE_STR("Failed to allocate one int64_t.");
-               ret = -1;
-               goto end;
-       }
+       struct bt_event_class *event_class = NULL;
+       uint64_t i;
 
-       /* Check for duplicate event classes */
-       struct search_query query = { .value = event_class, .found = 0 };
-       g_ptr_array_foreach(stream_class->event_classes, event_class_exists,
-               &query);
-       if (query.found) {
-               BT_LOGW_STR("Another event class part of this stream class has the same ID.");
-               ret = -1;
-               goto end;
-       }
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
 
-       old_stream_class = bt_event_class_borrow_stream_class(event_class);
-       if (old_stream_class) {
-               /* Event class is already associated to a stream class. */
-               BT_LOGW("Event class is already part of another stream class: "
-                       "event-class-stream-class-addr=%p, "
-                       "event-class-stream-class-name=\"%s\", "
-                       "event-class-stream-class-id=%" PRId64,
-                       old_stream_class,
-                       bt_stream_class_get_name(old_stream_class),
-                       bt_stream_class_get_id(old_stream_class));
-               ret = -1;
-               goto end;
-       }
+       for (i = 0; i < trace->event_classes->len; i++) {
+               struct bt_event_class *event_class_candidate =
+                       g_ptr_array_index(trace->event_classes, i);
 
-       if (trace) {
-               /*
-                * If the stream class is associated with a trace, then
-                * both those objects are frozen. Also, this event class
-                * is about to be frozen.
-                *
-                * Therefore the event class must be validated here.
-                * The trace and stream class should be valid at this
-                * point.
-                */
-               BT_ASSERT(trace->valid);
-               BT_ASSERT(stream_class->valid);
-               packet_header_type =
-                       bt_trace_borrow_packet_header_field_type(trace);
-               packet_context_type =
-                       bt_stream_class_borrow_packet_context_field_type(
-                               stream_class);
-               event_header_type =
-                       bt_stream_class_borrow_event_header_field_type(
-                               stream_class);
-               stream_event_ctx_type =
-                       bt_stream_class_borrow_event_context_field_type(
-                               stream_class);
-               event_context_type =
-                       bt_event_class_borrow_context_field_type(
-                               event_class);
-               event_payload_type =
-                       bt_event_class_borrow_payload_field_type(
-                               event_class);
-               ret = bt_validate_class_types(
-                       trace->environment, packet_header_type,
-                       packet_context_type, event_header_type,
-                       stream_event_ctx_type, event_context_type,
-                       event_payload_type, trace->valid,
-                       stream_class->valid, event_class->valid,
-                       &validation_output, validation_flags,
-                       bt_field_type_copy);
-
-               if (ret) {
-                       /*
-                        * This means something went wrong during the
-                        * validation process, not that the objects are
-                        * invalid.
-                        */
-                       BT_LOGE("Failed to validate event class: ret=%d", ret);
+               if (event_class_candidate->id == id) {
+                       event_class = event_class_candidate;
                        goto end;
                }
-
-               if ((validation_output.valid_flags & validation_flags) !=
-                               validation_flags) {
-                       /* Invalid event class */
-                       BT_LOGW("Invalid trace, stream class, or event class: "
-                               "valid-flags=0x%x",
-                               validation_output.valid_flags);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /* Only set an event ID if none was explicitly set before */
-       *event_id = bt_event_class_get_id(event_class);
-       if (*event_id < 0) {
-               BT_LOGV("Event class has no ID: automatically setting it: "
-                       "id=%" PRId64, stream_class->next_event_id);
-
-               if (bt_event_class_set_id(event_class,
-                               stream_class->next_event_id)) {
-                       BT_LOGE("Cannot set event class's ID: id=%" PRId64,
-                               stream_class->next_event_id);
-                       ret = -1;
-                       goto end;
-               }
-               stream_class->next_event_id++;
-               *event_id = stream_class->next_event_id;
-       }
-
-       bt_object_set_parent(&event_class->base, &stream_class->base);
-
-       if (trace) {
-               /*
-                * At this point we know that the function will be
-                * successful. Therefore we can replace the event
-                * class's field types with what's in the validation
-                * output structure and mark this event class as valid.
-                */
-               bt_validation_replace_types(NULL, NULL, event_class,
-                       &validation_output, validation_flags);
-               event_class->valid = 1;
-
-               /*
-                * Put what was not moved in
-                * bt_validation_replace_types().
-                */
-               bt_validation_output_put_types(&validation_output);
-       }
-
-       /* Add to the event classes of the stream class */
-       g_ptr_array_add(stream_class->event_classes, event_class);
-       g_hash_table_insert(stream_class->event_classes_ht, event_id,
-                       event_class);
-       event_id = NULL;
-
-       /* Freeze the event class */
-       bt_event_class_freeze(event_class);
-
-       /*
-        * It is safe to set the stream class's unique clock class
-        * now if the stream class is frozen.
-        */
-       if (stream_class->frozen && expected_clock_class) {
-               BT_ASSERT(!stream_class->clock_class ||
-                       stream_class->clock_class == expected_clock_class);
-               BT_MOVE(stream_class->clock_class, expected_clock_class);
-       }
-
-       /* Notifiy listeners of the trace's schema modification. */
-       if (trace) {
-               struct bt_visitor_object obj = { .object = event_class,
-                               .type = BT_VISITOR_OBJECT_TYPE_EVENT_CLASS };
-
-               (void) bt_trace_object_modification(&obj, trace);
-       }
-
-       BT_LOGD("Added event class to stream class: "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64 ", event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class),
-               event_class,
-               bt_event_class_get_name(event_class),
-               bt_event_class_get_id(event_class));
-
-end:
-       bt_validation_output_put_types(&validation_output);
-       bt_put(expected_clock_class);
-       g_free(event_id);
-       return ret;
-}
-
-int64_t bt_stream_class_get_event_class_count(
-               struct bt_stream_class *stream_class)
-{
-       int64_t ret;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = (int64_t) -1;
-               goto end;
        }
 
-       ret = (int64_t) stream_class->event_classes->len;
 end:
-       return ret;
-}
-
-struct bt_event_class *bt_stream_class_borrow_event_class_by_index(
-               struct bt_stream_class *stream_class, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(index < stream_class->event_classes->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, stream_class->event_classes->len);
-       return g_ptr_array_index(stream_class->event_classes, index);
-}
-
-struct bt_event_class *bt_stream_class_borrow_event_class_by_id(
-               struct bt_stream_class *stream_class, uint64_t id)
-{
-       int64_t id_key = (int64_t) id;
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(id_key >= 0,
-               "Invalid event class ID: %" PRIu64, id);
-       return g_hash_table_lookup(stream_class->event_classes_ht,
-                       &id_key);
+       return event_class;
 }
 
 struct bt_field_type *bt_stream_class_borrow_packet_context_field_type(
                struct bt_stream_class *stream_class)
 {
        BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->packet_context_field_type;
+       return stream_class->packet_context_ft;
 }
 
 int bt_stream_class_set_packet_context_field_type(
                struct bt_stream_class *stream_class,
-               struct bt_field_type *packet_context_type)
+               struct bt_field_type *field_type)
 {
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class, bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
+       int ret;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_header = NULL,
+               .packet_context = field_type,
+               .event_header = NULL,
+               .event_common_context = NULL,
+               .event_specific_context = NULL,
+               .event_payload = NULL,
+       };
 
-       if (packet_context_type &&
-                       bt_field_type_get_type_id(packet_context_type) !=
-                               BT_FIELD_TYPE_ID_STRUCT) {
-               /* A packet context must be a structure. */
-               BT_LOGW("Invalid parameter: stream class's packet context field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "packet-context-ft-addr=%p, packet-context-ft-id=%s",
-                       stream_class, bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class),
-                       packet_context_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(packet_context_type)));
-               ret = -1;
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(field_type, "Field type");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(bt_field_type_get_type_id(field_type) ==
+               BT_FIELD_TYPE_ID_STRUCTURE,
+               "Packet context field type is not a structure field type: %!+F",
+               field_type);
+       resolve_ctx.packet_header =
+               bt_stream_class_borrow_trace_inline(stream_class)->packet_header_ft;
+       ret = bt_resolve_field_paths(field_type, &resolve_ctx);
+       if (ret) {
                goto end;
        }
 
-       bt_put(stream_class->packet_context_field_type);
-       bt_get(packet_context_type);
-       stream_class->packet_context_field_type = packet_context_type;
-       BT_LOGV("Set stream class's packet context field type: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "packet-context-ft-addr=%p",
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class),
-               packet_context_type);
+       bt_field_type_make_part_of_trace(field_type);
+       bt_put(stream_class->packet_context_ft);
+       stream_class->packet_context_ft = bt_get(field_type);
+       bt_field_type_freeze(field_type);
+       BT_LIB_LOGV("Set stream class's packet context field type: %!+S",
+               stream_class);
 
 end:
        return ret;
@@ -755,295 +316,252 @@ end:
 struct bt_field_type *bt_stream_class_borrow_event_header_field_type(
                struct bt_stream_class *stream_class)
 {
-       struct bt_field_type *ret = NULL;
-
        BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-
-       if (!stream_class->event_header_field_type) {
-               BT_LOGV("Stream class has no event header field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class));
-               goto end;
-       }
-
-       ret = stream_class->event_header_field_type;
-
-end:
-       return ret;
+       return stream_class->event_header_ft;
 }
 
 int bt_stream_class_set_event_header_field_type(
                struct bt_stream_class *stream_class,
-               struct bt_field_type *event_header_type)
+               struct bt_field_type *field_type)
 {
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
+       int ret;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_header = NULL,
+               .packet_context = NULL,
+               .event_header = field_type,
+               .event_common_context = NULL,
+               .event_specific_context = NULL,
+               .event_payload = NULL,
+       };
 
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class));
-               ret = -1;
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(field_type, "Field type");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(bt_field_type_get_type_id(field_type) ==
+               BT_FIELD_TYPE_ID_STRUCTURE,
+               "Event header field type is not a structure field type: %!+F",
+               field_type);
+       resolve_ctx.packet_header =
+               bt_stream_class_borrow_trace_inline(stream_class)->packet_header_ft;
+       resolve_ctx.packet_context = stream_class->packet_context_ft;
+       ret = bt_resolve_field_paths(field_type, &resolve_ctx);
+       if (ret) {
                goto end;
        }
 
-       if (event_header_type &&
-                       bt_field_type_get_type_id(event_header_type) !=
-                               BT_FIELD_TYPE_ID_STRUCT) {
-               /* An event header must be a structure. */
-               BT_LOGW("Invalid parameter: stream class's event header field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "event-header-ft-addr=%p, event-header-ft-id=%s",
-                       stream_class, bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class),
-                       event_header_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(event_header_type)));
-               ret = -1;
-               goto end;
-       }
+       bt_field_type_make_part_of_trace(field_type);
+       bt_put(stream_class->event_header_ft);
+       stream_class->event_header_ft = bt_get(field_type);
+       bt_field_type_freeze(field_type);
+       BT_LIB_LOGV("Set stream class's event header field type: %!+S",
+               stream_class);
 
-       bt_put(stream_class->event_header_field_type);
-       stream_class->event_header_field_type = bt_get(event_header_type);
-       BT_LOGV("Set stream class's event header field type: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "event-header-ft-addr=%p",
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class),
-               event_header_type);
 end:
        return ret;
 }
 
-struct bt_field_type *bt_stream_class_borrow_event_context_field_type(
+struct bt_field_type *bt_stream_class_borrow_event_common_context_field_type(
                struct bt_stream_class *stream_class)
 {
-       struct bt_field_type *ret = NULL;
-
        BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-
-       if (!stream_class->event_context_field_type) {
-               goto end;
-       }
-
-       ret = stream_class->event_context_field_type;
-
-end:
-       return ret;
+       return stream_class->event_common_context_ft;
 }
 
-int bt_stream_class_set_event_context_field_type(
+int bt_stream_class_set_event_common_context_field_type(
                struct bt_stream_class *stream_class,
-               struct bt_field_type *event_context_type)
+               struct bt_field_type *field_type)
 {
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
+       int ret;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_header = NULL,
+               .packet_context = NULL,
+               .event_header = NULL,
+               .event_common_context = field_type,
+               .event_specific_context = NULL,
+               .event_payload = NULL,
+       };
 
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class, bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class));
-               ret = -1;
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(field_type, "Field type");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(bt_field_type_get_type_id(field_type) ==
+               BT_FIELD_TYPE_ID_STRUCTURE,
+               "Event common context field type is not a structure field type: %!+F",
+               field_type);
+       resolve_ctx.packet_header =
+               bt_stream_class_borrow_trace_inline(stream_class)->packet_header_ft;
+       resolve_ctx.packet_context = stream_class->packet_context_ft;
+       resolve_ctx.event_header = stream_class->event_header_ft;
+       ret = bt_resolve_field_paths(field_type, &resolve_ctx);
+       if (ret) {
                goto end;
        }
 
-       if (event_context_type &&
-                       bt_field_type_get_type_id(event_context_type) !=
-                               BT_FIELD_TYPE_ID_STRUCT) {
-               /* A packet context must be a structure. */
-               BT_LOGW("Invalid parameter: stream class's event context field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "event-context-ft-addr=%p, event-context-ft-id=%s",
-                       stream_class, bt_stream_class_get_name(stream_class),
-                       bt_stream_class_get_id(stream_class),
-                       event_context_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(event_context_type)));
-               ret = -1;
-               goto end;
-       }
+       bt_field_type_make_part_of_trace(field_type);
+       bt_put(stream_class->event_common_context_ft);
+       stream_class->event_common_context_ft = bt_get(field_type);
+       bt_field_type_freeze(field_type);
+       BT_LIB_LOGV("Set stream class's event common context field type: %!+S",
+               stream_class);
 
-       bt_put(stream_class->event_context_field_type);
-       stream_class->event_context_field_type = bt_get(event_context_type);
-       BT_LOGV("Set stream class's event context field type: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "event-context-ft-addr=%p",
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class),
-               event_context_type);
 end:
        return ret;
 }
 
-static
-int64_t get_event_class_count(void *element)
+BT_HIDDEN
+void _bt_stream_class_freeze(struct bt_stream_class *stream_class)
 {
-       return bt_stream_class_get_event_class_count(
-                       (struct bt_stream_class *) element);
+       /* The field types and default clock class are already frozen */
+       BT_ASSERT(stream_class);
+       BT_LIB_LOGD("Freezing stream class: %!+S", stream_class);
+       stream_class->frozen = true;
 }
 
-static
-void *get_event_class(void *element, int i)
+int bt_stream_class_set_default_clock_class(
+               struct bt_stream_class *stream_class,
+               struct bt_clock_class *clock_class)
 {
-       return bt_stream_class_get_event_class_by_index(
-                       (struct bt_stream_class *) element, i);
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       bt_put(stream_class->default_clock_class);
+       stream_class->default_clock_class = bt_get(clock_class);
+       bt_clock_class_freeze(clock_class);
+       BT_LIB_LOGV("Set stream class's default clock class: %!+S",
+               stream_class);
+       return 0;
 }
 
-static
-int visit_event_class(void *object, bt_visitor visitor,void *data)
+struct bt_clock_class *bt_stream_class_borrow_default_clock_class(
+               struct bt_stream_class *stream_class)
 {
-       struct bt_visitor_object obj = {
-               .object = object,
-               .type = BT_VISITOR_OBJECT_TYPE_EVENT_CLASS
-       };
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->default_clock_class;
+}
 
-       return visitor(&obj, data);
+bt_bool bt_stream_class_assigns_automatic_event_class_id(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->assigns_automatic_event_class_id;
 }
 
-BT_HIDDEN
-int bt_stream_class_visit(struct bt_stream_class *stream_class,
-               bt_visitor visitor, void *data)
+int bt_stream_class_set_assigns_automatic_event_class_id(
+               struct bt_stream_class *stream_class, bt_bool value)
 {
-       int ret;
-       struct bt_visitor_object obj = {
-               .object = stream_class,
-               .type = BT_VISITOR_OBJECT_TYPE_STREAM_CLASS
-       };
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       stream_class->assigns_automatic_event_class_id = (bool) value;
+       BT_LIB_LOGV("Set stream class's automatic event class ID "
+               "assignment property: %!+S", stream_class);
+       return 0;
+}
 
-       if (!stream_class || !visitor) {
-               BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
-                       "stream-class-addr=%p, visitor=%p",
-                       stream_class, visitor);
-               ret = -1;
-               goto end;
-       }
+bt_bool bt_stream_class_assigns_automatic_stream_id(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->assigns_automatic_stream_id;
+}
 
-       ret = visitor_helper(&obj, get_event_class_count,
-                       get_event_class,
-                       visit_event_class, visitor, data);
-       BT_LOGV("visitor_helper() returned: ret=%d", ret);
+int bt_stream_class_set_assigns_automatic_stream_id(
+               struct bt_stream_class *stream_class, bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       stream_class->assigns_automatic_stream_id = (bool) value;
+       BT_LIB_LOGV("Set stream class's automatic stream ID "
+               "assignment property: %!+S", stream_class);
+       return 0;
+}
 
-end:
-       return ret;
+bt_bool bt_stream_class_packets_have_discarded_event_counter_snapshot(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->packets_have_discarded_event_counter_snapshot;
 }
 
-BT_HIDDEN
-void bt_stream_class_freeze(struct bt_stream_class *stream_class)
+int bt_stream_class_set_packets_have_discarded_event_counter_snapshot(
+               struct bt_stream_class *stream_class, bt_bool value)
 {
-       if (!stream_class || stream_class->frozen) {
-               return;
-       }
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       stream_class->packets_have_discarded_event_counter_snapshot =
+               (bool) value;
+       BT_LIB_LOGV("Set stream class's "
+               "\"packets have discarded event counter snapshot\" property: "
+               "%!+S", stream_class);
+       return 0;
+}
 
-       BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class));
-       stream_class->frozen = 1;
-       bt_field_type_freeze(stream_class->event_header_field_type);
-       bt_field_type_freeze(stream_class->packet_context_field_type);
-       bt_field_type_freeze(stream_class->event_context_field_type);
-       bt_clock_class_freeze(stream_class->clock_class);
+bt_bool bt_stream_class_packets_have_packet_counter_snapshot(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->packets_have_packet_counter_snapshot;
 }
 
-BT_HIDDEN
-int bt_stream_class_validate_single_clock_class(
-               struct bt_stream_class *stream_class,
-               struct bt_clock_class **expected_clock_class)
+int bt_stream_class_set_packets_have_packet_counter_snapshot(
+               struct bt_stream_class *stream_class, bt_bool value)
 {
-       int ret;
-       uint64_t i;
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       stream_class->packets_have_packet_counter_snapshot =
+               (bool) value;
+       BT_LIB_LOGV("Set stream class's "
+               "\"packets have packet counter snapshot\" property: "
+               "%!+S", stream_class);
+       return 0;
+}
 
-       BT_ASSERT(stream_class);
-       BT_ASSERT(expected_clock_class);
-       ret = bt_field_type_validate_single_clock_class(
-               stream_class->packet_context_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Stream class's packet context field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->packet_context_field_type);
-               goto end;
-       }
+bt_bool bt_stream_class_packets_have_default_beginning_clock_value(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->packets_have_default_beginning_cv;
+}
 
-       ret = bt_field_type_validate_single_clock_class(
-               stream_class->event_header_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Stream class's event header field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->event_header_field_type);
-               goto end;
-       }
+int bt_stream_class_set_packets_have_default_beginning_clock_value(
+               struct bt_stream_class *stream_class, bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(!value || stream_class->default_clock_class,
+               "Stream class does not have a default clock class: %!+S",
+               stream_class);
+       stream_class->packets_have_default_beginning_cv = (bool) value;
+       BT_LIB_LOGV("Set stream class's "
+               "\"packets have default beginning clock value\" property: "
+               "%!+S", stream_class);
+       return 0;
+}
 
-       ret = bt_field_type_validate_single_clock_class(
-               stream_class->event_context_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Stream class's event context field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       stream_class,
-                       bt_stream_class_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->event_context_field_type);
-               goto end;
-       }
+bt_bool bt_stream_class_packets_have_default_end_clock_value(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->packets_have_default_end_cv;
+}
 
-       for (i = 0; i < stream_class->event_classes->len; i++) {
-               struct bt_event_class *event_class =
-                       g_ptr_array_index(stream_class->event_classes, i);
-
-               BT_ASSERT(event_class);
-               ret = bt_event_class_validate_single_clock_class(
-                       event_class, expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Stream class's event class contains a "
-                               "field type which is not recursively mapped to "
-                               "the expected clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-name=\"%s\", "
-                               "stream-class-id=%" PRId64,
-                               stream_class,
-                               bt_stream_class_get_name(stream_class),
-                               stream_class->id);
-                       goto end;
-               }
-       }
+int bt_stream_class_set_packets_have_default_end_clock_value(
+               struct bt_stream_class *stream_class, bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(!value || stream_class->default_clock_class,
+               "Stream class does not have a default clock class: %!+S",
+               stream_class);
+       stream_class->packets_have_default_end_cv = (bool) value;
+       BT_LIB_LOGV("Set stream class's "
+               "\"packets have default end clock value\" property: "
+               "%!+S", stream_class);
+       return 0;
+}
 
-end:
-       return ret;
+bt_bool bt_stream_class_default_clock_is_always_known(
+               struct bt_stream_class *stream_class)
+{
+       /* BT_CLOCK_VALUE_STATUS_UNKNOWN is not supported as of 2.0 */
+       return BT_TRUE;
 }
index 61636206015624ab6b53ecc0d5e6901cf2d1d752..665347a2404701cc31815fc1f7e0bc424733a9ec 100644 (file)
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/align-internal.h>
 #include <babeltrace/assert-internal.h>
+#include <babeltrace/property-internal.h>
 #include <inttypes.h>
 #include <unistd.h>
 
-static inline
-void bt_stream_finalize(struct bt_stream *stream)
-{
-       BT_LOGD("Finalizing stream object: addr=%p, name=\"%s\"",
-               stream, bt_stream_get_name(stream));
-
-       if (stream->name) {
-               g_string_free(stream->name, TRUE);
-       }
-}
+#define BT_ASSERT_PRE_STREAM_HOT(_stream) \
+       BT_ASSERT_PRE_HOT((_stream), "Stream", ": %!+s", (_stream))
 
 static
-void bt_stream_destroy(struct bt_object *obj)
+void destroy_stream(struct bt_object *obj)
 {
        struct bt_stream *stream = (void *) obj;
 
-       BT_LOGD("Destroying stream object: addr=%p, name=\"%s\"",
-               stream, bt_stream_get_name(stream));
+       BT_LIB_LOGD("Destroying stream object: %!+s", stream);
+
+       if (stream->name.str) {
+               g_string_free(stream->name.str, TRUE);
+       }
+
        bt_object_pool_finalize(&stream->packet_pool);
-       bt_stream_finalize((void *) obj);
        g_free(stream);
 }
 
-static inline
-int bt_stream_initialize(
-               struct bt_stream *stream,
-               struct bt_stream_class *stream_class, const char *name,
-               uint64_t id, bt_object_release_func release_func)
+static
+void bt_stream_free_packet(struct bt_packet *packet, struct bt_stream *stream)
 {
-       int ret = 0;
-       struct bt_trace *trace = NULL;
-
-       bt_object_init_shared_with_parent(&stream->base, release_func);
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               goto error;
-       }
-
-       BT_LOGD("Initializing stream object: stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-name=\"%s\", "
-               "stream-id=%" PRIu64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               name, id);
-       trace = bt_stream_class_borrow_trace(stream_class);
-       if (!trace) {
-               BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-name=\"%s\"",
-                       stream_class,
-                       bt_stream_class_get_name(stream_class), name);
-               goto error;
-       }
-
-       if (id != -1ULL) {
-               /*
-                * Validate that the given ID is unique amongst all the
-                * existing trace's streams created from the same stream
-                * class.
-                */
-               size_t i;
+       bt_packet_destroy(packet);
+}
 
-               for (i = 0; i < trace->streams->len; i++) {
-                       struct bt_stream *trace_stream =
-                               g_ptr_array_index(trace->streams, i);
+BT_ASSERT_PRE_FUNC
+static inline
+bool stream_id_is_unique(struct bt_trace *trace,
+               struct bt_stream_class *stream_class, uint64_t id)
+{
+       uint64_t i;
+       bool is_unique = true;
 
-                       if (trace_stream->stream_class != (void *) stream_class) {
-                               continue;
-                       }
+       for (i = 0; i < trace->streams->len; i++) {
+               struct bt_stream *stream = trace->streams->pdata[i];
 
-                       if (trace_stream->id == id) {
-                               BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID.");
-                               goto error;
-                       }
+               if (stream->class != stream_class) {
+                       continue;
                }
-       }
 
-       /*
-        * Acquire reference to parent since stream will become publicly
-        * reachable; it needs its parent to remain valid.
-        */
-       bt_object_set_parent(&stream->base, &trace->base);
-       stream->stream_class = stream_class;
-       stream->id = (int64_t) id;
-
-       if (name) {
-               stream->name = g_string_new(name);
-               if (!stream->name) {
-                       BT_LOGE_STR("Failed to allocate a GString.");
-                       goto error;
+               if (stream->id == id) {
+                       is_unique = false;
+                       goto end;
                }
        }
 
-       BT_LOGD("Set stream's trace parent: trace-addr=%p", trace);
-
-       /* Add this stream to the trace's streams */
-       BT_LOGD("Created stream object: addr=%p", stream);
-       goto end;
-
-error:
-       ret = -1;
-
 end:
-       return ret;
-}
-
-static
-void bt_stream_free_packet(struct bt_packet *packet, struct bt_stream *stream)
-{
-       bt_packet_destroy(packet);
+       return is_unique;
 }
 
 static
-struct bt_stream *bt_stream_create_with_id_no_check(
-               struct bt_stream_class *stream_class,
-               const char *name, uint64_t id)
+struct bt_stream *create_stream_with_id(struct bt_stream_class *stream_class,
+                 uint64_t id)
 {
        int ret;
-       struct bt_stream *stream = NULL;
-       struct bt_trace *trace = NULL;
-
-       BT_LOGD("Creating stream object: stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-name=\"%s\", "
-               "stream-id=%" PRIu64,
-               stream_class, bt_stream_class_get_name(stream_class),
-               name, id);
-
-       trace = bt_stream_class_borrow_trace(stream_class);
-       if (!trace) {
-               BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-name=\"%s\"",
-                       stream_class, bt_stream_class_get_name(stream_class),
-                       name);
-               goto error;
-       }
-
-       if (bt_trace_is_static(trace)) {
-               /*
-                * A static trace has the property that all its stream
-                * classes, clock classes, and streams are definitive:
-                * no more can be added, and each object is also frozen.
-                */
-               BT_LOGW("Invalid parameter: cannot create stream from a stream class which is part of a static trace: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-name=\"%s\", trace-addr=%p",
-                       stream_class, bt_stream_class_get_name(stream_class),
-                       name, trace);
-               goto error;
-       }
-
+       struct bt_stream *stream;
+       struct bt_trace *trace;
+
+       BT_ASSERT(stream_class);
+       trace = bt_stream_class_borrow_trace_inline(stream_class);
+       BT_ASSERT_PRE(stream_id_is_unique(trace, stream_class, id),
+               "Duplicate stream ID: %![trace-]+t, id=%" PRIu64, trace, id);
+       BT_ASSERT_PRE(!trace->is_static,
+               "Trace is static: %![trace-]+t", trace);
+       BT_LIB_LOGD("Creating stream object: %![trace-]+t, id=%" PRIu64,
+               trace, id);
        stream = g_new0(struct bt_stream, 1);
        if (!stream) {
                BT_LOGE_STR("Failed to allocate one stream.");
                goto error;
        }
 
-       ret = bt_stream_initialize(stream, stream_class, name,
-               id, bt_stream_destroy);
-       if (ret) {
-               /* bt_stream_initialize() logs errors */
+       bt_object_init_shared_with_parent(&stream->base, destroy_stream);
+       stream->name.str = g_string_new(NULL);
+       if (!stream->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
                goto error;
        }
 
+       stream->id = id;
        ret = bt_object_pool_initialize(&stream->packet_pool,
                (bt_object_pool_new_object_func) bt_packet_new,
                (bt_object_pool_destroy_object_func) bt_stream_free_packet,
@@ -217,8 +133,10 @@ struct bt_stream *bt_stream_create_with_id_no_check(
                goto error;
        }
 
-       g_ptr_array_add(trace->streams, stream);
-       BT_LOGD("Created stream object: addr=%p", stream);
+       stream->class = stream_class;
+       bt_trace_add_stream(trace, stream);
+       bt_stream_class_freeze(stream_class);
+       BT_LIB_LOGD("Created stream object: %!+s", stream);
        goto end;
 
 error:
@@ -228,53 +146,63 @@ end:
        return stream;
 }
 
-struct bt_stream *bt_stream_create(struct bt_stream_class *stream_class,
-               const char *name, uint64_t id_param)
+struct bt_stream *bt_stream_create(struct bt_stream_class *stream_class)
 {
-       struct bt_stream *stream = NULL;
-       int64_t id = (int64_t) id_param;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               goto end;
-       }
-
-       if (id < 0) {
-               BT_LOGW("Invalid parameter: invalid stream's ID: "
-                       "name=\"%s\", id=%" PRIu64,
-                       name, id_param);
-               goto end;
-       }
-
-       stream = bt_stream_create_with_id_no_check(stream_class,
-               name, id_param);
+       uint64_t id;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(stream_class->assigns_automatic_stream_id,
+               "Stream class does not automatically assigns stream IDs: "
+               "%![sc-]+S", stream_class);
+       id = bt_trace_get_automatic_stream_id(
+                       bt_stream_class_borrow_trace_inline(stream_class),
+                       stream_class);
+       return create_stream_with_id(stream_class, id);
+}
 
-end:
-       return stream;
+struct bt_stream *bt_stream_create_with_id(struct bt_stream_class *stream_class,
+               uint64_t id)
+{
+       BT_ASSERT_PRE(!stream_class->assigns_automatic_stream_id,
+               "Stream class automatically assigns stream IDs: "
+               "%![sc-]+S", stream_class);
+       return create_stream_with_id(stream_class, id);
 }
 
 struct bt_stream_class *bt_stream_borrow_class(struct bt_stream *stream)
 {
-       BT_ASSERT(stream);
-       return stream->stream_class;
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       return stream->class;
 }
 
 const char *bt_stream_get_name(struct bt_stream *stream)
 {
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       return stream->name ? stream->name->str : NULL;
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream class");
+       return stream->name.value;
 }
 
-int64_t bt_stream_get_id(struct bt_stream *stream)
+int bt_stream_set_name(struct bt_stream *stream, const char *name)
 {
-       int64_t ret;
+       BT_ASSERT_PRE_NON_NULL(stream, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_STREAM_HOT(stream);
+       g_string_assign(stream->name.str, name);
+       stream->name.value = stream->name.str->str;
+       BT_LIB_LOGV("Set stream class's name: %!+S", stream);
+       return 0;
+}
 
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       ret = stream->id;
-       if (ret < 0) {
-               BT_LOGV("Stream's ID is not set: addr=%p, name=\"%s\"",
-                       stream, bt_stream_get_name(stream));
-       }
+uint64_t bt_stream_get_id(struct bt_stream *stream)
+{
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream class");
+       return stream->id;
+}
 
-       return ret;
+BT_HIDDEN
+void _bt_stream_freeze(struct bt_stream *stream)
+{
+       /* The field types and default clock class are already frozen */
+       BT_ASSERT(stream);
+       BT_LIB_LOGD("Freezing stream: %!+s", stream);
+       stream->frozen = true;
 }
index 57a3769bc4c4b6ea33eaebf88aac04fe5d36aefe..69189c44cf8df64a198ffa3b170e5d5a36cb9064 100644 (file)
 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/attributes-internal.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
-#include <babeltrace/ctf-ir/visitor-internal.h>
-#include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
+#include <babeltrace/ctf-ir/resolve-field-path-internal.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/values.h>
 #include <babeltrace/values-internal.h>
 #include <babeltrace/types.h>
 #include <babeltrace/endian-internal.h>
 #include <babeltrace/assert-internal.h>
+#include <babeltrace/compat/glib-internal.h>
 #include <inttypes.h>
 #include <stdint.h>
 #include <string.h>
 #include <stdlib.h>
 
-#define DEFAULT_IDENTIFIER_SIZE 128
-#define DEFAULT_METADATA_STRING_SIZE 4096
-
-struct listener_wrapper {
-       bt_listener_cb listener;
-       void *data;
-};
-
 struct bt_trace_is_static_listener_elem {
        bt_trace_is_static_listener func;
        bt_trace_listener_removed removed;
        void *data;
 };
 
-static inline
-void bt_trace_finalize(struct bt_trace *trace)
-{
-       BT_LOGD("Finalizing trace object: addr=%p, name=\"%s\"",
-               trace, bt_trace_get_name(trace));
-
-       if (trace->environment) {
-               BT_LOGD_STR("Destroying environment attributes.");
-               bt_attributes_destroy(trace->environment);
-       }
-
-       if (trace->name) {
-               g_string_free(trace->name, TRUE);
-       }
-
-       if (trace->clock_classes) {
-               BT_LOGD_STR("Putting clock classes.");
-               g_ptr_array_free(trace->clock_classes, TRUE);
-       }
-
-       if (trace->streams) {
-               BT_LOGD_STR("Destroying streams.");
-               g_ptr_array_free(trace->streams, TRUE);
-       }
-
-       if (trace->stream_classes) {
-               BT_LOGD_STR("Destroying stream classes.");
-               g_ptr_array_free(trace->stream_classes, TRUE);
-       }
-
-       BT_LOGD_STR("Putting packet header field type.");
-       bt_put(trace->packet_header_field_type);
-}
+#define BT_ASSERT_PRE_TRACE_HOT(_trace) \
+       BT_ASSERT_PRE_HOT((_trace), "Trace", ": %!+t", (_trace))
 
 static
-void bt_trace_destroy(struct bt_object *obj)
+void destroy_trace(struct bt_object *obj)
 {
        struct bt_trace *trace = (void *) obj;
 
-       BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
-               trace, bt_trace_get_name(trace));
+       BT_LIB_LOGD("Destroying trace object: %!+t", trace);
 
        /*
         * Call remove listeners first so that everything else still
@@ -134,60 +93,34 @@ void bt_trace_destroy(struct bt_object *obj)
                g_array_free(trace->is_static_listeners, TRUE);
        }
 
-       if (trace->listeners) {
-               g_ptr_array_free(trace->listeners, TRUE);
-       }
-
        bt_object_pool_finalize(&trace->packet_header_field_pool);
-       bt_trace_finalize(trace);
-       g_free(trace);
-}
 
-static inline
-int bt_trace_initialize(struct bt_trace *trace,
-               bt_object_release_func release_func)
-{
-       int ret = 0;
-
-       BT_LOGD_STR("Initializing trace object.");
-       trace->native_byte_order = BT_BYTE_ORDER_UNSPECIFIED;
-       bt_object_init_shared_with_parent(&trace->base, release_func);
-       trace->clock_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_put);
-       if (!trace->clock_classes) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
+       if (trace->environment) {
+               BT_LOGD_STR("Destroying environment attributes.");
+               bt_attributes_destroy(trace->environment);
        }
 
-       trace->streams = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!trace->streams) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
+       if (trace->name.str) {
+               g_string_free(trace->name.str, TRUE);
        }
 
-       trace->stream_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!trace->stream_classes) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
+       if (trace->streams) {
+               BT_LOGD_STR("Destroying streams.");
+               g_ptr_array_free(trace->streams, TRUE);
        }
 
-       /* Create the environment array object */
-       trace->environment = bt_attributes_create();
-       if (!trace->environment) {
-               BT_LOGE_STR("Cannot create empty attributes object.");
-               goto error;
+       if (trace->stream_classes) {
+               BT_LOGD_STR("Destroying stream classes.");
+               g_ptr_array_free(trace->stream_classes, TRUE);
        }
 
-       BT_LOGD("Initialized trace object: addr=%p", trace);
-       goto end;
-
-error:
-       ret = -1;
+       if (trace->stream_classes_stream_count) {
+               g_hash_table_destroy(trace->stream_classes_stream_count);
+       }
 
-end:
-       return ret;
+       BT_LOGD_STR("Putting packet header field type.");
+       bt_put(trace->packet_header_ft);
+       g_free(trace);
 }
 
 static
@@ -202,26 +135,47 @@ struct bt_trace *bt_trace_create(void)
        struct bt_trace *trace = NULL;
        int ret;
 
-       BT_LOGD_STR("Creating trace object.");
+       BT_LOGD_STR("Creating default trace object.");
        trace = g_new0(struct bt_trace, 1);
        if (!trace) {
                BT_LOGE_STR("Failed to allocate one trace.");
                goto error;
        }
 
-       ret = bt_trace_initialize(trace, bt_trace_destroy);
-       if (ret) {
-               /* bt_trace_initialize() logs errors */
+       bt_object_init_shared_with_parent(&trace->base, destroy_trace);
+       trace->streams = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!trace->streams) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
                goto error;
        }
 
-       trace->listeners = g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) g_free);
-       if (!trace->listeners) {
+       trace->stream_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!trace->stream_classes) {
                BT_LOGE_STR("Failed to allocate one GPtrArray.");
                goto error;
        }
 
+       trace->stream_classes_stream_count = g_hash_table_new(g_direct_hash,
+               g_direct_equal);
+       if (!trace->stream_classes_stream_count) {
+               BT_LOGE_STR("Failed to allocate one GHashTable.");
+               goto error;
+       }
+
+       trace->name.str = g_string_new(NULL);
+       if (!trace->name.str) {
+               BT_LOGE_STR("Failed to allocate one GString.");
+               goto error;
+       }
+
+       trace->environment = bt_attributes_create();
+       if (!trace->environment) {
+               BT_LOGE_STR("Cannot create empty attributes object.");
+               goto error;
+       }
+
        trace->is_static_listeners = g_array_new(FALSE, TRUE,
                sizeof(struct bt_trace_is_static_listener_elem));
        if (!trace->is_static_listeners) {
@@ -229,6 +183,7 @@ struct bt_trace *bt_trace_create(void)
                goto error;
        }
 
+       trace->assigns_automatic_stream_class_id = true;
        ret = bt_object_pool_initialize(&trace->packet_header_field_pool,
                (bt_object_pool_new_object_func) bt_field_wrapper_new,
                (bt_object_pool_destroy_object_func) free_packet_header_field,
@@ -239,282 +194,163 @@ struct bt_trace *bt_trace_create(void)
                goto error;
        }
 
-       BT_LOGD("Created trace object: addr=%p", trace);
-       return trace;
+       BT_LIB_LOGD("Created trace object: %!+t", trace);
+       goto end;
 
 error:
        BT_PUT(trace);
+
+end:
        return trace;
 }
 
 const char *bt_trace_get_name(struct bt_trace *trace)
 {
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->name ? trace->name->str : NULL;
+       return trace->name.value;
 }
 
 int bt_trace_set_name(struct bt_trace *trace, const char *name)
 {
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!name) {
-               BT_LOGW_STR("Invalid parameter: name is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       trace->name = trace->name ? g_string_assign(trace->name, name) :
-                       g_string_new(name);
-       if (!trace->name) {
-               BT_LOGE_STR("Failed to allocate one GString.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_TRACE_HOT(trace);
+       g_string_assign(trace->name.str, name);
+       trace->name.value = trace->name.str->str;
+       BT_LIB_LOGV("Set trace's name: %!+t", trace);
+       return 0;
 }
 
-const unsigned char *bt_trace_get_uuid(struct bt_trace *trace)
+bt_uuid bt_trace_get_uuid(struct bt_trace *trace)
 {
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->uuid_set ? trace->uuid : NULL;
+       return trace->uuid.value;
 }
 
-int bt_trace_set_uuid(struct bt_trace *trace,
-               const unsigned char *uuid)
+int bt_trace_set_uuid(struct bt_trace *trace, bt_uuid uuid)
 {
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!uuid) {
-               BT_LOGW_STR("Invalid parameter: UUID is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       memcpy(trace->uuid, uuid, BABELTRACE_UUID_LEN);
-       trace->uuid_set = BT_TRUE;
-       BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
-               "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-               trace, bt_trace_get_name(trace),
-               (unsigned int) uuid[0],
-               (unsigned int) uuid[1],
-               (unsigned int) uuid[2],
-               (unsigned int) uuid[3],
-               (unsigned int) uuid[4],
-               (unsigned int) uuid[5],
-               (unsigned int) uuid[6],
-               (unsigned int) uuid[7],
-               (unsigned int) uuid[8],
-               (unsigned int) uuid[9],
-               (unsigned int) uuid[10],
-               (unsigned int) uuid[11],
-               (unsigned int) uuid[12],
-               (unsigned int) uuid[13],
-               (unsigned int) uuid[14],
-               (unsigned int) uuid[15]);
-
-end:
-       return ret;
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(uuid, "UUID");
+       BT_ASSERT_PRE_TRACE_HOT(trace);
+       memcpy(trace->uuid.uuid, uuid, BABELTRACE_UUID_LEN);
+       trace->uuid.value = trace->uuid.uuid;
+       BT_LIB_LOGV("Set trace's UUID: %!+t", trace);
+       return 0;
 }
 
-int bt_trace_set_environment_field(struct bt_trace *trace,
-               const char *name, struct bt_value *value)
+BT_ASSERT_FUNC
+static
+bool trace_has_environment_entry(struct bt_trace *trace, const char *name)
 {
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!name) {
-               BT_LOGW_STR("Invalid parameter: name is NULL.");
-               ret = -1;
-               goto end;
-       }
+       struct bt_value *attribute;
 
-       if (!value) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->is_static) {
-               BT_LOGW("Invalid parameter: trace is static: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_identifier_is_valid(name)) {
-               BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\"",
-                       trace, bt_trace_get_name(trace), name);
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_value_is_integer(value) && !bt_value_is_string(value)) {
-               BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\", env-value-type=%s",
-                       trace, bt_trace_get_name(trace), name,
-                       bt_value_type_string(bt_value_get_type(value)));
-               ret = -1;
-               goto end;
-       }
+       BT_ASSERT(trace);
 
-       if (trace->frozen) {
-               /*
-                * New environment fields may be added to a frozen trace,
-                * but existing fields may not be changed.
-                *
-                * The object passed is frozen like all other attributes.
-                */
-               struct bt_value *attribute =
-                       bt_attributes_borrow_field_value_by_name(
-                               trace->environment, name);
-
-               if (attribute) {
-                       BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
-                               "trace-addr=%p, trace-name=\"%s\", "
-                               "env-name=\"%s\"",
-                               trace, bt_trace_get_name(trace), name);
-                       ret = -1;
-                       goto end;
-               }
+       attribute = bt_attributes_borrow_field_value_by_name(
+               trace->environment, name);
+       return attribute != NULL;
+}
 
-               bt_value_freeze(value);
-       }
+static
+int set_environment_entry(struct bt_trace *trace, const char *name,
+               struct bt_value *value)
+{
+       int ret;
 
+       BT_ASSERT(trace);
+       BT_ASSERT(name);
+       BT_ASSERT(value);
+       BT_ASSERT_PRE(!trace->frozen ||
+               !trace_has_environment_entry(trace, name),
+               "Trace is frozen: cannot replace environment entry: "
+               "%![trace-]+t, entry-name=\"%s\"", trace, name);
        ret = bt_attributes_set_field_value(trace->environment, name,
                value);
+       bt_value_freeze(value);
        if (ret) {
-               BT_LOGE("Cannot set environment field's value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\"",
-                       trace, bt_trace_get_name(trace), name);
+               BT_LIB_LOGE("Cannot set trace's environment entry: "
+                       "%![trace-]+t, entry-name=\"%s\"", trace, name);
        } else {
-               BT_LOGV("Set environment field's value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\", value-addr=%p",
-                       trace, bt_trace_get_name(trace), name, value);
+               BT_LIB_LOGV("Set trace's environment entry: "
+                       "%![trace-]+t, entry-name=\"%s\"", trace, name);
        }
 
-end:
        return ret;
 }
 
-int bt_trace_set_environment_field_string(struct bt_trace *trace,
+int bt_trace_set_environment_entry_string(struct bt_trace *trace,
                const char *name, const char *value)
 {
-       int ret = 0;
-       struct bt_value *env_value_string_obj = NULL;
-
-       if (!value) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               ret = -1;
-               goto end;
-       }
+       int ret;
+       struct bt_value *value_obj;
 
-       env_value_string_obj = bt_value_string_create_init(value);
-       if (!env_value_string_obj) {
-               BT_LOGE_STR("Cannot create string value object.");
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       value_obj = bt_value_string_create_init(value);
+       if (!value_obj) {
+               BT_LOGE_STR("Cannot create a string value object.");
                ret = -1;
                goto end;
        }
 
-       /* bt_trace_set_environment_field() logs errors */
-       ret = bt_trace_set_environment_field(trace, name,
-               env_value_string_obj);
+       /* set_environment_entry() logs errors */
+       ret = set_environment_entry(trace, name, value_obj);
 
 end:
-       bt_put(env_value_string_obj);
+       bt_put(value_obj);
        return ret;
 }
 
-int bt_trace_set_environment_field_integer(
+int bt_trace_set_environment_entry_integer(
                struct bt_trace *trace, const char *name, int64_t value)
 {
-       int ret = 0;
-       struct bt_value *env_value_integer_obj = NULL;
+       int ret;
+       struct bt_value *value_obj;
 
-       env_value_integer_obj = bt_value_integer_create_init(value);
-       if (!env_value_integer_obj) {
-               BT_LOGE_STR("Cannot create integer value object.");
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       value_obj = bt_value_integer_create_init(value);
+       if (!value_obj) {
+               BT_LOGE_STR("Cannot create an integer value object.");
                ret = -1;
                goto end;
        }
 
-       /* bt_trace_set_environment_field() logs errors */
-       ret = bt_trace_set_environment_field(trace, name,
-               env_value_integer_obj);
+       /* set_environment_entry() logs errors */
+       ret = set_environment_entry(trace, name, value_obj);
 
 end:
-       bt_put(env_value_integer_obj);
+       bt_put(value_obj);
        return ret;
 }
 
-int64_t bt_trace_get_environment_field_count(struct bt_trace *trace)
+uint64_t bt_trace_get_environment_entry_count(struct bt_trace *trace)
 {
        int64_t ret;
 
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
        ret = bt_attributes_get_count(trace->environment);
        BT_ASSERT(ret >= 0);
-       return ret;
-}
-
-const char *
-bt_trace_get_environment_field_name_by_index(struct bt_trace *trace,
-               uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return bt_attributes_get_field_name(trace->environment, index);
+       return (uint64_t) ret;
 }
 
-struct bt_value *bt_trace_borrow_environment_field_value_by_index(
-               struct bt_trace *trace, uint64_t index)
+void bt_trace_borrow_environment_entry_by_index(
+               struct bt_trace *trace, uint64_t index,
+               const char **name, struct bt_value **value)
 {
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return bt_attributes_borrow_field_value(trace->environment, index);
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_VALID_INDEX(index,
+               bt_attributes_get_count(trace->environment));
+       *value = bt_attributes_borrow_field_value(trace->environment, index);
+       BT_ASSERT(*value);
+       *name = bt_attributes_get_field_name(trace->environment, index);
+       BT_ASSERT(*name);
 }
 
-struct bt_value *bt_trace_borrow_environment_field_value_by_name(
+struct bt_value *bt_trace_borrow_environment_entry_value_by_name(
                struct bt_trace *trace, const char *name)
 {
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
@@ -523,1249 +359,134 @@ struct bt_value *bt_trace_borrow_environment_field_value_by_name(
                name);
 }
 
-int bt_trace_add_clock_class(struct bt_trace *trace,
-               struct bt_clock_class *clock_class)
+uint64_t bt_trace_get_stream_count(struct bt_trace *trace)
 {
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return (uint64_t) trace->streams->len;
+}
 
-       if (trace->is_static) {
-               BT_LOGW("Invalid parameter: trace is static: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
+struct bt_stream *bt_trace_borrow_stream_by_index(
+               struct bt_trace *trace, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_VALID_INDEX(index, trace->streams->len);
+       return g_ptr_array_index(trace->streams, index);
+}
 
-       if (!bt_clock_class_is_valid(clock_class)) {
-               BT_LOGW("Invalid parameter: clock class is invalid: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                       trace, bt_trace_get_name(trace),
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
+struct bt_stream *bt_trace_borrow_stream_by_id(
+               struct bt_trace *trace, uint64_t id)
+{
+       struct bt_stream *stream = NULL;
+       uint64_t i;
 
-       /* Check for duplicate clock classes */
-       if (bt_trace_has_clock_class(trace, clock_class)) {
-               BT_LOGW("Invalid parameter: clock class already exists in trace: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                       trace, bt_trace_get_name(trace),
-                       clock_class, bt_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
 
-       bt_get(clock_class);
-       g_ptr_array_add(trace->clock_classes, clock_class);
+       for (i = 0; i < trace->streams->len; i++) {
+               struct bt_stream *stream_candidate =
+                       g_ptr_array_index(trace->streams, i);
 
-       if (trace->frozen) {
-               BT_LOGV_STR("Freezing added clock class because trace is frozen.");
-               bt_clock_class_freeze(clock_class);
+               if (stream_candidate->id == id) {
+                       stream = stream_candidate;
+                       goto end;
+               }
        }
 
-       BT_LOGV("Added clock class to trace: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "clock-class-addr=%p, clock-class-name=\"%s\"",
-               trace, bt_trace_get_name(trace),
-               clock_class, bt_clock_class_get_name(clock_class));
-
 end:
-       return ret;
+       return stream;
 }
 
-int64_t bt_trace_get_clock_class_count(struct bt_trace *trace)
+uint64_t bt_trace_get_stream_class_count(struct bt_trace *trace)
 {
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->clock_classes->len;
+       return (uint64_t) trace->stream_classes->len;
 }
 
-struct bt_clock_class *bt_trace_borrow_clock_class_by_index(
+struct bt_stream_class *bt_trace_borrow_stream_class_by_index(
                struct bt_trace *trace, uint64_t index)
 {
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(index < trace->clock_classes->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, trace->clock_classes->len);
-       return g_ptr_array_index(trace->clock_classes, index);
+       BT_ASSERT_PRE_VALID_INDEX(index, trace->stream_classes->len);
+       return g_ptr_array_index(trace->stream_classes, index);
 }
 
-static
-bool packet_header_field_type_is_valid(struct bt_trace *trace,
-               struct bt_field_type *packet_header_type)
+struct bt_stream_class *bt_trace_borrow_stream_class_by_id(
+               struct bt_trace *trace, uint64_t id)
 {
-       int ret;
-       bool is_valid = true;
-       struct bt_field_type *field_type = NULL;
-
-       if (!packet_header_type) {
-               /*
-                * No packet header field type: trace must have only
-                * one stream. At this point the stream class being
-                * added is not part of the trace yet, so we validate
-                * that the trace contains no stream classes yet.
-                */
-               if (trace->stream_classes->len >= 1) {
-                       BT_LOGW_STR("Invalid packet header field type: "
-                               "packet header field type does not exist but there's more than one stream class in the trace.");
-                       goto invalid;
-               }
+       struct bt_stream_class *stream_class = NULL;
+       uint64_t i;
 
-               /* No packet header field type: valid at this point */
-               goto end;
-       }
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
 
-       /* Packet header field type, if it exists, must be a structure */
-       if (packet_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
-                       "ft-addr=%p, ft-id=%s",
-                       packet_header_type,
-                       bt_common_field_type_id_string(packet_header_type->id));
-               goto invalid;
-       }
+       for (i = 0; i < trace->stream_classes->len; i++) {
+               struct bt_stream_class *stream_class_candidate =
+                       g_ptr_array_index(trace->stream_classes, i);
 
-       /*
-        * If there's a `magic` field, it must be a 32-bit unsigned
-        * integer field type. Also it must be the first field of the
-        * packet header field type.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_header_type, "magic");
-       if (field_type) {
-               const char *field_name;
-
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
-                               "magic-ft-addr=%p, magic-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
+               if (stream_class_candidate->id == id) {
+                       stream_class = stream_class_candidate;
+                       goto end;
                }
+       }
 
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
-                               "magic-ft-addr=%p", field_type);
-                       goto invalid;
-               }
+end:
+       return stream_class;
+}
 
-               if (bt_field_type_integer_get_size(field_type) != 32) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
-                               "magic-ft-addr=%p, magic-ft-size=%u",
-                               field_type,
-                               bt_field_type_integer_get_size(field_type));
-                       goto invalid;
-               }
+struct bt_field_type *bt_trace_borrow_packet_header_field_type(
+               struct bt_trace *trace)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->packet_header_ft;
+}
 
-               ret = bt_field_type_structure_borrow_field_by_index(
-                       packet_header_type, &field_name, NULL, 0);
-               BT_ASSERT(ret == 0);
+int bt_trace_set_packet_header_field_type(struct bt_trace *trace,
+               struct bt_field_type *field_type)
+{
+       int ret;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_header = field_type,
+               .packet_context = NULL,
+               .event_header = NULL,
+               .event_common_context = NULL,
+               .event_specific_context = NULL,
+               .event_payload = NULL,
+       };
 
-               if (strcmp(field_name, "magic") != 0) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
-                               "magic-ft-addr=%p, first-field-name=\"%s\"",
-                               field_type, field_name);
-                       goto invalid;
-               }
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(field_type, "Field type");
+       BT_ASSERT_PRE_TRACE_HOT(trace);
+       BT_ASSERT_PRE(bt_field_type_get_type_id(field_type) ==
+               BT_FIELD_TYPE_ID_STRUCTURE,
+               "Packet header field type is not a structure field type: %!+F",
+               field_type);
+       ret = bt_resolve_field_paths(field_type, &resolve_ctx);
+       if (ret) {
+               goto end;
        }
 
-       /*
-        * If there's a `uuid` field, it must be an array field type of
-        * length 16 with an 8-bit unsigned integer element field type.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_header_type, "uuid");
-       if (field_type) {
-               struct bt_field_type *elem_ft;
-
-               if (field_type->id != BT_FIELD_TYPE_ID_ARRAY) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
-                               "uuid-ft-addr=%p, uuid-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_array_get_length(field_type) != 16) {
-                       BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
-                               "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
-                               field_type,
-                               bt_field_type_array_get_length(field_type));
-                       goto invalid;
-               }
-
-               elem_ft = bt_field_type_array_borrow_element_field_type(field_type);
-               BT_ASSERT(elem_ft);
+       bt_field_type_make_part_of_trace(field_type);
+       bt_put(trace->packet_header_ft);
+       trace->packet_header_ft = bt_get(field_type);
+       bt_field_type_freeze(field_type);
+       BT_LIB_LOGV("Set trace's packet header field type: %!+t", trace);
 
-               if (elem_ft->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
-                               "elem-ft-addr=%p, elem-ft-id=%s",
-                               elem_ft,
-                               bt_common_field_type_id_string(elem_ft->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(elem_ft)) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
-                               "elem-ft-addr=%p", elem_ft);
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_get_size(elem_ft) != 8) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
-                               "elem-ft-addr=%p, elem-ft-size=%u",
-                               elem_ft,
-                               bt_field_type_integer_get_size(elem_ft));
-                       goto invalid;
-               }
-       }
-
-       /*
-        * The `stream_id` field must exist if there's more than one
-        * stream classes in the trace.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_header_type, "stream_id");
-
-       if (!field_type && trace->stream_classes->len >= 1) {
-               BT_LOGW_STR("Invalid packet header field type: "
-                       "`stream_id` field does not exist but there's more than one stream class in the trace.");
-               goto invalid;
-       }
-
-       /*
-        * If there's a `stream_id` field, it must be an unsigned
-        * integer field type.
-        */
-       if (field_type) {
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
-                               "stream-id-ft-addr=%p, stream-id-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
-                               "stream-id-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `packet_seq_num` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_header_type, "packet_seq_num");
-       if (field_type) {
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: "
-                               "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: "
-                               "packet-seq-num-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       goto end;
-
-invalid:
-       is_valid = false;
-
-end:
-       return is_valid;
-}
-
-static
-bool packet_context_field_type_is_valid(struct bt_trace *trace,
-               struct bt_stream_class *stream_class,
-               struct bt_field_type *packet_context_type,
-               bool check_ts_begin_end_mapped)
-{
-       bool is_valid = true;
-       struct bt_field_type *field_type = NULL;
-
-       if (!packet_context_type) {
-               /* No packet context field type: valid at this point */
-               goto end;
-       }
-
-       /* Packet context field type, if it exists, must be a structure */
-       if (packet_context_type->id != BT_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
-                       "ft-addr=%p, ft-id=%s",
-                       packet_context_type,
-                       bt_common_field_type_id_string(packet_context_type->id));
-               goto invalid;
-       }
-
-       /*
-        * If there's a `packet_size` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_context_type, "packet_size");
-       if (field_type) {
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
-                               "packet-size-ft-addr=%p, packet-size-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
-                               "packet-size-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `content_size` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_context_type, "content_size");
-       if (field_type) {
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
-                               "content-size-ft-addr=%p, content-size-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
-                               "content-size-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `events_discarded` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_context_type, "events_discarded");
-       if (field_type) {
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
-                               "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
-                               "events-discarded-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `timestamp_begin` field, it must be an unsigned
-        * integer field type. Also, if the trace is not a CTF writer's
-        * trace, then we cannot automatically set the mapped clock
-        * class of this field, so it must have a mapped clock class.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_context_type, "timestamp_begin");
-       if (field_type) {
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
-                               "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
-                               "timestamp-begin-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-
-               if (check_ts_begin_end_mapped) {
-                       struct bt_clock_class *clock_class =
-                               bt_field_type_integer_borrow_mapped_clock_class(
-                                       field_type);
-
-                       if (!clock_class) {
-                               BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
-                                       "timestamp-begin-ft-addr=%p", field_type);
-                               goto invalid;
-                       }
-               }
-       }
-
-       /*
-        * If there's a `timestamp_end` field, it must be an unsigned
-        * integer field type. Also, if the trace is not a CTF writer's
-        * trace, then we cannot automatically set the mapped clock
-        * class of this field, so it must have a mapped clock class.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               packet_context_type, "timestamp_end");
-       if (field_type) {
-               if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
-                               "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_field_type_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
-                               "timestamp-end-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-
-               if (check_ts_begin_end_mapped) {
-                       struct bt_clock_class *clock_class =
-                               bt_field_type_integer_borrow_mapped_clock_class(
-                                       field_type);
-
-                       if (!clock_class) {
-                               BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
-                                       "timestamp-end-ft-addr=%p", field_type);
-                               goto invalid;
-                       }
-               }
-       }
-
-       goto end;
-
-invalid:
-       is_valid = false;
-
-end:
-       return is_valid;
-}
-
-static
-bool event_header_field_type_is_valid(struct bt_trace *trace,
-               struct bt_stream_class *stream_class,
-               struct bt_field_type *event_header_type)
-{
-       bool is_valid = true;
-       struct bt_field_type *field_type = NULL;
-
-       /*
-        * We do not validate that the `timestamp` field exists here
-        * because CTF does not require this exact name to be mapped to
-        * a clock class.
-        */
-
-       if (!event_header_type) {
-               /*
-                * No event header field type: stream class must have
-                * only one event class.
-                */
-               if (bt_stream_class_get_event_class_count(stream_class) > 1) {
-                       BT_LOGW_STR("Invalid event header field type: "
-                               "event header field type does not exist but there's more than one event class in the stream class.");
-                       goto invalid;
-               }
-
-               /* No event header field type: valid at this point */
-               goto end;
-       }
-
-       /* Event header field type, if it exists, must be a structure */
-       if (event_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
-                       "ft-addr=%p, ft-id=%s",
-                       event_header_type,
-                       bt_common_field_type_id_string(event_header_type->id));
-               goto invalid;
-       }
-
-       /*
-        * If there's an `id` field, it must be an unsigned integer
-        * field type or an enumeration field type with an unsigned
-        * integer container field type.
-        */
-       field_type = bt_field_type_structure_borrow_field_type_by_name(
-               event_header_type, "id");
-       if (field_type) {
-               struct bt_field_type *int_ft;
-
-               if (field_type->id == BT_FIELD_TYPE_ID_INTEGER) {
-                       int_ft = field_type;
-               } else if (field_type->id == BT_FIELD_TYPE_ID_ENUM) {
-                       int_ft = bt_field_type_enumeration_borrow_container_field_type(
-                               field_type);
-               } else {
-                       BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
-                               "id-ft-addr=%p, id-ft-id=%s",
-                               field_type,
-                               bt_common_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               BT_ASSERT(int_ft);
-               if (bt_field_type_integer_is_signed(int_ft)) {
-                       BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
-                               "id-ft-addr=%p", int_ft);
-                       goto invalid;
-               }
-       }
-
-       goto end;
-
-invalid:
-       is_valid = false;
-
-end:
-       return is_valid;
-}
-
-static
-int check_packet_header_type_has_no_clock_class(struct bt_trace *trace)
-{
-       int ret = 0;
-
-       if (trace->packet_header_field_type) {
-               struct bt_clock_class *clock_class = NULL;
-
-               ret = bt_field_type_validate_single_clock_class(
-                       trace->packet_header_field_type,
-                       &clock_class);
-               bt_put(clock_class);
-               if (ret || clock_class) {
-                       BT_LOGW("Trace's packet header field type cannot "
-                               "contain a field type which is mapped to "
-                               "a clock class: "
-                               "trace-addr=%p, trace-name=\"%s\", "
-                               "clock-class-name=\"%s\"",
-                               trace, bt_trace_get_name(trace),
-                               clock_class ?
-                                       bt_clock_class_get_name(clock_class) :
-                                       NULL);
-                       ret = -1;
-               }
-       }
-
-       return ret;
-}
-
-int bt_trace_add_stream_class(struct bt_trace *trace,
-               struct bt_stream_class *stream_class)
-{
-       int ret;
-       int64_t i;
-       int64_t stream_id;
-       struct bt_validation_output trace_sc_validation_output = { 0 };
-       struct bt_validation_output *ec_validation_outputs = NULL;
-       const enum bt_validation_flag trace_sc_validation_flags =
-               BT_VALIDATION_FLAG_TRACE |
-               BT_VALIDATION_FLAG_STREAM;
-       const enum bt_validation_flag ec_validation_flags =
-               BT_VALIDATION_FLAG_EVENT;
-       struct bt_field_type *packet_header_type = NULL;
-       struct bt_field_type *packet_context_type = NULL;
-       struct bt_field_type *event_header_type = NULL;
-       struct bt_field_type *stream_event_ctx_type = NULL;
-       int64_t event_class_count;
-       struct bt_trace *current_parent_trace = NULL;
-       struct bt_clock_class *expected_clock_class = NULL;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->is_static) {
-               BT_LOGW_STR("Invalid parameter: trace is static.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGD("Adding stream class to trace: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64,
-               trace, bt_trace_get_name(trace),
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class));
-
-       current_parent_trace = bt_stream_class_borrow_trace(stream_class);
-       if (current_parent_trace) {
-               /* Stream class is already associated to a trace, abort. */
-               BT_LOGW("Invalid parameter: stream class is already part of a trace: "
-                       "stream-class-trace-addr=%p, "
-                       "stream-class-trace-name=\"%s\"",
-                       current_parent_trace,
-                       bt_trace_get_name(current_parent_trace));
-               ret = -1;
-               goto end;
-       }
-
-       event_class_count =
-               bt_stream_class_get_event_class_count(stream_class);
-       BT_ASSERT(event_class_count >= 0);
-
-       if (!stream_class->frozen) {
-               /*
-                * Stream class is not frozen yet. Validate that the
-                * stream class contains at most a single clock class
-                * because the previous
-                * bt_stream_class_add_event_class() calls did
-                * not make this validation since the stream class's
-                * direct field types (packet context, event header,
-                * event context) could change afterwards. This stream
-                * class is about to be frozen and those field types
-                * won't be changed if this function succeeds.
-                *
-                * At this point we're also sure that the stream class's
-                * clock, if any, has the same class as the stream
-                * class's expected clock class, if any. This is why, if
-                * bt_stream_class_validate_single_clock_class()
-                * succeeds below, the call to
-                * bt_stream_class_map_clock_class() at the end of this
-                * function is safe because it maps to the same, single
-                * clock class.
-                */
-               ret = bt_stream_class_validate_single_clock_class(
-                       stream_class, &expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Invalid parameter: stream class or one of its "
-                               "event classes contains a field type which is "
-                               "not recursively mapped to the expected "
-                               "clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-id=%" PRId64 ", "
-                               "stream-class-name=\"%s\", "
-                               "expected-clock-class-addr=%p, "
-                               "expected-clock-class-name=\"%s\"",
-                               stream_class, bt_stream_class_get_id(stream_class),
-                               bt_stream_class_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_clock_class_get_name(expected_clock_class) :
-                                       NULL);
-                       goto end;
-               }
-       }
-
-       ret = check_packet_header_type_has_no_clock_class(trace);
-       if (ret) {
-               /* check_packet_header_type_has_no_clock_class() logs errors */
-               goto end;
-       }
-
-       /*
-        * We're about to freeze both the trace and the stream class.
-        * Also, each event class contained in this stream class are
-        * already frozen.
-        *
-        * This trace, this stream class, and all its event classes
-        * should be valid at this point.
-        *
-        * Validate trace and stream class first, then each event
-        * class of this stream class can be validated individually.
-        */
-       packet_header_type =
-               bt_trace_borrow_packet_header_field_type(trace);
-       packet_context_type =
-               bt_stream_class_borrow_packet_context_field_type(stream_class);
-       event_header_type =
-               bt_stream_class_borrow_event_header_field_type(stream_class);
-       stream_event_ctx_type =
-               bt_stream_class_borrow_event_context_field_type(stream_class);
-
-       BT_LOGD("Validating trace and stream class field types.");
-       ret = bt_validate_class_types(trace->environment,
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type, NULL, NULL, trace->valid,
-               stream_class->valid, 1, &trace_sc_validation_output,
-               trace_sc_validation_flags, bt_field_type_copy);
-
-       if (ret) {
-               /*
-                * This means something went wrong during the validation
-                * process, not that the objects are invalid.
-                */
-               BT_LOGE("Failed to validate trace and stream class field types: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       if ((trace_sc_validation_output.valid_flags &
-                       trace_sc_validation_flags) !=
-                       trace_sc_validation_flags) {
-               /* Invalid trace/stream class */
-               BT_LOGW("Invalid trace or stream class field types: "
-                       "valid-flags=0x%x",
-                       trace_sc_validation_output.valid_flags);
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class_count > 0) {
-               ec_validation_outputs = g_new0(struct bt_validation_output,
-                       event_class_count);
-               if (!ec_validation_outputs) {
-                       BT_LOGE_STR("Failed to allocate one validation output structure.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /* Validate each event class individually */
-       for (i = 0; i < event_class_count; i++) {
-               struct bt_event_class *event_class =
-                       bt_stream_class_borrow_event_class_by_index(
-                               stream_class, i);
-               struct bt_field_type *event_context_type = NULL;
-               struct bt_field_type *event_payload_type = NULL;
-
-               event_context_type =
-                       bt_event_class_borrow_context_field_type(
-                               event_class);
-               event_payload_type =
-                       bt_event_class_borrow_payload_field_type(
-                               event_class);
-
-               /*
-                * It is important to use the field types returned by
-                * the previous trace and stream class validation here
-                * because copies could have been made.
-                */
-               BT_LOGD("Validating event class's field types: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_event_class_get_name(event_class),
-                       bt_event_class_get_id(event_class));
-               ret = bt_validate_class_types(trace->environment,
-                       trace_sc_validation_output.packet_header_type,
-                       trace_sc_validation_output.packet_context_type,
-                       trace_sc_validation_output.event_header_type,
-                       trace_sc_validation_output.stream_event_ctx_type,
-                       event_context_type, event_payload_type,
-                       1, 1, event_class->valid, &ec_validation_outputs[i],
-                       ec_validation_flags, bt_field_type_copy);
-
-               if (ret) {
-                       BT_LOGE("Failed to validate event class field types: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-
-               if ((ec_validation_outputs[i].valid_flags &
-                               ec_validation_flags) != ec_validation_flags) {
-                       /* Invalid event class */
-                       BT_LOGW("Invalid event class field types: "
-                               "valid-flags=0x%x",
-                               ec_validation_outputs[i].valid_flags);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       stream_id = bt_stream_class_get_id(stream_class);
-       if (stream_id < 0) {
-               stream_id = trace->next_stream_id++;
-               if (stream_id < 0) {
-                       BT_LOGE_STR("No more stream class IDs available.");
-                       ret = -1;
-                       goto end;
-               }
-
-               /* Try to assign a new stream id */
-               for (i = 0; i < trace->stream_classes->len; i++) {
-                       if (stream_id == bt_stream_class_get_id(
-                               trace->stream_classes->pdata[i])) {
-                               /* Duplicate stream id found */
-                               BT_LOGW("Duplicate stream class ID: "
-                                       "id=%" PRId64, (int64_t) stream_id);
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               if (bt_stream_class_set_id_no_check(stream_class,
-                               stream_id)) {
-                       /* TODO Should retry with a different stream id */
-                       BT_LOGE("Cannot set stream class's ID: "
-                               "id=%" PRId64, (int64_t) stream_id);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * At this point all the field types in the validation output
-        * are valid. Validate the semantics of some scopes according to
-        * the CTF specification.
-        */
-       if (!packet_header_field_type_is_valid(trace,
-                       trace_sc_validation_output.packet_header_type)) {
-               BT_LOGW_STR("Invalid trace's packet header field type.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!packet_context_field_type_is_valid(trace,
-                       stream_class,
-                       trace_sc_validation_output.packet_context_type, true)) {
-               BT_LOGW_STR("Invalid stream class's packet context field type.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!event_header_field_type_is_valid(trace,
-                       stream_class,
-                       trace_sc_validation_output.event_header_type)) {
-               BT_LOGW_STR("Invalid steam class's event header field type.");
-               ret = -1;
-               goto end;
-       }
-
-       bt_object_set_parent(&stream_class->base, &trace->base);
-       g_ptr_array_add(trace->stream_classes, stream_class);
-
-       /*
-        * At this point we know that the function will be successful.
-        * Therefore we can replace the trace and stream class field
-        * types with what's in their validation output structure and
-        * mark them as valid. We can also replace the field types of
-        * all the event classes of the stream class and mark them as
-        * valid.
-        */
-       bt_validation_replace_types(trace, stream_class, NULL,
-               &trace_sc_validation_output, trace_sc_validation_flags);
-       trace->valid = 1;
-       stream_class->valid = 1;
-
-       /*
-        * Put what was not moved in bt_validation_replace_types().
-        */
-       bt_validation_output_put_types(&trace_sc_validation_output);
-
-       for (i = 0; i < event_class_count; i++) {
-               struct bt_event_class *event_class =
-                       bt_stream_class_borrow_event_class_by_index(
-                               stream_class, i);
-
-               bt_validation_replace_types(NULL, NULL, event_class,
-                       &ec_validation_outputs[i], ec_validation_flags);
-               event_class->valid = 1;
-
-               /*
-                * Put what was not moved in
-                * bt_validation_replace_types().
-                */
-               bt_validation_output_put_types(&ec_validation_outputs[i]);
-       }
-
-       /*
-        * Freeze the trace and the stream class.
-        */
-       bt_stream_class_freeze(stream_class);
-       bt_trace_freeze(trace);
-
-       /*
-        * It is safe to set the stream class's unique clock class
-        * now because the stream class is frozen.
-        */
-       if (expected_clock_class) {
-               BT_MOVE(stream_class->clock_class, expected_clock_class);
-       }
-
-       /* Notify listeners of the trace's schema modification. */
-       bt_stream_class_visit(stream_class,
-                       bt_trace_object_modification, trace);
-       BT_LOGD("Added stream class to trace: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64,
-               trace, bt_trace_get_name(trace),
-               stream_class, bt_stream_class_get_name(stream_class),
-               bt_stream_class_get_id(stream_class));
-
-end:
-       if (ret) {
-               bt_object_set_parent(&stream_class->base, NULL);
-
-               if (ec_validation_outputs) {
-                       for (i = 0; i < event_class_count; i++) {
-                               bt_validation_output_put_types(
-                                       &ec_validation_outputs[i]);
-                       }
-               }
-       }
-
-       g_free(ec_validation_outputs);
-       bt_validation_output_put_types(&trace_sc_validation_output);
-       bt_put(expected_clock_class);
-       return ret;
-}
-
-int64_t bt_trace_get_stream_count(struct bt_trace *trace)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return (int64_t) trace->streams->len;
-}
-
-struct bt_stream *bt_trace_borrow_stream_by_index(
-               struct bt_trace *trace, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(index < trace->streams->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, trace->streams->len);
-       return g_ptr_array_index(trace->streams, index);
-}
-
-int64_t bt_trace_get_stream_class_count(struct bt_trace *trace)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return (int64_t) trace->stream_classes->len;
-}
-
-struct bt_stream_class *bt_trace_borrow_stream_class_by_index(
-               struct bt_trace *trace, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(index < trace->stream_classes->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, trace->stream_classes->len);
-       return g_ptr_array_index(trace->stream_classes, index);
-}
-
-struct bt_stream_class *bt_trace_borrow_stream_class_by_id(
-               struct bt_trace *trace, uint64_t id_param)
-{
-       int i;
-       struct bt_stream_class *stream_class = NULL;
-       int64_t id = (int64_t) id_param;
-
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(id >= 0,
-               "Invalid stream class ID: %" PRIu64, id_param);
-
-       for (i = 0; i < trace->stream_classes->len; i++) {
-               struct bt_stream_class *stream_class_candidate;
-
-               stream_class_candidate =
-                       g_ptr_array_index(trace->stream_classes, i);
-
-               if (bt_stream_class_get_id(stream_class_candidate) ==
-                               (int64_t) id) {
-                       stream_class = stream_class_candidate;
-                       goto end;
-               }
-       }
-
-end:
-       return stream_class;
-}
-
-struct bt_clock_class *bt_trace_borrow_clock_class_by_name(
-               struct bt_trace *trace, const char *name)
-{
-       size_t i;
-       struct bt_clock_class *clock_class = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-
-       for (i = 0; i < trace->clock_classes->len; i++) {
-               struct bt_clock_class *cur_clk =
-                       g_ptr_array_index(trace->clock_classes, i);
-               const char *cur_clk_name = bt_clock_class_get_name(cur_clk);
-
-               if (!cur_clk_name) {
-                       goto end;
-               }
-
-               if (!strcmp(cur_clk_name, name)) {
-                       clock_class = cur_clk;
-                       goto end;
-               }
-       }
-
-end:
-       return clock_class;
-}
-
-BT_HIDDEN
-bt_bool bt_trace_has_clock_class(struct bt_trace *trace,
-               struct bt_clock_class *clock_class)
-{
-       struct search_query query = { .value = clock_class, .found = 0 };
-
-       BT_ASSERT(trace);
-       BT_ASSERT(clock_class);
-
-       g_ptr_array_foreach(trace->clock_classes, value_exists, &query);
-       return query.found;
-}
-
-enum bt_byte_order bt_trace_get_native_byte_order(
-               struct bt_trace *trace)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->native_byte_order;
-}
-
-int bt_trace_set_native_byte_order(struct bt_trace *trace,
-               enum bt_byte_order byte_order)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order != BT_BYTE_ORDER_LITTLE_ENDIAN &&
-                       byte_order != BT_BYTE_ORDER_BIG_ENDIAN &&
-                       byte_order != BT_BYTE_ORDER_NETWORK) {
-               BT_LOGW("Invalid parameter: invalid byte order: "
-                       "addr=%p, name=\"%s\", bo=%s",
-                       trace, bt_trace_get_name(trace),
-                       bt_common_byte_order_string(byte_order));
-               ret = -1;
-               goto end;
-       }
-
-       trace->native_byte_order = byte_order;
-       BT_LOGV("Set trace's native byte order: "
-               "addr=%p, name=\"%s\", bo=%s",
-               trace, bt_trace_get_name(trace),
-               bt_common_byte_order_string(byte_order));
-
-end:
-       return ret;
-}
-
-struct bt_field_type *bt_trace_borrow_packet_header_field_type(
-               struct bt_trace *trace)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->packet_header_field_type;
-}
-
-int bt_trace_set_packet_header_field_type(struct bt_trace *trace,
-               struct bt_field_type *packet_header_type)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       /* packet_header_type must be a structure. */
-       if (packet_header_type &&
-                       packet_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
-                       "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
-                       trace, bt_trace_get_name(trace),
-                       packet_header_type,
-                       bt_common_field_type_id_string(packet_header_type->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_put(trace->packet_header_field_type);
-       trace->packet_header_field_type = bt_get(packet_header_type);
-       BT_LOGV("Set trace's packet header field type: "
-               "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
-               trace, bt_trace_get_name(trace), packet_header_type);
-end:
-       return ret;
-}
-
-static
-int64_t get_stream_class_count(void *element)
-{
-       return bt_trace_get_stream_class_count(
-                       (struct bt_trace *) element);
-}
-
-static
-void *get_stream_class(void *element, int i)
-{
-       return bt_trace_get_stream_class_by_index(
-                       (struct bt_trace *) element, i);
-}
-
-static
-int visit_stream_class(void *object, bt_visitor visitor,void *data)
-{
-       return bt_stream_class_visit(object, visitor, data);
-}
-
-int bt_trace_visit(struct bt_trace *trace,
-               bt_visitor visitor, void *data)
-{
-       int ret;
-       struct bt_visitor_object obj = {
-               .object = trace,
-               .type = BT_VISITOR_OBJECT_TYPE_TRACE
-       };
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!visitor) {
-               BT_LOGW_STR("Invalid parameter: visitor is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
-               trace, bt_trace_get_name(trace));
-       ret = visitor_helper(&obj, get_stream_class_count,
-                       get_stream_class, visit_stream_class, visitor, data);
 end:
        return ret;
 }
 
-static
-int invoke_listener(struct bt_visitor_object *object, void *data)
-{
-       struct listener_wrapper *listener_wrapper = data;
-
-       listener_wrapper->listener(object, listener_wrapper->data);
-       return 0;
-}
-
-// TODO: add logging to this function once we use it internally.
-int bt_trace_add_listener(struct bt_trace *trace,
-               bt_listener_cb listener, void *listener_data)
-{
-       int ret = 0;
-       struct listener_wrapper *listener_wrapper =
-                       g_new0(struct listener_wrapper, 1);
-
-       if (!trace || !listener || !listener_wrapper) {
-               ret = -1;
-               goto error;
-       }
-
-       listener_wrapper->listener = listener;
-       listener_wrapper->data = listener_data;
-
-       /* Visit the current schema. */
-       ret = bt_trace_visit(trace, invoke_listener, listener_wrapper);
-       if (ret) {
-               goto error;
-       }
-
-       /*
-        * Add listener to the array of callbacks which will be invoked on
-        * schema changes.
-        */
-       g_ptr_array_add(trace->listeners, listener_wrapper);
-       return ret;
-error:
-       g_free(listener_wrapper);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_trace_object_modification(struct bt_visitor_object *object,
-               void *trace_ptr)
-{
-       size_t i;
-       struct bt_trace *trace = trace_ptr;
-
-       BT_ASSERT(trace);
-       BT_ASSERT(object);
-
-       if (trace->listeners->len == 0) {
-               goto end;
-       }
-
-       for (i = 0; i < trace->listeners->len; i++) {
-               struct listener_wrapper *listener =
-                               g_ptr_array_index(trace->listeners, i);
-
-               listener->listener(object, listener->data);
-       }
-end:
-       return 0;
-}
-
 bt_bool bt_trace_is_static(struct bt_trace *trace)
 {
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->is_static;
+       return (bt_bool) trace->is_static;
 }
 
-int bt_trace_set_is_static(struct bt_trace *trace)
+int bt_trace_make_static(struct bt_trace *trace)
 {
-       int ret = 0;
-       size_t i;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = check_packet_header_type_has_no_clock_class(trace);
-       if (ret) {
-               /* check_packet_header_type_has_no_clock_class() logs errors */
-               goto end;
-       }
+       uint64_t i;
 
-       trace->is_static = BT_TRUE;
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       trace->is_static = true;
        bt_trace_freeze(trace);
-       BT_LOGV("Set trace static: addr=%p, name=\"%s\"",
-               trace, bt_trace_get_name(trace));
+       BT_LIB_LOGV("Trace is now static: %!+t", trace);
 
        /* Call all the "trace is static" listeners */
        for (i = 0; i < trace->is_static_listeners->len; i++) {
@@ -1778,48 +499,28 @@ int bt_trace_set_is_static(struct bt_trace *trace)
                }
        }
 
-end:
-       return ret;
+       return 0;
 }
 
 int bt_trace_add_is_static_listener(struct bt_trace *trace,
                bt_trace_is_static_listener listener,
-               bt_trace_listener_removed listener_removed, void *data)
+               bt_trace_listener_removed listener_removed, void *data,
+               uint64_t *listener_id)
 {
-       int i;
+       uint64_t i;
        struct bt_trace_is_static_listener_elem new_elem = {
                .func = listener,
                .removed = listener_removed,
                .data = data,
        };
 
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               i = -1;
-               goto end;
-       }
-
-       if (!listener) {
-               BT_LOGW_STR("Invalid parameter: listener is NULL.");
-               i = -1;
-               goto end;
-       }
-
-       if (trace->is_static) {
-               BT_LOGW("Invalid parameter: trace is already static: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               i = -1;
-               goto end;
-       }
-
-       if (trace->in_remove_listener) {
-               BT_LOGW("Cannot call this function during the execution of a remove listener: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_trace_get_name(trace));
-               i = -1;
-               goto end;
-       }
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(listener, "Listener");
+       BT_ASSERT_PRE(!trace->is_static,
+               "Trace is already static: %!+t", trace);
+       BT_ASSERT_PRE(trace->in_remove_listener,
+               "Cannot call this function while executing a "
+               "remove listener: %!+t", trace);
 
        /* Find the next available spot */
        for (i = 0; i < trace->is_static_listeners->len; i++) {
@@ -1838,115 +539,122 @@ int bt_trace_add_is_static_listener(struct bt_trace *trace,
                g_array_insert_val(trace->is_static_listeners, i, new_elem);
        }
 
-       BT_LOGV("Added \"trace is static\" listener: "
-               "trace-addr=%p, trace-name=\"%s\", func-addr=%p, "
-               "data-addr=%p, listener-id=%d",
-               trace, bt_trace_get_name(trace), listener, data, i);
+       if (listener_id) {
+               *listener_id = i;
+       }
 
-end:
-       return i;
+       BT_LIB_LOGV("Added \"trace is static\" listener: "
+               "%![trace-]+t, listener-id=%" PRIu64, trace, i);
+       return 0;
+}
+
+BT_ASSERT_PRE_FUNC
+static
+bool has_listener_id(struct bt_trace *trace, uint64_t listener_id)
+{
+       BT_ASSERT(listener_id < trace->is_static_listeners->len);
+       return (&g_array_index(trace->is_static_listeners,
+                       struct bt_trace_is_static_listener_elem,
+                       listener_id))->func != NULL;
 }
 
 int bt_trace_remove_is_static_listener(
-               struct bt_trace *trace, int listener_id)
+               struct bt_trace *trace, uint64_t listener_id)
 {
-       int ret = 0;
        struct bt_trace_is_static_listener_elem *elem;
 
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->in_remove_listener) {
-               BT_LOGW("Cannot call this function during the execution of a remove listener: "
-                       "addr=%p, name=\"%s\", listener-id=%d",
-                       trace, bt_trace_get_name(trace),
-                       listener_id);
-               ret = -1;
-               goto end;
-       }
-
-       if (listener_id < 0) {
-               BT_LOGW("Invalid listener ID: must be zero or positive: "
-                       "listener-id=%d", listener_id);
-               ret = -1;
-               goto end;
-       }
-
-       if (listener_id >= trace->is_static_listeners->len) {
-               BT_LOGW("Invalid parameter: no listener with this listener ID: "
-                       "addr=%p, name=\"%s\", listener-id=%d",
-                       trace, bt_trace_get_name(trace),
-                       listener_id);
-               ret = -1;
-               goto end;
-       }
-
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(!trace->is_static,
+               "Trace is already static: %!+t", trace);
+       BT_ASSERT_PRE(trace->in_remove_listener,
+               "Cannot call this function while executing a "
+               "remove listener: %!+t", trace);
+       BT_ASSERT_PRE(has_listener_id(trace, listener_id),
+               "Trace has no such \"trace is static\" listener ID: "
+               "%![trace-]+t, %" PRIu64, trace, listener_id);
        elem = &g_array_index(trace->is_static_listeners,
                        struct bt_trace_is_static_listener_elem,
                        listener_id);
-       if (!elem->func) {
-               BT_LOGW("Invalid parameter: no listener with this listener ID: "
-                       "addr=%p, name=\"%s\", listener-id=%d",
-                       trace, bt_trace_get_name(trace),
-                       listener_id);
-               ret = -1;
-               goto end;
-       }
+       BT_ASSERT(elem->func);
 
        if (elem->removed) {
                /* Call remove listener */
-               BT_LOGV("Calling remove listener: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "listener-id=%d", trace, bt_trace_get_name(trace),
-                       listener_id);
-               trace->in_remove_listener = BT_TRUE;
+               BT_LIB_LOGV("Calling remove listener: "
+                       "%![trace-]+t, listener-id=%" PRIu64,
+                       trace, listener_id);
+               trace->in_remove_listener = true;
                elem->removed(trace, elem->data);
-               trace->in_remove_listener = BT_FALSE;
+               trace->in_remove_listener = false;
        }
 
        elem->func = NULL;
        elem->removed = NULL;
        elem->data = NULL;
-       BT_LOGV("Removed \"trace is static\" listener: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "listener-id=%d", trace, bt_trace_get_name(trace),
-               listener_id);
+       BT_LIB_LOGV("Removed \"trace is static\" listener: "
+               "%![trace-]+t, listener-id=%" PRIu64,
+               trace, listener_id);
+       return 0;
+}
 
-end:
-       return ret;
+BT_HIDDEN
+void _bt_trace_freeze(struct bt_trace *trace)
+{
+       /* The packet header field type is already frozen */
+       BT_ASSERT(trace);
+       BT_LIB_LOGD("Freezing trace: %!+t", trace);
+       trace->frozen = true;
 }
 
-struct bt_packet_header_field *bt_trace_create_packet_header_field(
-               struct bt_trace *trace)
+bt_bool bt_trace_assigns_automatic_stream_class_id(struct bt_trace *trace)
 {
-       struct bt_field_wrapper *field_wrapper;
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return (bt_bool) trace->assigns_automatic_stream_class_id;
+}
 
+int bt_trace_set_assigns_automatic_stream_class_id(
+               struct bt_trace *trace, bt_bool value)
+{
        BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(trace->packet_header_field_type,
-               "Trace has no packet header field type: %!+t",
-               trace);
-       field_wrapper = bt_field_wrapper_create(
-               &trace->packet_header_field_pool,
-               (void *) trace->packet_header_field_type);
-       if (!field_wrapper) {
-               BT_LIB_LOGE("Cannot allocate one packet header field from trace: "
-                       "%![trace-]+t", trace);
-               goto error;
-       }
+       BT_ASSERT_PRE_TRACE_HOT(trace);
+       trace->assigns_automatic_stream_class_id = (bool) value;
+       BT_LIB_LOGV("Set trace's automatic stream class ID "
+               "assignment property: %!+t", trace);
+       return 0;
+}
 
-       BT_ASSERT(field_wrapper->field);
+BT_HIDDEN
+void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream)
+{
+       guint count = 0;
+
+       bt_object_set_parent(&stream->base, &trace->base);
+       g_ptr_array_add(trace->streams, stream);
        bt_trace_freeze(trace);
-       goto end;
 
-error:
-       if (field_wrapper) {
-               bt_field_wrapper_destroy(field_wrapper);
-               field_wrapper = NULL;
+       if (bt_g_hash_table_contains(trace->stream_classes_stream_count,
+                       stream->class)) {
+               count = GPOINTER_TO_UINT(g_hash_table_lookup(
+                       trace->stream_classes_stream_count, stream->class));
        }
 
-end:
-       return (void *) field_wrapper;
+       g_hash_table_insert(trace->stream_classes_stream_count,
+               stream->class, GUINT_TO_POINTER(count + 1));
+}
+
+BT_HIDDEN
+uint64_t bt_trace_get_automatic_stream_id(struct bt_trace *trace,
+               struct bt_stream_class *stream_class)
+{
+       gpointer orig_key;
+       gpointer value;
+       uint64_t id = 0;
+
+       BT_ASSERT(stream_class);
+       BT_ASSERT(trace);
+       if (g_hash_table_lookup_extended(trace->stream_classes_stream_count,
+                       stream_class, &orig_key, &value)) {
+               id = (uint64_t) GPOINTER_TO_UINT(value);
+       }
+
+       return id;
 }
index 312deb9dea835308d06fb967d7351c306357d7c1..41337cfddb1914d94cc1bc67c83f5c9e6d3751bd 100644 (file)
 
 #include <stdlib.h>
 #include <glib.h>
-#include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/clock-class.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/assert-internal.h>
-
-static
-const char * const reserved_keywords_str[] = {"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 GHashTable *reserved_keywords_set;
-static int init_done;
-
-static
-void try_init_reserved_keywords(void)
-{
-       size_t i;
-       const size_t reserved_keywords_count =
-               sizeof(reserved_keywords_str) / sizeof(char *);
-
-       if (reserved_keywords_set) {
-               return;
-       }
-
-       reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal);
-       BT_ASSERT(reserved_keywords_set);
-
-       for (i = 0; i < reserved_keywords_count; i++) {
-               gpointer quark = GINT_TO_POINTER(g_quark_from_string(
-                       reserved_keywords_str[i]));
-
-               g_hash_table_insert(reserved_keywords_set, quark, quark);
-       }
-
-       init_done = 1;
-}
-
-static __attribute__((destructor))
-void trace_finalize(void)
-{
-       if (reserved_keywords_set) {
-               g_hash_table_destroy(reserved_keywords_set);
-       }
-}
-
-bt_bool bt_identifier_is_valid(const char *identifier)
-{
-       bt_bool is_valid = BT_TRUE;
-       char *string = NULL;
-       char *save_ptr, *token;
-
-       if (!identifier) {
-               BT_LOGV_STR("Invalid parameter: input string is NULL.");
-               is_valid = BT_FALSE;
-               goto end;
-       }
-
-       try_init_reserved_keywords();
-
-       if (identifier[0] == '\0') {
-               is_valid = BT_FALSE;
-               goto end;
-       }
-
-       string = strdup(identifier);
-       if (!string) {
-               BT_LOGE("strdup() failed.");
-               is_valid = BT_FALSE;
-               goto end;
-       }
-
-       token = strtok_r(string, " ", &save_ptr);
-       while (token) {
-               if (g_hash_table_lookup_extended(reserved_keywords_set,
-                       GINT_TO_POINTER(g_quark_from_string(token)),
-                       NULL, NULL)) {
-                       is_valid = BT_FALSE;
-                       goto end;
-               }
-
-               token = strtok_r(NULL, " ", &save_ptr);
-       }
-end:
-       free(string);
-       return is_valid;
-}
diff --git a/lib/ctf-ir/validation.c b/lib/ctf-ir/validation.c
deleted file mode 100644 (file)
index cc653ec..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * validation.c
- *
- * Babeltrace - CTF IR: Validation of trace, stream class, and event class
- *
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "VALIDATION"
-#include <babeltrace/lib-logging-internal.h>
-
-#include <babeltrace/assert-pre-internal.h>
-#include <babeltrace/ctf-ir/validation-internal.h>
-#include <babeltrace/ctf-ir/resolve-internal.h>
-#include <babeltrace/ctf-ir/trace-internal.h>
-#include <babeltrace/ctf-ir/stream-class-internal.h>
-#include <babeltrace/ctf-ir/field-types-internal.h>
-#include <babeltrace/ctf-ir/event-class-internal.h>
-#include <babeltrace/ctf-ir/field-types-internal.h>
-#include <babeltrace/values.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <babeltrace/ref.h>
-
-/*
- * This function resolves and validates the field types of an event
- * class. Only `event_context_type` and `event_payload_type` are
- * resolved and validated; the other field types are used as eventual
- * resolving targets.
- *
- * All parameters are owned by the caller.
- */
-static
-int validate_event_class_types(struct bt_value *environment,
-               struct bt_field_type *packet_header_type,
-               struct bt_field_type *packet_context_type,
-               struct bt_field_type *event_header_type,
-               struct bt_field_type *stream_event_ctx_type,
-               struct bt_field_type *event_context_type,
-               struct bt_field_type *event_payload_type)
-{
-       int ret = 0;
-
-       BT_LOGV("Validating event class field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p, "
-               "event-context-ft-addr=%p, "
-               "event-payload-ft-addr=%p",
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type, event_context_type, event_payload_type);
-
-       /* Resolve sequence type lengths and variant type tags first */
-       ret = bt_resolve_types(environment, packet_header_type,
-               packet_context_type, event_header_type, stream_event_ctx_type,
-               event_context_type, event_payload_type,
-               BT_RESOLVE_FLAG_EVENT_CONTEXT |
-               BT_RESOLVE_FLAG_EVENT_PAYLOAD);
-       if (ret) {
-               BT_LOGW("Cannot resolve event class field types: ret=%d",
-                       ret);
-               goto end;
-       }
-
-       /* Validate field types individually */
-       if (event_context_type) {
-               ret = bt_field_type_validate(event_context_type);
-               if (ret) {
-                       BT_LOGW("Invalid event class's context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       if (event_payload_type) {
-               ret = bt_field_type_validate(event_payload_type);
-               if (ret) {
-                       BT_LOGW("Invalid event class's payload field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * This function resolves and validates the field types of a stream
- * class. Only `packet_context_type`, `event_header_type`, and
- * `stream_event_ctx_type` are resolved and validated; the other field
- * type is used as an eventual resolving target.
- *
- * All parameters are owned by the caller.
- */
-static
-int validate_stream_class_types(struct bt_value *environment,
-               struct bt_field_type *packet_header_type,
-               struct bt_field_type *packet_context_type,
-               struct bt_field_type *event_header_type,
-               struct bt_field_type *stream_event_ctx_type)
-{
-       int ret = 0;
-
-       BT_LOGV("Validating stream class field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p",
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type);
-
-       /* Resolve sequence type lengths and variant type tags first */
-       ret = bt_resolve_types(environment, packet_header_type,
-               packet_context_type, event_header_type, stream_event_ctx_type,
-               NULL, NULL,
-               BT_RESOLVE_FLAG_PACKET_CONTEXT |
-               BT_RESOLVE_FLAG_EVENT_HEADER |
-               BT_RESOLVE_FLAG_STREAM_EVENT_CTX);
-       if (ret) {
-               BT_LOGW("Cannot resolve stream class field types: ret=%d",
-                       ret);
-               goto end;
-       }
-
-       /* Validate field types individually */
-       if (packet_context_type) {
-               ret = bt_field_type_validate(packet_context_type);
-               if (ret) {
-                       BT_LOGW("Invalid stream class's packet context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       if (event_header_type) {
-               ret = bt_field_type_validate(event_header_type);
-               if (ret) {
-                       BT_LOGW("Invalid stream class's event header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       if (stream_event_ctx_type) {
-               ret = bt_field_type_validate(
-                       stream_event_ctx_type);
-               if (ret) {
-                       BT_LOGW("Invalid stream class's event context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * This function resolves and validates the field types of a trace.
- *
- * All parameters are owned by the caller.
- */
-static
-int validate_trace_types(struct bt_value *environment,
-               struct bt_field_type *packet_header_type)
-{
-       int ret = 0;
-
-       BT_LOGV("Validating event class field types: "
-               "packet-header-ft-addr=%p", packet_header_type);
-
-       /* Resolve sequence type lengths and variant type tags first */
-       ret = bt_resolve_types(environment, packet_header_type,
-               NULL, NULL, NULL, NULL, NULL,
-               BT_RESOLVE_FLAG_PACKET_HEADER);
-       if (ret) {
-               BT_LOGW("Cannot resolve trace field types: ret=%d",
-                       ret);
-               goto end;
-       }
-
-       /* Validate field types individually */
-       if (packet_header_type) {
-               ret = bt_field_type_validate(packet_header_type);
-               if (ret) {
-                       BT_LOGW("Invalid trace's packet header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Checks whether or not `field_type` contains a variant or a sequence
- * field type, recursively. Returns 1 if it's the case.
- *
- * `field_type` is owned by the caller.
- */
-static
-int field_type_contains_sequence_or_variant_ft(struct bt_field_type *type)
-{
-       int ret = 0;
-       enum bt_field_type_id type_id = bt_field_type_get_type_id(type);
-
-       switch (type_id) {
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-       case BT_FIELD_TYPE_ID_VARIANT:
-               ret = 1;
-               goto end;
-       case BT_FIELD_TYPE_ID_ARRAY:
-       case BT_FIELD_TYPE_ID_STRUCT:
-       {
-               int i;
-               int field_count = bt_field_type_get_field_count(type);
-
-               if (field_count < 0) {
-                       ret = -1;
-                       goto end;
-               }
-
-               for (i = 0; i < field_count; ++i) {
-                       struct bt_field_type *child_type =
-                               bt_field_type_borrow_field_at_index(
-                                       type, i);
-
-                       ret = field_type_contains_sequence_or_variant_ft(
-                               child_type);
-                       if (ret != 0) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_validate_class_types(struct bt_value *environment,
-               struct bt_field_type *packet_header_type,
-               struct bt_field_type *packet_context_type,
-               struct bt_field_type *event_header_type,
-               struct bt_field_type *stream_event_ctx_type,
-               struct bt_field_type *event_context_type,
-               struct bt_field_type *event_payload_type,
-               int trace_valid, int stream_class_valid, int event_class_valid,
-               struct bt_validation_output *output,
-               enum bt_validation_flag validate_flags,
-               bt_validation_flag_copy_field_type_func copy_field_type_func)
-{
-       int ret = 0;
-       int contains_seq_var;
-       int valid_ret;
-
-       BT_LOGV("Validating field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p, "
-               "event-context-ft-addr=%p, "
-               "event-payload-ft-addr=%p, "
-               "trace-is-valid=%d, stream-class-is-valid=%d, "
-               "event-class-is-valid=%d, validation-flags=%x",
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type, event_context_type, event_payload_type,
-               trace_valid, stream_class_valid, event_class_valid,
-               (unsigned int) validate_flags);
-
-       /* Clean output values */
-       memset(output, 0, sizeof(*output));
-
-       /* Set initial valid flags according to valid parameters */
-       if (trace_valid) {
-               output->valid_flags |= BT_VALIDATION_FLAG_TRACE;
-       }
-
-       if (stream_class_valid) {
-               output->valid_flags |= BT_VALIDATION_FLAG_STREAM;
-       }
-
-       if (event_class_valid) {
-               output->valid_flags |= BT_VALIDATION_FLAG_EVENT;
-       }
-
-       /* Own the type parameters */
-       bt_get(packet_header_type);
-       bt_get(packet_context_type);
-       bt_get(event_header_type);
-       bt_get(stream_event_ctx_type);
-       bt_get(event_context_type);
-       bt_get(event_payload_type);
-
-       /* Validate trace */
-       if ((validate_flags & BT_VALIDATION_FLAG_TRACE) && !trace_valid) {
-               struct bt_field_type *packet_header_type_copy = NULL;
-
-               /* Create field type copies */
-               if (packet_header_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       packet_header_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               packet_header_type_copy = packet_header_type;
-                               bt_get(packet_header_type_copy);
-                               goto skip_packet_header_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying packet header field type because it contains at least one sequence or variant field type.");
-                       packet_header_type_copy =
-                               copy_field_type_func(packet_header_type);
-                       if (!packet_header_type_copy) {
-                               ret = -1;
-                               BT_LOGE_STR("Cannot copy packet header field type.");
-                               goto error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_field_type_freeze(packet_header_type_copy);
-               }
-
-skip_packet_header_type_copy:
-               /* Put original reference and move copy */
-               BT_MOVE(packet_header_type, packet_header_type_copy);
-
-               /* Validate trace field types */
-               valid_ret = validate_trace_types(environment,
-                       packet_header_type);
-               if (valid_ret == 0) {
-                       /* Trace is valid */
-                       output->valid_flags |= BT_VALIDATION_FLAG_TRACE;
-               }
-       }
-
-       /* Validate stream class */
-       if ((validate_flags & BT_VALIDATION_FLAG_STREAM) &&
-                       !stream_class_valid) {
-               struct bt_field_type *packet_context_type_copy = NULL;
-               struct bt_field_type *event_header_type_copy = NULL;
-               struct bt_field_type *stream_event_ctx_type_copy = NULL;
-
-               if (packet_context_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       packet_context_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               packet_context_type_copy = packet_context_type;
-                               bt_get(packet_context_type_copy);
-                               goto skip_packet_context_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying packet context field type because it contains at least one sequence or variant field type.");
-                       packet_context_type_copy =
-                               copy_field_type_func(packet_context_type);
-                       if (!packet_context_type_copy) {
-                               BT_LOGE_STR("Cannot copy packet context field type.");
-                               goto sc_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_field_type_freeze(packet_context_type_copy);
-               }
-
-skip_packet_context_type_copy:
-               if (event_header_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       event_header_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               event_header_type_copy = event_header_type;
-                               bt_get(event_header_type_copy);
-                               goto skip_event_header_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying event header field type because it contains at least one sequence or variant field type.");
-                       event_header_type_copy =
-                               copy_field_type_func(event_header_type);
-                       if (!event_header_type_copy) {
-                               BT_LOGE_STR("Cannot copy event header field type.");
-                               goto sc_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_field_type_freeze(event_header_type_copy);
-               }
-
-skip_event_header_type_copy:
-               if (stream_event_ctx_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       stream_event_ctx_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               stream_event_ctx_type_copy =
-                                       stream_event_ctx_type;
-                               bt_get(stream_event_ctx_type_copy);
-                               goto skip_stream_event_ctx_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying stream event context field type because it contains at least one sequence or variant field type.");
-                       stream_event_ctx_type_copy =
-                               copy_field_type_func(stream_event_ctx_type);
-                       if (!stream_event_ctx_type_copy) {
-                               BT_LOGE_STR("Cannot copy stream event context field type.");
-                               goto sc_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_field_type_freeze(stream_event_ctx_type_copy);
-               }
-
-skip_stream_event_ctx_type_copy:
-               /* Put original references and move copies */
-               BT_MOVE(packet_context_type, packet_context_type_copy);
-               BT_MOVE(event_header_type, event_header_type_copy);
-               BT_MOVE(stream_event_ctx_type, stream_event_ctx_type_copy);
-
-               /* Validate stream class field types */
-               valid_ret = validate_stream_class_types(environment,
-                       packet_header_type, packet_context_type,
-                       event_header_type, stream_event_ctx_type);
-               if (valid_ret == 0) {
-                       /* Stream class is valid */
-                       output->valid_flags |= BT_VALIDATION_FLAG_STREAM;
-               }
-
-               goto sc_validation_done;
-
-sc_validation_error:
-               BT_PUT(packet_context_type_copy);
-               BT_PUT(event_header_type_copy);
-               BT_PUT(stream_event_ctx_type_copy);
-               ret = -1;
-               goto error;
-       }
-
-sc_validation_done:
-       /* Validate event class */
-       if ((validate_flags & BT_VALIDATION_FLAG_EVENT) &&
-                       !event_class_valid) {
-               struct bt_field_type *event_context_type_copy = NULL;
-               struct bt_field_type *event_payload_type_copy = NULL;
-
-               if (event_context_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       event_context_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               event_context_type_copy = event_context_type;
-                               bt_get(event_context_type_copy);
-                               goto skip_event_context_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying event context field type because it contains at least one sequence or variant field type.");
-                       event_context_type_copy =
-                               copy_field_type_func(event_context_type);
-                       if (!event_context_type_copy) {
-                               BT_LOGE_STR("Cannot copy event context field type.");
-                               goto ec_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_field_type_freeze(event_context_type_copy);
-               }
-
-skip_event_context_type_copy:
-               if (event_payload_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       event_payload_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               event_payload_type_copy = event_payload_type;
-                               bt_get(event_payload_type_copy);
-                               goto skip_event_payload_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying event payload field type because it contains at least one sequence or variant field type.");
-                       event_payload_type_copy =
-                               copy_field_type_func(event_payload_type);
-                       if (!event_payload_type_copy) {
-                               BT_LOGE_STR("Cannot copy event payload field type.");
-                               goto ec_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_field_type_freeze(event_payload_type_copy);
-               }
-
-skip_event_payload_type_copy:
-               /* Put original references and move copies */
-               BT_MOVE(event_context_type, event_context_type_copy);
-               BT_MOVE(event_payload_type, event_payload_type_copy);
-
-               /* Validate event class field types */
-               valid_ret = validate_event_class_types(environment,
-                       packet_header_type, packet_context_type,
-                       event_header_type, stream_event_ctx_type,
-                       event_context_type, event_payload_type);
-               if (valid_ret == 0) {
-                       /* Event class is valid */
-                       output->valid_flags |= BT_VALIDATION_FLAG_EVENT;
-               }
-
-               goto ec_validation_done;
-
-ec_validation_error:
-               BT_PUT(event_context_type_copy);
-               BT_PUT(event_payload_type_copy);
-               ret = -1;
-               goto error;
-       }
-
-ec_validation_done:
-       /*
-        * Validation is complete. Move the field types that were used
-        * to validate (and that were possibly altered by the validation
-        * process) to the output values.
-        */
-       BT_MOVE(output->packet_header_type, packet_header_type);
-       BT_MOVE(output->packet_context_type, packet_context_type);
-       BT_MOVE(output->event_header_type, event_header_type);
-       BT_MOVE(output->stream_event_ctx_type, stream_event_ctx_type);
-       BT_MOVE(output->event_context_type, event_context_type);
-       BT_MOVE(output->event_payload_type, event_payload_type);
-       return ret;
-
-error:
-       BT_PUT(packet_header_type);
-       BT_PUT(packet_context_type);
-       BT_PUT(event_header_type);
-       BT_PUT(stream_event_ctx_type);
-       BT_PUT(event_context_type);
-       BT_PUT(event_payload_type);
-       return ret;
-}
-
-BT_HIDDEN
-void bt_validation_replace_types(struct bt_trace *trace,
-               struct bt_stream_class *stream_class,
-               struct bt_event_class *event_class,
-               struct bt_validation_output *output,
-               enum bt_validation_flag replace_flags)
-{
-       if ((replace_flags & BT_VALIDATION_FLAG_TRACE) && trace) {
-               bt_field_type_freeze(trace->packet_header_field_type);
-               BT_MOVE(trace->packet_header_field_type,
-                       output->packet_header_type);
-       }
-
-       if ((replace_flags & BT_VALIDATION_FLAG_STREAM) && stream_class) {
-               bt_field_type_freeze(stream_class->packet_context_field_type);
-               bt_field_type_freeze(stream_class->event_header_field_type);
-               bt_field_type_freeze(stream_class->event_context_field_type);
-               BT_MOVE(stream_class->packet_context_field_type,
-                       output->packet_context_type);
-               BT_MOVE(stream_class->event_header_field_type,
-                       output->event_header_type);
-               BT_MOVE(stream_class->event_context_field_type,
-                       output->stream_event_ctx_type);
-       }
-
-       if ((replace_flags & BT_VALIDATION_FLAG_EVENT) && event_class) {
-               bt_field_type_freeze(event_class->context_field_type);
-               bt_field_type_freeze(event_class->payload_field_type);
-               BT_MOVE(event_class->context_field_type, output->event_context_type);
-               BT_MOVE(event_class->payload_field_type, output->event_payload_type);
-       }
-}
-
-BT_HIDDEN
-void bt_validation_output_put_types(
-               struct bt_validation_output *output)
-{
-       BT_PUT(output->packet_header_type);
-       BT_PUT(output->packet_context_type);
-       BT_PUT(output->event_header_type);
-       BT_PUT(output->stream_event_ctx_type);
-       BT_PUT(output->event_context_type);
-       BT_PUT(output->event_payload_type);
-}
diff --git a/lib/ctf-ir/visitor.c b/lib/ctf-ir/visitor.c
deleted file mode 100644 (file)
index e2ec1fe..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * visitor.c
- *
- * Babeltrace CTF IR - Visitor
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace/ctf-ir/visitor-internal.h>
-#include <babeltrace/ref.h>
-
-BT_HIDDEN
-int visitor_helper(struct bt_visitor_object *root,
-               bt_child_count_accessor child_counter,
-               bt_child_accessor child_accessor,
-               bt_child_visitor child_visitor,
-               bt_visitor visitor,
-               void *data)
-{
-       int ret, child_count, i;
-
-       ret = visitor(root, data);
-       if (ret) {
-               goto end;
-       }
-
-       child_count = child_counter(root->object);
-       if (child_count < 0) {
-               ret = child_count;
-               goto end;
-       }
-
-       for (i = 0; i < child_count; i++) {
-               void *child;
-
-               child = child_accessor(root->object, i);
-               if (!child) {
-                       ret = -1;
-                       goto end;
-               }
-               ret = child_visitor(child, visitor, data);
-               BT_PUT(child);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       return ret;
-}
-
-enum bt_visitor_object_type bt_visitor_object_get_type(
-               struct bt_visitor_object *object)
-{
-       enum bt_visitor_object_type ret = BT_VISITOR_OBJECT_TYPE_UNKNOWN;
-
-       if (!object) {
-               goto end;
-       }
-
-       ret = object->type;
-end:
-       return ret;
-}
-
-void *bt_visitor_object_get_object(struct bt_visitor_object *object)
-{
-       void *ret = NULL;
-
-       if (!object) {
-               goto end;
-       }
-
-       ret = object->object;
-end:
-       return ret;
-}
index 6461a7cb3386ee24d22cf24008adc55307a2362d..46ec8afbe121d8beb559c24858428c85347a455a 100644 (file)
@@ -68,7 +68,8 @@ int aligned_integer_write(struct bt_ctf_stream_pos *pos, union intval value,
                unsigned int alignment, unsigned int size, bt_bool is_signed,
                enum bt_ctf_byte_order byte_order)
 {
-       bt_bool rbo = ((int) byte_order != BT_MY_BYTE_ORDER); /* reverse byte order */
+       /* reverse byte order */
+       bt_bool rbo = (byte_order != BT_CTF_MY_BYTE_ORDER);
 
        if (!bt_ctf_stream_pos_align(pos, alignment))
                return -EFAULT;
index 67550f0b5a6db128c00b7b1415e6a289d4ad9a81..7e3b8518ad30cb942c4c5793f7185a15999c390f 100644 (file)
@@ -433,10 +433,10 @@ int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_c
                goto end;
        }
 
-       ret = visitor_helper(&obj, get_event_class_count,
+       ret = bt_ctf_visitor_helper(&obj, get_event_class_count,
                        get_event_class,
                        visit_event_class, visitor, data);
-       BT_LOGV("visitor_helper() returned: ret=%d", ret);
+       BT_LOGV("bt_ctf_visitor_helper() returned: ret=%d", ret);
 
 end:
        return ret;
index 25055383b2c8431a66fa5997ef4f39b43c937f61..0ab61ab8a8cb09c619606a8f8caeb69a6a25a75d 100644 (file)
@@ -1411,7 +1411,7 @@ int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
 
        BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
                trace, bt_ctf_trace_get_name(trace));
-       ret = visitor_helper(&obj, get_stream_class_count,
+       ret = bt_ctf_visitor_helper(&obj, get_stream_class_count,
                        get_stream_class, visit_stream_class, visitor, data);
 end:
        return ret;
index 4a5a45ff56e8f7133b095c1fe01ea7233a8d2242..c9909d9dfc42eb8b34424decc17cfc0983b5bbb6 100644 (file)
@@ -373,7 +373,7 @@ int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer,
        }
 
        if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
-               byte_order = (int) BT_MY_BYTE_ORDER;
+               byte_order = BT_CTF_MY_BYTE_ORDER;
        }
 
        ret = bt_ctf_trace_set_native_byte_order(writer->trace,
index 6251979d266a20f845334277302a1ea18077e725..4b50d7fefe5496135eff1ad29b69d75ab273d6e5 100644 (file)
@@ -84,7 +84,6 @@ struct bt_notification *bt_notification_event_create(
        struct bt_notification_event *notification = NULL;
        struct bt_event *event;
        struct bt_graph *graph;
-       int ret;
 
        BT_ASSERT_PRE_NON_NULL(notif_iter, "Notification iterator");
        BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
@@ -104,20 +103,6 @@ struct bt_notification *bt_notification_event_create(
                goto error;
        }
 
-       /*
-        * Set packet's properties. This can fail so it happens before
-        * creating the notification below. We freeze it after we know
-        * this function succeeds.
-        */
-       if (unlikely(!packet->props_are_set)) {
-               ret = bt_packet_set_properties(packet);
-               if (ret) {
-                       BT_LIB_LOGE("Cannot update packet's properties: "
-                               "%![prev-packet-]+a", packet);
-                       goto error;
-               }
-       }
-
        /*
         * Create notification from pool _after_ we have everything
         * (in this case, a valid event object) so that we never have an
@@ -145,7 +130,7 @@ struct bt_notification *bt_notification_event_create(
        BT_ASSERT(!notification->event);
        notification->event = event;
        bt_packet_set_is_frozen(packet, true);
-       bt_packet_validate_properties(packet);
+       bt_event_class_freeze(event_class);
        BT_LOGD("Created event notification object: "
                "event-addr=%p, event-class-addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
index 6c7c6cf403818473a2a1189541289ee27681c53a..9523bb86bc77993a13847a710f7592b020819bd3 100644 (file)
@@ -39,17 +39,23 @@ void bt_notification_inactivity_destroy(struct bt_object *obj)
                        (struct bt_notification_inactivity *) obj;
 
        BT_LOGD("Destroying inactivity notification: addr=%p", notification);
-       bt_clock_value_set_finalize(&notification->cv_set);
+
+       if (notification->default_cv) {
+               bt_clock_value_recycle(notification->default_cv);
+       }
+
        g_free(notification);
 }
 
 struct bt_notification *bt_notification_inactivity_create(
-               struct bt_private_connection_private_notification_iterator *notif_iter)
+               struct bt_private_connection_private_notification_iterator *notif_iter,
+               struct bt_clock_class *default_clock_class)
 {
        struct bt_notification_inactivity *notification;
        struct bt_notification *ret_notif = NULL;
-       int ret;
 
+       BT_ASSERT_PRE_NON_NULL(notif_iter, "Notification iterator");
+       BT_ASSERT_PRE_NON_NULL(default_clock_class, "Default clock class");
        BT_LOGD_STR("Creating inactivity notification object.");
        notification = g_new0(struct bt_notification_inactivity, 1);
        if (!notification) {
@@ -60,8 +66,8 @@ struct bt_notification *bt_notification_inactivity_create(
                BT_NOTIFICATION_TYPE_INACTIVITY,
                bt_notification_inactivity_destroy, NULL);
        ret_notif = &notification->parent;
-       ret = bt_clock_value_set_initialize(&notification->cv_set);
-       if (ret) {
+       notification->default_cv = bt_clock_value_create(default_clock_class);
+       if (!notification->default_cv) {
                goto error;
        }
 
@@ -76,34 +82,26 @@ end:
        return ret_notif;
 }
 
-int bt_notification_inactivity_set_clock_value(struct bt_notification *notif,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default)
+int bt_notification_inactivity_set_default_clock_value(
+               struct bt_notification *notif, uint64_t value_cycles)
 {
        struct bt_notification_inactivity *inactivity = (void *) notif;
 
        BT_ASSERT_PRE_NON_NULL(notif, "Notification");
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_HOT(notif, "Notification", ": %!+n", notif);
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notif, BT_NOTIFICATION_TYPE_INACTIVITY);
-       BT_ASSERT_PRE(is_default,
-               "You can only set a default clock value as of this version.");
-       return bt_clock_value_set_set_clock_value(&inactivity->cv_set,
-               clock_class, raw_value, is_default);
+       BT_ASSERT_PRE_HOT(notif, "Notification", ": %!+n", notif);
+       bt_clock_value_set_value_inline(inactivity->default_cv, value_cycles);
+       BT_LIB_LOGV("Set inactivity notification's default clock value: "
+               "%![notif-]+n, value=%" PRIu64, notif, value_cycles);
+       return 0;
 }
 
 struct bt_clock_value *bt_notification_inactivity_borrow_default_clock_value(
                struct bt_notification *notif)
 {
        struct bt_notification_inactivity *inactivity = (void *) notif;
-       struct bt_clock_value *clock_value = NULL;
 
        BT_ASSERT_PRE_NON_NULL(notif, "Notification");
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notif, BT_NOTIFICATION_TYPE_INACTIVITY);
-       clock_value = inactivity->cv_set.default_cv;
-       if (!clock_value) {
-               BT_LIB_LOGV("No default clock value: %![notif-]+n", notif);
-       }
-
-       return clock_value;
+       return inactivity->default_cv;
 }
index 552a99f1b1c6ec34c131092f2cfa264d06bcfab9..70694e963bbfcc8645f236cafcaa2d309fe09c4a 100644 (file)
@@ -73,7 +73,6 @@ struct bt_notification *bt_notification_packet_begin_create(
        struct bt_stream *stream;
        struct bt_stream_class *stream_class;
        struct bt_graph *graph;
-       int ret;
 
        BT_ASSERT_PRE_NON_NULL(notif_iter, "Notification iterator");
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
@@ -89,16 +88,6 @@ struct bt_notification *bt_notification_packet_begin_create(
                stream_class,
                bt_stream_class_get_name(stream_class),
                bt_stream_class_get_id(stream_class));
-
-       if (likely(!packet->props_are_set)) {
-               ret = bt_packet_set_properties(packet);
-               if (ret) {
-                       BT_LIB_LOGE("Cannot update packet's properties: "
-                               "%![prev-packet-]+a", packet);
-                       goto end;
-               }
-       }
-
        graph = bt_private_connection_private_notification_iterator_borrow_graph(
                notif_iter);
        notification = (void *) bt_notification_create_from_pool(
@@ -113,7 +102,6 @@ struct bt_notification *bt_notification_packet_begin_create(
        bt_object_get_no_null_check_no_parent_check(
                &notification->packet->base);
        bt_packet_set_is_frozen(packet, true);
-       bt_packet_validate_properties(packet);
        BT_LOGD("Created packet beginning notification object: "
                "packet-addr=%p, stream-addr=%p, stream-name=\"%s\", "
                "stream-class-addr=%p, stream-class-name=\"%s\", "
@@ -206,7 +194,6 @@ struct bt_notification *bt_notification_packet_end_create(
        struct bt_stream *stream;
        struct bt_stream_class *stream_class;
        struct bt_graph *graph;
-       int ret;
 
        BT_ASSERT_PRE_NON_NULL(notif_iter, "Notification iterator");
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
@@ -222,16 +209,6 @@ struct bt_notification *bt_notification_packet_end_create(
                stream_class,
                bt_stream_class_get_name(stream_class),
                bt_stream_class_get_id(stream_class));
-
-       if (unlikely(!packet->props_are_set)) {
-               ret = bt_packet_set_properties(packet);
-               if (ret) {
-                       BT_LIB_LOGE("Cannot update packet's properties: "
-                               "%![prev-packet-]+a", packet);
-                       goto end;
-               }
-       }
-
        graph = bt_private_connection_private_notification_iterator_borrow_graph(
                notif_iter);
        notification = (void *) bt_notification_create_from_pool(
@@ -246,7 +223,6 @@ struct bt_notification *bt_notification_packet_end_create(
        bt_object_get_no_null_check_no_parent_check(
                &notification->packet->base);
        bt_packet_set_is_frozen(packet, true);
-       bt_packet_validate_properties(packet);
        BT_LOGD("Created packet end notification object: "
                "packet-addr=%p, stream-addr=%p, stream-name=\"%s\", "
                "stream-class-addr=%p, stream-class-name=\"%s\", "
index c9e694311b74081321c881ae0764c98766fb36d9..e6015c250d15b06b2b632e8881c6ecc2be8cdcbf 100644 (file)
@@ -31,6 +31,7 @@
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/ctf-ir/stream-internal.h>
 #include <babeltrace/ctf-ir/stream-class.h>
+#include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/graph/notification-stream-internal.h>
 #include <babeltrace/graph/private-connection-private-notification-iterator.h>
 #include <babeltrace/assert-internal.h>
@@ -46,7 +47,11 @@ void bt_notification_stream_end_destroy(struct bt_object *obj)
                notification);
        BT_LOGD_STR("Putting stream.");
        BT_PUT(notification->stream);
-       bt_clock_value_set_finalize(&notification->cv_set);
+
+       if (notification->default_cv) {
+               bt_clock_value_recycle(notification->default_cv);
+       }
+
        g_free(notification);
 }
 
@@ -56,7 +61,6 @@ struct bt_notification *bt_notification_stream_end_create(
 {
        struct bt_notification_stream_end *notification;
        struct bt_stream_class *stream_class;
-       int ret;
 
        BT_ASSERT_PRE_NON_NULL(stream, "Stream");
        stream_class = bt_stream_borrow_class(stream);
@@ -79,11 +83,6 @@ struct bt_notification *bt_notification_stream_end_create(
                        BT_NOTIFICATION_TYPE_STREAM_END,
                        bt_notification_stream_end_destroy, NULL);
        notification->stream = bt_get(stream);
-       ret = bt_clock_value_set_initialize(&notification->cv_set);
-       if (ret) {
-               goto error;
-       }
-
        BT_LOGD("Created stream end notification object: "
                "stream-addr=%p, stream-name=\"%s\", "
                "stream-class-addr=%p, stream-class-name=\"%s\", "
@@ -110,36 +109,44 @@ struct bt_stream *bt_notification_stream_end_borrow_stream(
        return stream_end->stream;
 }
 
-int bt_notification_stream_end_set_clock_value(struct bt_notification *notif,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default)
+int bt_notification_stream_end_set_default_clock_value(
+               struct bt_notification *notif, uint64_t value_cycles)
 {
-       struct bt_notification_stream_end *stream_end = (void *) notif;
+       int ret = 0;
+       struct bt_notification_stream_end *se_notif = (void *) notif;
 
        BT_ASSERT_PRE_NON_NULL(notif, "Notification");
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
        BT_ASSERT_PRE_HOT(notif, "Notification", ": %!+n", notif);
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notif, BT_NOTIFICATION_TYPE_STREAM_END);
-       BT_ASSERT_PRE(is_default,
-               "You can only set a default clock value as of this version.");
-       return bt_clock_value_set_set_clock_value(&stream_end->cv_set,
-               clock_class, raw_value, is_default);
+       BT_ASSERT_PRE(se_notif->stream->class->default_clock_class,
+               "Notification's stream class has no default clock class: "
+               "%![notif-]+n, %![sc-]+S", notif, se_notif->stream->class);
+
+       if (!se_notif->default_cv) {
+               se_notif->default_cv = bt_clock_value_create(
+                       se_notif->stream->class->default_clock_class);
+               if (!se_notif->default_cv) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       bt_clock_value_set_value_inline(se_notif->default_cv, value_cycles);
+       BT_LIB_LOGV("Set notification's default clock value: %![notif-]+n, "
+               "value=%" PRIu64, value_cycles);
+
+end:
+       return ret;
 }
 
 struct bt_clock_value *bt_notification_stream_end_borrow_default_clock_value(
                struct bt_notification *notif)
 {
        struct bt_notification_stream_end *stream_end = (void *) notif;
-       struct bt_clock_value *clock_value = NULL;
 
        BT_ASSERT_PRE_NON_NULL(notif, "Notification");
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notif, BT_NOTIFICATION_TYPE_STREAM_END);
-       clock_value = stream_end->cv_set.default_cv;
-       if (!clock_value) {
-               BT_LIB_LOGV("No default clock value: %![notif-]+n", notif);
-       }
-
-       return clock_value;
+       return stream_end->default_cv;
 }
 
 static
@@ -152,7 +159,11 @@ void bt_notification_stream_begin_destroy(struct bt_object *obj)
                notification);
        BT_LOGD_STR("Putting stream.");
        BT_PUT(notification->stream);
-       bt_clock_value_set_finalize(&notification->cv_set);
+
+       if (notification->default_cv) {
+               bt_clock_value_recycle(notification->default_cv);
+       }
+
        g_free(notification);
 }
 
@@ -160,7 +171,6 @@ struct bt_notification *bt_notification_stream_begin_create(
                struct bt_private_connection_private_notification_iterator *notif_iter,
                struct bt_stream *stream)
 {
-       int ret;
        struct bt_notification_stream_begin *notification;
        struct bt_stream_class *stream_class;
 
@@ -185,11 +195,6 @@ struct bt_notification *bt_notification_stream_begin_create(
                        BT_NOTIFICATION_TYPE_STREAM_BEGIN,
                        bt_notification_stream_begin_destroy, NULL);
        notification->stream = bt_get(stream);
-       ret = bt_clock_value_set_initialize(&notification->cv_set);
-       if (ret) {
-               goto error;
-       }
-
        BT_LOGD("Created stream beginning notification object: "
                "stream-addr=%p, stream-name=\"%s\", "
                "stream-class-addr=%p, stream-class-name=\"%s\", "
@@ -216,34 +221,42 @@ struct bt_stream *bt_notification_stream_begin_borrow_stream(
        return stream_begin->stream;
 }
 
-int bt_notification_stream_begin_set_clock_value(struct bt_notification *notif,
-               struct bt_clock_class *clock_class, uint64_t raw_value,
-               bt_bool is_default)
+int bt_notification_stream_begin_set_default_clock_value(
+               struct bt_notification *notif, uint64_t value_cycles)
 {
-       struct bt_notification_stream_begin *stream_begin = (void *) notif;
+       int ret = 0;
+       struct bt_notification_stream_begin *sb_notif = (void *) notif;
 
        BT_ASSERT_PRE_NON_NULL(notif, "Notification");
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
        BT_ASSERT_PRE_HOT(notif, "Notification", ": %!+n", notif);
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notif, BT_NOTIFICATION_TYPE_STREAM_BEGIN);
-       BT_ASSERT_PRE(is_default,
-               "You can only set a default clock value as of this version.");
-       return bt_clock_value_set_set_clock_value(&stream_begin->cv_set,
-               clock_class, raw_value, is_default);
+       BT_ASSERT_PRE(sb_notif->stream->class->default_clock_class,
+               "Notification's stream class has no default clock class: "
+               "%![notif-]+n, %![sc-]+S", notif, sb_notif->stream->class);
+
+       if (!sb_notif->default_cv) {
+               sb_notif->default_cv = bt_clock_value_create(
+                       sb_notif->stream->class->default_clock_class);
+               if (!sb_notif->default_cv) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       bt_clock_value_set_value_inline(sb_notif->default_cv, value_cycles);
+       BT_LIB_LOGV("Set notification's default clock value: %![notif-]+n, "
+               "value=%" PRIu64, value_cycles);
+
+end:
+       return ret;
 }
 
 struct bt_clock_value *bt_notification_stream_begin_borrow_default_clock_value(
                struct bt_notification *notif)
 {
        struct bt_notification_stream_begin *stream_begin = (void *) notif;
-       struct bt_clock_value *clock_value = NULL;
 
        BT_ASSERT_PRE_NON_NULL(notif, "Notification");
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notif, BT_NOTIFICATION_TYPE_STREAM_BEGIN);
-       clock_value = stream_begin->cv_set.default_cv;
-       if (!clock_value) {
-               BT_LIB_LOGV("No default clock value: %![notif-]+n", notif);
-       }
-
-       return clock_value;
+       return stream_begin->default_cv;
 }
index 80fe9ef3939cb04927ff7a286762566517e37455..d09b176d41dde24d38995f96a75c6e45f8adc73c 100644 (file)
@@ -82,24 +82,10 @@ static char __thread lib_logging_buf[LIB_LOGGING_BUF_SIZE];
        } while (0)
 
 #define BUF_APPEND_UUID(_uuid)                                         \
-       BUF_APPEND(", %suuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", \
-               prefix,                                                 \
-               (unsigned int) (_uuid)[0],                              \
-               (unsigned int) (_uuid)[1],                              \
-               (unsigned int) (_uuid)[2],                              \
-               (unsigned int) (_uuid)[3],                              \
-               (unsigned int) (_uuid)[4],                              \
-               (unsigned int) (_uuid)[5],                              \
-               (unsigned int) (_uuid)[6],                              \
-               (unsigned int) (_uuid)[7],                              \
-               (unsigned int) (_uuid)[8],                              \
-               (unsigned int) (_uuid)[9],                              \
-               (unsigned int) (_uuid)[10],                             \
-               (unsigned int) (_uuid)[11],                             \
-               (unsigned int) (_uuid)[12],                             \
-               (unsigned int) (_uuid)[13],                             \
-               (unsigned int) (_uuid)[14],                             \
-               (unsigned int) (_uuid)[15])
+       do {                                                            \
+               BUF_APPEND(", %suuid=", prefix);                        \
+               format_uuid(buf_ch, (_uuid));                           \
+       } while (0)
 
 #define PRFIELD(_expr) prefix, (_expr)
 
@@ -121,28 +107,34 @@ static inline void format_connection(char **buf_ch, bool extended,
 static inline void format_clock_value(char **buf_ch, bool extended,
                const char *prefix, struct bt_clock_value *clock_value);
 
+static inline void format_field_path(char **buf_ch, bool extended,
+               const char *prefix, struct bt_field_path *field_path);
+
 static inline void format_object(char **buf_ch, bool extended,
                const char *prefix, struct bt_object *obj)
 {
        BUF_APPEND(", %sref-count=%llu", prefix, obj->ref_count);
 }
 
-static inline void format_clock_value_set(char **buf_ch, bool extended,
-               const char *prefix, struct bt_clock_value_set *cv_set)
+static inline void format_uuid(char **buf_ch, bt_uuid uuid)
 {
-       char tmp_prefix[64];
-
-       if (!cv_set->clock_values) {
-               return;
-       }
-
-       BUF_APPEND(", %ssize=%u", PRFIELD(cv_set->clock_values->len));
-
-       if (cv_set->default_cv) {
-               SET_TMP_PREFIX("default-cv-");
-               format_clock_value(buf_ch, extended, tmp_prefix,
-                       cv_set->default_cv);
-       }
+       BUF_APPEND("\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+               (unsigned int) uuid[0],
+               (unsigned int) uuid[1],
+               (unsigned int) uuid[2],
+               (unsigned int) uuid[3],
+               (unsigned int) uuid[4],
+               (unsigned int) uuid[5],
+               (unsigned int) uuid[6],
+               (unsigned int) uuid[7],
+               (unsigned int) uuid[8],
+               (unsigned int) uuid[9],
+               (unsigned int) uuid[10],
+               (unsigned int) uuid[11],
+               (unsigned int) uuid[12],
+               (unsigned int) uuid[13],
+               (unsigned int) uuid[14],
+               (unsigned int) uuid[15]);
 }
 
 static inline void format_object_pool(char **buf_ch, bool extended,
@@ -155,97 +147,133 @@ static inline void format_object_pool(char **buf_ch, bool extended,
        }
 }
 
+static inline void format_integer_field_type(char **buf_ch,
+               bool extended, const char *prefix,
+               struct bt_field_type *field_type)
+{
+       struct bt_field_type_integer *int_ft = (void *) field_type;
+
+       BUF_APPEND(", %srange-size=%" PRIu64 ", %sbase=%s",
+               PRFIELD(int_ft->range),
+               PRFIELD(bt_common_field_type_integer_preferred_display_base_string(int_ft->base)));
+}
+
+static inline void format_array_field_type(char **buf_ch,
+               bool extended, const char *prefix,
+               struct bt_field_type *field_type)
+{
+       struct bt_field_type_array *array_ft = (void *) field_type;
+
+       BUF_APPEND(", %selement-ft-addr=%p, %selement-ft-id=%s",
+               PRFIELD(array_ft->element_ft),
+               PRFIELD(bt_common_field_type_id_string(array_ft->element_ft->id)));
+}
+
 static inline void format_field_type(char **buf_ch, bool extended,
                const char *prefix, struct bt_field_type *field_type)
 {
-       BUF_APPEND(", %stype-id=%s, %salignment=%u",
-               PRFIELD(bt_common_field_type_id_string(field_type->id)),
-               PRFIELD(field_type->alignment));
+       char tmp_prefix[64];
+
+       BUF_APPEND(", %sid=%s",
+               PRFIELD(bt_common_field_type_id_string(field_type->id)));
 
        if (extended) {
                BUF_APPEND(", %sis-frozen=%d", PRFIELD(field_type->frozen));
+               BUF_APPEND(", %sis-part-of-trace=%d",
+                       PRFIELD(field_type->part_of_trace));
        } else {
                return;
        }
 
-       if (field_type->id == BT_FIELD_TYPE_ID_UNKNOWN) {
-               return;
-       }
-
        switch (field_type->id) {
-       case BT_FIELD_TYPE_ID_INTEGER:
+       case BT_FIELD_TYPE_ID_UNSIGNED_INTEGER:
+       case BT_FIELD_TYPE_ID_SIGNED_INTEGER:
        {
-               struct bt_field_type_integer *integer = (void *) field_type;
-
-               BUF_APPEND(", %ssize=%u, %sis-signed=%d, %sbyte-order=%s, "
-                       "%sbase=%d, %sencoding=%s, "
-                       "%smapped-clock-class-addr=%p",
-                       PRFIELD(integer->size), PRFIELD(integer->is_signed),
-                       PRFIELD(bt_common_byte_order_string(
-                               integer->user_byte_order)),
-                       PRFIELD(integer->base),
-                       PRFIELD(bt_common_string_encoding_string(
-                               integer->encoding)),
-                       PRFIELD(integer->mapped_clock_class));
-
-               if (integer->mapped_clock_class) {
-                       BUF_APPEND(", %smapped-clock-class-name=\"%s\"",
-                               PRFIELD(bt_clock_class_get_name(
-                                       integer->mapped_clock_class)));
-               }
+               format_integer_field_type(buf_ch, extended, prefix, field_type);
                break;
        }
-       case BT_FIELD_TYPE_ID_FLOAT:
+       case BT_FIELD_TYPE_ID_REAL:
        {
-               struct bt_field_type_floating_point *flt = (void *) field_type;
+               struct bt_field_type_real *real_ft = (void *) field_type;
 
-               BUF_APPEND(", %sexp-dig=%u, %smant-dig=%u, %sbyte-order=%s",
-                       PRFIELD(flt->exp_dig), PRFIELD(flt->mant_dig),
-                       PRFIELD(bt_common_byte_order_string(
-                               flt->user_byte_order)));
+               BUF_APPEND(", %sis-single-precision=%d",
+                       PRFIELD(real_ft->is_single_precision));
                break;
        }
-       case BT_FIELD_TYPE_ID_ENUM:
+       case BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION:
+       case BT_FIELD_TYPE_ID_SIGNED_ENUMERATION:
        {
-               struct bt_field_type_enumeration *enm = (void *) field_type;
+               struct bt_field_type_enumeration *enum_ft =
+                       (void *) field_type;
 
+               format_integer_field_type(buf_ch, extended, prefix, field_type);
                BUF_APPEND(", %smapping-count=%u",
-                       PRFIELD(enm->entries->len));
+                       PRFIELD(enum_ft->mappings->len));
                break;
        }
-       case BT_FIELD_TYPE_ID_STRING:
+       case BT_FIELD_TYPE_ID_STRUCTURE:
        {
-               struct bt_field_type_string *str = (void *) field_type;
+               struct bt_field_type_structure *struct_ft =
+                       (void *) field_type;
+
+               if (struct_ft->common.named_fts) {
+                       BUF_APPEND(", %smember-count=%u",
+                               PRFIELD(struct_ft->common.named_fts->len));
+               }
 
-               BUF_APPEND(", %sencoding=%s",
-                       PRFIELD(bt_common_string_encoding_string(
-                               str->encoding)));
                break;
        }
-       case BT_FIELD_TYPE_ID_STRUCT:
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
        {
-               struct bt_field_type_structure *structure = (void *) field_type;
+               struct bt_field_type_static_array *array_ft =
+                       (void *) field_type;
 
-               BUF_APPEND(", %sfield-count=%u",
-                       PRFIELD(structure->fields->len));
+               format_array_field_type(buf_ch, extended, prefix, field_type);
+               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(array_ft->length));
                break;
        }
-       case BT_FIELD_TYPE_ID_SEQUENCE:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
        {
-               struct bt_field_type_sequence *seq = (void *) field_type;
+               struct bt_field_type_dynamic_array *array_ft =
+                       (void *) field_type;
+
+               format_array_field_type(buf_ch, extended, prefix, field_type);
+
+               if (array_ft->length_ft) {
+                       SET_TMP_PREFIX("length-ft-");
+                       format_field_type(buf_ch, extended, tmp_prefix,
+                               array_ft->length_ft);
+               }
+
+               if (array_ft->length_field_path) {
+                       SET_TMP_PREFIX("length-field-path-");
+                       format_field_path(buf_ch, extended, tmp_prefix,
+                               array_ft->length_field_path);
+               }
 
-               BUF_APPEND(", %slength-ft-addr=\"%s\", %selem-ft-addr=%p",
-                       PRFIELD(seq->length_field_name->str),
-                       PRFIELD(seq->element_ft));
                break;
        }
        case BT_FIELD_TYPE_ID_VARIANT:
        {
-               struct bt_field_type_variant *variant = (void *) field_type;
+               struct bt_field_type_variant *var_ft = (void *) field_type;
+
+               if (var_ft->common.named_fts) {
+                       BUF_APPEND(", %soption-count=%u",
+                               PRFIELD(var_ft->common.named_fts->len));
+               }
+
+               if (var_ft->selector_ft) {
+                       SET_TMP_PREFIX("selector-ft-");
+                       format_field_type(buf_ch, extended, tmp_prefix,
+                               var_ft->selector_ft);
+               }
+
+               if (var_ft->selector_field_path) {
+                       SET_TMP_PREFIX("selector-field-path-");
+                       format_field_path(buf_ch, extended, tmp_prefix,
+                               var_ft->selector_field_path);
+               }
 
-               BUF_APPEND(", %stag-name=\"%s\", %sfield-count=%u",
-                       PRFIELD(variant->tag_name->str),
-                       PRFIELD(variant->choices->len));
                break;
        }
        default:
@@ -262,33 +290,32 @@ static inline void format_field_integer_extended(char **buf_ch,
 
        BT_ASSERT(field_type);
 
-       if (field_type->base == 8) {
+       if (field_type->base == BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL) {
                fmt = ", %svalue=%" PRIo64;
-       } else if (field_type->base == 16) {
+       } else if (field_type->base == BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL) {
                fmt = ", %svalue=%" PRIx64;
        }
 
-       if (field_type->is_signed) {
+       if (field_type->common.id == BT_FIELD_TYPE_ID_SIGNED_INTEGER ||
+                       field_type->common.id == BT_FIELD_TYPE_ID_SIGNED_ENUMERATION) {
                if (!fmt) {
                        fmt = ", %svalue=%" PRId64;
                }
 
-               BUF_APPEND(fmt, PRFIELD(integer->payload.signd));
+               BUF_APPEND(fmt, PRFIELD(integer->value.i));
        } else {
                if (!fmt) {
                        fmt = ", %svalue=%" PRIu64;
                }
 
-               BUF_APPEND(fmt, PRFIELD(integer->payload.unsignd));
+               BUF_APPEND(fmt, PRFIELD(integer->value.u));
        }
 }
 
 static inline void format_field(char **buf_ch, bool extended,
                const char *prefix, struct bt_field *field)
 {
-       struct bt_field *common_field = (void *) field;
-
-       BUF_APPEND(", %sis-set=%d", PRFIELD(field->payload_set));
+       BUF_APPEND(", %sis-set=%d", PRFIELD(field->is_set));
 
        if (extended) {
                BUF_APPEND(", %sis-frozen=%d", PRFIELD(field->frozen));
@@ -303,22 +330,24 @@ static inline void format_field(char **buf_ch, bool extended,
        BUF_APPEND(", %stype-id=%s",
                PRFIELD(bt_common_field_type_id_string(field->type->id)));
 
-       if (!extended || field->type->id == BT_FIELD_TYPE_ID_UNKNOWN ||
-                       !field->payload_set) {
+       if (!extended || !field->is_set) {
                return;
        }
 
        switch (field->type->id) {
-       case BT_FIELD_TYPE_ID_INTEGER:
+       case BT_FIELD_TYPE_ID_UNSIGNED_INTEGER:
+       case BT_FIELD_TYPE_ID_SIGNED_INTEGER:
+       case BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION:
+       case BT_FIELD_TYPE_ID_SIGNED_ENUMERATION:
        {
                format_field_integer_extended(buf_ch, prefix, field);
                break;
        }
-       case BT_FIELD_TYPE_ID_FLOAT:
+       case BT_FIELD_TYPE_ID_REAL:
        {
-               struct bt_field_floating_point *flt = (void *) field;
+               struct bt_field_real *real_field = (void *) field;
 
-               BUF_APPEND(", %svalue=%f", PRFIELD(flt->payload));
+               BUF_APPEND(", %svalue=%f", PRFIELD(real_field->value));
                break;
        }
        case BT_FIELD_TYPE_ID_STRING:
@@ -329,54 +358,30 @@ static inline void format_field(char **buf_ch, bool extended,
                        BT_ASSERT(str->buf->data);
                        BUF_APPEND(", %spartial-value=\"%.32s\"",
                                PRFIELD(str->buf->data));
-
                }
+
                break;
        }
-       case BT_FIELD_TYPE_ID_SEQUENCE:
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
        {
-               struct bt_field_sequence *seq = (void *) field;
+               struct bt_field_array *array_field = (void *) field;
 
-               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(seq->length));
+               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(array_field->length));
 
-               if (seq->elements) {
+               if (array_field->fields) {
                        BUF_APPEND(", %sallocated-length=%u",
-                               PRFIELD(seq->elements->len));
+                               PRFIELD(array_field->fields->len));
                }
+
                break;
        }
        case BT_FIELD_TYPE_ID_VARIANT:
        {
-               struct bt_field_variant *variant = (void *) field;
-
-               BUF_APPEND(", %scur-field-addr=%p",
-                       PRFIELD(variant->current_field));
-               break;
-       }
-       default:
-               break;
-       }
-
-       if (!common_field->type) {
-               return;
-       }
+               struct bt_field_variant *var_field = (void *) field;
 
-       switch (common_field->type->id) {
-       case BT_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_field_integer *integer = (void *) field;
-               struct bt_field_type_enumeration *enum_ft =
-                       (void *) common_field->type;
-
-               if (enum_ft->container_ft) {
-                       if (enum_ft->container_ft->is_signed) {
-                               BUF_APPEND(", %svalue=%" PRId64,
-                                       PRFIELD(integer->payload.signd));
-                       } else {
-                               BUF_APPEND(", %svalue=%" PRIu64,
-                                       PRFIELD(integer->payload.unsignd));
-                       }
-               }
+               BUF_APPEND(", %sselected-field-index=%" PRIu64,
+                       PRFIELD(var_field->selected_index));
                break;
        }
        default:
@@ -403,9 +408,10 @@ static inline void format_field_path(char **buf_ch, bool extended,
                PRFIELD(bt_common_scope_string(field_path->root)));
 
        for (i = 0; i < field_path->indexes->len; i++) {
-               int index = g_array_index(field_path->indexes, int, i);
+               uint64_t index = bt_field_path_get_index_by_index_inline(
+                       field_path, i);
 
-               BUF_APPEND(", %d", index);
+               BUF_APPEND(", %" PRIu64, index);
        }
 
        BUF_APPEND("%s", "]");
@@ -416,8 +422,8 @@ static inline void format_trace(char **buf_ch, bool extended,
 {
        char tmp_prefix[64];
 
-       if (trace->name) {
-               BUF_APPEND(", %sname=\"%s\"", PRFIELD(trace->name->str));
+       if (trace->name.value) {
+               BUF_APPEND(", %sname=\"%s\"", PRFIELD(trace->name.value));
        }
 
        if (!extended) {
@@ -426,13 +432,8 @@ static inline void format_trace(char **buf_ch, bool extended,
 
        BUF_APPEND(", %sis-frozen=%d", PRFIELD(trace->frozen));
 
-       if (trace->uuid_set) {
-               BUF_APPEND_UUID(trace->uuid);
-       }
-
-       if (trace->clock_classes) {
-               BUF_APPEND(", %sclock-class-count=%u",
-                       PRFIELD(trace->clock_classes->len));
+       if (trace->uuid.value) {
+               BUF_APPEND_UUID(trace->uuid.value);
        }
 
        if (trace->stream_classes) {
@@ -445,9 +446,11 @@ static inline void format_trace(char **buf_ch, bool extended,
                        PRFIELD(trace->streams->len));
        }
 
-       BUF_APPEND(", %spacket-header-ft-addr=%p",
-               PRFIELD(trace->packet_header_field_type));
-       BUF_APPEND(", %sis-static=%d", PRFIELD(trace->is_static));
+       BUF_APPEND(", %spacket-header-ft-addr=%p, %sis-static=%d, "
+               "%sassigns-auto-sc-id=%d",
+               PRFIELD(trace->packet_header_ft),
+               PRFIELD(trace->is_static),
+               PRFIELD(trace->assigns_automatic_stream_class_id));
        SET_TMP_PREFIX("phf-pool-");
        format_object_pool(buf_ch, extended, prefix,
                &trace->packet_header_field_pool);
@@ -459,12 +462,11 @@ static inline void format_stream_class(char **buf_ch, bool extended,
        struct bt_trace *trace;
        char tmp_prefix[64];
 
-       if (stream_class->id_set) {
-               BUF_APPEND(", %sid=%" PRId64, PRFIELD(stream_class->id));
-       }
+       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream_class->id));
 
-       if (stream_class->name) {
-               BUF_APPEND(", %sname=\"%s\"", PRFIELD(stream_class->name->str));
+       if (stream_class->name.value) {
+               BUF_APPEND(", %sname=\"%s\"",
+                       PRFIELD(stream_class->name.value));
        }
 
        if (!extended) {
@@ -479,15 +481,26 @@ static inline void format_stream_class(char **buf_ch, bool extended,
        }
 
        BUF_APPEND(", %spacket-context-ft-addr=%p, "
-               "%sevent-header-ft-addr=%p, %sevent-context-ft-addr=%p",
-               PRFIELD(stream_class->packet_context_field_type),
-               PRFIELD(stream_class->event_header_field_type),
-               PRFIELD(stream_class->event_context_field_type));
-       trace = bt_stream_class_borrow_trace(stream_class);
+               "%sevent-header-ft-addr=%p, %sevent-common-context-ft-addr=%p",
+               PRFIELD(stream_class->packet_context_ft),
+               PRFIELD(stream_class->event_header_ft),
+               PRFIELD(stream_class->event_common_context_ft));
+       trace = bt_stream_class_borrow_trace_inline(stream_class);
        if (!trace) {
                return;
        }
 
+       BUF_APPEND(", %sassigns-auto-ec-id=%d, %sassigns-auto-stream-id=%d, "
+               "%spackets-have-discarded-ev-counter-snapshot=%d, "
+               "%spackets-have-packet-counter-snapshot=%d, "
+               "%spackets-have-default-begin-cv=%d, "
+               "%spackets-have-default-end-cv=%d",
+               PRFIELD(stream_class->assigns_automatic_event_class_id),
+               PRFIELD(stream_class->assigns_automatic_stream_id),
+               PRFIELD(stream_class->packets_have_discarded_event_counter_snapshot),
+               PRFIELD(stream_class->packets_have_packet_counter_snapshot),
+               PRFIELD(stream_class->packets_have_default_beginning_cv),
+               PRFIELD(stream_class->packets_have_default_end_cv));
        BUF_APPEND(", %strace-addr=%p", PRFIELD(trace));
        SET_TMP_PREFIX("trace-");
        format_trace(buf_ch, false, tmp_prefix, trace);
@@ -506,30 +519,33 @@ static inline void format_event_class(char **buf_ch, bool extended,
        struct bt_trace *trace;
        char tmp_prefix[64];
 
-       BUF_APPEND(", %sid=%" PRId64, PRFIELD(event_class->id));
+       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(event_class->id));
 
-       if (event_class->name) {
+       if (event_class->name.value) {
                BUF_APPEND(", %sname=\"%s\"",
-                       PRFIELD(event_class->name->str));
+                       PRFIELD(event_class->name.value));
        }
 
        if (!extended) {
                return;
        }
 
-       BUF_APPEND(", %sis-frozen=%d, %slog-level=%s",
-               PRFIELD(event_class->frozen),
-               PRFIELD(bt_common_event_class_log_level_string(
-                       event_class->log_level)));
+       BUF_APPEND(", %sis-frozen=%d", PRFIELD(event_class->frozen));
+
+       if (event_class->log_level.base.avail) {
+               BUF_APPEND(", %slog-level=%s",
+                       PRFIELD(bt_common_event_class_log_level_string(
+                               (int) event_class->log_level.value)));
+       }
 
-       if (event_class->emf_uri) {
+       if (event_class->emf_uri.value) {
                BUF_APPEND(", %semf-uri=\"%s\"",
-                       PRFIELD(event_class->emf_uri->str));
+                       PRFIELD(event_class->emf_uri.value));
        }
 
-       BUF_APPEND(", %scontext-ft-addr=%p, %spayload-ft-addr=%p",
-               PRFIELD(event_class->context_field_type),
-               PRFIELD(event_class->payload_field_type));
+       BUF_APPEND(", %sspecific-context-ft-addr=%p, %spayload-ft-addr=%p",
+               PRFIELD(event_class->specific_context_ft),
+               PRFIELD(event_class->payload_ft));
 
        stream_class = bt_event_class_borrow_stream_class(event_class);
        if (!stream_class) {
@@ -539,7 +555,7 @@ static inline void format_event_class(char **buf_ch, bool extended,
        BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
        SET_TMP_PREFIX("stream-class-");
        format_stream_class(buf_ch, false, tmp_prefix, stream_class);
-       trace = bt_stream_class_borrow_trace(stream_class);
+       trace = bt_stream_class_borrow_trace_inline(stream_class);
        if (!trace) {
                return;
        }
@@ -558,10 +574,10 @@ static inline void format_stream(char **buf_ch, bool extended,
        struct bt_trace *trace;
        char tmp_prefix[64];
 
-       BUF_APPEND(", %sid=%" PRId64, PRFIELD(stream->id));
+       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream->id));
 
-       if (stream->name) {
-               BUF_APPEND(", %sname=\"%s\"", PRFIELD(stream->name->str));
+       if (stream->name.value) {
+               BUF_APPEND(", %sname=\"%s\"", PRFIELD(stream->name.value));
        }
 
        if (!extended) {
@@ -576,7 +592,7 @@ static inline void format_stream(char **buf_ch, bool extended,
        BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
        SET_TMP_PREFIX("stream-class-");
        format_stream_class(buf_ch, false, tmp_prefix, stream_class);
-       trace = bt_stream_class_borrow_trace(stream_class);
+       trace = bt_stream_class_borrow_trace_inline(stream_class);
        if (!trace) {
                return;
        }
@@ -607,18 +623,39 @@ static inline void format_packet(char **buf_ch, bool extended,
        BUF_APPEND(", %sis-frozen=%d, %sheader-field-addr=%p, "
                "%scontext-field-addr=%p",
                PRFIELD(packet->frozen),
-               PRFIELD(packet->header ? packet->header->field : NULL),
-               PRFIELD(packet->context));
+               PRFIELD(packet->header_field ? packet->header_field->field : NULL),
+               PRFIELD(packet->context_field ? packet->context_field->field : NULL));
        stream = bt_packet_borrow_stream(packet);
        if (!stream) {
                return;
        }
 
+       if (packet->default_beginning_cv) {
+               SET_TMP_PREFIX("default-begin-cv-");
+               format_clock_value(buf_ch, true, tmp_prefix,
+                       packet->default_beginning_cv);
+       }
+
+       if (packet->default_end_cv) {
+               SET_TMP_PREFIX("default-end-cv-");
+               format_clock_value(buf_ch, true, tmp_prefix,
+                       packet->default_end_cv);
+       }
+
+       if (packet->discarded_event_counter_snapshot.base.avail) {
+               BUF_APPEND(", %sdiscarded-ev-counter-snapshot=%" PRIu64,
+                       PRFIELD(packet->discarded_event_counter_snapshot.value));
+       }
+
+       if (packet->packet_counter_snapshot.base.avail) {
+               BUF_APPEND(", %spacket-counter-snapshot=%" PRIu64,
+                       PRFIELD(packet->packet_counter_snapshot.value));
+       }
+
        BUF_APPEND(", %sstream-addr=%p", PRFIELD(stream));
        SET_TMP_PREFIX("stream-");
        format_stream(buf_ch, false, tmp_prefix, stream);
-       trace = (struct bt_trace *)
-               bt_object_borrow_parent(&stream->base);
+       trace = (struct bt_trace *) bt_object_borrow_parent(&stream->base);
        if (!trace) {
                return;
        }
@@ -642,13 +679,14 @@ static inline void format_event(char **buf_ch, bool extended,
        }
 
        BUF_APPEND(", %sis-frozen=%d, %sheader-field-addr=%p, "
-               "%sstream-context-field-addr=%p, "
-               "%scontext-field-addr=%p, %spayload-field-addr=%p, ",
+               "%scommon-context-field-addr=%p, "
+               "%specific-scontext-field-addr=%p, "
+               "%spayload-field-addr=%p, ",
                PRFIELD(event->frozen),
                PRFIELD(event->header_field ?
                        event->header_field->field : NULL),
-               PRFIELD(event->stream_event_context_field),
-               PRFIELD(event->context_field),
+               PRFIELD(event->common_context_field),
+               PRFIELD(event->specific_context_field),
                PRFIELD(event->payload_field));
        BUF_APPEND(", %sevent-class-addr=%p", PRFIELD(event->class));
 
@@ -665,7 +703,7 @@ static inline void format_event(char **buf_ch, bool extended,
                format_stream_class(buf_ch, false, tmp_prefix,
                        stream_class);
 
-               trace = bt_stream_class_borrow_trace(stream_class);
+               trace = bt_stream_class_borrow_trace_inline(stream_class);
                if (trace) {
                        BUF_APPEND(", %strace-addr=%p", PRFIELD(trace));
                        SET_TMP_PREFIX("trace-");
@@ -673,8 +711,12 @@ static inline void format_event(char **buf_ch, bool extended,
                }
        }
 
-       SET_TMP_PREFIX("cvs-");
-       format_clock_value_set(buf_ch, extended, tmp_prefix, &event->cv_set);
+       if (event->default_cv) {
+               SET_TMP_PREFIX("default-cv-");
+               format_clock_value(buf_ch, true, tmp_prefix,
+                       event->default_cv);
+       }
+
        packet = bt_event_borrow_packet(event);
        if (!packet) {
                return;
@@ -698,29 +740,34 @@ static inline void format_clock_class(char **buf_ch, bool extended,
 {
        char tmp_prefix[64];
 
-       BUF_APPEND(", %sname=\"%s\", %sfreq=%" PRIu64,
-               PRFIELD(clock_class->name->str),
-               PRFIELD(clock_class->frequency));
+       if (clock_class->name.value) {
+               BUF_APPEND(", %sname=\"%s\"", PRFIELD(clock_class->name.value));
+       }
+
+       BUF_APPEND(", %sfreq=%" PRIu64, PRFIELD(clock_class->frequency));
 
        if (!extended) {
                return;
        }
 
-       if (clock_class->description) {
-               BUF_APPEND(", %spartial-description=\"%.32s\"",
-                       PRFIELD(clock_class->description->str));
+       if (clock_class->description.value) {
+               BUF_APPEND(", %spartial-descr=\"%.32s\"",
+                       PRFIELD(clock_class->description.value));
+       }
+
+       if (clock_class->uuid.value) {
+               BUF_APPEND_UUID(clock_class->uuid.value);
        }
 
        BUF_APPEND(", %sis-frozen=%d, %sprecision=%" PRIu64 ", "
                "%soffset-s=%" PRId64 ", "
-               "%soffset-cycles=%" PRId64 ", %sis-absolute=%d",
+               "%soffset-cycles=%" PRIu64 ", %sis-absolute=%d, "
+               "%sbase-offset-ns=%" PRId64,
                PRFIELD(clock_class->frozen), PRFIELD(clock_class->precision),
-               PRFIELD(clock_class->offset_s), PRFIELD(clock_class->offset),
-               PRFIELD(clock_class->absolute));
-
-       if (clock_class->uuid_set) {
-               BUF_APPEND_UUID(clock_class->uuid);
-       }
+               PRFIELD(clock_class->offset_seconds),
+               PRFIELD(clock_class->offset_cycles),
+               PRFIELD(clock_class->is_absolute),
+               PRFIELD(clock_class->base_offset.value_ns));
 
        SET_TMP_PREFIX("cv-pool-");
        format_object_pool(buf_ch, extended, prefix, &clock_class->cv_pool);
@@ -730,16 +777,15 @@ static inline void format_clock_value(char **buf_ch, bool extended,
                const char *prefix, struct bt_clock_value *clock_value)
 {
        char tmp_prefix[64];
-       BUF_APPEND(", %sraw-value=%" PRIu64 ", %sns-from-epoch=%" PRId64,
-               PRFIELD(clock_value->value),
-               PRFIELD(clock_value->ns_from_epoch));
+       BUF_APPEND(", %svalue=%" PRIu64 ", %sns-from-origin=%" PRId64,
+               PRFIELD(clock_value->value_cycles),
+               PRFIELD(clock_value->ns_from_origin));
 
        if (!extended) {
                return;
        }
 
-       BUF_APPEND(", %sis-frozen=%d, %sis-set=%d",
-               PRFIELD(clock_value->frozen), PRFIELD(clock_value->is_set));
+       BUF_APPEND(", %sis-set=%d", PRFIELD(clock_value->is_set));
        BUF_APPEND(", %sclock-class-addr=%p",
                PRFIELD(clock_value->clock_class));
        SET_TMP_PREFIX("clock-class-");
@@ -1139,6 +1185,13 @@ static inline void handle_conversion_specifier_bt(void *priv_data,
        /* skip "%!" */
        fmt_ch += 2;
 
+       if (*fmt_ch == 'u') {
+               /* UUID */
+               obj = va_arg(*args, void *);
+               format_uuid(buf_ch, obj);
+               goto update_fmt;
+       }
+
        if (*fmt_ch == '[') {
                /* local prefix */
                fmt_ch++;
@@ -1225,7 +1278,7 @@ static inline void handle_conversion_specifier_bt(void *priv_data,
        case 'x':
                format_connection(buf_ch, extended, prefix, obj);
                break;
-       case 'u':
+       case 'l':
                format_plugin(buf_ch, extended, prefix, obj);
                break;
        case 'g':
index 4622c0729c88c94a23c9748956126468f897010e..a1dd508a08726b2522441b73044128a27edaaac3 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = utils ctf text
+SUBDIRS = utils text ctf
 # libctfcopytrace
 
 if ENABLE_DEBUG_INFO
index 63a4e302f842e88dd287fa1da58632c9a2a3aa58..2cc43c4c5ddfa53d9778ca216272906850e886c3 100644 (file)
@@ -1,10 +1,10 @@
-SUBDIRS = utils btr notif-iter metadata
+SUBDIRS = metadata btr notif-iter utils
 
 noinst_LTLIBRARIES = libbabeltrace-plugin-ctf-common.la
 libbabeltrace_plugin_ctf_common_la_SOURCES = print.h
 libbabeltrace_plugin_ctf_common_la_LIBADD =            \
-       $(builddir)/btr/libctf-btr.la                   \
        $(builddir)/metadata/libctf-parser.la           \
        $(builddir)/metadata/libctf-ast.la              \
+       $(builddir)/btr/libctf-btr.la                   \
        $(builddir)/notif-iter/libctf-notif-iter.la     \
        $(builddir)/utils/libctf-utils.la
index c255c76ce0ce4cfd64316d56f310c0907b0e6746..848e219198c961541cb8fb820be998f2aeba90c6 100644 (file)
@@ -42,6 +42,7 @@
 #include <glib.h>
 
 #include "btr.h"
+#include "../metadata/ctf-meta.h"
 
 #define DIV8(_x)                       ((_x) >> 3)
 #define BYTES_TO_BITS(_x)              ((_x) * 8)
@@ -59,12 +60,12 @@ struct stack_entry {
         *   * Sequence
         *   * Variant
         */
-       struct bt_field_type *base_type;
+       struct ctf_field_type *base_type;
 
        /* Length of base field (always 1 for variant types) */
        int64_t base_len;
 
-       /* Lndex of next field to read */
+       /* Index of next field to read */
        int64_t index;
 };
 
@@ -93,7 +94,7 @@ struct bt_btr {
        struct stack *stack;
 
        /* Current basic field type */
-       struct bt_field_type *cur_basic_field_type;
+       struct ctf_field_type *cur_basic_field_type;
 
        /* Current state */
        enum btr_state state;
@@ -105,13 +106,13 @@ struct bt_btr {
         * types for which the common boundary is not the boundary of
         * a byte cannot have different byte orders.
         *
-        * This is set to BT_BYTE_ORDER_UNKNOWN on reset and when
-        * the last basic field type was a string type.
+        * This is set to -1 on reset and when the last basic field type
+        * was a string type.
         */
-       enum bt_byte_order last_bo;
+       enum ctf_byte_order last_bo;
 
        /* Current byte order (copied to last_bo after a successful read) */
-       enum bt_byte_order cur_bo;
+       enum ctf_byte_order cur_bo;
 
        /* Stitch buffer infos */
        struct {
@@ -218,42 +219,8 @@ void stack_destroy(struct stack *stack)
        g_free(stack);
 }
 
-static inline
-int64_t get_compound_field_type_length(struct bt_btr *btr,
-               struct bt_field_type *field_type)
-{
-       int64_t length;
-
-       switch (bt_field_type_get_type_id(field_type)) {
-       case BT_FIELD_TYPE_ID_STRUCT:
-               length = (int64_t) bt_field_type_structure_get_field_count(
-                       field_type);
-               break;
-       case BT_FIELD_TYPE_ID_VARIANT:
-               /* Variant field types always "contain" a single type */
-               length = 1;
-               break;
-       case BT_FIELD_TYPE_ID_ARRAY:
-               length = bt_field_type_array_get_length(field_type);
-               break;
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               length = btr->user.cbs.query.get_sequence_length(field_type,
-                       btr->user.data);
-               break;
-       default:
-               BT_LOGW("Cannot get field type's field count: btr-addr=%p, "
-                       "ft-addr=%p, ft-id=%s",
-                       btr, field_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(field_type)));
-               length = BT_BTR_STATUS_ERROR;
-       }
-
-       return length;
-}
-
 static
-int stack_push(struct stack *stack, struct bt_field_type *base_type,
+int stack_push(struct stack *stack, struct ctf_field_type *base_type,
        size_t base_len)
 {
        struct stack_entry *entry;
@@ -261,10 +228,9 @@ int stack_push(struct stack *stack, struct bt_field_type *base_type,
        BT_ASSERT(stack);
        BT_ASSERT(base_type);
        BT_LOGV("Pushing field type on stack: stack-addr=%p, "
-               "ft-addr=%p, ft-id=%s, base-length=%zu, "
+               "ft-addr=%p, ft-id=%d, base-length=%zu, "
                "stack-size-before=%zu, stack-size-after=%zu",
-               stack, base_type, bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(base_type)),
+               stack, base_type, base_type->id,
                base_len, stack->size, stack->size + 1);
 
        if (stack->entries->len == stack->size) {
@@ -279,23 +245,59 @@ int stack_push(struct stack *stack, struct bt_field_type *base_type,
        return 0;
 }
 
+static inline
+int64_t get_compound_field_type_length(struct bt_btr *btr,
+               struct ctf_field_type *ft)
+{
+       int64_t length;
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               length = (int64_t) struct_ft->members->len;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               /* Variant field types always "contain" a single type */
+               length = 1;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       {
+               struct ctf_field_type_array *array_ft = (void *) ft;
+
+               length = (int64_t) array_ft->length;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+               length = btr->user.cbs.query.get_sequence_length(ft,
+                       btr->user.data);
+               break;
+       default:
+               abort();
+       }
+
+       return length;
+}
+
 static
-int stack_push_with_len(struct bt_btr *btr,
-               struct bt_field_type *base_type)
+int stack_push_with_len(struct bt_btr *btr, struct ctf_field_type *base_type)
 {
-       int ret = 0;
-       int64_t base_len = get_compound_field_type_length(btr, base_type);
+       int ret;
+       int64_t length = get_compound_field_type_length(btr, base_type);
 
-       if (base_len < 0) {
+       if (length < 0) {
                BT_LOGW("Cannot get compound field type's field count: "
-                       "btr-addr=%p, ft-addr=%p, ft-id=%s",
-                       btr, base_type, bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(base_type)));
+                       "btr-addr=%p, ft-addr=%p, ft-id=%d",
+                       btr, base_type, base_type->id);
                ret = BT_BTR_STATUS_ERROR;
                goto end;
        }
 
-       ret = stack_push(btr->stack, base_type, (size_t) base_len);
+       ret = stack_push(btr->stack, base_type, (size_t) length);
 
 end:
        return ret;
@@ -392,50 +394,6 @@ size_t buf_at_from_addr(struct bt_btr *btr)
        return btr->buf.offset + btr->buf.at;
 }
 
-static inline
-int get_basic_field_type_size(struct bt_btr *btr,
-               struct bt_field_type *field_type)
-{
-       int size;
-
-       switch (bt_field_type_get_type_id(field_type)) {
-       case BT_FIELD_TYPE_ID_INTEGER:
-               size = bt_field_type_integer_get_size(field_type);
-               break;
-       case BT_FIELD_TYPE_ID_FLOAT:
-       {
-               int exp_dig, mant_dig;
-
-               exp_dig =
-                       bt_field_type_floating_point_get_exponent_digits(
-                               field_type);
-               mant_dig =
-                       bt_field_type_floating_point_get_mantissa_digits(
-                               field_type);
-               BT_ASSERT(exp_dig >= 0);
-               BT_ASSERT(mant_dig >= 0);
-               size = exp_dig + mant_dig;
-               break;
-       }
-       case BT_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_field_type *int_type;
-
-               int_type =
-                       bt_field_type_enumeration_borrow_container_field_type(
-                               field_type);
-               BT_ASSERT(int_type);
-               size = get_basic_field_type_size(btr, int_type);
-               break;
-       }
-       default:
-               size = BT_BTR_STATUS_ERROR;
-               break;
-       }
-
-       return size;
-}
-
 static
 void stitch_reset(struct bt_btr *btr)
 {
@@ -487,53 +445,42 @@ void stitch_set_from_remaining_buf(struct bt_btr *btr)
 }
 
 static inline
-enum bt_btr_status read_unsigned_bitfield(const uint8_t *buf, size_t at,
-               int64_t field_size, enum bt_byte_order bo, uint64_t *v)
+void read_unsigned_bitfield(const uint8_t *buf, size_t at,
+               unsigned int field_size, enum ctf_byte_order bo,
+               uint64_t *v)
 {
-       enum bt_btr_status status = BT_BTR_STATUS_OK;
-
        switch (bo) {
-       case BT_BYTE_ORDER_BIG_ENDIAN:
-       case BT_BYTE_ORDER_NETWORK:
+       case CTF_BYTE_ORDER_BIG:
                bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
                break;
-       case BT_BYTE_ORDER_LITTLE_ENDIAN:
+       case CTF_BYTE_ORDER_LITTLE:
                bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
                break;
        default:
-               BT_LOGF("Cannot read unsigned bit array: unknown byte order: bo=%d", bo);
                abort();
        }
 
-       BT_LOGV("Read unsigned bit array: cur=%zu, size=%" PRId64 ", "
-               "bo=%s, val=%" PRIu64, at, field_size,
-               bt_common_byte_order_string(bo), *v);
-       return status;
+       BT_LOGV("Read unsigned bit array: cur=%zu, size=%u, "
+               "bo=%d, val=%" PRIu64, at, field_size, bo, *v);
 }
 
 static inline
-enum bt_btr_status read_signed_bitfield(const uint8_t *buf, size_t at,
-               int64_t field_size, enum bt_byte_order bo, int64_t *v)
+void read_signed_bitfield(const uint8_t *buf, size_t at,
+               unsigned int field_size, enum ctf_byte_order bo, int64_t *v)
 {
-       enum bt_btr_status status = BT_BTR_STATUS_OK;
-
        switch (bo) {
-       case BT_BYTE_ORDER_BIG_ENDIAN:
-       case BT_BYTE_ORDER_NETWORK:
+       case CTF_BYTE_ORDER_BIG:
                bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
                break;
-       case BT_BYTE_ORDER_LITTLE_ENDIAN:
+       case CTF_BYTE_ORDER_LITTLE:
                bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
                break;
        default:
-               BT_LOGF("Cannot read signed bit array: unknown byte order: bo=%d", bo);
                abort();
        }
 
-       BT_LOGV("Read signed bit array: cur=%zu, size=%" PRId64 ", "
-               "bo=%s, val=%" PRId64, at, field_size,
-               bt_common_byte_order_string(bo), *v);
-       return status;
+       BT_LOGV("Read signed bit array: cur=%zu, size=%u, "
+               "bo=%d, val=%" PRId64, at, field_size, bo, *v);
 }
 
 typedef enum bt_btr_status (* read_basic_and_call_cb_t)(struct bt_btr *,
@@ -541,7 +488,7 @@ typedef enum bt_btr_status (* read_basic_and_call_cb_t)(struct bt_btr *,
 
 static inline
 enum bt_btr_status validate_contiguous_bo(struct bt_btr *btr,
-               enum bt_byte_order next_bo)
+               enum ctf_byte_order next_bo)
 {
        enum bt_btr_status status = BT_BTR_STATUS_OK;
 
@@ -551,26 +498,24 @@ enum bt_btr_status validate_contiguous_bo(struct bt_btr *btr,
        }
 
        /* Always valid if last byte order is unknown */
-       if (btr->last_bo == BT_BYTE_ORDER_UNKNOWN) {
+       if (btr->last_bo == -1) {
                goto end;
        }
 
        /* Always valid if next byte order is unknown */
-       if (next_bo == BT_BYTE_ORDER_UNKNOWN) {
+       if (next_bo == -1) {
                goto end;
        }
 
        /* Make sure last byte order is compatible with the next byte order */
        switch (btr->last_bo) {
-       case BT_BYTE_ORDER_BIG_ENDIAN:
-       case BT_BYTE_ORDER_NETWORK:
-               if (next_bo != BT_BYTE_ORDER_BIG_ENDIAN &&
-                               next_bo != BT_BYTE_ORDER_NETWORK) {
+       case CTF_BYTE_ORDER_BIG:
+               if (next_bo != CTF_BYTE_ORDER_BIG) {
                        status = BT_BTR_STATUS_ERROR;
                }
                break;
-       case BT_BYTE_ORDER_LITTLE_ENDIAN:
-               if (next_bo != BT_BYTE_ORDER_LITTLE_ENDIAN) {
+       case CTF_BYTE_ORDER_LITTLE:
+               if (next_bo != CTF_BYTE_ORDER_LITTLE) {
                        status = BT_BTR_STATUS_ERROR;
                }
                break;
@@ -581,9 +526,8 @@ enum bt_btr_status validate_contiguous_bo(struct bt_btr *btr,
 end:
        if (status < 0) {
                BT_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
-                       "btr-addr=%p, last-bo=%s, next-bo=%s",
-                       btr, bt_common_byte_order_string(btr->last_bo),
-                       bt_common_byte_order_string(next_bo));
+                       "btr-addr=%p, last-bo=%d, next-bo=%d",
+                       btr, btr->last_bo, next_bo);
        }
 
        return status;
@@ -593,14 +537,15 @@ static
 enum bt_btr_status read_basic_float_and_call_cb(struct bt_btr *btr,
                const uint8_t *buf, size_t at)
 {
-       int ret;
        double dblval;
-       int64_t field_size;
-       enum bt_byte_order bo;
+       unsigned int field_size;
+       enum ctf_byte_order bo;
        enum bt_btr_status status = BT_BTR_STATUS_OK;
+       struct ctf_field_type_float *ft = (void *) btr->cur_basic_field_type;
 
-       field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
-       bo = bt_field_type_get_byte_order(btr->cur_basic_field_type);
+       BT_ASSERT(ft);
+       field_size = ft->base.size;
+       bo = ft->base.byte_order;
        btr->cur_bo = bo;
 
        switch (field_size) {
@@ -612,20 +557,7 @@ enum bt_btr_status read_basic_float_and_call_cb(struct bt_btr *btr,
                        float f;
                } f32;
 
-               ret = bt_field_type_floating_point_get_mantissa_digits(
-                       btr->cur_basic_field_type);
-               BT_ASSERT(ret == 24);
-               ret = bt_field_type_floating_point_get_exponent_digits(
-                       btr->cur_basic_field_type);
-               BT_ASSERT(ret == 8);
-               status = read_unsigned_bitfield(buf, at, field_size, bo, &v);
-               if (status != BT_BTR_STATUS_OK) {
-                       BT_LOGW("Cannot read unsigned 32-bit bit array for floating point number field: "
-                               "btr-addr=%p, status=%s",
-                               btr, bt_btr_status_string(status));
-                       goto end;
-               }
-
+               read_unsigned_bitfield(buf, at, field_size, bo, &v);
                f32.u = (uint32_t) v;
                dblval = (double) f32.f;
                break;
@@ -637,30 +569,13 @@ enum bt_btr_status read_basic_float_and_call_cb(struct bt_btr *btr,
                        double d;
                } f64;
 
-               ret = bt_field_type_floating_point_get_mantissa_digits(
-                       btr->cur_basic_field_type);
-               BT_ASSERT(ret == 53);
-               ret = bt_field_type_floating_point_get_exponent_digits(
-                       btr->cur_basic_field_type);
-               BT_ASSERT(ret == 11);
-               status = read_unsigned_bitfield(buf, at, field_size, bo,
-                       &f64.u);
-               if (status != BT_BTR_STATUS_OK) {
-                       BT_LOGW("Cannot read unsigned 64-bit bit array for floating point number field: "
-                               "btr-addr=%p, status=%s",
-                               btr, bt_btr_status_string(status));
-                       goto end;
-               }
-
+               read_unsigned_bitfield(buf, at, field_size, bo, &f64.u);
                dblval = f64.d;
                break;
        }
        default:
                /* Only 32-bit and 64-bit fields are supported currently */
-               BT_LOGW("Only 32-bit and 64-bit floating point number fields are supported: "
-                       "btr-addr=%p", btr);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
+               abort();
        }
 
        BT_LOGV("Read floating point number value: btr=%p, cur=%zu, val=%f",
@@ -678,32 +593,20 @@ enum bt_btr_status read_basic_float_and_call_cb(struct bt_btr *btr,
                }
        }
 
-end:
        return status;
 }
 
 static inline
-enum bt_btr_status read_basic_int_and_call(struct bt_btr *btr,
-               const uint8_t *buf, size_t at,
-               struct bt_field_type *int_type,
-               struct bt_field_type *orig_type)
+enum bt_btr_status read_basic_int_and_call_cb(struct bt_btr *btr,
+               const uint8_t *buf, size_t at)
 {
-       bt_bool signd;
-       int64_t field_size;
-       enum bt_byte_order bo;
+       unsigned int field_size;
+       enum ctf_byte_order bo;
        enum bt_btr_status status = BT_BTR_STATUS_OK;
+       struct ctf_field_type_int *ft = (void *) btr->cur_basic_field_type;
 
-       signd = bt_field_type_integer_is_signed(int_type);
-       field_size = get_basic_field_type_size(btr, int_type);
-       if (field_size < 1) {
-               BT_LOGW("Cannot get integer field type's size: "
-                       "btr=%p, at=%zu, ft-addr=%p",
-                       btr, at, int_type);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
-
-       bo = bt_field_type_get_byte_order(int_type);
+       field_size = ft->base.size;
+       bo = ft->base.byte_order;
 
        /*
         * Update current byte order now because we could be reading
@@ -712,16 +615,10 @@ enum bt_btr_status read_basic_int_and_call(struct bt_btr *btr,
         */
        btr->cur_bo = bo;
 
-       if (signd) {
+       if (ft->is_signed) {
                int64_t v;
 
-               status = read_signed_bitfield(buf, at, field_size, bo, &v);
-               if (status != BT_BTR_STATUS_OK) {
-                       BT_LOGW("Cannot read signed bit array for signed integer field: "
-                               "btr-addr=%p, status=%s",
-                               btr, bt_btr_status_string(status));
-                       goto end;
-               }
+               read_signed_bitfield(buf, at, field_size, bo, &v);
 
                if (btr->user.cbs.types.signed_int) {
                        BT_LOGV("Calling user function (signed integer).");
@@ -738,13 +635,7 @@ enum bt_btr_status read_basic_int_and_call(struct bt_btr *btr,
        } else {
                uint64_t v;
 
-               status = read_unsigned_bitfield(buf, at, field_size, bo, &v);
-               if (status != BT_BTR_STATUS_OK) {
-                       BT_LOGW("Cannot read unsigned bit array for unsigned integer field: "
-                               "btr-addr=%p, status=%s",
-                               btr, bt_btr_status_string(status));
-                       goto end;
-               }
+               read_unsigned_bitfield(buf, at, field_size, bo, &v);
 
                if (btr->user.cbs.types.unsigned_int) {
                        BT_LOGV("Calling user function (unsigned integer).");
@@ -760,41 +651,18 @@ enum bt_btr_status read_basic_int_and_call(struct bt_btr *btr,
                }
        }
 
-end:
-       return status;
-}
-
-static
-enum bt_btr_status read_basic_int_and_call_cb(struct bt_btr *btr,
-               const uint8_t *buf, size_t at)
-{
-       return read_basic_int_and_call(btr, buf, at, btr->cur_basic_field_type,
-               btr->cur_basic_field_type);
-}
-
-static
-enum bt_btr_status read_basic_enum_and_call_cb(struct bt_btr *btr,
-               const uint8_t *buf, size_t at)
-{
-       struct bt_field_type *int_field_type;
-       enum bt_btr_status status = BT_BTR_STATUS_OK;
-
-       int_field_type = bt_field_type_enumeration_borrow_container_field_type(
-               btr->cur_basic_field_type);
-       BT_ASSERT(int_field_type);
-       status = read_basic_int_and_call(btr, buf, at,
-               int_field_type, btr->cur_basic_field_type);
        return status;
 }
 
 static inline
-enum bt_btr_status read_basic_type_and_call_continue(struct bt_btr *btr,
+enum bt_btr_status read_bit_array_type_and_call_continue(struct bt_btr *btr,
                read_basic_and_call_cb_t read_basic_and_call_cb)
 {
        size_t available;
-       int64_t field_size;
-       int64_t needed_bits;
+       size_t needed_bits;
        enum bt_btr_status status = BT_BTR_STATUS_OK;
+       struct ctf_field_type_bit_array *ft =
+               (void *) btr->cur_basic_field_type;
 
        if (!at_least_one_bit_left(btr)) {
                BT_LOGV("Reached end of data: btr-addr=%p", btr);
@@ -802,21 +670,12 @@ enum bt_btr_status read_basic_type_and_call_continue(struct bt_btr *btr,
                goto end;
        }
 
-       field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
-       if (field_size < 1) {
-               BT_LOGW("Cannot get basic field type's size: "
-                       "btr-addr=%p, ft-addr=%p",
-                       btr, btr->cur_basic_field_type);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
-
        available = available_bits(btr);
-       needed_bits = field_size - btr->stitch.at;
+       needed_bits = ft->size - btr->stitch.at;
        BT_LOGV("Continuing basic field decoding: "
-               "btr-addr=%p, field-size=%" PRId64 ", needed-size=%" PRId64 ", "
+               "btr-addr=%p, field-size=%u, needed-size=%" PRId64 ", "
                "available-size=%zu",
-               btr, field_size, needed_bits, available);
+               btr, ft->size, needed_bits, available);
        if (needed_bits <= available) {
                /* We have all the bits; append to stitch, then decode */
                stitch_append_from_buf(btr, needed_bits);
@@ -852,13 +711,13 @@ end:
 }
 
 static inline
-enum bt_btr_status read_basic_type_and_call_begin(struct bt_btr *btr,
+enum bt_btr_status read_bit_array_type_and_call_begin(struct bt_btr *btr,
                read_basic_and_call_cb_t read_basic_and_call_cb)
 {
        size_t available;
-       int64_t field_size;
-       enum bt_byte_order bo;
        enum bt_btr_status status = BT_BTR_STATUS_OK;
+       struct ctf_field_type_bit_array *ft =
+               (void *) btr->cur_basic_field_type;
 
        if (!at_least_one_bit_left(btr)) {
                BT_LOGV("Reached end of data: btr-addr=%p", btr);
@@ -866,17 +725,7 @@ enum bt_btr_status read_basic_type_and_call_begin(struct bt_btr *btr,
                goto end;
        }
 
-       field_size = get_basic_field_type_size(btr, btr->cur_basic_field_type);
-       if (field_size < 1) {
-               BT_LOGW("Cannot get basic field type's size: "
-                       "btr-addr=%p, ft-addr=%p",
-                       btr, btr->cur_basic_field_type);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
-
-       bo = bt_field_type_get_byte_order(btr->cur_basic_field_type);
-       status = validate_contiguous_bo(btr, bo);
+       status = validate_contiguous_bo(btr, ft->byte_order);
        if (status != BT_BTR_STATUS_OK) {
                /* validate_contiguous_bo() logs errors */
                goto end;
@@ -884,7 +733,7 @@ enum bt_btr_status read_basic_type_and_call_begin(struct bt_btr *btr,
 
        available = available_bits(btr);
 
-       if (field_size <= available) {
+       if (ft->size <= available) {
                /* We have all the bits; decode and set now */
                BT_ASSERT(btr->buf.addr);
                status = read_basic_and_call_cb(btr, btr->buf.addr,
@@ -897,7 +746,7 @@ enum bt_btr_status read_basic_type_and_call_begin(struct bt_btr *btr,
                        goto end;
                }
 
-               consume_bits(btr, field_size);
+               consume_bits(btr, ft->size);
 
                if (stack_empty(btr->stack)) {
                        /* Root is a basic type */
@@ -926,14 +775,14 @@ static inline
 enum bt_btr_status read_basic_int_type_and_call_begin(
                struct bt_btr *btr)
 {
-       return read_basic_type_and_call_begin(btr, read_basic_int_and_call_cb);
+       return read_bit_array_type_and_call_begin(btr, read_basic_int_and_call_cb);
 }
 
 static inline
 enum bt_btr_status read_basic_int_type_and_call_continue(
                struct bt_btr *btr)
 {
-       return read_basic_type_and_call_continue(btr,
+       return read_bit_array_type_and_call_continue(btr,
                read_basic_int_and_call_cb);
 }
 
@@ -941,7 +790,7 @@ static inline
 enum bt_btr_status read_basic_float_type_and_call_begin(
                struct bt_btr *btr)
 {
-       return read_basic_type_and_call_begin(btr,
+       return read_bit_array_type_and_call_begin(btr,
                read_basic_float_and_call_cb);
 }
 
@@ -949,26 +798,10 @@ static inline
 enum bt_btr_status read_basic_float_type_and_call_continue(
                struct bt_btr *btr)
 {
-       return read_basic_type_and_call_continue(btr,
+       return read_bit_array_type_and_call_continue(btr,
                read_basic_float_and_call_cb);
 }
 
-static inline
-enum bt_btr_status read_basic_enum_type_and_call_begin(
-               struct bt_btr *btr)
-{
-       return read_basic_type_and_call_begin(btr,
-               read_basic_enum_and_call_cb);
-}
-
-static inline
-enum bt_btr_status read_basic_enum_type_and_call_continue(
-               struct bt_btr *btr)
-{
-       return read_basic_type_and_call_continue(btr,
-               read_basic_enum_and_call_cb);
-}
-
 static inline
 enum bt_btr_status read_basic_string_type_and_call(
                struct bt_btr *btr, bool begin)
@@ -1084,26 +917,18 @@ enum bt_btr_status read_basic_begin_state(struct bt_btr *btr)
 
        BT_ASSERT(btr->cur_basic_field_type);
 
-       switch (bt_field_type_get_type_id(btr->cur_basic_field_type)) {
-       case BT_FIELD_TYPE_ID_INTEGER:
+       switch (btr->cur_basic_field_type->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+       case CTF_FIELD_TYPE_ID_ENUM:
                status = read_basic_int_type_and_call_begin(btr);
                break;
-       case BT_FIELD_TYPE_ID_FLOAT:
+       case CTF_FIELD_TYPE_ID_FLOAT:
                status = read_basic_float_type_and_call_begin(btr);
                break;
-       case BT_FIELD_TYPE_ID_ENUM:
-               status = read_basic_enum_type_and_call_begin(btr);
-               break;
-       case BT_FIELD_TYPE_ID_STRING:
+       case CTF_FIELD_TYPE_ID_STRING:
                status = read_basic_string_type_and_call(btr, true);
                break;
        default:
-               BT_LOGF("Unknown basic field type ID: "
-                       "btr-addr=%p, ft-addr=%p, ft-id=%s",
-                       btr, btr->cur_basic_field_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(
-                                       btr->cur_basic_field_type)));
                abort();
        }
 
@@ -1117,26 +942,18 @@ enum bt_btr_status read_basic_continue_state(struct bt_btr *btr)
 
        BT_ASSERT(btr->cur_basic_field_type);
 
-       switch (bt_field_type_get_type_id(btr->cur_basic_field_type)) {
-       case BT_FIELD_TYPE_ID_INTEGER:
+       switch (btr->cur_basic_field_type->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+       case CTF_FIELD_TYPE_ID_ENUM:
                status = read_basic_int_type_and_call_continue(btr);
                break;
-       case BT_FIELD_TYPE_ID_FLOAT:
+       case CTF_FIELD_TYPE_ID_FLOAT:
                status = read_basic_float_type_and_call_continue(btr);
                break;
-       case BT_FIELD_TYPE_ID_ENUM:
-               status = read_basic_enum_type_and_call_continue(btr);
-               break;
-       case BT_FIELD_TYPE_ID_STRING:
+       case CTF_FIELD_TYPE_ID_STRING:
                status = read_basic_string_type_and_call(btr, false);
                break;
        default:
-               BT_LOGF("Unknown basic field type ID: "
-                       "btr-addr=%p, ft-addr=%p, ft-id=%s",
-                       btr, btr->cur_basic_field_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(
-                                       btr->cur_basic_field_type)));
                abort();
        }
 
@@ -1154,34 +971,23 @@ size_t bits_to_skip_to_align_to(struct bt_btr *btr, size_t align)
 
 static inline
 enum bt_btr_status align_type_state(struct bt_btr *btr,
-               struct bt_field_type *field_type, enum btr_state next_state)
+               struct ctf_field_type *field_type, enum btr_state next_state)
 {
-       int field_alignment;
+       unsigned int field_alignment;
        size_t skip_bits;
        enum bt_btr_status status = BT_BTR_STATUS_OK;
 
        /* Get field's alignment */
-       field_alignment = bt_field_type_get_alignment(field_type);
-       if (field_alignment < 0) {
-               BT_LOGW("Cannot get field type's alignment: "
-                       "btr-addr=%p, ft-addr=%p, ft-id=%s",
-                       btr, field_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(field_type)));
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
+       field_alignment = field_type->alignment;
 
        /*
         * 0 means "undefined" for variants; what we really want is 1
         * (always aligned)
         */
-       if (field_alignment == 0) {
-               field_alignment = 1;
-       }
+       BT_ASSERT(field_alignment >= 1);
 
        /* Compute how many bits we need to skip */
-       skip_bits = bits_to_skip_to_align_to(btr, field_alignment);
+       skip_bits = bits_to_skip_to_align_to(btr, (size_t) field_alignment);
 
        /* Nothing to skip? aligned */
        if (skip_bits == 0) {
@@ -1214,21 +1020,12 @@ end:
        return status;
 }
 
-static inline
-bool is_compound_type(struct bt_field_type *field_type)
-{
-       enum bt_field_type_id id = bt_field_type_get_type_id(field_type);
-
-       return id == BT_FIELD_TYPE_ID_STRUCT || id == BT_FIELD_TYPE_ID_ARRAY ||
-               id == BT_FIELD_TYPE_ID_SEQUENCE || id == BT_FIELD_TYPE_ID_VARIANT;
-}
-
 static inline
 enum bt_btr_status next_field_state(struct bt_btr *btr)
 {
        int ret;
        struct stack_entry *top;
-       struct bt_field_type *next_field_type = NULL;
+       struct ctf_field_type *next_field_type = NULL;
        enum bt_btr_status status = BT_BTR_STATUS_OK;
 
        if (stack_empty(btr->stack)) {
@@ -1265,29 +1062,24 @@ enum bt_btr_status next_field_state(struct bt_btr *btr)
        }
 
        /* Get next field's type */
-       switch (bt_field_type_get_type_id(top->base_type)) {
-       case BT_FIELD_TYPE_ID_STRUCT:
-               ret = bt_field_type_structure_borrow_field_by_index(
-                       top->base_type, NULL, &next_field_type,
-                       top->index);
-               if (ret) {
-                       next_field_type = NULL;
-               }
-               break;
-       case BT_FIELD_TYPE_ID_ARRAY:
-               next_field_type =
-                       bt_field_type_array_borrow_element_field_type(
-                               top->base_type);
+       switch (top->base_type->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+               next_field_type = ctf_field_type_struct_borrow_member_by_index(
+                       (void *) top->base_type, (uint64_t) top->index)->ft;
                break;
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               next_field_type =
-                       bt_field_type_sequence_borrow_element_field_type(
-                               top->base_type);
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_array_base *array_ft =
+                       (void *) top->base_type;
+
+               next_field_type = array_ft->elem_ft;
                break;
-       case BT_FIELD_TYPE_ID_VARIANT:
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
                /* Variant types are dynamic: query the user, he should know! */
                next_field_type =
-                       btr->user.cbs.query.borrow_variant_field_type(
+                       btr->user.cbs.query.borrow_variant_selected_field_type(
                                top->base_type, btr->user.data);
                break;
        default:
@@ -1296,17 +1088,14 @@ enum bt_btr_status next_field_state(struct bt_btr *btr)
 
        if (!next_field_type) {
                BT_LOGW("Cannot get the field type of the next field: "
-                       "btr-addr=%p, base-ft-addr=%p, base-ft-id=%s, "
+                       "btr-addr=%p, base-ft-addr=%p, base-ft-id=%d, "
                        "index=%" PRId64,
-                       btr, top->base_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(top->base_type)),
-                       top->index);
+                       btr, top->base_type, top->base_type->id, top->index);
                status = BT_BTR_STATUS_ERROR;
                goto end;
        }
 
-       if (is_compound_type(next_field_type)) {
+       if (next_field_type->is_compound) {
                if (btr->user.cbs.types.compound_begin) {
                        BT_LOGV("Calling user function (compound, begin).");
                        status = btr->user.cbs.types.compound_begin(
@@ -1380,6 +1169,7 @@ enum bt_btr_status handle_state(struct bt_btr *btr)
        return status;
 }
 
+BT_HIDDEN
 struct bt_btr *bt_btr_create(struct bt_btr_cbs cbs, void *data)
 {
        struct bt_btr *btr;
@@ -1408,6 +1198,7 @@ end:
        return btr;
 }
 
+BT_HIDDEN
 void bt_btr_destroy(struct bt_btr *btr)
 {
        if (btr->stack) {
@@ -1425,7 +1216,7 @@ void reset(struct bt_btr *btr)
        stack_clear(btr->stack);
        stitch_reset(btr);
        btr->buf.addr = NULL;
-       btr->last_bo = BT_BYTE_ORDER_UNKNOWN;
+       btr->last_bo = -1;
 }
 
 static
@@ -1438,8 +1229,9 @@ void update_packet_offset(struct bt_btr *btr)
        btr->buf.packet_offset += btr->buf.at;
 }
 
+BT_HIDDEN
 size_t bt_btr_start(struct bt_btr *btr,
-       struct bt_field_type *type, const uint8_t *buf,
+       struct ctf_field_type *type, const uint8_t *buf,
        size_t offset, size_t packet_offset, size_t sz,
        enum bt_btr_status *status)
 {
@@ -1460,7 +1252,7 @@ size_t bt_btr_start(struct bt_btr *btr,
                btr, type, buf, sz, offset, packet_offset);
 
        /* Set root type */
-       if (is_compound_type(type)) {
+       if (type->is_compound) {
                /* Compound type: push on visit stack */
                int stack_ret;
 
@@ -1509,9 +1301,9 @@ end:
        return btr->buf.at;
 }
 
-size_t bt_btr_continue(struct bt_btr *btr,
-       const uint8_t *buf, size_t sz,
-       enum bt_btr_status *status)
+BT_HIDDEN
+size_t bt_btr_continue(struct bt_btr *btr, const uint8_t *buf, size_t sz,
+               enum bt_btr_status *status)
 {
        BT_ASSERT(btr);
        BT_ASSERT(buf);
@@ -1541,3 +1333,12 @@ size_t bt_btr_continue(struct bt_btr *btr,
        update_packet_offset(btr);
        return btr->buf.at;
 }
+
+BT_HIDDEN
+void bt_btr_set_unsigned_int_cb(struct bt_btr *btr,
+               bt_btr_unsigned_int_cb_func cb)
+{
+       BT_ASSERT(btr);
+       BT_ASSERT(cb);
+       btr->user.cbs.types.unsigned_int = cb;
+}
index dbfef72a69a79b6f81023d8a9942edd5544b0d14..c87eda014fc2af54a94cfcaabeeb0e5e4deef4ea 100644 (file)
@@ -32,6 +32,8 @@
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/babeltrace-internal.h>
 
+#include "../metadata/ctf-meta.h"
+
 /**
  * @file ctf-btr.h
  *
@@ -78,6 +80,9 @@ enum bt_btr_status {
 /** Type reader. */
 struct bt_btr;
 
+typedef enum bt_btr_status (* bt_btr_unsigned_int_cb_func)(uint64_t,
+               struct ctf_field_type *, void *);
+
 /*
  * Type reader user callback functions.
  */
@@ -90,15 +95,13 @@ struct bt_btr_cbs {
         * a compound type begins/ends, or when a basic type is
         * completely decoded (along with its value).
         *
-        * Each function also receives the CTF IR field type associated
+        * Each function also receives the CTF field type associated
         * with the call, and user data (registered to the type reader
-        * calling them). This field type is a weak reference; the
-        * callback function must use bt_field_type_get() to keep
-        * its own reference of it.
+        * calling them).
         *
-        * Actual CTF IR fields are \em not created here; this would be
-        * the responsibility of a type reader's user (the provider of
-        * those callback functions).
+        * Actual trace IR fields are \em not created here; this would
+        * be the responsibility of a type reader's user (the provider
+        * of those callback functions).
         *
         * All the type callback functions return one of the following
         * values:
@@ -119,14 +122,13 @@ struct bt_btr_cbs {
                 * indicate this).
                 *
                 * @param value         Signed integer value
-                * @param type          Integer or enumeration type (weak
-                *                      reference)
+                * @param type          Integer or enumeration type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
                enum bt_btr_status (* signed_int)(int64_t value,
-                               struct bt_field_type *type, void *data);
+                               struct ctf_field_type *type, void *data);
 
                /**
                 * Called when an unsigned integer type is completely
@@ -135,28 +137,25 @@ struct bt_btr_cbs {
                 * indicate this).
                 *
                 * @param value         Unsigned integer value
-                * @param type          Integer or enumeration type (weak
-                *                      reference)
+                * @param type          Integer or enumeration type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
-               enum bt_btr_status (* unsigned_int)(uint64_t value,
-                               struct bt_field_type *type, void *data);
+               bt_btr_unsigned_int_cb_func unsigned_int;
 
                /**
                 * Called when a floating point number type is
                 * completely decoded.
                 *
                 * @param value         Floating point number value
-                * @param type          Floating point number type (weak
-                *                      reference)
+                * @param type          Floating point number type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
                enum bt_btr_status (* floating_point)(double value,
-                               struct bt_field_type *type, void *data);
+                               struct ctf_field_type *type, void *data);
 
                /**
                 * Called when a string type begins.
@@ -166,13 +165,13 @@ struct bt_btr_cbs {
                 * them providing one substring of the complete string
                 * type's value.
                 *
-                * @param type          Beginning string type (weak reference)
+                * @param type          Beginning string type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
                enum bt_btr_status (* string_begin)(
-                               struct bt_field_type *type, void *data);
+                               struct ctf_field_type *type, void *data);
 
                /**
                 * Called when a string type's substring is decoded
@@ -181,25 +180,25 @@ struct bt_btr_cbs {
                 *
                 * @param value         String value (\em not null-terminated)
                 * @param len           String value length
-                * @param type          String type (weak reference)
+                * @param type          String type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
                enum bt_btr_status (* string)(const char *value,
-                               size_t len, struct bt_field_type *type,
+                               size_t len, struct ctf_field_type *type,
                                void *data);
 
                /**
                 * Called when a string type ends.
                 *
-                * @param type          Ending string type (weak reference)
+                * @param type          Ending string type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
                enum bt_btr_status (* string_end)(
-                               struct bt_field_type *type, void *data);
+                               struct ctf_field_type *type, void *data);
 
                /**
                 * Called when a compound type begins.
@@ -215,24 +214,24 @@ struct bt_btr_cbs {
                 * call indicates the selected type of this variant
                 * type.
                 *
-                * @param type          Beginning compound type (weak reference)
+                * @param type          Beginning compound type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
                enum bt_btr_status (* compound_begin)(
-                               struct bt_field_type *type, void *data);
+                               struct ctf_field_type *type, void *data);
 
                /**
                 * Called when a compound type ends.
                 *
-                * @param type          Ending compound type (weak reference)
+                * @param type          Ending compound type
                 * @param data          User data
                 * @returns             #BT_BTR_STATUS_OK or
                 *                      #BT_BTR_STATUS_ERROR
                 */
                enum bt_btr_status (* compound_end)(
-                               struct bt_field_type *type, void *data);
+                               struct ctf_field_type *type, void *data);
        } types;
 
        /**
@@ -248,25 +247,25 @@ struct bt_btr_cbs {
                 * Called to query the current length of a given sequence
                 * type.
                 *
-                * @param type          Sequence type (weak reference)
+                * @param type          Sequence type
                 * @param data          User data
                 * @returns             Sequence length or
                 *                      #BT_BTR_STATUS_ERROR on error
                 */
-               int64_t (* get_sequence_length)(struct bt_field_type *type,
+               int64_t (* get_sequence_length)(struct ctf_field_type *type,
                                void *data);
 
                /**
                 * Called to query the current selected type of a given
                 * variant type.
                 *
-                * @param type          Variant type (weak reference)
+                * @param type          Variant type
                 * @param data          User data
                 * @returns             Current selected type (owned by
                 *                      this) or \c NULL on error
                 */
-               struct bt_field_type * (* borrow_variant_field_type)(
-                               struct bt_field_type *type, void *data);
+               struct ctf_field_type * (* borrow_variant_selected_field_type)(
+                               struct ctf_field_type *type, void *data);
        } query;
 };
 
@@ -277,6 +276,7 @@ struct bt_btr_cbs {
  * @param data         User data (passed to user callback functions)
  * @returns            New binary type reader on success, or \c NULL on error
  */
+BT_HIDDEN
 struct bt_btr *bt_btr_create(struct bt_btr_cbs cbs, void *data);
 
 /**
@@ -284,6 +284,7 @@ struct bt_btr *bt_btr_create(struct bt_btr_cbs cbs, void *data);
  *
  * @param btr  Binary type reader
  */
+BT_HIDDEN
 void bt_btr_destroy(struct bt_btr *btr);
 
 /**
@@ -308,7 +309,7 @@ void bt_btr_destroy(struct bt_btr *btr);
  * be called next, \em not bt_btr_decode().
  *
  * @param btr                  Binary type reader
- * @param type                 Type to decode (weak reference)
+ * @param type                 Type to decode
  * @param buf                  Buffer
  * @param offset               Offset of first bit from \p buf (bits)
  * @param packet_offset                Offset of \p offset within the CTF
@@ -317,8 +318,9 @@ void bt_btr_destroy(struct bt_btr *btr);
  * @param status               Returned status (see description above)
  * @returns                    Number of consumed bits
  */
+BT_HIDDEN
 size_t bt_btr_start(struct bt_btr *btr,
-               struct bt_field_type *type, const uint8_t *buf,
+               struct ctf_field_type *type, const uint8_t *buf,
                size_t offset, size_t packet_offset, size_t sz,
                enum bt_btr_status *status);
 
@@ -345,10 +347,15 @@ size_t bt_btr_start(struct bt_btr *btr,
  * @param status       Returned status (see description above)
  * @returns            Number of consumed bits
  */
+BT_HIDDEN
 size_t bt_btr_continue(struct bt_btr *btr,
                const uint8_t *buf, size_t sz,
                enum bt_btr_status *status);
 
+BT_HIDDEN
+void bt_btr_set_unsigned_int_cb(struct bt_btr *btr,
+               bt_btr_unsigned_int_cb_func cb);
+
 static inline
 const char *bt_btr_status_string(enum bt_btr_status status)
 {
index 7eaae453e12494d1ff3d61c1485ff15713a77408..c1f89c351e31a42edc01a88297410eafad071c6a 100644 (file)
@@ -24,7 +24,17 @@ libctf_ast_la_SOURCES = \
        decoder.c \
        decoder.h \
        logging.c \
-       logging.h
+       logging.h \
+       ctf-meta.h \
+       ctf-meta-visitors.h \
+       ctf-meta-validate.c \
+       ctf-meta-update-meanings.c \
+       ctf-meta-update-in-ir.c \
+       ctf-meta-update-default-clock-classes.c \
+       ctf-meta-update-text-array-sequence.c \
+       ctf-meta-update-value-storing-indexes.c \
+       ctf-meta-translate.c \
+       ctf-meta-resolve.c
 
 libctf_ast_la_LIBADD = $(UUID_LIBS)
 
index 9e697bdae1cdf906f314996a907d1b79dcabe005..e06d6e69d62b72f3f4e6a1f3f2633fc4153cde5d 100644 (file)
@@ -25,6 +25,7 @@
 #include <babeltrace/babeltrace-internal.h>
 
 #include "decoder.h"
+#include "ctf-meta.h"
 
 // the parameter name (of the reentrant 'yyparse' function)
 // data is a pointer to a 'SParserParam' structure
@@ -317,7 +318,11 @@ struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(
 void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor);
 
 BT_HIDDEN
-struct bt_trace *ctf_visitor_generate_ir_get_trace(
+struct bt_trace *ctf_visitor_generate_ir_get_ir_trace(
+               struct ctf_visitor_generate_ir *visitor);
+
+BT_HIDDEN
+struct ctf_trace_class *ctf_visitor_generate_ir_borrow_ctf_trace_class(
                struct ctf_visitor_generate_ir *visitor);
 
 BT_HIDDEN
diff --git a/plugins/ctf/common/metadata/ctf-meta-resolve.c b/plugins/ctf/common/metadata/ctf-meta-resolve.c
new file mode 100644 (file)
index 0000000..d41edef
--- /dev/null
@@ -0,0 +1,1316 @@
+/*
+ * Copyright 2016-2018 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-RESOLVE"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <babeltrace/common-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include "ctf-meta-visitors.h"
+
+typedef GPtrArray field_type_stack;
+
+/*
+ * A stack frame.
+ *
+ * `type` contains a compound field type (structure, variant, array,
+ * or sequence) and `index` indicates the index of the field type in
+ * the upper frame (-1 for array and sequence field types). `name`
+ * indicates the name of the field type in the upper frame (empty
+ * string for array and sequence field types).
+ */
+struct field_type_stack_frame {
+       struct ctf_field_type *ft;
+       int64_t index;
+};
+
+/*
+ * The current context of the resolving engine.
+ */
+struct resolve_context {
+       struct ctf_trace_class *tc;
+       struct ctf_stream_class *sc;
+       struct ctf_event_class *ec;
+
+       struct {
+               struct ctf_field_type *packet_header;
+               struct ctf_field_type *packet_context;
+               struct ctf_field_type *event_header;
+               struct ctf_field_type *event_common_context;
+               struct ctf_field_type *event_spec_context;
+               struct ctf_field_type *event_payload;
+       } scopes;
+
+       /* Root scope being visited */
+       enum bt_scope root_scope;
+       field_type_stack *field_type_stack;
+       struct ctf_field_type *cur_ft;
+};
+
+/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
+static const char * const absolute_path_prefixes[] = {
+       [BT_SCOPE_PACKET_HEADER]                = "trace.packet.header.",
+       [BT_SCOPE_PACKET_CONTEXT]               = "stream.packet.context.",
+       [BT_SCOPE_EVENT_HEADER]                 = "stream.event.header.",
+       [BT_SCOPE_EVENT_COMMON_CONTEXT]         = "stream.event.context.",
+       [BT_SCOPE_EVENT_SPECIFIC_CONTEXT]       = "event.context.",
+       [BT_SCOPE_EVENT_PAYLOAD]                = "event.fields.",
+};
+
+/* Number of path tokens used for the absolute prefixes */
+static const uint64_t absolute_path_prefix_ptoken_counts[] = {
+       [BT_SCOPE_PACKET_HEADER]                = 3,
+       [BT_SCOPE_PACKET_CONTEXT]               = 3,
+       [BT_SCOPE_EVENT_HEADER]                 = 3,
+       [BT_SCOPE_EVENT_COMMON_CONTEXT]         = 3,
+       [BT_SCOPE_EVENT_SPECIFIC_CONTEXT]       = 2,
+       [BT_SCOPE_EVENT_PAYLOAD]                = 2,
+};
+
+static
+void destroy_field_type_stack_frame(struct field_type_stack_frame *frame)
+{
+       if (!frame) {
+               return;
+       }
+
+       g_free(frame);
+}
+
+/*
+ * Creates a type stack.
+ */
+static
+field_type_stack *field_type_stack_create(void)
+{
+       return g_ptr_array_new_with_free_func(
+               (GDestroyNotify) destroy_field_type_stack_frame);
+}
+
+/*
+ * Destroys a type stack.
+ */
+static
+void field_type_stack_destroy(field_type_stack *stack)
+{
+       if (stack) {
+               g_ptr_array_free(stack, TRUE);
+       }
+}
+
+/*
+ * Pushes a field type onto a type stack.
+ */
+static
+int field_type_stack_push(field_type_stack *stack, struct ctf_field_type *ft)
+{
+       int ret = 0;
+       struct field_type_stack_frame *frame = NULL;
+
+       if (!stack || !ft) {
+               BT_LOGE("Invalid parameter: stack or type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       frame = g_new0(struct field_type_stack_frame, 1);
+       if (!frame) {
+               BT_LOGE_STR("Failed to allocate one field type stack frame.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Pushing field type on context's stack: "
+               "ft-addr=%p, stack-size-before=%u", ft, stack->len);
+       frame->ft = ft;
+       g_ptr_array_add(stack, frame);
+
+end:
+       return ret;
+}
+
+/*
+ * Checks whether or not `stack` is empty.
+ */
+static
+bool field_type_stack_empty(field_type_stack *stack)
+{
+       return stack->len == 0;
+}
+
+/*
+ * Returns the number of frames in `stack`.
+ */
+static
+size_t field_type_stack_size(field_type_stack *stack)
+{
+       return stack->len;
+}
+
+/*
+ * Returns the top frame of `stack`.
+ */
+static
+struct field_type_stack_frame *field_type_stack_peek(field_type_stack *stack)
+{
+       struct field_type_stack_frame *entry = NULL;
+
+       if (!stack || field_type_stack_empty(stack)) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, stack->len - 1);
+end:
+       return entry;
+}
+
+/*
+ * Returns the frame at index `index` in `stack`.
+ */
+static
+struct field_type_stack_frame *field_type_stack_at(field_type_stack *stack,
+               size_t index)
+{
+       struct field_type_stack_frame *entry = NULL;
+
+       if (!stack || index >= stack->len) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, index);
+
+end:
+       return entry;
+}
+
+/*
+ * Removes the top frame of `stack`.
+ */
+static
+void field_type_stack_pop(field_type_stack *stack)
+{
+       if (!field_type_stack_empty(stack)) {
+               /*
+                * This will call the frame's destructor and free it, as
+                * well as put its contained field type.
+                */
+               BT_LOGV("Popping context's stack: stack-size-before=%u",
+                       stack->len);
+               g_ptr_array_set_size(stack, stack->len - 1);
+       }
+}
+
+/*
+ * Returns the scope field type of `scope` in the context `ctx`.
+ */
+static
+struct ctf_field_type *borrow_type_from_ctx(struct resolve_context *ctx,
+               enum bt_scope scope)
+{
+       switch (scope) {
+       case BT_SCOPE_PACKET_HEADER:
+               return ctx->scopes.packet_header;
+       case BT_SCOPE_PACKET_CONTEXT:
+               return ctx->scopes.packet_context;
+       case BT_SCOPE_EVENT_HEADER:
+               return ctx->scopes.event_header;
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               return ctx->scopes.event_common_context;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               return ctx->scopes.event_spec_context;
+       case BT_SCOPE_EVENT_PAYLOAD:
+               return ctx->scopes.event_payload;
+       default:
+               abort();
+       }
+
+       return NULL;
+}
+
+/*
+ * Returns the CTF scope from a path string. May return -1 if the path
+ * is found to be relative.
+ */
+static
+enum bt_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
+{
+       enum bt_scope scope;
+       enum bt_scope ret = -1;
+       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
+               sizeof(*absolute_path_prefixes);
+
+       for (scope = BT_SCOPE_PACKET_HEADER; scope < BT_SCOPE_PACKET_HEADER +
+                       prefixes_count; scope++) {
+               /*
+                * Chech if path string starts with a known absolute
+                * path prefix.
+                *
+                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
+                */
+               if (strncmp(pathstr, absolute_path_prefixes[scope],
+                               strlen(absolute_path_prefixes[scope]))) {
+                       /* Prefix does not match: try the next one */
+                       BT_LOGV("Prefix does not match: trying the next one: "
+                               "path=\"%s\", path-prefix=\"%s\", scope=%s",
+                               pathstr, absolute_path_prefixes[scope],
+                               bt_common_scope_string(scope));
+                       continue;
+               }
+
+               /* Found it! */
+               ret = scope;
+               BT_LOGV("Found root scope from absolute path: "
+                       "path=\"%s\", scope=%s", pathstr,
+                       bt_common_scope_string(scope));
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Destroys a path token.
+ */
+static
+void ptokens_destroy_func(gpointer ptoken, gpointer data)
+{
+       g_string_free(ptoken, TRUE);
+}
+
+/*
+ * Destroys a path token list.
+ */
+static
+void ptokens_destroy(GList *ptokens)
+{
+       if (!ptokens) {
+               return;
+       }
+
+       g_list_foreach(ptokens, ptokens_destroy_func, NULL);
+       g_list_free(ptokens);
+}
+
+/*
+ * Returns the string contained in a path token.
+ */
+static
+const char *ptoken_get_string(GList *ptoken)
+{
+       GString *tokenstr = (GString *) ptoken->data;
+
+       return tokenstr->str;
+}
+
+/*
+ * Converts a path string to a path token list, that is, splits the
+ * individual words of a path string into a list of individual
+ * strings.
+ */
+static
+GList *pathstr_to_ptokens(const char *pathstr)
+{
+       const char *at = pathstr;
+       const char *last = at;
+       GList *ptokens = NULL;
+
+       for (;;) {
+               if (*at == '.' || *at == '\0') {
+                       GString *tokenstr;
+
+                       if (at == last) {
+                               /* Error: empty token */
+                               BT_LOGE("Empty path token: path=\"%s\", pos=%u",
+                                       pathstr, (unsigned int) (at - pathstr));
+                               goto error;
+                       }
+
+                       tokenstr = g_string_new(NULL);
+                       g_string_append_len(tokenstr, last, at - last);
+                       ptokens = g_list_append(ptokens, tokenstr);
+                       last = at + 1;
+               }
+
+               if (*at == '\0') {
+                       break;
+               }
+
+               at++;
+       }
+
+       return ptokens;
+
+error:
+       ptokens_destroy(ptokens);
+       return NULL;
+}
+
+/*
+ * Converts a path token list to a field path object. The path token
+ * list is relative from `ft`. The index of the source looking for its
+ * target within `ft` is indicated by `src_index`. This can be `INT64_MAX`
+ * if the source is contained in `ft`.
+ *
+ * `field_path` is an output parameter owned by the caller that must be
+ * filled here.
+ */
+static
+int ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path,
+               struct ctf_field_type *ft, int64_t src_index)
+{
+       int ret = 0;
+       GList *cur_ptoken = ptokens;
+       bool first_level_done = false;
+
+       /* Locate target */
+       while (cur_ptoken) {
+               int64_t child_index;
+               struct ctf_field_type *child_ft;
+               const char *ft_name = ptoken_get_string(cur_ptoken);
+
+               BT_LOGV("Current path token: token=\"%s\"", ft_name);
+
+               /* Find to which index corresponds the current path token */
+               if (ft->id == CTF_FIELD_TYPE_ID_ARRAY ||
+                               ft->id == CTF_FIELD_TYPE_ID_SEQUENCE) {
+                       child_index = -1;
+               } else {
+                       child_index =
+                               ctf_field_type_compound_get_field_type_index_from_name(
+                                       ft, ft_name);
+                       if (child_index < 0) {
+                               /*
+                                * Error: field name does not exist or
+                                * wrong current type.
+                                */
+                               BT_LOGV("Cannot get index of field type: "
+                                       "field-name=\"%s\", "
+                                       "src-index=%" PRId64 ", "
+                                       "child-index=%" PRId64 ", "
+                                       "first-level-done=%d",
+                                       ft_name, src_index, child_index,
+                                       first_level_done);
+                               ret = -1;
+                               goto end;
+                       } else if (child_index > src_index &&
+                                       !first_level_done) {
+                               BT_LOGV("Child field type is located after source field type: "
+                                       "field-name=\"%s\", "
+                                       "src-index=%" PRId64 ", "
+                                       "child-index=%" PRId64 ", "
+                                       "first-level-done=%d",
+                                       ft_name, src_index, child_index,
+                                       first_level_done);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       /* Next path token */
+                       cur_ptoken = g_list_next(cur_ptoken);
+                       first_level_done = true;
+               }
+
+               /* Create new field path entry */
+               ctf_field_path_append_index(field_path, child_index);
+
+               /* Get child field type */
+               child_ft = ctf_field_type_compound_borrow_field_type_by_index(
+                       ft, child_index);
+               BT_ASSERT(child_ft);
+
+               /* Move child type to current type */
+               ft = child_ft;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Converts a known absolute path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `field_path` is an output parameter owned by the caller that must be
+ * filled here.
+ */
+static
+int absolute_ptokens_to_field_path(GList *ptokens,
+               struct ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       GList *cur_ptoken;
+       struct ctf_field_type *ft;
+
+       /*
+        * Make sure we're not referring to a scope within a translated
+        * object.
+        */
+       switch (field_path->root) {
+       case BT_SCOPE_PACKET_HEADER:
+               if (ctx->tc->is_translated) {
+                       BT_LOGE("Trace class is already translated: "
+                               "root-scope=%s",
+                               bt_common_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               break;
+       case BT_SCOPE_PACKET_CONTEXT:
+       case BT_SCOPE_EVENT_HEADER:
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               if (!ctx->sc) {
+                       BT_LOGE("No current stream class: "
+                               "root-scope=%s",
+                               bt_common_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               if (ctx->sc->is_translated) {
+                       BT_LOGE("Stream class is already translated: "
+                               "root-scope=%s",
+                               bt_common_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               break;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+       case BT_SCOPE_EVENT_PAYLOAD:
+               if (!ctx->ec) {
+                       BT_LOGE("No current event class: "
+                               "root-scope=%s",
+                               bt_common_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               if (ctx->ec->is_translated) {
+                       BT_LOGE("Event class is already translated: "
+                               "root-scope=%s",
+                               bt_common_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               break;
+
+       default:
+               abort();
+       }
+
+       /* Skip absolute path tokens */
+       cur_ptoken = g_list_nth(ptokens,
+               absolute_path_prefix_ptoken_counts[field_path->root]);
+
+       /* Start with root type */
+       ft = borrow_type_from_ctx(ctx, field_path->root);
+       if (!ft) {
+               /* Error: root type is not available */
+               BT_LOGE("Root field type is not available: "
+                       "root-scope=%s",
+                       bt_common_scope_string(field_path->root));
+               ret = -1;
+               goto end;
+       }
+
+       /* Locate target */
+       ret = ptokens_to_field_path(cur_ptoken, field_path, ft, INT64_MAX);
+
+end:
+       return ret;
+}
+
+/*
+ * Converts a known relative path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `field_path` is an output parameter owned by the caller that must be
+ * filled here.
+ */
+static
+int relative_ptokens_to_field_path(GList *ptokens,
+               struct ctf_field_path *field_path, struct resolve_context *ctx)
+{
+       int ret = 0;
+       int64_t parent_pos_in_stack;
+       struct ctf_field_path tail_field_path;
+
+       ctf_field_path_init(&tail_field_path);
+       parent_pos_in_stack = field_type_stack_size(ctx->field_type_stack) - 1;
+
+       while (parent_pos_in_stack >= 0) {
+               struct ctf_field_type *parent_type =
+                       field_type_stack_at(ctx->field_type_stack,
+                               parent_pos_in_stack)->ft;
+               int64_t cur_index = field_type_stack_at(ctx->field_type_stack,
+                       parent_pos_in_stack)->index;
+
+               BT_LOGV("Locating target field type from current parent field type: "
+                       "parent-pos=%" PRId64 ", parent-ft-addr=%p, "
+                       "cur-index=%" PRId64,
+                       parent_pos_in_stack, parent_type, cur_index);
+
+               /* Locate target from current parent type */
+               ret = ptokens_to_field_path(ptokens, &tail_field_path,
+                       parent_type, cur_index);
+               if (ret) {
+                       /* Not found... yet */
+                       BT_LOGV_STR("Not found at this point.");
+                       ctf_field_path_clear(&tail_field_path);
+               } else {
+                       /* Found: stitch tail field path to head field path */
+                       uint64_t i = 0;
+                       size_t tail_field_path_len =
+                               tail_field_path.path->len;
+
+                       while (BT_TRUE) {
+                               struct ctf_field_type *cur_type =
+                                       field_type_stack_at(ctx->field_type_stack,
+                                               i)->ft;
+                               int64_t index = field_type_stack_at(
+                                       ctx->field_type_stack, i)->index;
+
+                               if (cur_type == parent_type) {
+                                       break;
+                               }
+
+                               ctf_field_path_append_index(field_path,
+                                       index);
+                               i++;
+                       }
+
+                       for (i = 0; i < tail_field_path_len; i++) {
+                               int64_t index =
+                                       ctf_field_path_borrow_index_by_index(
+                                               &tail_field_path, i);
+
+                               ctf_field_path_append_index(field_path,
+                                       (int64_t) index);
+                       }
+                       break;
+               }
+
+               parent_pos_in_stack--;
+       }
+
+       if (parent_pos_in_stack < 0) {
+               /* Not found */
+               ret = -1;
+       }
+
+       ctf_field_path_fini(&tail_field_path);
+       return ret;
+}
+
+/*
+ * Converts a path string to a field path object within the resolving
+ * context `ctx`.
+ */
+static
+int pathstr_to_field_path(const char *pathstr,
+               struct ctf_field_path *field_path, struct resolve_context *ctx)
+{
+       int ret = 0;
+       enum bt_scope root_scope;
+       GList *ptokens = NULL;
+
+       /* Convert path string to path tokens */
+       ptokens = pathstr_to_ptokens(pathstr);
+       if (!ptokens) {
+               BT_LOGE("Cannot convert path string to path tokens: "
+                       "path=\"%s\"", pathstr);
+               ret = -1;
+               goto end;
+       }
+
+       /* Absolute or relative path? */
+       root_scope = get_root_scope_from_absolute_pathstr(pathstr);
+
+       if (root_scope == -1) {
+               /* Relative path: start with current root scope */
+               field_path->root = ctx->root_scope;
+               BT_LOGV("Detected relative path: starting with current root scope: "
+                       "scope=%s", bt_common_scope_string(field_path->root));
+               ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot get relative field path of path string: "
+                               "path=\"%s\", start-scope=%s, end-scope=%s",
+                               pathstr, bt_common_scope_string(ctx->root_scope),
+                               bt_common_scope_string(field_path->root));
+                       goto end;
+               }
+       } else {
+               /* Absolute path: use found root scope */
+               field_path->root = root_scope;
+               BT_LOGV("Detected absolute path: using root scope: "
+                       "scope=%s", bt_common_scope_string(field_path->root));
+               ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot get absolute field path of path string: "
+                               "path=\"%s\", root-scope=%s",
+                               pathstr, bt_common_scope_string(root_scope));
+                       goto end;
+               }
+       }
+
+       if (BT_LOG_ON_VERBOSE && ret == 0) {
+               GString *field_path_pretty = ctf_field_path_string(field_path);
+               const char *field_path_pretty_str =
+                       field_path_pretty ? field_path_pretty->str : NULL;
+
+               BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"",
+                       pathstr, field_path_pretty_str);
+
+               if (field_path_pretty) {
+                       g_string_free(field_path_pretty, TRUE);
+               }
+       }
+
+end:
+       ptokens_destroy(ptokens);
+       return ret;
+}
+
+/*
+ * Retrieves a field type by following the field path `field_path` in
+ * the resolving context `ctx`.
+ */
+static
+struct ctf_field_type *field_path_to_field_type(
+               struct ctf_field_path *field_path, struct resolve_context *ctx)
+{
+       uint64_t i;
+       struct ctf_field_type *ft;
+
+       /* Start with root type */
+       ft = borrow_type_from_ctx(ctx, field_path->root);
+       if (!ft) {
+               /* Error: root type is not available */
+               BT_LOGE("Root field type is not available: root-scope=%s",
+                       bt_common_scope_string(field_path->root));
+               goto end;
+       }
+
+       /* Locate target */
+       for (i = 0; i < field_path->path->len; i++) {
+               struct ctf_field_type *child_ft;
+               int64_t child_index =
+                       ctf_field_path_borrow_index_by_index(field_path, i);
+
+               /* Get child field type */
+               child_ft = ctf_field_type_compound_borrow_field_type_by_index(
+                       ft, child_index);
+               BT_ASSERT(child_ft);
+
+               /* Move child type to current type */
+               ft = child_ft;
+       }
+
+end:
+       return ft;
+}
+
+/*
+ * Fills the equivalent field path object of the context type stack.
+ */
+static
+void get_ctx_stack_field_path(struct resolve_context *ctx,
+               struct ctf_field_path *field_path)
+{
+       uint64_t i;
+
+       BT_ASSERT(field_path);
+       field_path->root = ctx->root_scope;
+       ctf_field_path_clear(field_path);
+
+       for (i = 0; i < field_type_stack_size(ctx->field_type_stack); i++) {
+               struct field_type_stack_frame *frame =
+                       field_type_stack_at(ctx->field_type_stack, i);
+
+               ctf_field_path_append_index(field_path, frame->index);
+       }
+}
+
+/*
+ * Returns the index of the lowest common ancestor of two field path
+ * objects having the same root scope.
+ */
+int64_t get_field_paths_lca_index(struct ctf_field_path *field_path1,
+               struct ctf_field_path *field_path2)
+{
+       int64_t lca_index = 0;
+       uint64_t field_path1_len, field_path2_len;
+
+       if (BT_LOG_ON_VERBOSE) {
+               GString *field_path1_pretty =
+                       ctf_field_path_string(field_path1);
+               GString *field_path2_pretty =
+                       ctf_field_path_string(field_path2);
+               const char *field_path1_pretty_str =
+                       field_path1_pretty ? field_path1_pretty->str : NULL;
+               const char *field_path2_pretty_str =
+                       field_path2_pretty ? field_path2_pretty->str : NULL;
+
+               BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: "
+                       "field-path-1=\"%s\", field-path-2=\"%s\"",
+                       field_path1_pretty_str, field_path2_pretty_str);
+
+               if (field_path1_pretty) {
+                       g_string_free(field_path1_pretty, TRUE);
+               }
+
+               if (field_path2_pretty) {
+                       g_string_free(field_path2_pretty, TRUE);
+               }
+       }
+
+       /*
+        * Start from both roots and find the first mismatch.
+        */
+       BT_ASSERT(field_path1->root == field_path2->root);
+       field_path1_len = field_path1->path->len;
+       field_path2_len = field_path2->path->len;
+
+       while (true) {
+               int64_t target_index, ctx_index;
+
+               if (lca_index == (int64_t) field_path2_len ||
+                               lca_index == (int64_t) field_path1_len) {
+                       /*
+                        * This means that both field paths never split.
+                        * This is invalid because the target cannot be
+                        * an ancestor of the source.
+                        */
+                       BT_LOGE("Source field type is an ancestor of target field type or vice versa: "
+                               "lca-index=%" PRId64 ", "
+                               "field-path-1-len=%" PRIu64 ", "
+                               "field-path-2-len=%" PRIu64,
+                               lca_index, field_path1_len, field_path2_len);
+                       lca_index = -1;
+                       break;
+               }
+
+               target_index = ctf_field_path_borrow_index_by_index(field_path1,
+                       lca_index);
+               ctx_index = ctf_field_path_borrow_index_by_index(field_path2,
+                       lca_index);
+
+               if (target_index != ctx_index) {
+                       /* LCA index is the previous */
+                       break;
+               }
+
+               lca_index++;
+       }
+
+       BT_LOGV("Found LCA: lca-index=%" PRId64, lca_index);
+       return lca_index;
+}
+
+/*
+ * Validates a target field path.
+ */
+static
+int validate_target_field_path(struct ctf_field_path *target_field_path,
+               struct ctf_field_type *target_ft,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       struct ctf_field_path ctx_field_path;
+       uint64_t target_field_path_len = target_field_path->path->len;
+       int64_t lca_index;
+
+       /* Get context field path */
+       ctf_field_path_init(&ctx_field_path);
+       get_ctx_stack_field_path(ctx, &ctx_field_path);
+
+       /*
+        * Make sure the target is not a root.
+        */
+       if (target_field_path_len == 0) {
+               BT_LOGE_STR("Target field path's length is 0 (targeting the root).");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Make sure the root of the target field path is not located
+        * after the context field path's root.
+        */
+       if (target_field_path->root > ctx_field_path.root) {
+               BT_LOGE("Target field type is located after source field type: "
+                       "target-root=%s, source-root=%s",
+                       bt_common_scope_string(target_field_path->root),
+                       bt_common_scope_string(ctx_field_path.root));
+               ret = -1;
+               goto end;
+       }
+
+       if (target_field_path->root == ctx_field_path.root) {
+               int64_t target_index, ctx_index;
+
+               /*
+                * Find the index of the lowest common ancestor of both field
+                * paths.
+                */
+               lca_index = get_field_paths_lca_index(target_field_path,
+                       &ctx_field_path);
+               if (lca_index < 0) {
+                       BT_LOGE_STR("Cannot get least common ancestor.");
+                       ret = -1;
+                       goto end;
+               }
+
+               /*
+                * Make sure the target field path is located before the
+                * context field path.
+                */
+               target_index = ctf_field_path_borrow_index_by_index(
+                       target_field_path, (uint64_t) lca_index);
+               ctx_index = ctf_field_path_borrow_index_by_index(
+                       &ctx_field_path, (uint64_t) lca_index);
+
+               if (target_index >= ctx_index) {
+                       BT_LOGE("Target field type's index is greater than or equal to source field type's index in LCA: "
+                               "lca-index=%" PRId64 ", "
+                               "target-index=%" PRId64 ", "
+                               "source-index=%" PRId64,
+                               lca_index, target_index, ctx_index);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * Make sure the target type has the right type and properties.
+        */
+       switch (ctx->cur_ft->id) {
+       case CTF_FIELD_TYPE_ID_VARIANT:
+               if (target_ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE("Variant field type's tag field type is not an enumeration field type: "
+                               "tag-ft-addr=%p, tag-ft-id=%d",
+                               target_ft, target_ft->id);
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_int *int_ft = (void *) target_ft;
+
+               if (target_ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               target_ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE("Sequence field type's length field type is not an unsigned integer field type: "
+                               "length-ft-addr=%p, length-ft-id=%d",
+                               target_ft, target_ft->id);
+                       ret = -1;
+                       goto end;
+               }
+
+               if (int_ft->is_signed) {
+                       BT_LOGE("Sequence field type's length field type is not an unsigned integer field type: "
+                               "length-ft-addr=%p, length-ft-id=%d",
+                               target_ft, target_ft->id);
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       }
+       default:
+               abort();
+       }
+
+end:
+       ctf_field_path_fini(&ctx_field_path);
+       return ret;
+}
+
+/*
+ * Resolves a variant or sequence field type `ft`.
+ */
+static
+int resolve_sequence_or_variant_field_type(struct ctf_field_type *ft,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       const char *pathstr;
+       struct ctf_field_path target_field_path;
+       struct ctf_field_type *target_ft = NULL;
+       GString *target_field_path_pretty = NULL;
+       const char *target_field_path_pretty_str;
+
+       ctf_field_path_init(&target_field_path);
+
+       /* Get path string */
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_sequence *seq_ft = (void *) ft;
+               pathstr = seq_ft->length_ref->str;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+               pathstr = var_ft->tag_ref->str;
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (!pathstr) {
+               BT_LOGE_STR("Cannot get path string.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Get target field path out of path string */
+       ret = pathstr_to_field_path(pathstr, &target_field_path, ctx);
+       if (ret) {
+               BT_LOGE("Cannot get target field path for path string: "
+                       "path=\"%s\"", pathstr);
+               goto end;
+       }
+
+       target_field_path_pretty = ctf_field_path_string(
+               &target_field_path);
+       target_field_path_pretty_str =
+               target_field_path_pretty ? target_field_path_pretty->str : NULL;
+
+       /* Get target field type */
+       target_ft = field_path_to_field_type(&target_field_path, ctx);
+       if (!target_ft) {
+               BT_LOGE("Cannot get target field type for path string: "
+                       "path=\"%s\", target-field-path=\"%s\"",
+                       pathstr, target_field_path_pretty_str);
+               ret = -1;
+               goto end;
+       }
+
+       ret = validate_target_field_path(&target_field_path,
+               target_ft, ctx);
+       if (ret) {
+               BT_LOGE("Invalid target field path for path string: "
+                       "path=\"%s\", target-field-path=\"%s\"",
+                       pathstr, target_field_path_pretty_str);
+               goto end;
+       }
+
+       /* Set target field path and target field type */
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_sequence *seq_ft = (void *) ft;
+
+               ctf_field_path_copy_content(&seq_ft->length_path,
+                       &target_field_path);
+               seq_ft->length_ft = (void *) target_ft;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               ctf_field_path_copy_content(&var_ft->tag_path,
+                       &target_field_path);
+               ctf_field_type_variant_set_tag_field_type(var_ft,
+                       (void *) target_ft);
+               break;
+       }
+       default:
+               abort();
+       }
+
+end:
+       if (target_field_path_pretty) {
+               g_string_free(target_field_path_pretty, TRUE);
+       }
+
+       ctf_field_path_fini(&target_field_path);
+       return ret;
+}
+
+/*
+ * Resolves a field type `ft`.
+ */
+static
+int resolve_field_type(struct ctf_field_type *ft, struct resolve_context *ctx)
+{
+       int ret = 0;
+
+       if (!ft) {
+               /* Type is not available; still valid */
+               goto end;
+       }
+
+       ctx->cur_ft = ft;
+
+       /* Resolve sequence/variant field type */
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       case CTF_FIELD_TYPE_ID_VARIANT:
+               ret = resolve_sequence_or_variant_field_type(ft, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve sequence field type's length or variant field type's tag: "
+                               "ret=%d, ft-addr=%p", ret, ft);
+                       goto end;
+               }
+
+               break;
+       default:
+               break;
+       }
+
+       /* Recurse into compound types */
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       {
+               uint64_t i;
+               uint64_t field_count =
+                       ctf_field_type_compound_get_field_type_count(ft);
+
+               ret = field_type_stack_push(ctx->field_type_stack, ft);
+               if (ret) {
+                       BT_LOGE("Cannot push field type on context's stack: "
+                               "ft-addr=%p", ft);
+                       goto end;
+               }
+
+               for (i = 0; i < field_count; i++) {
+                       struct ctf_field_type *child_ft =
+                               ctf_field_type_compound_borrow_field_type_by_index(
+                                       ft, i);
+
+                       BT_ASSERT(child_ft);
+
+                       if (ft->id == CTF_FIELD_TYPE_ID_ARRAY||
+                                       ft->id == CTF_FIELD_TYPE_ID_SEQUENCE) {
+                               field_type_stack_peek(
+                                       ctx->field_type_stack)->index = -1;
+                       } else {
+                               field_type_stack_peek(
+                                       ctx->field_type_stack)->index =
+                                               (int64_t) i;
+                       }
+
+                       BT_LOGV("Resolving field type's child field type: "
+                               "parent-ft-addr=%p, child-ft-addr=%p, "
+                               "index=%" PRIu64 ", count=%" PRIu64,
+                               ft, child_ft, i, field_count);
+                       ret = resolve_field_type(child_ft, ctx);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               field_type_stack_pop(ctx->field_type_stack);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Resolves the root field type corresponding to the scope `root_scope`.
+ */
+static
+int resolve_root_type(enum bt_scope root_scope, struct resolve_context *ctx)
+{
+       int ret;
+
+       BT_ASSERT(field_type_stack_size(ctx->field_type_stack) == 0);
+       ctx->root_scope = root_scope;
+       ret = resolve_field_type(borrow_type_from_ctx(ctx, root_scope), ctx);
+       ctx->root_scope = -1;
+       return ret;
+}
+
+static
+int resolve_event_class_field_types(struct resolve_context *ctx,
+               struct ctf_event_class *ec)
+{
+       int ret = 0;
+
+       BT_ASSERT(!ctx->scopes.event_spec_context);
+       BT_ASSERT(!ctx->scopes.event_payload);
+
+       if (ec->is_translated) {
+               goto end;
+       }
+
+       ctx->ec = ec;
+       ctx->scopes.event_spec_context = ec->spec_context_ft;
+       ret = resolve_root_type(BT_SCOPE_EVENT_COMMON_CONTEXT, ctx);
+       if (ret) {
+               BT_LOGE("Cannot resolve event specific context field type: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       ctx->scopes.event_payload = ec->payload_ft;
+       ret = resolve_root_type(BT_SCOPE_EVENT_PAYLOAD, ctx);
+       if (ret) {
+               BT_LOGE("Cannot resolve event payload field type: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+end:
+       ctx->scopes.event_spec_context = NULL;
+       ctx->scopes.event_payload = NULL;
+       ctx->ec = NULL;
+       return ret;
+}
+
+static
+int resolve_stream_class_field_types(struct resolve_context *ctx,
+               struct ctf_stream_class *sc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       BT_ASSERT(!ctx->scopes.packet_context);
+       BT_ASSERT(!ctx->scopes.event_header);
+       BT_ASSERT(!ctx->scopes.event_common_context);
+       ctx->sc = sc;
+
+       if (!sc->is_translated) {
+               ctx->scopes.packet_context = sc->packet_context_ft;
+               ret = resolve_root_type(BT_SCOPE_PACKET_CONTEXT, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve packet context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+
+               ctx->scopes.event_header = sc->event_header_ft;
+               ret = resolve_root_type(BT_SCOPE_EVENT_HEADER, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve event header field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+
+               ctx->scopes.event_common_context = sc->event_common_context_ft;
+               ret = resolve_root_type(BT_SCOPE_EVENT_SPECIFIC_CONTEXT, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve event common context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       ctx->scopes.packet_context = sc->packet_context_ft;
+       ctx->scopes.event_header = sc->event_header_ft;
+       ctx->scopes.event_common_context = sc->event_common_context_ft;
+
+       for (i = 0; i < sc->event_classes->len; i++) {
+               struct ctf_event_class *ec = sc->event_classes->pdata[i];
+
+               ret = resolve_event_class_field_types(ctx, ec);
+               if (ret) {
+                       BT_LOGE("Cannot resolve event class's field types: "
+                               "ec-id=%" PRIu64 ", ec-name=\"%s\"",
+                               ec->id, ec->name->str);
+                       goto end;
+               }
+       }
+
+end:
+       ctx->scopes.packet_context = NULL;
+       ctx->scopes.event_header = NULL;
+       ctx->scopes.event_common_context = NULL;
+       ctx->sc = NULL;
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_resolve_field_types(struct ctf_trace_class *tc)
+{
+       int ret = 0;
+       uint64_t i;
+       struct resolve_context ctx = {
+               .tc = tc,
+               .sc = NULL,
+               .ec = NULL,
+               .scopes = {
+                       .packet_header = tc->packet_header_ft,
+                       .packet_context = NULL,
+                       .event_header = NULL,
+                       .event_common_context = NULL,
+                       .event_spec_context = NULL,
+                       .event_payload = NULL,
+               },
+               .root_scope = BT_SCOPE_PACKET_HEADER,
+               .cur_ft = NULL,
+       };
+
+       /* Initialize type stack */
+       ctx.field_type_stack = field_type_stack_create();
+       if (!ctx.field_type_stack) {
+               BT_LOGE_STR("Cannot create field type stack.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!tc->is_translated) {
+               ctx.scopes.packet_header = tc->packet_header_ft;
+               ret = resolve_root_type(BT_SCOPE_PACKET_HEADER, &ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve packet header field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       ctx.scopes.packet_header = tc->packet_header_ft;
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = tc->stream_classes->pdata[i];
+
+               ret = resolve_stream_class_field_types(&ctx, sc);
+               if (ret) {
+                       BT_LOGE("Cannot resolve stream class's field types: "
+                               "sc-id=%" PRIu64, sc->id);
+                       goto end;
+               }
+       }
+
+end:
+       field_type_stack_destroy(ctx.field_type_stack);
+       return ret;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-translate.c b/plugins/ctf/common/metadata/ctf-meta-translate.c
new file mode 100644 (file)
index 0000000..0756ffc
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-TRANSLATE"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static inline
+struct bt_field_type *ctf_field_type_to_ir(struct ctf_field_type *ft,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec);
+
+static inline
+void ctf_field_type_int_set_props(struct ctf_field_type_int *ft,
+               struct bt_field_type *ir_ft)
+{
+       int ret;
+
+       ret = bt_field_type_integer_set_field_value_range(ir_ft, ft->base.size);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_integer_set_preferred_display_base(ir_ft,
+               ft->disp_base);
+       BT_ASSERT(ret == 0);
+}
+
+static inline
+struct bt_field_type *ctf_field_type_int_to_ir(struct ctf_field_type_int *ft)
+{
+       struct bt_field_type *ir_ft;
+
+       if (ft->is_signed) {
+               ir_ft = bt_field_type_signed_integer_create();
+       } else {
+               ir_ft = bt_field_type_unsigned_integer_create();
+       }
+
+       BT_ASSERT(ir_ft);
+       ctf_field_type_int_set_props(ft, ir_ft);
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_enum_to_ir(struct ctf_field_type_enum *ft)
+{
+       int ret;
+       struct bt_field_type *ir_ft;
+       uint64_t i;
+
+       if (ft->base.is_signed) {
+               ir_ft = bt_field_type_signed_enumeration_create();
+       } else {
+               ir_ft = bt_field_type_unsigned_enumeration_create();
+       }
+
+       BT_ASSERT(ir_ft);
+       ctf_field_type_int_set_props((void *) ft, ir_ft);
+
+       for (i = 0; i < ft->mappings->len; i++) {
+               struct ctf_field_type_enum_mapping *mapping =
+                       ctf_field_type_enum_borrow_mapping_by_index(ft, i);
+
+               if (ft->base.is_signed) {
+                       ret = bt_field_type_signed_enumeration_map_range(
+                               ir_ft, mapping->label->str,
+                               mapping->range.lower.i, mapping->range.upper.i);
+               } else {
+                       ret = bt_field_type_unsigned_enumeration_map_range(
+                               ir_ft, mapping->label->str,
+                               mapping->range.lower.u, mapping->range.upper.u);
+               }
+
+               BT_ASSERT(ret == 0);
+       }
+
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_float_to_ir(
+               struct ctf_field_type_float *ft)
+{
+       struct bt_field_type *ir_ft;
+       int ret;
+
+       ir_ft = bt_field_type_real_create();
+       BT_ASSERT(ir_ft);
+
+       if (ft->base.size == 32) {
+               ret = bt_field_type_real_set_is_single_precision(ir_ft,
+                       BT_TRUE);
+               BT_ASSERT(ret == 0);
+       }
+
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_string_to_ir(
+               struct ctf_field_type_string *ft)
+{
+       struct bt_field_type *ir_ft = bt_field_type_string_create();
+
+       BT_ASSERT(ir_ft);
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_struct_to_ir(
+               struct ctf_field_type_struct *ft,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       int ret;
+       struct bt_field_type *ir_ft = bt_field_type_structure_create();
+       uint64_t i;
+
+       BT_ASSERT(ir_ft);
+
+       for (i = 0; i < ft->members->len; i++) {
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_struct_borrow_member_by_index(ft, i);
+               struct bt_field_type *member_ir_ft;
+
+               if (!named_ft->ft->in_ir) {
+                       continue;
+               }
+
+               member_ir_ft = ctf_field_type_to_ir(named_ft->ft, tc, sc, ec);
+               BT_ASSERT(member_ir_ft);
+               ret = bt_field_type_structure_append_member(ir_ft,
+                       named_ft->name->str, member_ir_ft);
+               BT_ASSERT(ret == 0);
+               bt_put(member_ir_ft);
+       }
+
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *borrow_ir_ft_from_field_path(
+               struct ctf_field_path *field_path,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       struct bt_field_type *ir_ft = NULL;
+       struct ctf_field_type *ft = ctf_field_path_borrow_field_type(
+               field_path, tc, sc, ec);
+
+       BT_ASSERT(ft);
+
+       if (ft->in_ir) {
+               ir_ft = ft->ir_ft;
+       }
+
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_variant_to_ir(
+               struct ctf_field_type_variant *ft,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       int ret;
+       struct bt_field_type *ir_ft = bt_field_type_variant_create();
+       uint64_t i;
+
+       BT_ASSERT(ir_ft);
+       ret = bt_field_type_variant_set_selector_field_type(ir_ft,
+               borrow_ir_ft_from_field_path(&ft->tag_path, tc, sc, ec));
+       BT_ASSERT(ret == 0);
+
+       for (i = 0; i < ft->options->len; i++) {
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_variant_borrow_option_by_index(ft, i);
+               struct bt_field_type *option_ir_ft;
+
+               BT_ASSERT(named_ft->ft->in_ir);
+               option_ir_ft = ctf_field_type_to_ir(named_ft->ft, tc, sc, ec);
+               BT_ASSERT(option_ir_ft);
+               ret = bt_field_type_variant_append_option(ir_ft,
+                       named_ft->name->str, option_ir_ft);
+               BT_ASSERT(ret == 0);
+               bt_put(option_ir_ft);
+       }
+
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_array_to_ir(
+               struct ctf_field_type_array *ft,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       struct bt_field_type *ir_ft;
+       struct bt_field_type *elem_ir_ft;
+
+       if (ft->base.is_text) {
+               ir_ft = bt_field_type_string_create();
+               BT_ASSERT(ir_ft);
+               goto end;
+       }
+
+       elem_ir_ft = ctf_field_type_to_ir(ft->base.elem_ft, tc, sc, ec);
+       BT_ASSERT(elem_ir_ft);
+       ir_ft = bt_field_type_static_array_create(elem_ir_ft, ft->length);
+       BT_ASSERT(ir_ft);
+       bt_put(elem_ir_ft);
+
+end:
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_sequence_to_ir(
+               struct ctf_field_type_sequence *ft,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       int ret;
+       struct bt_field_type *ir_ft;
+       struct bt_field_type *elem_ir_ft;
+
+       if (ft->base.is_text) {
+               ir_ft = bt_field_type_string_create();
+               BT_ASSERT(ir_ft);
+               goto end;
+       }
+
+       elem_ir_ft = ctf_field_type_to_ir(ft->base.elem_ft, tc, sc, ec);
+       BT_ASSERT(elem_ir_ft);
+       ir_ft = bt_field_type_dynamic_array_create(elem_ir_ft);
+       BT_ASSERT(ir_ft);
+       bt_put(elem_ir_ft);
+       BT_ASSERT(ir_ft);
+       ret = bt_field_type_dynamic_array_set_length_field_type(ir_ft,
+               borrow_ir_ft_from_field_path(&ft->length_path, tc, sc, ec));
+       BT_ASSERT(ret == 0);
+
+end:
+       return ir_ft;
+}
+
+static inline
+struct bt_field_type *ctf_field_type_to_ir(struct ctf_field_type *ft,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       struct bt_field_type *ir_ft = NULL;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(ft->in_ir);
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+               ir_ft = ctf_field_type_int_to_ir((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_ENUM:
+               ir_ft = ctf_field_type_enum_to_ir((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_FLOAT:
+               ir_ft = ctf_field_type_float_to_ir((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_STRING:
+               ir_ft = ctf_field_type_string_to_ir((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_STRUCT:
+               ir_ft = ctf_field_type_struct_to_ir((void *) ft, tc, sc, ec);
+               break;
+       case CTF_FIELD_TYPE_ID_ARRAY:
+               ir_ft = ctf_field_type_array_to_ir((void *) ft, tc, sc, ec);
+               break;
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+               ir_ft = ctf_field_type_sequence_to_ir((void *) ft, tc, sc, ec);
+               break;
+       case CTF_FIELD_TYPE_ID_VARIANT:
+               ir_ft = ctf_field_type_variant_to_ir((void *) ft, tc, sc, ec);
+               break;
+       default:
+               abort();
+       }
+
+       ft->ir_ft = ir_ft;
+       return ir_ft;
+}
+
+static inline
+bool ctf_field_type_struct_has_immediate_member_in_ir(
+               struct ctf_field_type_struct *ft)
+{
+       uint64_t i;
+       bool has_immediate_member_in_ir = false;
+
+       for (i = 0; i < ft->members->len; i++) {
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_struct_borrow_member_by_index(ft, i);
+
+               if (named_ft->ft->in_ir) {
+                       has_immediate_member_in_ir = true;
+                       goto end;
+               }
+       }
+
+end:
+       return has_immediate_member_in_ir;
+}
+
+static inline
+struct bt_field_type *scope_ctf_field_type_to_ir(struct ctf_field_type *ft,
+       struct ctf_trace_class *tc,
+       struct ctf_stream_class *sc,
+       struct ctf_event_class *ec)
+{
+       struct bt_field_type *ir_ft = NULL;
+
+       if (!ft) {
+               goto end;
+       }
+
+       BT_ASSERT(ft->id == CTF_FIELD_TYPE_ID_STRUCT);
+
+       if (!ctf_field_type_struct_has_immediate_member_in_ir((void *) ft)) {
+               /*
+                * Nothing for IR in this scope: typical for packet
+                * header, packet context, and event header.
+                */
+               goto end;
+       }
+
+       ir_ft = ctf_field_type_to_ir(ft, tc, sc, ec);
+
+end:
+       return ir_ft;
+}
+
+static inline
+struct ctf_field_type_int *borrow_named_int_field_type(
+               struct ctf_field_type_struct *struct_ft, const char *name)
+{
+       struct ctf_named_field_type *named_ft = NULL;
+       struct ctf_field_type_int *int_ft = NULL;
+
+       if (!struct_ft) {
+               goto end;
+       }
+
+       named_ft = ctf_field_type_struct_borrow_member_by_name(struct_ft, name);
+       if (!named_ft) {
+               goto end;
+       }
+
+       if (named_ft->ft->id != CTF_FIELD_TYPE_ID_INT &&
+                       named_ft->ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+               goto end;
+       }
+
+       int_ft = (void *) named_ft->ft;
+
+end:
+       return int_ft;
+}
+
+static inline
+struct bt_event_class *ctf_event_class_to_ir(struct ctf_event_class *ec,
+               struct bt_stream_class *ir_sc, struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc)
+{
+       int ret;
+       struct bt_event_class *ir_ec = NULL;
+
+       if (ec->is_translated) {
+               ir_ec = bt_stream_class_borrow_event_class_by_id(
+                       ir_sc, ec->id);
+               BT_ASSERT(ir_ec);
+               goto end;
+       }
+
+       ir_ec = bt_event_class_create_with_id(ir_sc, ec->id);
+       BT_ASSERT(ir_ec);
+       bt_put(ir_ec);
+
+       if (ec->spec_context_ft) {
+               struct bt_field_type *ir_ft = scope_ctf_field_type_to_ir(
+                       ec->spec_context_ft, tc, sc, ec);
+
+               if (ir_ft) {
+                       ret = bt_event_class_set_specific_context_field_type(
+                               ir_ec, ir_ft);
+                       BT_ASSERT(ret == 0);
+                       bt_put(ir_ft);
+               }
+       }
+
+       if (ec->payload_ft) {
+               struct bt_field_type *ir_ft = scope_ctf_field_type_to_ir(
+                       ec->payload_ft, tc, sc, ec);
+
+               if (ir_ft) {
+                       ret = bt_event_class_set_payload_field_type(ir_ec,
+                               ir_ft);
+                       BT_ASSERT(ret == 0);
+                       bt_put(ir_ft);
+               }
+       }
+
+       if (ec->name->len > 0) {
+               ret = bt_event_class_set_name(ir_ec, ec->name->str);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (ec->emf_uri->len > 0) {
+               ret = bt_event_class_set_emf_uri(ir_ec, ec->emf_uri->str);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (ec->log_level != -1) {
+               ret = bt_event_class_set_log_level(ir_ec, ec->log_level);
+               BT_ASSERT(ret == 0);
+       }
+
+       ec->is_translated = true;
+       ec->ir_ec = ir_ec;
+
+end:
+       return ir_ec;
+}
+
+
+static inline
+struct bt_stream_class *ctf_stream_class_to_ir(struct ctf_stream_class *sc,
+               struct bt_trace *ir_trace, struct ctf_trace_class *tc)
+{
+       int ret;
+       struct bt_stream_class *ir_sc = NULL;
+       struct ctf_field_type_int *int_ft;
+
+       if (sc->is_translated) {
+               ir_sc = bt_trace_borrow_stream_class_by_id(ir_trace, sc->id);
+               BT_ASSERT(ir_sc);
+               goto end;
+       }
+
+       ir_sc = bt_stream_class_create_with_id(ir_trace, sc->id);
+       BT_ASSERT(ir_sc);
+       bt_put(ir_sc);
+
+       if (sc->packet_context_ft) {
+               struct bt_field_type *ir_ft = scope_ctf_field_type_to_ir(
+                       sc->packet_context_ft, tc, sc, NULL);
+
+               if (ir_ft) {
+                       ret = bt_stream_class_set_packet_context_field_type(
+                               ir_sc, ir_ft);
+                       BT_ASSERT(ret == 0);
+                       bt_put(ir_ft);
+               }
+       }
+
+       if (sc->event_header_ft) {
+               struct bt_field_type *ir_ft = scope_ctf_field_type_to_ir(
+                       sc->event_header_ft, tc, sc, NULL);
+
+               if (ir_ft) {
+                       ret = bt_stream_class_set_event_header_field_type(ir_sc,
+                               ir_ft);
+                       BT_ASSERT(ret == 0);
+                       bt_put(ir_ft);
+               }
+       }
+
+       if (sc->event_common_context_ft) {
+               struct bt_field_type *ir_ft = scope_ctf_field_type_to_ir(
+                       sc->event_common_context_ft, tc, sc, NULL);
+
+               if (ir_ft) {
+                       ret = bt_stream_class_set_event_common_context_field_type(
+                               ir_sc, ir_ft);
+                       BT_ASSERT(ret == 0);
+                       bt_put(ir_ft);
+               }
+       }
+
+       ret = bt_stream_class_set_assigns_automatic_event_class_id(ir_sc,
+               BT_FALSE);
+       BT_ASSERT(ret == 0);
+       ret = bt_stream_class_set_assigns_automatic_stream_id(ir_sc, BT_FALSE);
+       BT_ASSERT(ret == 0);
+
+       if (sc->default_clock_class) {
+               ret = bt_stream_class_set_default_clock_class(ir_sc,
+                       sc->default_clock_class);
+               BT_ASSERT(ret == 0);
+       }
+
+       int_ft = borrow_named_int_field_type((void *) sc->packet_context_ft,
+               "events_discarded");
+       if (int_ft) {
+               if (int_ft->meaning == CTF_FIELD_TYPE_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT) {
+                       ret = bt_stream_class_set_packets_have_discarded_event_counter_snapshot(
+                               ir_sc, BT_TRUE);
+                       BT_ASSERT(ret == 0);
+               }
+       }
+
+       int_ft = borrow_named_int_field_type((void *) sc->packet_context_ft,
+               "packet_seq_num");
+       if (int_ft) {
+               if (int_ft->meaning == CTF_FIELD_TYPE_MEANING_PACKET_COUNTER_SNAPSHOT) {
+                       ret = bt_stream_class_set_packets_have_packet_counter_snapshot(
+                               ir_sc, BT_TRUE);
+                       BT_ASSERT(ret == 0);
+               }
+       }
+
+       int_ft = borrow_named_int_field_type((void *) sc->packet_context_ft,
+               "timestamp_begin");
+       if (int_ft) {
+               if (int_ft->meaning == CTF_FIELD_TYPE_MEANING_PACKET_BEGINNING_TIME) {
+                       ret = bt_stream_class_set_packets_have_default_beginning_clock_value(
+                               ir_sc, BT_TRUE);
+                       BT_ASSERT(ret == 0);
+               }
+       }
+
+       int_ft = borrow_named_int_field_type((void *) sc->packet_context_ft,
+               "timestamp_end");
+       if (int_ft) {
+               if (int_ft->meaning == CTF_FIELD_TYPE_MEANING_PACKET_END_TIME) {
+                       ret = bt_stream_class_set_packets_have_default_end_clock_value(
+                               ir_sc, BT_TRUE);
+                       BT_ASSERT(ret == 0);
+               }
+       }
+
+       sc->is_translated = true;
+       sc->ir_sc = ir_sc;
+
+end:
+       return ir_sc;
+}
+
+static inline
+int ctf_trace_class_to_ir(struct bt_trace *ir_trace,
+               struct ctf_trace_class *tc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (tc->is_translated) {
+               goto end;
+       }
+
+       if (tc->packet_header_ft) {
+               struct bt_field_type *ir_ft = scope_ctf_field_type_to_ir(
+                       tc->packet_header_ft, tc, NULL, NULL);
+
+               if (ir_ft) {
+                       ret = bt_trace_set_packet_header_field_type(ir_trace,
+                               ir_ft);
+                       BT_ASSERT(ret == 0);
+                       bt_put(ir_ft);
+               }
+       }
+
+       if (tc->name->len > 0) {
+               ret = bt_trace_set_name(ir_trace, tc->name->str);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       if (tc->is_uuid_set) {
+               ret = bt_trace_set_uuid(ir_trace, tc->uuid);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < tc->env_entries->len; i++) {
+               struct ctf_trace_class_env_entry *env_entry =
+                       ctf_trace_class_borrow_env_entry_by_index(tc, i);
+
+               switch (env_entry->type) {
+               case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT:
+                       ret = bt_trace_set_environment_entry_integer(
+                               ir_trace, env_entry->name->str,
+                               env_entry->value.i);
+                       break;
+               case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR:
+                       ret = bt_trace_set_environment_entry_string(
+                               ir_trace, env_entry->name->str,
+                               env_entry->value.str->str);
+                       break;
+               default:
+                       abort();
+               }
+
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = bt_trace_set_assigns_automatic_stream_class_id(ir_trace,
+               BT_FALSE);
+       if (ret) {
+               goto end;
+       }
+
+       tc->is_translated = true;
+       tc->ir_tc = ir_trace;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_translate(struct bt_trace *ir_trace,
+               struct ctf_trace_class *tc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       ret = ctf_trace_class_to_ir(ir_trace, tc);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               uint64_t j;
+               struct ctf_stream_class *sc = tc->stream_classes->pdata[i];
+               struct bt_stream_class *ir_sc;
+
+               ir_sc = ctf_stream_class_to_ir(sc, ir_trace, tc);
+               if (!ir_sc) {
+                       ret = -1;
+                       goto end;
+               }
+
+               for (j = 0; j < sc->event_classes->len; j++) {
+                       struct ctf_event_class *ec = sc->event_classes->pdata[j];
+                       struct bt_event_class *ir_ec;
+
+                       ir_ec = ctf_event_class_to_ir(ec, ir_sc, tc, sc);
+                       if (!ir_ec) {
+                               ret = -1;
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c b/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c
new file mode 100644 (file)
index 0000000..347d290
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-DEF-CC"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static inline
+int find_mapped_clock_class(struct ctf_field_type *ft,
+               struct bt_clock_class **clock_class)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!ft) {
+               goto end;
+       }
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+       case CTF_FIELD_TYPE_ID_ENUM:
+       {
+               struct ctf_field_type_int *int_ft = (void *) ft;
+
+               if (int_ft->mapped_clock_class) {
+                       if (*clock_class && *clock_class !=
+                                       int_ft->mapped_clock_class) {
+                               BT_LOGE("Stream class contains more than one "
+                                       "clock class: expected-cc-name=\"%s\", "
+                                       "other-cc-name=\"%s\"",
+                                       bt_clock_class_get_name(*clock_class),
+                                       bt_clock_class_get_name(int_ft->mapped_clock_class));
+                               ret = -1;
+                               goto end;
+                       }
+
+                       *clock_class = int_ft->mapped_clock_class;
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               for (i = 0; i < struct_ft->members->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_struct_borrow_member_by_index(
+                                       struct_ft, i);
+
+                       ret = find_mapped_clock_class(named_ft->ft,
+                               clock_class);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               for (i = 0; i < var_ft->options->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_variant_borrow_option_by_index(
+                                       var_ft, i);
+
+                       ret = find_mapped_clock_class(named_ft->ft,
+                               clock_class);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_array_base *array_ft = (void *) ft;
+
+               ret = find_mapped_clock_class(array_ft->elem_ft, clock_class);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int update_stream_class_default_clock_class(
+               struct ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct bt_clock_class *clock_class = stream_class->default_clock_class;
+       uint64_t i;
+
+       ret = find_mapped_clock_class(stream_class->packet_context_ft,
+               &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       ret = find_mapped_clock_class(stream_class->event_header_ft,
+               &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       ret = find_mapped_clock_class(stream_class->event_common_context_ft,
+               &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < stream_class->event_classes->len; i++) {
+               struct ctf_event_class *event_class =
+                       stream_class->event_classes->pdata[i];
+
+               ret = find_mapped_clock_class(event_class->spec_context_ft,
+                       &clock_class);
+               if (ret) {
+                       goto end;
+               }
+
+               ret = find_mapped_clock_class(event_class->payload_ft,
+                       &clock_class);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       if (!stream_class->default_clock_class) {
+               stream_class->default_clock_class = bt_get(clock_class);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc)
+{
+       uint64_t i;
+       int ret = 0;
+       struct bt_clock_class *clock_class = NULL;
+
+       ret = find_mapped_clock_class(ctf_tc->packet_header_ft,
+               &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       if (clock_class) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc =
+                       ctf_tc->stream_classes->pdata[i];
+
+               ret = update_stream_class_default_clock_class(
+                       ctf_tc->stream_classes->pdata[i]);
+               if (ret) {
+                       BT_LOGE("Stream class contains more than one "
+                               "clock class: stream-class-id=%" PRIu64,
+                               sc->id);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-in-ir.c b/plugins/ctf/common/metadata/ctf-meta-update-in-ir.c
new file mode 100644 (file)
index 0000000..5a36ea5
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-IN-IR"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <babeltrace/compat/glib-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static
+void update_field_type_in_ir(struct ctf_field_type *ft,
+               GHashTable *ft_dependents)
+{
+       int64_t i;
+
+       if (!ft) {
+               goto end;
+       }
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+       case CTF_FIELD_TYPE_ID_ENUM:
+       {
+               struct ctf_field_type_int *int_ft = (void *) ft;
+
+               if (int_ft->mapped_clock_class ||
+                               int_ft->meaning == CTF_FIELD_TYPE_MEANING_NONE ||
+                               bt_g_hash_table_contains(ft_dependents, ft)) {
+                       /*
+                        * Field type does not update a clock, has no
+                        * special meaning, and no sequence/variant
+                        * field type which is part of IR depends on it.
+                        */
+                       ft->in_ir = true;
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               /* Reverse order */
+               for (i = (int64_t) struct_ft->members->len - 1; i >= 0; i--) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_struct_borrow_member_by_index(
+                                       struct_ft, i);
+
+                       update_field_type_in_ir(named_ft->ft, ft_dependents);
+
+                       if (named_ft->ft->in_ir) {
+                               /* At least one member is part of IR */
+                               ft->in_ir = true;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_named_field_type *named_ft;
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               /*
+                * Reverse order, although it is not important for this
+                * loop because a field type within a variant field
+                * type's option cannot depend on a field type in
+                * another option of the same variant field type.
+                */
+               for (i = (int64_t) var_ft->options->len - 1; i >= 0; i--) {
+                       named_ft =
+                               ctf_field_type_variant_borrow_option_by_index(
+                                       var_ft, i);
+
+                       update_field_type_in_ir(named_ft->ft, ft_dependents);
+
+                       if (named_ft->ft->in_ir) {
+                               /* At least one option is part of IR */
+                               ft->in_ir = true;
+                       }
+               }
+
+               if (ft->in_ir) {
+                       /*
+                        * At least one option will make it to IR. In
+                        * this case, make all options part of IR
+                        * because the variant's tag could still select
+                        * (dynamically) a removed option. This can mean
+                        * having an empty structure as an option, for
+                        * example, but at least all the options are
+                        * selectable.
+                        */
+                       for (i = 0; i < var_ft->options->len; i++) {
+                               ctf_field_type_variant_borrow_option_by_index(
+                                       var_ft, i)->ft->in_ir = true;
+                       }
+
+                       /*
+                        * This variant field type is part of IR and
+                        * depends on a tag field type (which must also
+                        * be part of IR).
+                        */
+                       g_hash_table_insert(ft_dependents, var_ft->tag_ft,
+                               var_ft->tag_ft);
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_array_base *array_ft = (void *) ft;
+
+               update_field_type_in_ir(array_ft->elem_ft, ft_dependents);
+               ft->in_ir = array_ft->elem_ft->in_ir;
+
+               if (ft->id == CTF_FIELD_TYPE_ID_ARRAY) {
+                       struct ctf_field_type_array *arr_ft = (void *) ft;
+
+                       assert(arr_ft->meaning == CTF_FIELD_TYPE_MEANING_NONE ||
+                               arr_ft->meaning == CTF_FIELD_TYPE_MEANING_UUID);
+
+                       /*
+                        * UUID field type: nothing depends on this, so
+                        * it's not part of IR.
+                        */
+                       if (arr_ft->meaning == CTF_FIELD_TYPE_MEANING_UUID) {
+                               ft->in_ir = false;
+                               array_ft->elem_ft->in_ir = false;
+                       }
+               } else if (ft->id == CTF_FIELD_TYPE_ID_SEQUENCE) {
+                       if (ft->in_ir) {
+                               struct ctf_field_type_sequence *seq_ft = (void *) ft;
+
+                               /*
+                                * This sequence field type is part of
+                                * IR and depends on a length field type
+                                * (which must also be part of IR).
+                                */
+                               g_hash_table_insert(ft_dependents,
+                                       seq_ft->length_ft, seq_ft->length_ft);
+                       }
+               }
+
+               break;
+       }
+       default:
+               ft->in_ir = true;
+               break;
+       }
+
+end:
+       return;
+}
+
+/*
+ * Scopes and field types are processed in reverse order because we need
+ * to know if a given integer field type has dependents (sequence or
+ * variant field types) when we reach it. Dependents can only be located
+ * after the length/tag field type in the metadata tree.
+ */
+BT_HIDDEN
+int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       GHashTable *ft_dependents = g_hash_table_new(g_direct_hash,
+               g_direct_equal);
+
+       BT_ASSERT(ft_dependents);
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
+               uint64_t j;
+
+               for (j = 0; j < sc->event_classes->len; j++) {
+                       struct ctf_event_class *ec = sc->event_classes->pdata[j];
+
+                       if (ec->is_translated) {
+                               continue;
+                       }
+
+                       update_field_type_in_ir(ec->payload_ft, ft_dependents);
+                       update_field_type_in_ir(ec->spec_context_ft,
+                               ft_dependents);
+               }
+
+               if (!sc->is_translated) {
+                       update_field_type_in_ir(sc->event_common_context_ft,
+                               ft_dependents);
+                       update_field_type_in_ir(sc->event_header_ft,
+                               ft_dependents);
+                       update_field_type_in_ir(sc->packet_context_ft,
+                               ft_dependents);
+               }
+       }
+
+       if (!ctf_tc->is_translated) {
+               update_field_type_in_ir(ctf_tc->packet_header_ft,
+                       ft_dependents);
+       }
+
+       g_hash_table_destroy(ft_dependents);
+       return ret;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-meanings.c b/plugins/ctf/common/metadata/ctf-meta-update-meanings.c
new file mode 100644 (file)
index 0000000..075ac2d
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-MEANINGS"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static
+int set_int_field_type_meaning_by_name(struct ctf_field_type *ft,
+               const char *field_name, const char *id_name,
+               enum ctf_field_type_meaning meaning)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!ft) {
+               goto end;
+       }
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+       case CTF_FIELD_TYPE_ID_ENUM:
+       {
+               struct ctf_field_type_int *int_ft = (void *) ft;
+
+               if (field_name && strcmp(field_name, id_name) == 0) {
+                       int_ft->meaning = meaning;
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               for (i = 0; i < struct_ft->members->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_struct_borrow_member_by_index(
+                                       struct_ft, i);
+
+                       ret = set_int_field_type_meaning_by_name(named_ft->ft,
+                               named_ft->name->str, id_name, meaning);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               for (i = 0; i < var_ft->options->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_variant_borrow_option_by_index(
+                                       var_ft, i);
+
+                       ret = set_int_field_type_meaning_by_name(named_ft->ft,
+                               NULL, id_name, meaning);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_array_base *array_ft = (void *) ft;
+
+               ret = set_int_field_type_meaning_by_name(array_ft->elem_ft,
+                       NULL, id_name, meaning);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static
+int update_stream_class_meanings(struct ctf_stream_class *sc)
+{
+       int ret = 0;
+       struct ctf_field_type_int *int_ft;
+       uint64_t i;
+
+       if (!sc->is_translated) {
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) sc->packet_context_ft, "timestamp_begin");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_PACKET_BEGINNING_TIME;
+               }
+
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) sc->packet_context_ft, "timestamp_end");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_PACKET_END_TIME;
+
+                       /*
+                        * Remove mapped clock class to avoid updating
+                        * the clock immediately when decoding.
+                        */
+                       int_ft->mapped_clock_class = NULL;
+               }
+
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) sc->packet_context_ft, "events_discarded");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT;
+               }
+
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) sc->packet_context_ft, "packet_seq_num");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_PACKET_COUNTER_SNAPSHOT;
+
+               }
+
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) sc->packet_context_ft, "packet_size");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_EXP_PACKET_TOTAL_SIZE;
+               }
+
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) sc->packet_context_ft, "content_size");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_EXP_PACKET_CONTENT_SIZE;
+               }
+
+               ret = set_int_field_type_meaning_by_name(
+                       sc->event_header_ft, NULL, "id",
+                       CTF_FIELD_TYPE_MEANING_EVENT_CLASS_ID);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < sc->event_classes->len; i++) {
+               struct ctf_event_class *ec = sc->event_classes->pdata[i];
+
+               if (ec->is_translated) {
+                       continue;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       struct ctf_field_type_int *int_ft;
+       struct ctf_named_field_type *named_ft;
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) ctf_tc->packet_header_ft, "magic");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_MAGIC;
+               }
+
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) ctf_tc->packet_header_ft, "stream_id");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_STREAM_CLASS_ID;
+               }
+
+               int_ft = ctf_field_type_struct_borrow_member_int_field_type_by_name(
+                       (void *) ctf_tc->packet_header_ft,
+                       "stream_instance_id");
+               if (int_ft) {
+                       int_ft->meaning = CTF_FIELD_TYPE_MEANING_DATA_STREAM_ID;
+               }
+
+               named_ft = ctf_field_type_struct_borrow_member_by_name(
+                       (void *) ctf_tc->packet_header_ft, "uuid");
+               if (named_ft && named_ft->ft->id == CTF_FIELD_TYPE_ID_ARRAY) {
+                       struct ctf_field_type_array *array_ft =
+                               (void *) named_ft->ft;
+
+                       array_ft->meaning = CTF_FIELD_TYPE_MEANING_UUID;
+               }
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               ret = update_stream_class_meanings(
+                       ctf_tc->stream_classes->pdata[i]);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c b/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c
new file mode 100644 (file)
index 0000000..139f9bb
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-TEXT-ARRAY-SEQ"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static inline
+int set_text_array_sequence_field_type(struct ctf_field_type *ft)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!ft) {
+               goto end;
+       }
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               for (i = 0; i < struct_ft->members->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_struct_borrow_member_by_index(
+                                       struct_ft, i);
+
+                       ret = set_text_array_sequence_field_type(named_ft->ft);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               for (i = 0; i < var_ft->options->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_variant_borrow_option_by_index(
+                                       var_ft, i);
+
+                       ret = set_text_array_sequence_field_type(named_ft->ft);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_array_base *array_ft = (void *) ft;
+
+               if (array_ft->elem_ft->id == CTF_FIELD_TYPE_ID_INT ||
+                               array_ft->elem_ft->id == CTF_FIELD_TYPE_ID_ENUM) {
+                       struct ctf_field_type_int *int_ft =
+                               (void *) array_ft->elem_ft;
+
+                       if (int_ft->base.base.alignment == 8 &&
+                                       int_ft->base.size == 8 &&
+                                       int_ft->encoding == CTF_ENCODING_UTF8) {
+                               array_ft->is_text = true;
+
+                               /*
+                                * Force integer element to be unsigned;
+                                * this makes the decoder enter a single
+                                * path when reading a text
+                                * array/sequence and we can safely
+                                * decode bytes as characters anyway.
+                                */
+                               int_ft->is_signed = false;
+                       }
+               }
+
+               ret = set_text_array_sequence_field_type(array_ft->elem_ft);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               ret = set_text_array_sequence_field_type(
+                       ctf_tc->packet_header_ft);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
+               uint64_t j;
+
+               if (!sc->is_translated) {
+                       ret = set_text_array_sequence_field_type(
+                               sc->packet_context_ft);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       ret = set_text_array_sequence_field_type(
+                               sc->event_header_ft);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       ret = set_text_array_sequence_field_type(
+                               sc->event_common_context_ft);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               for (j = 0; j < sc->event_classes->len; j++) {
+                       struct ctf_event_class *ec =
+                               sc->event_classes->pdata[j];
+
+                       if (ec->is_translated) {
+                               continue;
+                       }
+
+                       ret = set_text_array_sequence_field_type(
+                               ec->spec_context_ft);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       ret = set_text_array_sequence_field_type(
+                               ec->payload_ft);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c b/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c
new file mode 100644 (file)
index 0000000..fe7c4ce
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-VALUE-STORING-INDEXES"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static
+int update_field_type_stored_value_index(struct ctf_field_type *ft,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       int ret = 0;
+       uint64_t i;
+       struct ctf_field_path *field_path = NULL;
+       struct ctf_field_type_int *tgt_ft = NULL;
+       uint64_t *stored_value_index = NULL;
+
+       if (!ft) {
+               goto end;
+       }
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               field_path = &var_ft->tag_path;
+               stored_value_index = &var_ft->stored_tag_index;
+               tgt_ft = (void *) var_ft->tag_ft;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_sequence *seq_ft = (void *) ft;
+
+               field_path = &seq_ft->length_path;
+               stored_value_index = &seq_ft->stored_length_index;
+               tgt_ft = seq_ft->length_ft;
+               break;
+       }
+       default:
+               break;
+       }
+
+       if (field_path) {
+               BT_ASSERT(tgt_ft);
+               BT_ASSERT(tgt_ft->base.base.id == CTF_FIELD_TYPE_ID_INT ||
+                       tgt_ft->base.base.id == CTF_FIELD_TYPE_ID_ENUM);
+               if (tgt_ft->storing_index >= 0) {
+                       /* Already storing its value */
+                       *stored_value_index = (uint64_t) tgt_ft->storing_index;
+               } else {
+                       /* Not storing its value: allocate new index */
+                       tgt_ft->storing_index = tc->stored_value_count;
+                       *stored_value_index = (uint64_t) tgt_ft->storing_index;
+                       tc->stored_value_count++;
+               }
+       }
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               for (i = 0; i < struct_ft->members->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_struct_borrow_member_by_index(
+                                       struct_ft, i);
+
+                       ret = update_field_type_stored_value_index(named_ft->ft,
+                               tc, sc, ec);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               for (i = 0; i < var_ft->options->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_variant_borrow_option_by_index(
+                                       var_ft, i);
+
+                       ret = update_field_type_stored_value_index(named_ft->ft,
+                               tc, sc, ec);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_array_base *array_ft = (void *) ft;
+
+               ret = update_field_type_stored_value_index(array_ft->elem_ft,
+                       tc, sc, ec);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc)
+{
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               update_field_type_stored_value_index(
+                       ctf_tc->packet_header_ft, ctf_tc, NULL, NULL);
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               uint64_t j;
+               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
+
+               if (!sc->is_translated) {
+                       update_field_type_stored_value_index(sc->packet_context_ft,
+                               ctf_tc, sc, NULL);
+                       update_field_type_stored_value_index(sc->event_header_ft,
+                               ctf_tc, sc, NULL);
+                       update_field_type_stored_value_index(
+                               sc->event_common_context_ft, ctf_tc, sc, NULL);
+               }
+
+               for (j = 0; j < sc->event_classes->len; j++) {
+                       struct ctf_event_class *ec =
+                               sc->event_classes->pdata[j];
+
+                       if (!ec->is_translated) {
+                               update_field_type_stored_value_index(
+                                       ec->spec_context_ft, ctf_tc, sc, ec);
+                               update_field_type_stored_value_index(
+                                       ec->payload_ft, ctf_tc, sc, ec);
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-validate.c b/plugins/ctf/common/metadata/ctf-meta-validate.c
new file mode 100644 (file)
index 0000000..4898390
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-VALIDATE"
+#include "logging.h"
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static
+int validate_stream_class(struct ctf_stream_class *sc)
+{
+       int ret = 0;
+       struct ctf_field_type_int *int_ft;
+       struct ctf_field_type *ft;
+       bool has_total_size = false;
+       bool has_content_size = false;
+
+       if (sc->is_translated) {
+               goto end;
+       }
+
+       ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+               (void *) sc->packet_context_ft, "timestamp_begin");
+       if (ft) {
+               if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`timestamp_begin` member is not an integer field type.");
+                       goto invalid;
+               }
+
+               int_ft = (void *) ft;
+
+               if (int_ft->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`timestamp_begin` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+               (void *) sc->packet_context_ft, "timestamp_end");
+       if (ft) {
+               if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`timestamp_end` member is not an integer field type.");
+                       goto invalid;
+               }
+
+               int_ft = (void *) ft;
+
+               if (int_ft->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`timestamp_end` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+               (void *) sc->packet_context_ft, "events_discarded");
+       if (ft) {
+               if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`events_discarded` member is not an integer field type.");
+                       goto invalid;
+               }
+
+               int_ft = (void *) ft;
+
+               if (int_ft->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`events_discarded` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+               (void *) sc->packet_context_ft, "packet_seq_num");
+       if (ft) {
+               if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`packet_seq_num` member is not an integer field type.");
+                       goto invalid;
+               }
+
+               int_ft = (void *) ft;
+
+               if (int_ft->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`packet_seq_num` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+               (void *) sc->packet_context_ft, "packet_size");
+       if (ft) {
+               if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`packet_size` member is not an integer field type.");
+                       goto invalid;
+               }
+
+               int_ft = (void *) ft;
+
+               if (int_ft->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`packet_size` member is signed.");
+                       goto invalid;
+               }
+
+               has_total_size = true;
+       }
+
+       ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+               (void *) sc->packet_context_ft, "content_size");
+       if (ft) {
+               if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`content_size` member is not an integer field type.");
+                       goto invalid;
+               }
+
+               int_ft = (void *) ft;
+
+               if (int_ft->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`content_size` member is signed.");
+                       goto invalid;
+               }
+
+               has_content_size = true;
+       }
+
+       if (has_content_size && !has_total_size) {
+                       BT_LOGE_STR("Invalid packet context field type: "
+                               "`content_size` member exists without "
+                               "`packet_size` member.");
+                       goto invalid;
+       }
+
+       ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+               (void *) sc->event_header_ft, "id");
+       if (ft) {
+               if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGE_STR("Invalid event header field type: "
+                               "`id` member is not an integer field type.");
+                       goto invalid;
+               }
+
+               int_ft = (void *) ft;
+
+               if (int_ft->is_signed) {
+                       BT_LOGE_STR("Invalid event header field type: "
+                               "`id` member is signed.");
+                       goto invalid;
+               }
+       } else {
+               if (sc->event_classes->len > 1) {
+                       BT_LOGE_STR("Invalid event header field type: "
+                               "missing `id` member as there's "
+                               "more than one event class.");
+                       goto invalid;
+               }
+       }
+
+       goto end;
+
+invalid:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       struct ctf_field_type_int *int_ft;
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               struct ctf_field_type *ft;
+
+               ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+                       (void *) ctf_tc->packet_header_ft, "magic");
+               if (ft) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_struct_borrow_member_by_index(
+                                       (void *) ctf_tc->packet_header_ft,
+                                       0);
+
+                       if (named_ft->ft != ft) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`magic` member is not the first member.");
+                               goto invalid;
+                       }
+
+                       if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                                       ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`magic` member is not an integer field type.");
+                               goto invalid;
+                       }
+
+                       int_ft = (void *) ft;
+
+                       if (int_ft->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`magic` member is signed.");
+                               goto invalid;
+                       }
+
+                       if (int_ft->base.size != 32) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`magic` member is not 32-bit.");
+                               goto invalid;
+                       }
+               }
+
+               ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+                       (void *) ctf_tc->packet_header_ft, "stream_id");
+               if (ft) {
+                       if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                                       ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`stream_id` member is not an integer field type.");
+                               goto invalid;
+                       }
+
+                       int_ft = (void *) ft;
+
+                       if (int_ft->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`stream_id` member is signed.");
+                               goto invalid;
+                       }
+               } else {
+                       if (ctf_tc->stream_classes->len > 1) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "missing `stream_id` member as there's "
+                                       "more than one stream class.");
+                               goto invalid;
+                       }
+               }
+
+               ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+                       (void *) ctf_tc->packet_header_ft,
+                       "stream_instance_id");
+               if (ft) {
+                       if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                                       ft->id != CTF_FIELD_TYPE_ID_ENUM) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`stream_instance_id` member is not an integer field type.");
+                               goto invalid;
+                       }
+
+                       int_ft = (void *) ft;
+
+                       if (int_ft->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`stream_instance_id` member is signed.");
+                               goto invalid;
+                       }
+               }
+
+               ft = ctf_field_type_struct_borrow_member_field_type_by_name(
+                       (void *) ctf_tc->packet_header_ft, "uuid");
+               if (ft) {
+                       struct ctf_field_type_array *array_ft = (void *) ft;
+
+                       if (ft->id != CTF_FIELD_TYPE_ID_ARRAY) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`uuid` member is not an array field type.");
+                               goto invalid;
+                       }
+
+                       array_ft = (void *) ft;
+
+                       if (array_ft->length != 16) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`uuid` member is not a 16-element array field type.");
+                               goto invalid;
+                       }
+
+                       if (array_ft->base.elem_ft->id != CTF_FIELD_TYPE_ID_INT) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`uuid` member's element field type is not "
+                                       "an integer field type.");
+                               goto invalid;
+                       }
+
+                       int_ft = (void *) array_ft->base.elem_ft;
+
+                       if (int_ft->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`uuid` member's element field type "
+                                       "is a signed integer field type.");
+                               goto invalid;
+                       }
+
+                       if (int_ft->base.size != 8) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`uuid` member's element field type "
+                                       "is not an 8-bit integer field type.");
+                               goto invalid;
+                       }
+
+                       if (int_ft->base.base.alignment != 8) {
+                               BT_LOGE_STR("Invalid packet header field type: "
+                                       "`uuid` member's element field type's "
+                                       "alignment is not 8.");
+                               goto invalid;
+                       }
+               }
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc =
+                       ctf_tc->stream_classes->pdata[i];
+
+               ret = validate_stream_class(sc);
+               if (ret) {
+                       BT_LOGE("Invalid stream class: sc-id=%" PRIu64, sc->id);
+                       goto invalid;
+               }
+       }
+
+       goto end;
+
+invalid:
+       ret = -1;
+
+end:
+       return ret;
+}
diff --git a/plugins/ctf/common/metadata/ctf-meta-visitors.h b/plugins/ctf/common/metadata/ctf-meta-visitors.h
new file mode 100644 (file)
index 0000000..cb1e3f8
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _CTF_META_VISITORS_H
+#define _CTF_META_VISITORS_H
+
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
+
+#include "ctf-meta.h"
+
+BT_HIDDEN
+int ctf_trace_class_resolve_field_types(struct ctf_trace_class *tc);
+
+BT_HIDDEN
+int ctf_trace_class_translate(struct bt_trace *ir_trace,
+               struct ctf_trace_class *tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_default_clock_classes(
+               struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc);
+
+#endif /* _CTF_META_VISITORS_H */
diff --git a/plugins/ctf/common/metadata/ctf-meta.h b/plugins/ctf/common/metadata/ctf-meta.h
new file mode 100644 (file)
index 0000000..f7c04c2
--- /dev/null
@@ -0,0 +1,1609 @@
+#ifndef _CTF_META_H
+#define _CTF_META_H
+
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/common-internal.h>
+#include <babeltrace/assert-internal.h>
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+
+enum ctf_field_type_id {
+       CTF_FIELD_TYPE_ID_INT,
+       CTF_FIELD_TYPE_ID_ENUM,
+       CTF_FIELD_TYPE_ID_FLOAT,
+       CTF_FIELD_TYPE_ID_STRING,
+       CTF_FIELD_TYPE_ID_STRUCT,
+       CTF_FIELD_TYPE_ID_ARRAY,
+       CTF_FIELD_TYPE_ID_SEQUENCE,
+       CTF_FIELD_TYPE_ID_VARIANT,
+};
+
+enum ctf_field_type_meaning {
+       CTF_FIELD_TYPE_MEANING_NONE,
+       CTF_FIELD_TYPE_MEANING_PACKET_BEGINNING_TIME,
+       CTF_FIELD_TYPE_MEANING_PACKET_END_TIME,
+       CTF_FIELD_TYPE_MEANING_EVENT_CLASS_ID,
+       CTF_FIELD_TYPE_MEANING_STREAM_CLASS_ID,
+       CTF_FIELD_TYPE_MEANING_DATA_STREAM_ID,
+       CTF_FIELD_TYPE_MEANING_MAGIC,
+       CTF_FIELD_TYPE_MEANING_PACKET_COUNTER_SNAPSHOT,
+       CTF_FIELD_TYPE_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT,
+       CTF_FIELD_TYPE_MEANING_EXP_PACKET_TOTAL_SIZE,
+       CTF_FIELD_TYPE_MEANING_EXP_PACKET_CONTENT_SIZE,
+       CTF_FIELD_TYPE_MEANING_UUID,
+};
+
+enum ctf_byte_order {
+       CTF_BYTE_ORDER_DEFAULT,
+       CTF_BYTE_ORDER_LITTLE,
+       CTF_BYTE_ORDER_BIG,
+};
+
+enum ctf_encoding {
+       CTF_ENCODING_NONE,
+       CTF_ENCODING_UTF8,
+};
+
+struct ctf_field_type {
+       enum ctf_field_type_id id;
+       unsigned int alignment;
+       bool is_compound;
+       bool in_ir;
+
+       /* Weak, set during translation. NULL if `in_ir` is false below. */
+       struct bt_field_type *ir_ft;
+};
+
+struct ctf_field_type_bit_array {
+       struct ctf_field_type base;
+       enum ctf_byte_order byte_order;
+       unsigned int size;
+};
+
+struct ctf_field_type_int {
+       struct ctf_field_type_bit_array base;
+       enum ctf_field_type_meaning meaning;
+       bool is_signed;
+       enum bt_field_type_integer_preferred_display_base disp_base;
+       enum ctf_encoding encoding;
+       int64_t storing_index;
+
+       /* Owned by this */
+       struct bt_clock_class *mapped_clock_class;
+};
+
+struct ctf_range {
+       union {
+               uint64_t u;
+               int64_t i;
+       } lower;
+
+       union {
+               uint64_t u;
+               int64_t i;
+       } upper;
+};
+
+struct ctf_field_type_enum_mapping {
+       GString *label;
+       struct ctf_range range;
+};
+
+struct ctf_field_type_enum {
+       struct ctf_field_type_int base;
+
+       /* Array of `struct ctf_field_type_enum_mapping` */
+       GArray *mappings;
+};
+
+struct ctf_field_type_float {
+       struct ctf_field_type_bit_array base;
+};
+
+struct ctf_field_type_string {
+       struct ctf_field_type base;
+       enum ctf_encoding encoding;
+};
+
+struct ctf_named_field_type {
+       GString *name;
+
+       /* Owned by this */
+       struct ctf_field_type *ft;
+};
+
+struct ctf_field_type_struct {
+       struct ctf_field_type base;
+
+       /* Array of `struct ctf_named_field_type` */
+       GArray *members;
+};
+
+struct ctf_field_path {
+       enum bt_scope root;
+
+       /* Array of `int64_t` */
+       GArray *path;
+};
+
+struct ctf_field_type_variant_range {
+       struct ctf_range range;
+       uint64_t option_index;
+};
+
+struct ctf_field_type_variant {
+       struct ctf_field_type base;
+       GString *tag_ref;
+       struct ctf_field_path tag_path;
+       uint64_t stored_tag_index;
+
+       /* Array of `struct ctf_named_field_type` */
+       GArray *options;
+
+       /* Array of `struct ctf_field_type_variant_range` */
+       GArray *ranges;
+
+       /* Weak */
+       struct ctf_field_type_enum *tag_ft;
+};
+
+struct ctf_field_type_array_base {
+       struct ctf_field_type base;
+       struct ctf_field_type *elem_ft;
+       bool is_text;
+};
+
+struct ctf_field_type_array {
+       struct ctf_field_type_array_base base;
+       enum ctf_field_type_meaning meaning;
+       uint64_t length;
+};
+
+struct ctf_field_type_sequence {
+       struct ctf_field_type_array_base base;
+       GString *length_ref;
+       struct ctf_field_path length_path;
+       uint64_t stored_length_index;
+
+       /* Weak */
+       struct ctf_field_type_int *length_ft;
+};
+
+struct ctf_event_class {
+       GString *name;
+       uint64_t id;
+       GString *emf_uri;
+       enum bt_event_class_log_level log_level;
+       bool is_translated;
+
+       /* Owned by this */
+       struct ctf_field_type *spec_context_ft;
+
+       /* Owned by this */
+       struct ctf_field_type *payload_ft;
+
+       /* Weak, set during translation */
+       struct bt_event_class *ir_ec;
+};
+
+struct ctf_stream_class {
+       uint64_t id;
+       bool is_translated;
+
+       /* Owned by this */
+       struct ctf_field_type *packet_context_ft;
+
+       /* Owned by this */
+       struct ctf_field_type *event_header_ft;
+
+       /* Owned by this */
+       struct ctf_field_type *event_common_context_ft;
+
+       /* Array of `struct ctf_event_class *`, owned by this */
+       GPtrArray *event_classes;
+
+       /*
+        * Hash table mapping event class IDs to `struct ctf_event_class *`,
+        * weak.
+        */
+       GHashTable *event_classes_by_id;
+
+       /* Owned by this */
+       struct bt_clock_class *default_clock_class;
+
+       /* Weak, set during translation */
+       struct bt_stream_class *ir_sc;
+};
+
+enum ctf_trace_class_env_entry_type {
+       CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT,
+       CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR,
+};
+
+struct ctf_trace_class_env_entry {
+       enum ctf_trace_class_env_entry_type type;
+       GString *name;
+
+       struct {
+               int64_t i;
+               GString *str;
+       } value;
+};
+
+struct ctf_trace_class {
+       GString *name;
+       unsigned int major;
+       unsigned int minor;
+       uint8_t uuid[16];
+       bool is_uuid_set;
+       enum ctf_byte_order default_byte_order;
+
+       /* Owned by this */
+       struct ctf_field_type *packet_header_ft;
+
+       uint64_t stored_value_count;
+
+       /* Array of `struct bt_clock_class *` (owned by this) */
+       GPtrArray *clock_classes;
+
+       /* Array of `struct ctf_stream_class *` */
+       GPtrArray *stream_classes;
+
+       /* Array of `struct ctf_trace_class_env_entry` */
+       GArray *env_entries;
+
+       bool is_translated;
+
+       /* Weak, set during translation */
+       struct bt_trace *ir_tc;
+};
+
+static inline
+void ctf_field_type_destroy(struct ctf_field_type *ft);
+
+static inline
+void _ctf_field_type_init(struct ctf_field_type *ft, enum ctf_field_type_id id,
+               unsigned int alignment)
+{
+       BT_ASSERT(ft);
+       ft->id = id;
+       ft->alignment = alignment;
+       ft->in_ir = false;
+}
+
+static inline
+void _ctf_field_type_bit_array_init(struct ctf_field_type_bit_array *ft,
+               enum ctf_field_type_id id)
+{
+       _ctf_field_type_init((void *) ft, id, 1);
+}
+
+static inline
+void _ctf_field_type_int_init(struct ctf_field_type_int *ft,
+               enum ctf_field_type_id id)
+{
+       _ctf_field_type_bit_array_init((void *) ft, id);
+       ft->meaning = CTF_FIELD_TYPE_MEANING_NONE;
+       ft->storing_index = -1;
+}
+
+static inline
+void ctf_field_path_init(struct ctf_field_path *field_path)
+{
+       BT_ASSERT(field_path);
+       field_path->path = g_array_new(FALSE, TRUE, sizeof(int64_t));
+       BT_ASSERT(field_path->path);
+}
+
+static inline
+void ctf_field_path_fini(struct ctf_field_path *field_path)
+{
+       BT_ASSERT(field_path);
+
+       if (field_path->path) {
+               g_array_free(field_path->path, TRUE);
+       }
+}
+
+static inline
+void _ctf_named_field_type_init(struct ctf_named_field_type *named_ft)
+{
+       BT_ASSERT(named_ft);
+       named_ft->name = g_string_new(NULL);
+       BT_ASSERT(named_ft->name);
+}
+
+static inline
+void _ctf_named_field_type_fini(struct ctf_named_field_type *named_ft)
+{
+       BT_ASSERT(named_ft);
+
+       if (named_ft->name) {
+               g_string_free(named_ft->name, TRUE);
+       }
+
+       ctf_field_type_destroy(named_ft->ft);
+}
+
+static inline
+void _ctf_field_type_enum_mapping_init(
+               struct ctf_field_type_enum_mapping *mapping)
+{
+       BT_ASSERT(mapping);
+       mapping->label = g_string_new(NULL);
+       BT_ASSERT(mapping->label);
+}
+
+static inline
+void _ctf_field_type_enum_mapping_fini(
+               struct ctf_field_type_enum_mapping *mapping)
+{
+       BT_ASSERT(mapping);
+
+       if (mapping->label) {
+               g_string_free(mapping->label, TRUE);
+       }
+}
+
+static inline
+struct ctf_field_type_int *ctf_field_type_int_create(void)
+{
+       struct ctf_field_type_int *ft = g_new0(struct ctf_field_type_int, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_int_init(ft, CTF_FIELD_TYPE_ID_INT);
+       return ft;
+}
+
+static inline
+struct ctf_field_type_float *ctf_field_type_float_create(void)
+{
+       struct ctf_field_type_float *ft =
+               g_new0(struct ctf_field_type_float, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_bit_array_init((void *) ft, CTF_FIELD_TYPE_ID_FLOAT);
+       return ft;
+}
+
+static inline
+struct ctf_field_type_string *ctf_field_type_string_create(void)
+{
+       struct ctf_field_type_string *ft =
+               g_new0(struct ctf_field_type_string, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_init((void *) ft, CTF_FIELD_TYPE_ID_STRING, 8);
+       return ft;
+}
+
+static inline
+struct ctf_field_type_enum *ctf_field_type_enum_create(void)
+{
+       struct ctf_field_type_enum *ft = g_new0(struct ctf_field_type_enum, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_int_init((void *) ft, CTF_FIELD_TYPE_ID_ENUM);
+       ft->mappings = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_field_type_enum_mapping));
+       BT_ASSERT(ft->mappings);
+       return ft;
+}
+
+static inline
+struct ctf_field_type_struct *ctf_field_type_struct_create(void)
+{
+       struct ctf_field_type_struct *ft =
+               g_new0(struct ctf_field_type_struct, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_init((void *) ft, CTF_FIELD_TYPE_ID_STRUCT, 1);
+       ft->members = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_named_field_type));
+       BT_ASSERT(ft->members);
+       ft->base.is_compound = true;
+       return ft;
+}
+
+static inline
+struct ctf_field_type_variant *ctf_field_type_variant_create(void)
+{
+       struct ctf_field_type_variant *ft =
+               g_new0(struct ctf_field_type_variant, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_init((void *) ft, CTF_FIELD_TYPE_ID_VARIANT, 1);
+       ft->options = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_named_field_type));
+       BT_ASSERT(ft->options);
+       ft->ranges = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_field_type_variant_range));
+       BT_ASSERT(ft->ranges);
+       ft->tag_ref = g_string_new(NULL);
+       BT_ASSERT(ft->tag_ref);
+       ctf_field_path_init(&ft->tag_path);
+       ft->base.is_compound = true;
+       return ft;
+}
+
+static inline
+struct ctf_field_type_array *ctf_field_type_array_create(void)
+{
+       struct ctf_field_type_array *ft =
+               g_new0(struct ctf_field_type_array, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_init((void *) ft, CTF_FIELD_TYPE_ID_ARRAY, 1);
+       ft->base.base.is_compound = true;
+       return ft;
+}
+
+static inline
+struct ctf_field_type_sequence *ctf_field_type_sequence_create(void)
+{
+       struct ctf_field_type_sequence *ft =
+               g_new0(struct ctf_field_type_sequence, 1);
+
+       BT_ASSERT(ft);
+       _ctf_field_type_init((void *) ft, CTF_FIELD_TYPE_ID_SEQUENCE, 1);
+       ft->length_ref = g_string_new(NULL);
+       BT_ASSERT(ft->length_ref);
+       ctf_field_path_init(&ft->length_path);
+       ft->base.base.is_compound = true;
+       return ft;
+}
+
+static inline
+void _ctf_field_type_int_destroy(struct ctf_field_type_int *ft)
+{
+       BT_ASSERT(ft);
+       bt_put(ft->mapped_clock_class);
+       g_free(ft);
+}
+
+static inline
+void _ctf_field_type_enum_destroy(struct ctf_field_type_enum *ft)
+{
+       BT_ASSERT(ft);
+       bt_put(ft->base.mapped_clock_class);
+
+       if (ft->mappings) {
+               uint64_t i;
+
+               for (i = 0; i < ft->mappings->len; i++) {
+                       struct ctf_field_type_enum_mapping *mapping =
+                               &g_array_index(ft->mappings,
+                                       struct ctf_field_type_enum_mapping, i);
+
+                       _ctf_field_type_enum_mapping_fini(mapping);
+               }
+
+               g_array_free(ft->mappings, TRUE);
+       }
+
+       g_free(ft);
+}
+
+static inline
+void _ctf_field_type_float_destroy(struct ctf_field_type_float *ft)
+{
+       BT_ASSERT(ft);
+       g_free(ft);
+}
+
+static inline
+void _ctf_field_type_string_destroy(struct ctf_field_type_string *ft)
+{
+       BT_ASSERT(ft);
+       g_free(ft);
+}
+
+static inline
+void _ctf_field_type_struct_destroy(struct ctf_field_type_struct *ft)
+{
+       BT_ASSERT(ft);
+
+       if (ft->members) {
+               uint64_t i;
+
+               for (i = 0; i < ft->members->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               &g_array_index(ft->members,
+                                       struct ctf_named_field_type, i);
+
+                       _ctf_named_field_type_fini(named_ft);
+               }
+
+               g_array_free(ft->members, TRUE);
+       }
+
+       g_free(ft);
+}
+
+static inline
+void _ctf_field_type_array_base_fini(struct ctf_field_type_array_base *ft)
+{
+       BT_ASSERT(ft);
+       ctf_field_type_destroy(ft->elem_ft);
+}
+
+static inline
+void _ctf_field_type_array_destroy(struct ctf_field_type_array *ft)
+{
+       BT_ASSERT(ft);
+       _ctf_field_type_array_base_fini((void *) ft);
+       g_free(ft);
+}
+
+static inline
+void _ctf_field_type_sequence_destroy(struct ctf_field_type_sequence *ft)
+{
+       BT_ASSERT(ft);
+       _ctf_field_type_array_base_fini((void *) ft);
+
+       if (ft->length_ref) {
+               g_string_free(ft->length_ref, TRUE);
+       }
+
+       ctf_field_path_fini(&ft->length_path);
+       g_free(ft);
+}
+
+static inline
+void _ctf_field_type_variant_destroy(struct ctf_field_type_variant *ft)
+{
+       BT_ASSERT(ft);
+
+       if (ft->options) {
+               uint64_t i;
+
+               for (i = 0; i < ft->options->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               &g_array_index(ft->options,
+                                       struct ctf_named_field_type, i);
+
+                       _ctf_named_field_type_fini(named_ft);
+               }
+
+               g_array_free(ft->options, TRUE);
+       }
+
+       if (ft->ranges) {
+               g_array_free(ft->ranges, TRUE);
+       }
+
+       if (ft->tag_ref) {
+               g_string_free(ft->tag_ref, TRUE);
+       }
+
+       ctf_field_path_fini(&ft->tag_path);
+       g_free(ft);
+}
+
+static inline
+void ctf_field_type_destroy(struct ctf_field_type *ft)
+{
+       if (!ft) {
+               return;
+       }
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+               _ctf_field_type_int_destroy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_ENUM:
+               _ctf_field_type_enum_destroy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_FLOAT:
+               _ctf_field_type_float_destroy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_STRING:
+               _ctf_field_type_string_destroy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_STRUCT:
+               _ctf_field_type_struct_destroy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_ARRAY:
+               _ctf_field_type_array_destroy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+               _ctf_field_type_sequence_destroy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_VARIANT:
+               _ctf_field_type_variant_destroy((void *) ft);
+               break;
+       default:
+               abort();
+       }
+}
+
+static inline
+void ctf_field_type_enum_append_mapping(struct ctf_field_type_enum *ft,
+               const char *label, uint64_t u_lower, uint64_t u_upper)
+{
+       struct ctf_field_type_enum_mapping *mapping;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(label);
+       g_array_set_size(ft->mappings, ft->mappings->len + 1);
+
+       mapping = &g_array_index(ft->mappings,
+               struct ctf_field_type_enum_mapping, ft->mappings->len - 1);
+       _ctf_field_type_enum_mapping_init(mapping);
+       g_string_assign(mapping->label, label);
+       mapping->range.lower.u = u_lower;
+       mapping->range.upper.u = u_upper;
+}
+
+static inline
+struct ctf_field_type_enum_mapping *ctf_field_type_enum_borrow_mapping_by_index(
+               struct ctf_field_type_enum *ft, uint64_t index)
+{
+       BT_ASSERT(ft);
+       BT_ASSERT(index < ft->mappings->len);
+       return &g_array_index(ft->mappings, struct ctf_field_type_enum_mapping,
+               index);
+}
+
+static inline
+struct ctf_named_field_type *ctf_field_type_struct_borrow_member_by_index(
+               struct ctf_field_type_struct *ft, uint64_t index)
+{
+       BT_ASSERT(ft);
+       BT_ASSERT(index < ft->members->len);
+       return &g_array_index(ft->members, struct ctf_named_field_type,
+               index);
+}
+
+static inline
+struct ctf_named_field_type *ctf_field_type_struct_borrow_member_by_name(
+               struct ctf_field_type_struct *ft, const char *name)
+{
+       uint64_t i;
+       struct ctf_named_field_type *ret_named_ft = NULL;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(name);
+
+       for (i = 0; i < ft->members->len; i++) {
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_struct_borrow_member_by_index(ft, i);
+
+               if (strcmp(name, named_ft->name->str) == 0) {
+                       ret_named_ft = named_ft;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_named_ft;
+}
+
+static inline
+struct ctf_field_type *ctf_field_type_struct_borrow_member_field_type_by_name(
+               struct ctf_field_type_struct *struct_ft, const char *name)
+{
+       struct ctf_named_field_type *named_ft = NULL;
+       struct ctf_field_type *ft = NULL;
+
+       if (!struct_ft) {
+               goto end;
+       }
+
+       named_ft = ctf_field_type_struct_borrow_member_by_name(struct_ft, name);
+       if (!named_ft) {
+               goto end;
+       }
+
+       ft = named_ft->ft;
+
+end:
+       return ft;
+}
+
+static inline
+struct ctf_field_type_int *
+ctf_field_type_struct_borrow_member_int_field_type_by_name(
+               struct ctf_field_type_struct *struct_ft, const char *name)
+{
+       struct ctf_field_type_int *int_ft = NULL;
+
+       int_ft = (void *)
+               ctf_field_type_struct_borrow_member_field_type_by_name(
+                       struct_ft, name);
+       if (!int_ft) {
+               goto end;
+       }
+
+       if (int_ft->base.base.id != CTF_FIELD_TYPE_ID_INT &&
+                       int_ft->base.base.id != CTF_FIELD_TYPE_ID_ENUM) {
+               int_ft = NULL;
+               goto end;
+       }
+
+end:
+       return int_ft;
+}
+
+
+static inline
+void ctf_field_type_struct_append_member(struct ctf_field_type_struct *ft,
+               const char *name, struct ctf_field_type *member_ft)
+{
+       struct ctf_named_field_type *named_ft;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(name);
+       g_array_set_size(ft->members, ft->members->len + 1);
+
+       named_ft = &g_array_index(ft->members, struct ctf_named_field_type,
+               ft->members->len - 1);
+       _ctf_named_field_type_init(named_ft);
+       g_string_assign(named_ft->name, name);
+       named_ft->ft = member_ft;
+
+       if (member_ft->alignment > ft->base.alignment) {
+               ft->base.alignment = member_ft->alignment;
+       }
+}
+
+static inline
+struct ctf_named_field_type *ctf_field_type_variant_borrow_option_by_index(
+               struct ctf_field_type_variant *ft, uint64_t index)
+{
+       BT_ASSERT(ft);
+       BT_ASSERT(index < ft->options->len);
+       return &g_array_index(ft->options, struct ctf_named_field_type,
+               index);
+}
+
+static inline
+struct ctf_named_field_type *ctf_field_type_variant_borrow_option_by_name(
+               struct ctf_field_type_variant *ft, const char *name)
+{
+       uint64_t i;
+       struct ctf_named_field_type *ret_named_ft = NULL;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(name);
+
+       for (i = 0; i < ft->options->len; i++) {
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_variant_borrow_option_by_index(ft, i);
+
+               if (strcmp(name, named_ft->name->str) == 0) {
+                       ret_named_ft = named_ft;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_named_ft;
+}
+
+static inline
+struct ctf_field_type_variant_range *
+ctf_field_type_variant_borrow_range_by_index(
+               struct ctf_field_type_variant *ft, uint64_t index)
+{
+       BT_ASSERT(ft);
+       BT_ASSERT(index < ft->ranges->len);
+       return &g_array_index(ft->ranges, struct ctf_field_type_variant_range,
+               index);
+}
+
+static inline
+void ctf_field_type_variant_append_option(struct ctf_field_type_variant *ft,
+               const char *name, struct ctf_field_type *option_ft)
+{
+       struct ctf_named_field_type *named_ft;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(name);
+       g_array_set_size(ft->options, ft->options->len + 1);
+
+       named_ft = &g_array_index(ft->options, struct ctf_named_field_type,
+               ft->options->len - 1);
+       _ctf_named_field_type_init(named_ft);
+       g_string_assign(named_ft->name, name);
+       named_ft->ft = option_ft;
+}
+
+static inline
+void ctf_field_type_variant_set_tag_field_type(
+               struct ctf_field_type_variant *ft,
+               struct ctf_field_type_enum *tag_ft)
+{
+       uint64_t option_i;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(tag_ft);
+       ft->tag_ft = tag_ft;
+
+       for (option_i = 0; option_i < ft->options->len; option_i++) {
+               uint64_t mapping_i;
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_variant_borrow_option_by_index(
+                               ft, option_i);
+
+               for (mapping_i = 0; mapping_i < tag_ft->mappings->len;
+                               mapping_i++) {
+                       struct ctf_field_type_enum_mapping *mapping =
+                               ctf_field_type_enum_borrow_mapping_by_index(
+                                       tag_ft, mapping_i);
+
+                       if (strcmp(named_ft->name->str,
+                                       mapping->label->str) == 0) {
+                               struct ctf_field_type_variant_range range;
+
+                               range.range = mapping->range;
+                               range.option_index = option_i;
+                               g_array_append_val(ft->ranges, range);
+                       }
+               }
+       }
+}
+
+static inline
+struct ctf_field_type *ctf_field_type_compound_borrow_field_type_by_index(
+               struct ctf_field_type *comp_ft, uint64_t index)
+{
+       struct ctf_field_type *ft = NULL;
+
+       switch (comp_ft->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_struct_borrow_member_by_index(
+                               (void *) comp_ft, index);
+
+               BT_ASSERT(named_ft);
+               ft = named_ft->ft;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_named_field_type *named_ft =
+                       ctf_field_type_variant_borrow_option_by_index(
+                               (void *) comp_ft, index);
+
+               BT_ASSERT(named_ft);
+               ft = named_ft->ft;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct ctf_field_type_array_base *array_ft = (void *) comp_ft;
+
+               ft = array_ft->elem_ft;
+               break;
+       }
+       default:
+               break;
+       }
+
+       return ft;
+}
+
+static inline
+uint64_t ctf_field_type_compound_get_field_type_count(struct ctf_field_type *ft)
+{
+       uint64_t field_count;
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               field_count = struct_ft->members->len;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               field_count = var_ft->options->len;
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_ARRAY:
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+               /*
+                * Array and sequence types always contain a single
+                * member (the element type).
+                */
+               field_count = 1;
+               break;
+       default:
+               abort();
+       }
+
+       return field_count;
+}
+
+static inline
+int64_t ctf_field_type_compound_get_field_type_index_from_name(
+               struct ctf_field_type *ft, const char *name)
+{
+       int64_t ret_index = -1;
+       uint64_t i;
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               struct ctf_field_type_struct *struct_ft = (void *) ft;
+
+               for (i = 0; i < struct_ft->members->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_struct_borrow_member_by_index(
+                                       struct_ft, i);
+
+                       if (strcmp(name, named_ft->name->str) == 0) {
+                               ret_index = (int64_t) i;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct ctf_field_type_variant *var_ft = (void *) ft;
+
+               for (i = 0; i < var_ft->options->len; i++) {
+                       struct ctf_named_field_type *named_ft =
+                               ctf_field_type_variant_borrow_option_by_index(
+                                       var_ft, i);
+
+                       if (strcmp(name, named_ft->name->str) == 0) {
+                               ret_index = (int64_t) i;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret_index;
+}
+
+static inline
+void ctf_field_path_append_index(struct ctf_field_path *fp, int64_t index)
+{
+       BT_ASSERT(fp);
+       g_array_append_val(fp->path, index);
+}
+
+static inline
+int64_t ctf_field_path_borrow_index_by_index(struct ctf_field_path *fp,
+               uint64_t index)
+{
+       BT_ASSERT(fp);
+       BT_ASSERT(index < fp->path->len);
+       return g_array_index(fp->path, int64_t, index);
+}
+
+static inline
+void ctf_field_path_clear(struct ctf_field_path *fp)
+{
+       BT_ASSERT(fp);
+       g_array_set_size(fp->path, 0);
+}
+
+static inline
+GString *ctf_field_path_string(struct ctf_field_path *path)
+{
+       GString *str = g_string_new(NULL);
+       uint64_t i;
+
+       BT_ASSERT(path);
+
+       if (!str) {
+               goto end;
+       }
+
+       g_string_append_printf(str, "[%s", bt_common_scope_string(
+               path->root));
+
+       for (i = 0; i < path->path->len; i++) {
+               g_string_append_printf(str, ", %" PRId64,
+                       ctf_field_path_borrow_index_by_index(path, i));
+       }
+
+       g_string_append(str, "]");
+
+end:
+       return str;
+}
+
+static inline
+struct ctf_field_type *ctf_field_path_borrow_field_type(
+               struct ctf_field_path *field_path,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       uint64_t i;
+       struct ctf_field_type *ft;
+
+       switch (field_path->root) {
+       case BT_SCOPE_PACKET_HEADER:
+               ft = tc->packet_header_ft;
+               break;
+       case BT_SCOPE_PACKET_CONTEXT:
+               ft = sc->packet_context_ft;
+               break;
+       case BT_SCOPE_EVENT_HEADER:
+               ft = sc->event_header_ft;
+               break;
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               ft = sc->event_common_context_ft;
+               break;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               ft = ec->spec_context_ft;
+               break;
+       case BT_SCOPE_EVENT_PAYLOAD:
+               ft = ec->payload_ft;
+               break;
+       default:
+               abort();
+       }
+
+       BT_ASSERT(ft);
+
+       for (i = 0; i < field_path->path->len; i++) {
+               int64_t child_index =
+                       ctf_field_path_borrow_index_by_index(field_path, i);
+               struct ctf_field_type *child_ft =
+                       ctf_field_type_compound_borrow_field_type_by_index(
+                               ft, child_index);
+               BT_ASSERT(child_ft);
+               ft = child_ft;
+       }
+
+       BT_ASSERT(ft);
+       return ft;
+}
+
+static inline
+struct ctf_field_type *ctf_field_type_copy(struct ctf_field_type *ft);
+
+static inline
+void ctf_field_type_bit_array_copy_content(
+               struct ctf_field_type_bit_array *dst_ft,
+               struct ctf_field_type_bit_array *src_ft)
+{
+       BT_ASSERT(dst_ft);
+       BT_ASSERT(src_ft);
+       dst_ft->byte_order = src_ft->byte_order;
+       dst_ft->size = src_ft->size;
+}
+
+static inline
+void ctf_field_type_int_copy_content(
+               struct ctf_field_type_int *dst_ft,
+               struct ctf_field_type_int *src_ft)
+{
+       ctf_field_type_bit_array_copy_content((void *) dst_ft, (void *) src_ft);
+       dst_ft->meaning = src_ft->meaning;
+       dst_ft->is_signed = src_ft->is_signed;
+       dst_ft->disp_base = src_ft->disp_base;
+       dst_ft->encoding = src_ft->encoding;
+       dst_ft->mapped_clock_class = bt_get(src_ft->mapped_clock_class);
+       dst_ft->storing_index = src_ft->storing_index;
+}
+
+static inline
+struct ctf_field_type_int *_ctf_field_type_int_copy(
+               struct ctf_field_type_int *ft)
+{
+       struct ctf_field_type_int *copy_ft = ctf_field_type_int_create();
+
+       BT_ASSERT(copy_ft);
+       ctf_field_type_int_copy_content(copy_ft, ft);
+       return copy_ft;
+}
+
+static inline
+struct ctf_field_type_enum *_ctf_field_type_enum_copy(
+               struct ctf_field_type_enum *ft)
+{
+       struct ctf_field_type_enum *copy_ft = ctf_field_type_enum_create();
+       uint64_t i;
+
+       BT_ASSERT(copy_ft);
+       ctf_field_type_int_copy_content((void *) copy_ft, (void *) ft);
+
+       for (i = 0; i < ft->mappings->len; i++) {
+               struct ctf_field_type_enum_mapping *mapping =
+                       &g_array_index(ft->mappings,
+                               struct ctf_field_type_enum_mapping, i);
+
+               ctf_field_type_enum_append_mapping(copy_ft, mapping->label->str,
+                       mapping->range.lower.u, mapping->range.upper.u);
+       }
+
+       return copy_ft;
+}
+
+static inline
+struct ctf_field_type_float *_ctf_field_type_float_copy(
+               struct ctf_field_type_float *ft)
+{
+       struct ctf_field_type_float *copy_ft = ctf_field_type_float_create();
+
+       BT_ASSERT(copy_ft);
+       ctf_field_type_bit_array_copy_content((void *) copy_ft, (void *) ft);
+       return copy_ft;
+}
+
+static inline
+struct ctf_field_type_string *_ctf_field_type_string_copy(
+               struct ctf_field_type_string *ft)
+{
+       struct ctf_field_type_string *copy_ft = ctf_field_type_string_create();
+
+       BT_ASSERT(copy_ft);
+       return copy_ft;
+}
+
+static inline
+struct ctf_field_type_struct *_ctf_field_type_struct_copy(
+               struct ctf_field_type_struct *ft)
+{
+       struct ctf_field_type_struct *copy_ft = ctf_field_type_struct_create();
+       uint64_t i;
+
+       BT_ASSERT(copy_ft);
+
+       for (i = 0; i < ft->members->len; i++) {
+               struct ctf_named_field_type *named_ft =
+                       &g_array_index(ft->members,
+                               struct ctf_named_field_type, i);
+
+               ctf_field_type_struct_append_member(copy_ft,
+                       named_ft->name->str,
+                       ctf_field_type_copy(named_ft->ft));
+       }
+
+       return copy_ft;
+}
+
+static inline
+void ctf_field_path_copy_content(struct ctf_field_path *dst_fp,
+               struct ctf_field_path *src_fp)
+{
+       uint64_t i;
+
+       BT_ASSERT(dst_fp);
+       BT_ASSERT(src_fp);
+       dst_fp->root = src_fp->root;
+       ctf_field_path_clear(dst_fp);
+
+       for (i = 0; i < src_fp->path->len; i++) {
+               int64_t index = ctf_field_path_borrow_index_by_index(
+                       src_fp, i);
+
+               ctf_field_path_append_index(dst_fp, index);
+       }
+}
+
+static inline
+struct ctf_field_type_variant *_ctf_field_type_variant_copy(
+               struct ctf_field_type_variant *ft)
+{
+       struct ctf_field_type_variant *copy_ft =
+               ctf_field_type_variant_create();
+       uint64_t i;
+
+       BT_ASSERT(copy_ft);
+
+       for (i = 0; i < ft->options->len; i++) {
+               struct ctf_named_field_type *named_ft =
+                       &g_array_index(ft->options,
+                               struct ctf_named_field_type, i);
+
+               ctf_field_type_variant_append_option(copy_ft,
+                       named_ft->name->str,
+                       ctf_field_type_copy(named_ft->ft));
+       }
+
+       for (i = 0; i < ft->ranges->len; i++) {
+               struct ctf_field_type_variant_range *range =
+                       &g_array_index(ft->ranges,
+                               struct ctf_field_type_variant_range, i);
+
+               g_array_append_val(copy_ft->ranges, *range);
+       }
+
+       ctf_field_path_copy_content(&copy_ft->tag_path, &ft->tag_path);
+       g_string_assign(copy_ft->tag_ref, ft->tag_ref->str);
+       copy_ft->stored_tag_index = ft->stored_tag_index;
+       return copy_ft;
+}
+
+static inline
+void ctf_field_type_array_base_copy_content(
+               struct ctf_field_type_array_base *dst_ft,
+               struct ctf_field_type_array_base *src_ft)
+{
+       BT_ASSERT(dst_ft);
+       BT_ASSERT(src_ft);
+       dst_ft->elem_ft = ctf_field_type_copy(src_ft->elem_ft);
+       dst_ft->is_text = src_ft->is_text;
+}
+
+static inline
+struct ctf_field_type_array *_ctf_field_type_array_copy(
+               struct ctf_field_type_array *ft)
+{
+       struct ctf_field_type_array *copy_ft = ctf_field_type_array_create();
+
+       BT_ASSERT(copy_ft);
+       ctf_field_type_array_base_copy_content((void *) copy_ft, (void *) ft);
+       copy_ft->length = ft->length;
+       return copy_ft;
+}
+
+static inline
+struct ctf_field_type_sequence *_ctf_field_type_sequence_copy(
+               struct ctf_field_type_sequence *ft)
+{
+       struct ctf_field_type_sequence *copy_ft =
+               ctf_field_type_sequence_create();
+
+       BT_ASSERT(copy_ft);
+       ctf_field_type_array_base_copy_content((void *) copy_ft, (void *) ft);
+       ctf_field_path_copy_content(&copy_ft->length_path, &ft->length_path);
+       g_string_assign(copy_ft->length_ref, ft->length_ref->str);
+       copy_ft->stored_length_index = ft->stored_length_index;
+       return copy_ft;
+}
+
+static inline
+struct ctf_field_type *ctf_field_type_copy(struct ctf_field_type *ft)
+{
+       struct ctf_field_type *copy_ft = NULL;
+
+       if (!ft) {
+               goto end;
+       }
+
+       /*
+        * Translation should not have happened yet.
+        */
+       BT_ASSERT(!ft->ir_ft);
+
+       switch (ft->id) {
+       case CTF_FIELD_TYPE_ID_INT:
+               copy_ft = (void *) _ctf_field_type_int_copy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_ENUM:
+               copy_ft = (void *) _ctf_field_type_enum_copy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_FLOAT:
+               copy_ft = (void *) _ctf_field_type_float_copy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_STRING:
+               copy_ft = (void *) _ctf_field_type_string_copy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_STRUCT:
+               copy_ft = (void *) _ctf_field_type_struct_copy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_ARRAY:
+               copy_ft = (void *) _ctf_field_type_array_copy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_SEQUENCE:
+               copy_ft = (void *) _ctf_field_type_sequence_copy((void *) ft);
+               break;
+       case CTF_FIELD_TYPE_ID_VARIANT:
+               copy_ft = (void *) _ctf_field_type_variant_copy((void *) ft);
+               break;
+       default:
+               abort();
+       }
+
+       copy_ft->id = ft->id;
+       copy_ft->alignment = ft->alignment;
+       copy_ft->in_ir = ft->in_ir;
+
+end:
+       return copy_ft;
+}
+
+static inline
+struct ctf_event_class *ctf_event_class_create(void)
+{
+       struct ctf_event_class *ec = g_new0(struct ctf_event_class, 1);
+
+       BT_ASSERT(ec);
+       ec->name = g_string_new(NULL);
+       BT_ASSERT(ec->name);
+       ec->emf_uri = g_string_new(NULL);
+       BT_ASSERT(ec->emf_uri);
+       ec->log_level = -1;
+       return ec;
+}
+
+static inline
+void ctf_event_class_destroy(struct ctf_event_class *ec)
+{
+       if (!ec) {
+               return;
+       }
+
+       if (ec->name) {
+               g_string_free(ec->name, TRUE);
+       }
+
+       if (ec->emf_uri) {
+               g_string_free(ec->emf_uri, TRUE);
+       }
+
+       ctf_field_type_destroy(ec->spec_context_ft);
+       ctf_field_type_destroy(ec->payload_ft);
+       g_free(ec);
+}
+
+static inline
+struct ctf_stream_class *ctf_stream_class_create(void)
+{
+       struct ctf_stream_class *sc = g_new0(struct ctf_stream_class, 1);
+
+       BT_ASSERT(sc);
+       sc->event_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_event_class_destroy);
+       BT_ASSERT(sc->event_classes);
+       sc->event_classes_by_id = g_hash_table_new(g_direct_hash,
+               g_direct_equal);
+       BT_ASSERT(sc->event_classes_by_id);
+       return sc;
+}
+
+static inline
+void ctf_stream_class_destroy(struct ctf_stream_class *sc)
+{
+       if (!sc) {
+               return;
+       }
+
+       if (sc->event_classes) {
+               g_ptr_array_free(sc->event_classes, TRUE);
+       }
+
+       if (sc->event_classes_by_id) {
+               g_hash_table_destroy(sc->event_classes_by_id);
+       }
+
+       ctf_field_type_destroy(sc->packet_context_ft);
+       ctf_field_type_destroy(sc->event_header_ft);
+       ctf_field_type_destroy(sc->event_common_context_ft);
+       bt_put(sc->default_clock_class);
+       g_free(sc);
+}
+
+static inline
+void ctf_stream_class_append_event_class(struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       g_ptr_array_add(sc->event_classes, ec);
+       g_hash_table_insert(sc->event_classes_by_id,
+               GUINT_TO_POINTER((guint) ec->id), ec);
+}
+
+static inline
+struct ctf_event_class *ctf_stream_class_borrow_event_class_by_id(
+               struct ctf_stream_class *sc, uint64_t id)
+{
+       BT_ASSERT(sc);
+       return g_hash_table_lookup(sc->event_classes_by_id,
+               GUINT_TO_POINTER((guint) id));
+}
+
+static inline
+void _ctf_trace_class_env_entry_init(struct ctf_trace_class_env_entry *entry)
+{
+       BT_ASSERT(entry);
+       entry->name = g_string_new(NULL);
+       BT_ASSERT(entry->name);
+       entry->value.str = g_string_new(NULL);
+       BT_ASSERT(entry->value.str);
+}
+
+static inline
+void _ctf_trace_class_env_entry_fini(struct ctf_trace_class_env_entry *entry)
+{
+       BT_ASSERT(entry);
+
+       if (entry->name) {
+               g_string_free(entry->name, TRUE);
+       }
+
+       if (entry->value.str) {
+               g_string_free(entry->value.str, TRUE);
+       }
+}
+
+static inline
+struct ctf_trace_class *ctf_trace_class_create(void)
+{
+       struct ctf_trace_class *tc = g_new0(struct ctf_trace_class, 1);
+
+       BT_ASSERT(tc);
+       tc->name = g_string_new(NULL);
+       tc->default_byte_order = -1;
+       BT_ASSERT(tc->name);
+       tc->clock_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_put);
+       BT_ASSERT(tc->clock_classes);
+       tc->stream_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_stream_class_destroy);
+       BT_ASSERT(tc->stream_classes);
+       tc->env_entries = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_trace_class_env_entry));
+       return tc;
+}
+
+static inline
+void ctf_trace_class_destroy(struct ctf_trace_class *tc)
+{
+       if (!tc) {
+               return;
+       }
+
+       if (tc->name) {
+               g_string_free(tc->name, TRUE);
+       }
+
+       ctf_field_type_destroy(tc->packet_header_ft);
+
+       if (tc->clock_classes) {
+               g_ptr_array_free(tc->clock_classes, TRUE);
+       }
+
+       if (tc->stream_classes) {
+               g_ptr_array_free(tc->stream_classes, TRUE);
+       }
+
+       if (tc->env_entries) {
+               uint64_t i;
+
+               for (i = 0; i < tc->env_entries->len; i++) {
+                       struct ctf_trace_class_env_entry *entry =
+                               &g_array_index(tc->env_entries,
+                                       struct ctf_trace_class_env_entry, i);
+
+                       _ctf_trace_class_env_entry_fini(entry);
+               }
+
+               g_array_free(tc->env_entries, TRUE);
+       }
+
+       g_free(tc);
+}
+
+static inline
+void ctf_trace_class_append_env_entry(struct ctf_trace_class *tc,
+               const char *name, enum ctf_trace_class_env_entry_type type,
+               const char *str_value, int64_t i_value)
+{
+       struct ctf_trace_class_env_entry *entry;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(name);
+       g_array_set_size(tc->env_entries, tc->env_entries->len + 1);
+
+       entry = &g_array_index(tc->env_entries,
+               struct ctf_trace_class_env_entry, tc->env_entries->len - 1);
+       entry->type = type;
+       _ctf_trace_class_env_entry_init(entry);
+       g_string_assign(entry->name, name);
+
+       if (str_value) {
+               g_string_assign(entry->value.str, str_value);
+       }
+
+       entry->value.i = i_value;
+}
+
+static inline
+struct ctf_stream_class *ctf_trace_class_borrow_stream_class_by_id(
+               struct ctf_trace_class *tc, uint64_t id)
+{
+       uint64_t i;
+       struct ctf_stream_class *ret_sc = NULL;
+
+       BT_ASSERT(tc);
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = tc->stream_classes->pdata[i];
+
+               if (sc->id == id) {
+                       ret_sc = sc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_sc;
+}
+
+static inline
+struct bt_clock_class *ctf_trace_class_borrow_clock_class_by_name(
+               struct ctf_trace_class *tc, const char *name)
+{
+       uint64_t i;
+       struct bt_clock_class *ret_cc = NULL;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < tc->clock_classes->len; i++) {
+               struct bt_clock_class *cc = tc->clock_classes->pdata[i];
+               const char *cc_name = bt_clock_class_get_name(cc);
+
+               BT_ASSERT(cc_name);
+               if (strcmp(cc_name, name) == 0) {
+                       ret_cc = cc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_cc;
+}
+
+static inline
+struct ctf_trace_class_env_entry *ctf_trace_class_borrow_env_entry_by_index(
+               struct ctf_trace_class *tc, uint64_t index)
+{
+       BT_ASSERT(tc);
+       BT_ASSERT(index < tc->env_entries->len);
+       return &g_array_index(tc->env_entries, struct ctf_trace_class_env_entry,
+               index);
+}
+
+static inline
+struct ctf_trace_class_env_entry *ctf_trace_class_borrow_env_entry_by_name(
+               struct ctf_trace_class *tc, const char *name)
+{
+       struct ctf_trace_class_env_entry *ret_entry = NULL;
+       uint64_t i;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < tc->env_entries->len; i++) {
+               struct ctf_trace_class_env_entry *env_entry =
+                       ctf_trace_class_borrow_env_entry_by_index(tc, i);
+
+               if (strcmp(env_entry->name->str, name) == 0) {
+                       ret_entry = env_entry;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_entry;
+}
+
+#endif /* _CTF_META_H */
index aa3b799f2dd3baa6e872e26bd48481319f6786cc..38733ae38b444a0fe04cc9d33424021ef33e14dd 100644 (file)
@@ -514,6 +514,10 @@ enum ctf_metadata_decoder_status ctf_metadata_decoder_decode(
 
        ret = ctf_visitor_generate_ir_visit_node(mdec->visitor,
                &scanner->ast->root);
+       // TODO
+       ret = -1;
+       goto end;
+
        switch (ret) {
        case 0:
                /* Success */
@@ -552,8 +556,15 @@ end:
 }
 
 BT_HIDDEN
-struct bt_trace *ctf_metadata_decoder_get_trace(
+struct bt_trace *ctf_metadata_decoder_get_ir_trace(
+               struct ctf_metadata_decoder *mdec)
+{
+       return ctf_visitor_generate_ir_get_ir_trace(mdec->visitor);
+}
+
+BT_HIDDEN
+struct ctf_trace_class *ctf_metadata_decoder_borrow_ctf_trace_class(
                struct ctf_metadata_decoder *mdec)
 {
-       return ctf_visitor_generate_ir_get_trace(mdec->visitor);
+       return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor);
 }
index 832de03b2081077e8758b9ff3418bb72aa52e5b6..51d3a185b3206d7c27c788c05cebec12c3025035 100644 (file)
@@ -64,7 +64,7 @@ void ctf_metadata_decoder_destroy(
  * until the end of this file stream. If it finds new information (new
  * event class, new stream class, or new clock class), it appends this
  * information to the decoder's trace object (as returned by
- * ctf_metadata_get_trace()), or it creates this trace.
+ * ctf_metadata_decoder_get_ir_trace()), or it creates this trace.
  *
  * The metadata can be packetized or not.
  *
@@ -88,16 +88,13 @@ BT_HIDDEN
 enum ctf_metadata_decoder_status ctf_metadata_decoder_decode(
                struct ctf_metadata_decoder *metadata_decoder, FILE *fp);
 
-/*
- * Returns a new reference to the current CTF IR trace object which is
- * the result of the metadata decoding process.
- *
- * The trace object, once created, remains the same until you call
- * ctf_metadata_decoder_destroy().
- */
 BT_HIDDEN
-struct bt_trace *ctf_metadata_decoder_get_trace(
-               struct ctf_metadata_decoder *metadata_decoder);
+struct bt_trace *ctf_metadata_decoder_get_ir_trace(
+               struct ctf_metadata_decoder *mdec);
+
+BT_HIDDEN
+struct ctf_trace_class *ctf_metadata_decoder_borrow_ctf_trace_class(
+               struct ctf_metadata_decoder *mdec);
 
 /*
  * Checks whether or not a given metadata file stream is packetized, and
index 743b61b1a58f788f8ebb5867a61ed3cc900b3fd5..2ba0603c232394b13290074fb8618632456e4d16 100644 (file)
@@ -6,7 +6,7 @@
  * Based on older ctf-visitor-generate-io-struct.c.
  *
  * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright 2015-2016 - Philippe Proulx <philippe.proulx@efficios.com>
+ * Copyright 2015-2018 - Philippe Proulx <philippe.proulx@efficios.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -49,6 +49,8 @@
 #include "parser.h"
 #include "ast.h"
 #include "decoder.h"
+#include "ctf-meta.h"
+#include "ctf-meta-visitors.h"
 
 /* Bit value (left shift) */
 #define _BV(_val)              (1 << (_val))
 /* Set bit in a set of bits */
 #define _SET(_set, _mask)      (*(_set) |= (_mask))
 
+/* Try to push scope, or go to the `error` label */
+#define _TRY_PUSH_SCOPE_OR_GOTO_ERROR()                                        \
+       do {                                                            \
+               ret = ctx_push_scope(ctx);                              \
+               if (ret) {                                              \
+                       BT_LOGE_STR("Cannot push scope.");              \
+                       goto error;                                     \
+               }                                                       \
+       } while (0)
+
 /* Bits for verifying existing attributes in various declarations */
 enum {
        _CLOCK_NAME_SET =               _BV(0),
@@ -112,27 +124,27 @@ enum {
        _EVENT_ID_SET =                 _BV(1),
        _EVENT_MODEL_EMF_URI_SET =      _BV(2),
        _EVENT_STREAM_ID_SET =          _BV(3),
-       _EVENT_LOGLEVEL_SET =           _BV(4),
+       _EVENT_LOG_LEVEL_SET =          _BV(4),
        _EVENT_CONTEXT_SET =            _BV(5),
        _EVENT_FIELDS_SET =             _BV(6),
 };
 
 enum loglevel {
-        LOGLEVEL_EMERG                  = 0,
-        LOGLEVEL_ALERT                  = 1,
-        LOGLEVEL_CRIT                   = 2,
-        LOGLEVEL_ERR                    = 3,
-        LOGLEVEL_WARNING                = 4,
-        LOGLEVEL_NOTICE                 = 5,
-        LOGLEVEL_INFO                   = 6,
-        LOGLEVEL_DEBUG_SYSTEM           = 7,
-        LOGLEVEL_DEBUG_PROGRAM          = 8,
-        LOGLEVEL_DEBUG_PROCESS          = 9,
-        LOGLEVEL_DEBUG_MODULE           = 10,
-        LOGLEVEL_DEBUG_UNIT             = 11,
-        LOGLEVEL_DEBUG_FUNCTION         = 12,
-        LOGLEVEL_DEBUG_LINE             = 13,
-        LOGLEVEL_DEBUG                  = 14,
+        LOG_LEVEL_EMERG                  = 0,
+        LOG_LEVEL_ALERT                  = 1,
+        LOG_LEVEL_CRIT                   = 2,
+        LOG_LEVEL_ERR                    = 3,
+        LOG_LEVEL_WARNING                = 4,
+        LOG_LEVEL_NOTICE                 = 5,
+        LOG_LEVEL_INFO                   = 6,
+        LOG_LEVEL_DEBUG_SYSTEM           = 7,
+        LOG_LEVEL_DEBUG_PROGRAM          = 8,
+        LOG_LEVEL_DEBUG_PROCESS          = 9,
+        LOG_LEVEL_DEBUG_MODULE           = 10,
+        LOG_LEVEL_DEBUG_UNIT             = 11,
+        LOG_LEVEL_DEBUG_FUNCTION         = 12,
+        LOG_LEVEL_DEBUG_LINE             = 13,
+        LOG_LEVEL_DEBUG                  = 14,
        _NR_LOGLEVELS                   = 15,
 };
 
@@ -143,11 +155,9 @@ enum loglevel {
 #define _PREFIX_VARIANT                        'v'
 
 /* First entry in a BT list */
-#define _BT_LIST_FIRST_ENTRY(_ptr, _type, _member)     \
+#define _BT_LIST_FIRST_ENTRY(_ptr, _type, _member)                     \
        bt_list_entry((_ptr)->next, _type, _member)
 
-#define _BT_FIELD_TYPE_INIT(_name)     struct bt_field_type *_name = NULL;
-
 #define _BT_LOGE_DUP_ATTR(_node, _attr, _entity)                       \
        _BT_LOGE_LINENO((_node)->lineno,                                \
                "Duplicate attribute in %s: attr-name=\"%s\"",          \
@@ -171,7 +181,7 @@ struct ctx_decl_scope {
        /*
         * Alias name to field type.
         *
-        * GQuark -> struct bt_field_type *
+        * GQuark -> struct ctf_field_type * (owned by this)
         */
        GHashTable *decl_map;
 
@@ -183,33 +193,23 @@ struct ctx_decl_scope {
  * Visitor context (private).
  */
 struct ctx {
-       /* Trace being filled (owned by this) */
+       /* Trace IR trace being filled (owned by this) */
        struct bt_trace *trace;
 
-       /* Current declaration scope (top of the stack) */
+       /* CTF meta trace being filled (owned by this) */
+       struct ctf_trace_class *ctf_tc;
+
+       /* Current declaration scope (top of the stack) (owned by this) */
        struct ctx_decl_scope *current_scope;
 
-       /* 1 if trace declaration is visited */
-       int is_trace_visited;
+       /* True if trace declaration is visited */
+       bool is_trace_visited;
 
-       /* 1 if this is an LTTng trace */
+       /* True if this is an LTTng trace */
        bool is_lttng;
 
-       /* Eventual name suffix of the trace to set */
-       char *trace_name_suffix;
-
-       /* Trace attributes */
-       enum bt_byte_order trace_bo;
-       uint64_t trace_major;
-       uint64_t trace_minor;
-       unsigned char trace_uuid[BABELTRACE_UUID_LEN];
-
-       /*
-        * Stream IDs to stream classes.
-        *
-        * int64_t -> struct bt_stream_class *
-        */
-       GHashTable *stream_classes;
+       /* Eventual name suffix of the trace to set (owned by this) */
+       char *trace_class_name_suffix;
 
        /* Config passed by the user */
        struct ctf_metadata_decoder_config decoder_config;
@@ -218,7 +218,7 @@ struct ctx {
 /*
  * Visitor (public).
  */
-struct ctf_visitor_generate_ir { };
+struct ctf_visitor_generate_ir;
 
 /**
  * Creates a new declaration scope.
@@ -238,7 +238,7 @@ struct ctx_decl_scope *ctx_decl_scope_create(struct ctx_decl_scope *par_scope)
        }
 
        scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-               NULL, (GDestroyNotify) bt_put);
+               NULL, (GDestroyNotify) ctf_field_type_destroy);
        scope->parent_scope = par_scope;
 
 end:
@@ -301,24 +301,26 @@ end:
  * @param scope                Declaration scope
  * @param prefix       Prefix character
  * @param name         Alias name
- * @param level                Number of levels to dig (-1 means infinite)
- * @returns            Declaration, or NULL if not found
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
  */
 static
-struct bt_field_type *ctx_decl_scope_lookup_prefix_alias(
-       struct ctx_decl_scope *scope, char prefix,
-       const char *name, int levels)
+struct ctf_field_type *ctx_decl_scope_lookup_prefix_alias(
+               struct ctx_decl_scope *scope, char prefix, const char *name,
+               int levels, bool copy)
 {
        GQuark qname = 0;
        int cur_levels = 0;
-       _BT_FIELD_TYPE_INIT(decl);
+       struct ctf_field_type *decl = NULL;
        struct ctx_decl_scope *cur_scope = scope;
 
        BT_ASSERT(scope);
        BT_ASSERT(name);
        qname = get_prefixed_named_quark(prefix, name);
        if (!qname) {
-               goto error;
+               goto end;
        }
 
        if (levels < 0) {
@@ -330,18 +332,20 @@ struct bt_field_type *ctx_decl_scope_lookup_prefix_alias(
                        (gconstpointer) GUINT_TO_POINTER(qname));
                if (decl) {
                        /* Caller's reference */
-                       bt_get(decl);
-                       break;
+                       if (copy) {
+                               decl = ctf_field_type_copy(decl);
+                               BT_ASSERT(decl);
+                       }
+
+                       goto end;
                }
 
                cur_scope = cur_scope->parent_scope;
                cur_levels++;
        }
 
+end:
        return decl;
-
-error:
-       return NULL;
 }
 
 /**
@@ -349,15 +353,18 @@ error:
  *
  * @param scope                Declaration scope
  * @param name         Alias name
- * @param level                Number of levels to dig (-1 means infinite)
- * @returns            Declaration, or NULL if not found
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
  */
 static
-struct bt_field_type *ctx_decl_scope_lookup_alias(
-       struct ctx_decl_scope *scope, const char *name, int levels)
+struct ctf_field_type *ctx_decl_scope_lookup_alias(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
 {
        return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS,
-               name, levels);
+               name, levels, copy);
 }
 
 /**
@@ -365,15 +372,18 @@ struct bt_field_type *ctx_decl_scope_lookup_alias(
  *
  * @param scope                Declaration scope
  * @param name         Enumeration name
- * @param level                Number of levels to dig (-1 means infinite)
- * @returns            Declaration, or NULL if not found
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
  */
 static
-struct bt_field_type *ctx_decl_scope_lookup_enum(
-       struct ctx_decl_scope *scope, const char *name, int levels)
+struct ctf_field_type_enum *ctx_decl_scope_lookup_enum(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
 {
-       return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM,
-               name, levels);
+       return (void *) ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM,
+               name, levels, copy);
 }
 
 /**
@@ -381,15 +391,18 @@ struct bt_field_type *ctx_decl_scope_lookup_enum(
  *
  * @param scope                Declaration scope
  * @param name         Structure name
- * @param level                Number of levels to dig (-1 means infinite)
- * @returns            Declaration, or NULL if not found
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
  */
 static
-struct bt_field_type *ctx_decl_scope_lookup_struct(
-       struct ctx_decl_scope *scope, const char *name, int levels)
+struct ctf_field_type_struct *ctx_decl_scope_lookup_struct(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
 {
-       return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_STRUCT,
-               name, levels);
+       return (void *) ctx_decl_scope_lookup_prefix_alias(scope,
+               _PREFIX_STRUCT, name, levels, copy);
 }
 
 /**
@@ -397,15 +410,18 @@ struct bt_field_type *ctx_decl_scope_lookup_struct(
  *
  * @param scope                Declaration scope
  * @param name         Variant name
- * @param level                Number of levels to dig (-1 means infinite)
- * @returns            Declaration, or NULL if not found
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
  */
 static
-struct bt_field_type *ctx_decl_scope_lookup_variant(
-       struct ctx_decl_scope *scope, const char *name, int levels)
+struct ctf_field_type_variant *ctx_decl_scope_lookup_variant(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
 {
-       return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_VARIANT,
-               name, levels);
+       return (void *) ctx_decl_scope_lookup_prefix_alias(scope,
+               _PREFIX_VARIANT, name, levels, copy);
 }
 
 /**
@@ -414,16 +430,15 @@ struct bt_field_type *ctx_decl_scope_lookup_variant(
  * @param scope                Declaration scope
  * @param prefix       Prefix character
  * @param name         Alias name (non-NULL)
- * @param decl         Declaration to register
+ * @param decl         Field type to register (copied)
  * @returns            0 if registration went okay, negative value otherwise
  */
 static
 int ctx_decl_scope_register_prefix_alias(struct ctx_decl_scope *scope,
-       char prefix, const char *name, struct bt_field_type *decl)
+               char prefix, const char *name, struct ctf_field_type *decl)
 {
        int ret = 0;
        GQuark qname = 0;
-       _BT_FIELD_TYPE_INIT(edecl);
 
        BT_ASSERT(scope);
        BT_ASSERT(name);
@@ -431,26 +446,21 @@ int ctx_decl_scope_register_prefix_alias(struct ctx_decl_scope *scope,
        qname = get_prefixed_named_quark(prefix, name);
        if (!qname) {
                ret = -ENOMEM;
-               goto error;
+               goto end;
        }
 
        /* Make sure alias does not exist in local scope */
-       edecl = ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1);
-       if (edecl) {
-               BT_PUT(edecl);
+       if (ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1,
+                       false)) {
                ret = -EEXIST;
-               goto error;
+               goto end;
        }
 
-       g_hash_table_insert(scope->decl_map,
-               GUINT_TO_POINTER(qname), decl);
-
-       /* Hash table's reference */
-       bt_get(decl);
-
-       return 0;
+       decl = ctf_field_type_copy(decl);
+       BT_ASSERT(decl);
+       g_hash_table_insert(scope->decl_map, GUINT_TO_POINTER(qname), decl);
 
-error:
+end:
        return ret;
 }
 
@@ -459,15 +469,15 @@ error:
  *
  * @param scope        Declaration scope
  * @param name Alias name (non-NULL)
- * @param decl Declaration to register
+ * @param decl Field type to register (copied)
  * @returns    0 if registration went okay, negative value otherwise
  */
 static
 int ctx_decl_scope_register_alias(struct ctx_decl_scope *scope,
-       const char *name, struct bt_field_type *decl)
+               const char *name, struct ctf_field_type *decl)
 {
        return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ALIAS,
-               name, decl);
+               name, (void *) decl);
 }
 
 /**
@@ -475,15 +485,15 @@ int ctx_decl_scope_register_alias(struct ctx_decl_scope *scope,
  *
  * @param scope        Declaration scope
  * @param name Enumeration name (non-NULL)
- * @param decl Enumeration declaration to register
+ * @param decl Enumeration field type to register (copied)
  * @returns    0 if registration went okay, negative value otherwise
  */
 static
 int ctx_decl_scope_register_enum(struct ctx_decl_scope *scope,
-       const char *name, struct bt_field_type *decl)
+               const char *name, struct ctf_field_type_enum *decl)
 {
        return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM,
-               name, decl);
+               name, (void *) decl);
 }
 
 /**
@@ -491,15 +501,15 @@ int ctx_decl_scope_register_enum(struct ctx_decl_scope *scope,
  *
  * @param scope        Declaration scope
  * @param name Structure name (non-NULL)
- * @param decl Structure declaration to register
+ * @param decl Structure field type to register (copied)
  * @returns    0 if registration went okay, negative value otherwise
  */
 static
 int ctx_decl_scope_register_struct(struct ctx_decl_scope *scope,
-       const char *name, struct bt_field_type *decl)
+               const char *name, struct ctf_field_type_struct *decl)
 {
        return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT,
-               name, decl);
+               name, (void *) decl);
 }
 
 /**
@@ -507,15 +517,15 @@ int ctx_decl_scope_register_struct(struct ctx_decl_scope *scope,
  *
  * @param scope        Declaration scope
  * @param name Variant name (non-NULL)
- * @param decl Variant declaration to register
+ * @param decl Variant field type to register
  * @returns    0 if registration went okay, negative value otherwise
  */
 static
 int ctx_decl_scope_register_variant(struct ctx_decl_scope *scope,
-       const char *name, struct bt_field_type *decl)
+               const char *name, struct ctf_field_type_variant *decl)
 {
        return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT,
-               name, decl);
+               name, (void *) decl);
 }
 
 /**
@@ -527,9 +537,6 @@ static
 void ctx_destroy(struct ctx *ctx)
 {
        struct ctx_decl_scope *scope;
-       /*
-        * Destroy all scopes, from current one to the root scope.
-        */
 
        if (!ctx) {
                goto end;
@@ -537,6 +544,9 @@ void ctx_destroy(struct ctx *ctx)
 
        scope = ctx->current_scope;
 
+       /*
+        * Destroy all scopes, from current one to the root scope.
+        */
        while (scope) {
                struct ctx_decl_scope *parent_scope = scope->parent_scope;
 
@@ -546,11 +556,14 @@ void ctx_destroy(struct ctx *ctx)
 
        bt_put(ctx->trace);
 
-       if (ctx->stream_classes) {
-               g_hash_table_destroy(ctx->stream_classes);
+       if (ctx->ctf_tc) {
+               ctf_trace_class_destroy(ctx->ctf_tc);
+       }
+
+       if (ctx->trace_class_name_suffix) {
+               free(ctx->trace_class_name_suffix);
        }
 
-       free(ctx->trace_name_suffix);
        g_free(ctx);
 
 end:
@@ -564,12 +577,10 @@ end:
  * @returns    New visitor context, or NULL on error
  */
 static
-struct ctx *ctx_create(struct bt_trace *trace,
-               const struct ctf_metadata_decoder_config *decoder_config,
-               const char *trace_name_suffix)
+struct ctx *ctx_create(const struct ctf_metadata_decoder_config *decoder_config,
+               const char *trace_class_name_suffix)
 {
        struct ctx *ctx = NULL;
-       struct ctx_decl_scope *scope = NULL;
 
        BT_ASSERT(decoder_config);
 
@@ -579,39 +590,42 @@ struct ctx *ctx_create(struct bt_trace *trace,
                goto error;
        }
 
-       /* Root declaration scope */
-       scope = ctx_decl_scope_create(NULL);
-       if (!scope) {
-               BT_LOGE_STR("Cannot create declaration scope.");
+       ctx->trace = bt_trace_create();
+       if (!ctx->trace) {
+               BT_LOGE_STR("Cannot create empty trace.");
+               goto error;
+       }
+
+       ctx->ctf_tc = ctf_trace_class_create();
+       if (!ctx->ctf_tc) {
+               BT_LOGE_STR("Cannot create CTF trace class.");
                goto error;
        }
 
-       ctx->stream_classes = g_hash_table_new_full(g_int64_hash,
-               g_int64_equal, g_free, (GDestroyNotify) bt_put);
-       if (!ctx->stream_classes) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
+       /* Root declaration scope */
+       ctx->current_scope = ctx_decl_scope_create(NULL);
+       if (!ctx->current_scope) {
+               BT_LOGE_STR("Cannot create declaration scope.");
                goto error;
        }
 
-       if (trace_name_suffix) {
-               ctx->trace_name_suffix = strdup(trace_name_suffix);
-               if (!ctx->trace_name_suffix) {
+       if (trace_class_name_suffix) {
+               ctx->trace_class_name_suffix = strdup(trace_class_name_suffix);
+               if (!ctx->trace_class_name_suffix) {
                        BT_LOGE_STR("Failed to copy string.");
                        goto error;
                }
        }
 
-       ctx->trace = trace;
-       ctx->current_scope = scope;
-       scope = NULL;
-       ctx->trace_bo = BT_BYTE_ORDER_NATIVE;
        ctx->decoder_config = *decoder_config;
-       return ctx;
+       goto end;
 
 error:
        ctx_destroy(ctx);
-       ctx_decl_scope_destroy(scope);
-       return NULL;
+       ctx = NULL;
+
+end:
+       return ctx;
 }
 
 /**
@@ -662,7 +676,7 @@ end:
 
 static
 int visit_type_specifier_list(struct ctx *ctx, struct ctf_node *ts_list,
-       struct bt_field_type **decl);
+               struct ctf_field_type **decl);
 
 static
 char *remove_underscores_from_field_ref(const char *field_ref)
@@ -1043,10 +1057,10 @@ end:
 }
 
 static
-enum bt_byte_order byte_order_from_unary_expr(struct ctf_node *unary_expr)
+enum ctf_byte_order byte_order_from_unary_expr(struct ctf_node *unary_expr)
 {
        const char *str;
-       enum bt_byte_order bo = BT_BYTE_ORDER_UNKNOWN;
+       enum ctf_byte_order bo = -1;
 
        if (unary_expr->u.unary_expression.type != UNARY_STRING) {
                _BT_LOGE_NODE(unary_expr,
@@ -1057,11 +1071,11 @@ enum bt_byte_order byte_order_from_unary_expr(struct ctf_node *unary_expr)
        str = unary_expr->u.unary_expression.u.string;
 
        if (!strcmp(str, "be") || !strcmp(str, "network")) {
-               bo = BT_BYTE_ORDER_BIG_ENDIAN;
+               bo = CTF_BYTE_ORDER_BIG;
        } else if (!strcmp(str, "le")) {
-               bo = BT_BYTE_ORDER_LITTLE_ENDIAN;
+               bo = CTF_BYTE_ORDER_LITTLE;
        } else if (!strcmp(str, "native")) {
-               bo = BT_BYTE_ORDER_NATIVE;
+               bo = CTF_BYTE_ORDER_DEFAULT;
        } else {
                _BT_LOGE_NODE(unary_expr,
                        "Unexpected \"byte_order\" attribute value: "
@@ -1075,13 +1089,13 @@ end:
 }
 
 static
-enum bt_byte_order get_real_byte_order(struct ctx *ctx,
-       struct ctf_node *uexpr)
+enum ctf_byte_order get_real_byte_order(struct ctx *ctx,
+               struct ctf_node *uexpr)
 {
-       enum bt_byte_order bo = byte_order_from_unary_expr(uexpr);
+       enum ctf_byte_order bo = byte_order_from_unary_expr(uexpr);
 
-       if (bo == BT_BYTE_ORDER_NATIVE) {
-               bo = bt_trace_get_native_byte_order(ctx->trace);
+       if (bo == CTF_BYTE_ORDER_DEFAULT) {
+               bo = ctx->ctf_tc->default_byte_order;
        }
 
        return bo;
@@ -1090,12 +1104,12 @@ enum bt_byte_order get_real_byte_order(struct ctx *ctx,
 static
 int is_align_valid(uint64_t align)
 {
-       return (align != 0) && !(align & (align - 1ULL));
+       return (align != 0) && !(align & (align - UINT64_C(1)));
 }
 
 static
 int get_type_specifier_name(struct ctx *ctx, struct ctf_node *type_specifier,
-       GString *str)
+               GString *str)
 {
        int ret = 0;
 
@@ -1213,7 +1227,7 @@ end:
 
 static
 int get_type_specifier_list_name(struct ctx *ctx,
-       struct ctf_node *type_specifier_list, GString *str)
+               struct ctf_node *type_specifier_list, GString *str)
 {
        int ret = 0;
        struct ctf_node *iter;
@@ -1239,8 +1253,8 @@ end:
 
 static
 GQuark create_typealias_identifier(struct ctx *ctx,
-       struct ctf_node *type_specifier_list,
-       struct ctf_node *node_type_declarator)
+               struct ctf_node *type_specifier_list,
+               struct ctf_node *node_type_declarator)
 {
        int ret;
        char *str_c;
@@ -1275,16 +1289,15 @@ end:
 
 static
 int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
-       GQuark *field_name, struct ctf_node *node_type_declarator,
-       struct bt_field_type **field_decl,
-       struct bt_field_type *nested_decl)
+               GQuark *field_name, struct ctf_node *node_type_declarator,
+               struct ctf_field_type **field_decl,
+               struct ctf_field_type *nested_decl)
 {
        /*
         * During this whole function, nested_decl is always OURS,
         * whereas field_decl is an output which we create, but
         * belongs to the caller (it is moved).
         */
-
        int ret = 0;
        *field_decl = NULL;
 
@@ -1316,17 +1329,16 @@ int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
 
                if (node_type_declarator && !bt_list_empty(pointers)) {
                        GQuark qalias;
-                       _BT_FIELD_TYPE_INIT(nested_decl_copy);
 
                        /*
                         * If we have a pointer declarator, it HAS to
-                        * be present in the typealiases (else fail).
+                        * be present in the typealiases (else fail).
                         */
                        qalias = create_typealias_identifier(ctx,
                                type_specifier_list, node_type_declarator);
                        nested_decl =
                                ctx_decl_scope_lookup_alias(ctx->current_scope,
-                                       g_quark_to_string(qalias), -1);
+                                       g_quark_to_string(qalias), -1, true);
                        if (!nested_decl) {
                                _BT_LOGE_NODE(node_type_declarator,
                                        "Cannot find type alias: name=\"%s\"",
@@ -1335,24 +1347,13 @@ int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
                                goto error;
                        }
 
-                       /* Make a copy of it */
-                       nested_decl_copy = bt_field_type_copy(nested_decl);
-                       BT_PUT(nested_decl);
-                       if (!nested_decl_copy) {
-                               _BT_LOGE_NODE(node_type_declarator,
-                                       "Cannot copy nested field type.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       BT_MOVE(nested_decl, nested_decl_copy);
+                       if (nested_decl->id == CTF_FIELD_TYPE_ID_INT) {
+                               /* Pointer: force integer's base to 16 */
+                               struct ctf_field_type_int *int_ft =
+                                       (void *) nested_decl;
 
-                       /* Force integer's base to 16 since it's a pointer */
-                       if (bt_field_type_is_integer(nested_decl)) {
-                               ret = bt_field_type_integer_set_base(
-                                       nested_decl,
-                                       BT_INTEGER_BASE_HEXADECIMAL);
-                               BT_ASSERT(ret == 0);
+                               int_ft->disp_base =
+                                       BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
                        }
                } else {
                        ret = visit_type_specifier_list(ctx,
@@ -1367,7 +1368,8 @@ int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
        BT_ASSERT(nested_decl);
 
        if (!node_type_declarator) {
-               BT_MOVE(*field_decl, nested_decl);
+               *field_decl = nested_decl;
+               nested_decl = NULL;
                goto end;
        }
 
@@ -1385,12 +1387,13 @@ int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
                        *field_name = 0;
                }
 
-               BT_MOVE(*field_decl, nested_decl);
+               *field_decl = nested_decl;
+               nested_decl = NULL;
                goto end;
        } else {
                struct ctf_node *first;
-               _BT_FIELD_TYPE_INIT(decl);
-               _BT_FIELD_TYPE_INIT(outer_field_decl);
+               struct ctf_field_type *decl = NULL;
+               struct ctf_field_type *outer_field_decl = NULL;
                struct bt_list_head *length =
                        &node_type_declarator->
                                u.type_declarator.u.nested.length;
@@ -1415,29 +1418,22 @@ int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
                switch (first->u.unary_expression.type) {
                case UNARY_UNSIGNED_CONSTANT:
                {
-                       size_t len;
-                       _BT_FIELD_TYPE_INIT(array_decl);
-
-                       len = first->u.unary_expression.u.unsigned_constant;
-                       array_decl = bt_field_type_array_create(nested_decl,
-                               len);
-                       BT_PUT(nested_decl);
-                       if (!array_decl) {
-                               _BT_LOGE_NODE(first,
-                                       "Cannot create array field type.");
-                               ret = -ENOMEM;
-                               goto error;
-                       }
-
-                       BT_MOVE(decl, array_decl);
+                       struct ctf_field_type_array *array_decl = NULL;
+
+                       array_decl = ctf_field_type_array_create();
+                       BT_ASSERT(array_decl);
+                       array_decl->length =
+                               first->u.unary_expression.u.unsigned_constant;
+                       array_decl->base.elem_ft = nested_decl;
+                       nested_decl = NULL;
+                       decl = (void *) array_decl;
                        break;
                }
                case UNARY_STRING:
                {
                        /* Lookup unsigned integer definition, create seq. */
-                       _BT_FIELD_TYPE_INIT(seq_decl);
+                       struct ctf_field_type_sequence *seq_decl = NULL;
                        char *length_name = concatenate_unary_strings(length);
-                       char *length_name_no_underscore;
 
                        if (!length_name) {
                                _BT_LOGE_NODE(node_type_declarator,
@@ -1446,26 +1442,72 @@ int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
                                goto error;
                        }
 
-                       length_name_no_underscore =
-                               remove_underscores_from_field_ref(length_name);
-                       if (!length_name_no_underscore) {
-                               /* remove_underscores_from_field_ref() logs errors */
-                               ret = -EINVAL;
-                               goto error;
-                       }
-                       seq_decl = bt_field_type_sequence_create(
-                               nested_decl, length_name_no_underscore);
-                       free(length_name_no_underscore);
-                       g_free(length_name);
-                       BT_PUT(nested_decl);
-                       if (!seq_decl) {
-                               _BT_LOGE_NODE(node_type_declarator,
-                                       "Cannot create sequence field type.");
-                               ret = -ENOMEM;
-                               goto error;
+                       if (strncmp(length_name, "env.", 4) == 0) {
+                               /* This is, in fact, an array */
+                               const char *env_entry_name = &length_name[4];
+                               struct ctf_trace_class_env_entry *env_entry =
+                                       ctf_trace_class_borrow_env_entry_by_name(
+                                               ctx->ctf_tc, env_entry_name);
+                               struct ctf_field_type_array *array_decl;
+
+                               if (!env_entry) {
+                                       _BT_LOGE_NODE(node_type_declarator,
+                                               "Cannot find environment entry: "
+                                               "name=\"%s\"", env_entry_name);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               if (env_entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
+                                       _BT_LOGE_NODE(node_type_declarator,
+                                               "Wrong environment entry type "
+                                               "(expecting integer): "
+                                               "name=\"%s\"", env_entry_name);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               if (env_entry->value.i < 0) {
+                                       _BT_LOGE_NODE(node_type_declarator,
+                                               "Invalid, negative array length: "
+                                               "env-entry-name=\"%s\", "
+                                               "value=%" PRId64,
+                                               env_entry_name,
+                                               env_entry->value.i);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               array_decl = ctf_field_type_array_create();
+                               BT_ASSERT(array_decl);
+                               array_decl->length =
+                                       (uint64_t) env_entry->value.i;
+                               array_decl->base.elem_ft = nested_decl;
+                               nested_decl = NULL;
+                               decl = (void *) array_decl;
+                       } else {
+                               char *length_name_no_underscore =
+                                       remove_underscores_from_field_ref(
+                                               length_name);
+                               if (!length_name_no_underscore) {
+                                       /*
+                                        * remove_underscores_from_field_ref()
+                                        * logs errors
+                                        */
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+                               seq_decl = ctf_field_type_sequence_create();
+                               BT_ASSERT(seq_decl);
+                               seq_decl->base.elem_ft = nested_decl;
+                               nested_decl = NULL;
+                               g_string_assign(seq_decl->length_ref,
+                                       length_name_no_underscore);
+                               free(length_name_no_underscore);
+                               decl = (void *) seq_decl;
                        }
 
-                       BT_MOVE(decl, seq_decl);
+                       g_free(length_name);
                        break;
                }
                default:
@@ -1497,37 +1539,41 @@ int visit_type_declarator(struct ctx *ctx, struct ctf_node *type_specifier_list,
                }
 
                BT_ASSERT(outer_field_decl);
-               BT_MOVE(*field_decl, outer_field_decl);
+               *field_decl = outer_field_decl;
+               outer_field_decl = NULL;
        }
 
-end:
-       BT_PUT(nested_decl);
        BT_ASSERT(*field_decl);
-
-       return 0;
+       goto end;
 
 error:
-       BT_PUT(nested_decl);
-       BT_PUT(*field_decl);
+       ctf_field_type_destroy(*field_decl);
+       *field_decl = NULL;
 
+       if (ret >= 0) {
+               ret = -1;
+       }
+
+end:
+       ctf_field_type_destroy(nested_decl);
+       nested_decl = NULL;
        return ret;
 }
 
 static
 int visit_struct_decl_field(struct ctx *ctx,
-       struct bt_field_type *struct_decl,
-       struct ctf_node *type_specifier_list,
-       struct bt_list_head *type_declarators)
+               struct ctf_field_type_struct *struct_decl,
+               struct ctf_node *type_specifier_list,
+               struct bt_list_head *type_declarators)
 {
        int ret = 0;
        struct ctf_node *iter;
-       _BT_FIELD_TYPE_INIT(field_decl);
+       struct ctf_field_type *field_decl = NULL;
 
        bt_list_for_each_entry(iter, type_declarators, siblings) {
                field_decl = NULL;
                GQuark qfield_name;
                const char *field_name;
-               _BT_FIELD_TYPE_INIT(efield_decl);
 
                ret = visit_type_declarator(ctx, type_specifier_list,
                        &qfield_name, iter, &field_decl, NULL);
@@ -1542,11 +1588,8 @@ int visit_struct_decl_field(struct ctx *ctx,
                field_name = g_quark_to_string(qfield_name);
 
                /* Check if field with same name already exists */
-               efield_decl =
-                       bt_field_type_structure_get_field_type_by_name(
-                               struct_decl, field_name);
-               if (efield_decl) {
-                       BT_PUT(efield_decl);
+               if (ctf_field_type_struct_borrow_member_by_name(
+                               struct_decl, field_name)) {
                        _BT_LOGE_NODE(type_specifier_list,
                                "Duplicate field in structure field type: "
                                "field-name=\"%s\"", field_name);
@@ -1555,41 +1598,33 @@ int visit_struct_decl_field(struct ctx *ctx,
                }
 
                /* Add field to structure */
-               ret = bt_field_type_structure_add_field(struct_decl,
-                       field_decl, field_name);
-               BT_PUT(field_decl);
-               if (ret) {
-                       _BT_LOGE_NODE(type_specifier_list,
-                               "Cannot add field to structure field type: "
-                               "field-name=\"%s\", ret=%d",
-                               g_quark_to_string(qfield_name), ret);
-                       goto error;
-               }
+               ctf_field_type_struct_append_member(struct_decl,
+                       field_name, field_decl);
+               field_decl = NULL;
        }
 
        return 0;
 
 error:
-       BT_PUT(field_decl);
-
+       ctf_field_type_destroy(field_decl);
+       field_decl = NULL;
        return ret;
 }
 
 static
 int visit_variant_decl_field(struct ctx *ctx,
-       struct bt_field_type *variant_decl,
-       struct ctf_node *type_specifier_list,
-       struct bt_list_head *type_declarators)
+               struct ctf_field_type_variant *variant_decl,
+               struct ctf_node *type_specifier_list,
+               struct bt_list_head *type_declarators)
 {
        int ret = 0;
        struct ctf_node *iter;
-       _BT_FIELD_TYPE_INIT(field_decl);
+       struct ctf_field_type *field_decl = NULL;
 
        bt_list_for_each_entry(iter, type_declarators, siblings) {
                field_decl = NULL;
                GQuark qfield_name;
                const char *field_name;
-               _BT_FIELD_TYPE_INIT(efield_decl);
 
                ret = visit_type_declarator(ctx, type_specifier_list,
                        &qfield_name, iter, &field_decl, NULL);
@@ -1604,11 +1639,8 @@ int visit_variant_decl_field(struct ctx *ctx,
                field_name = g_quark_to_string(qfield_name);
 
                /* Check if field with same name already exists */
-               efield_decl =
-                       bt_field_type_variant_get_field_type_by_name(
-                               variant_decl, field_name);
-               if (efield_decl) {
-                       BT_PUT(efield_decl);
+               if (ctf_field_type_variant_borrow_option_by_name(
+                               variant_decl, field_name)) {
                        _BT_LOGE_NODE(type_specifier_list,
                                "Duplicate field in variant field type: "
                                "field-name=\"%s\"", field_name);
@@ -1617,34 +1649,27 @@ int visit_variant_decl_field(struct ctx *ctx,
                }
 
                /* Add field to structure */
-               ret = bt_field_type_variant_add_field(variant_decl,
-                       field_decl, field_name);
-               BT_PUT(field_decl);
-               if (ret) {
-                       _BT_LOGE_NODE(type_specifier_list,
-                               "Cannot add field to variant field type: "
-                               "field-name=\"%s\", ret=%d",
-                               g_quark_to_string(qfield_name), ret);
-                       goto error;
-               }
+               ctf_field_type_variant_append_option(variant_decl,
+                       field_name, field_decl);
+               field_decl = NULL;
        }
 
        return 0;
 
 error:
-       BT_PUT(field_decl);
-
+       ctf_field_type_destroy(field_decl);
+       field_decl = NULL;
        return ret;
 }
 
 static
 int visit_typedef(struct ctx *ctx, struct ctf_node *type_specifier_list,
-       struct bt_list_head *type_declarators)
+               struct bt_list_head *type_declarators)
 {
        int ret = 0;
        GQuark qidentifier;
        struct ctf_node *iter;
-       _BT_FIELD_TYPE_INIT(type_decl);
+       struct ctf_field_type *type_decl = NULL;
 
        bt_list_for_each_entry(iter, type_declarators, siblings) {
                ret = visit_type_declarator(ctx, type_specifier_list,
@@ -1657,8 +1682,11 @@ int visit_typedef(struct ctx *ctx, struct ctf_node *type_specifier_list,
                }
 
                /* Do not allow typedef and typealias of untagged variants */
-               if (bt_field_type_is_variant(type_decl)) {
-                       if (bt_field_type_variant_get_tag_name(type_decl)) {
+               if (type_decl->id == CTF_FIELD_TYPE_ID_VARIANT) {
+                       struct ctf_field_type_variant *var_ft =
+                               (void *) type_decl;
+
+                       if (var_ft->tag_path.path->len == 0) {
                                _BT_LOGE_NODE(iter,
                                        "Type definition of untagged variant field type is not allowed.");
                                ret = -EPERM;
@@ -1677,20 +1705,20 @@ int visit_typedef(struct ctx *ctx, struct ctf_node *type_specifier_list,
        }
 
 end:
-       BT_PUT(type_decl);
-
+       ctf_field_type_destroy(type_decl);
+       type_decl = NULL;
        return ret;
 }
 
 static
 int visit_typealias(struct ctx *ctx, struct ctf_node *target,
-       struct ctf_node *alias)
+               struct ctf_node *alias)
 {
        int ret = 0;
        GQuark qalias;
        struct ctf_node *node;
        GQuark qdummy_field_name;
-       _BT_FIELD_TYPE_INIT(type_decl);
+       struct ctf_field_type *type_decl = NULL;
 
        /* Create target type declaration */
        if (bt_list_empty(&target->u.typealias_target.type_declarators)) {
@@ -1712,8 +1740,10 @@ int visit_typealias(struct ctx *ctx, struct ctf_node *target,
        }
 
        /* Do not allow typedef and typealias of untagged variants */
-       if (bt_field_type_is_variant(type_decl)) {
-               if (bt_field_type_variant_get_tag_name(type_decl)) {
+       if (type_decl->id == CTF_FIELD_TYPE_ID_VARIANT) {
+               struct ctf_field_type_variant *var_ft = (void *) type_decl;
+
+               if (var_ft->tag_path.path->len == 0) {
                        _BT_LOGE_NODE(target,
                                "Type definition of untagged variant field type is not allowed.");
                        ret = -EPERM;
@@ -1748,14 +1778,14 @@ int visit_typealias(struct ctx *ctx, struct ctf_node *target,
        }
 
 end:
-       BT_PUT(type_decl);
-
+       ctf_field_type_destroy(type_decl);
+       type_decl = NULL;
        return ret;
 }
 
 static
 int visit_struct_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
-       struct bt_field_type *struct_decl)
+               struct ctf_field_type_struct *struct_decl)
 {
        int ret = 0;
 
@@ -1805,7 +1835,7 @@ end:
 
 static
 int visit_variant_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
-       struct bt_field_type *variant_decl)
+               struct ctf_field_type_variant *variant_decl)
 {
        int ret = 0;
 
@@ -1856,18 +1886,17 @@ end:
 
 static
 int visit_struct_decl(struct ctx *ctx, const char *name,
-       struct bt_list_head *decl_list, int has_body,
-       struct bt_list_head *min_align,
-       struct bt_field_type **struct_decl)
+               struct bt_list_head *decl_list, int has_body,
+               struct bt_list_head *min_align,
+               struct ctf_field_type_struct **struct_decl)
 {
        int ret = 0;
 
+       BT_ASSERT(struct_decl);
        *struct_decl = NULL;
 
        /* For named struct (without body), lookup in declaration scope */
        if (!has_body) {
-               _BT_FIELD_TYPE_INIT(struct_decl_copy);
-
                if (!name) {
                        BT_LOGE_STR("Bodyless structure field type: missing name.");
                        ret = -EPERM;
@@ -1875,34 +1904,20 @@ int visit_struct_decl(struct ctx *ctx, const char *name,
                }
 
                *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope,
-                       name, -1);
+                       name, -1, true);
                if (!*struct_decl) {
                        BT_LOGE("Cannot find structure field type: name=\"struct %s\"",
                                name);
                        ret = -EINVAL;
                        goto error;
                }
-
-               /* Make a copy of it */
-               struct_decl_copy = bt_field_type_copy(*struct_decl);
-               if (!struct_decl_copy) {
-                       BT_LOGE_STR("Cannot create copy of structure field type.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               BT_MOVE(*struct_decl, struct_decl_copy);
        } else {
                struct ctf_node *entry_node;
                uint64_t min_align_value = 0;
 
                if (name) {
-                       _BT_FIELD_TYPE_INIT(estruct_decl);
-
-                       estruct_decl = ctx_decl_scope_lookup_struct(
-                               ctx->current_scope, name, 1);
-                       if (estruct_decl) {
-                               BT_PUT(estruct_decl);
+                       if (ctx_decl_scope_lookup_struct(
+                                       ctx->current_scope, name, 1, false)) {
                                BT_LOGE("Structure field type already declared in local scope: "
                                        "name=\"struct %s\"", name);
                                ret = -EINVAL;
@@ -1919,28 +1934,14 @@ int visit_struct_decl(struct ctx *ctx, const char *name,
                        }
                }
 
-               *struct_decl = bt_field_type_structure_create();
-               if (!*struct_decl) {
-                       BT_LOGE_STR("Cannot create empty structure field type.");
-                       ret = -ENOMEM;
-                       goto error;
-               }
+               *struct_decl = ctf_field_type_struct_create();
+               BT_ASSERT(*struct_decl);
 
                if (min_align_value != 0) {
-                       ret = bt_field_type_set_alignment(*struct_decl,
-                                       min_align_value);
-                       if (ret) {
-                               BT_LOGE("Cannot set structure field type's alignment: "
-                                       "ret=%d", ret);
-                               goto error;
-                       }
+                       (*struct_decl)->base.alignment = min_align_value;
                }
 
-               ret = ctx_push_scope(ctx);
-               if (ret) {
-                       BT_LOGE_STR("Cannot push scope.");
-                       goto error;
-               }
+               _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
 
                bt_list_for_each_entry(entry_node, decl_list, siblings) {
                        ret = visit_struct_decl_entry(ctx, entry_node,
@@ -1970,25 +1971,24 @@ int visit_struct_decl(struct ctx *ctx, const char *name,
        return 0;
 
 error:
-       BT_PUT(*struct_decl);
-
+       ctf_field_type_destroy((void *) *struct_decl);
+       *struct_decl = NULL;
        return ret;
 }
 
 static
 int visit_variant_decl(struct ctx *ctx, const char *name,
        const char *tag, struct bt_list_head *decl_list,
-       int has_body, struct bt_field_type **variant_decl)
+       int has_body, struct ctf_field_type_variant **variant_decl)
 {
        int ret = 0;
-       _BT_FIELD_TYPE_INIT(untagged_variant_decl);
+       struct ctf_field_type_variant *untagged_variant_decl = NULL;
 
+       BT_ASSERT(variant_decl);
        *variant_decl = NULL;
 
        /* For named variant (without body), lookup in declaration scope */
        if (!has_body) {
-               _BT_FIELD_TYPE_INIT(variant_decl_copy);
-
                if (!name) {
                        BT_LOGE_STR("Bodyless variant field type: missing name.");
                        ret = -EPERM;
@@ -1997,34 +1997,19 @@ int visit_variant_decl(struct ctx *ctx, const char *name,
 
                untagged_variant_decl =
                        ctx_decl_scope_lookup_variant(ctx->current_scope,
-                               name, -1);
+                               name, -1, true);
                if (!untagged_variant_decl) {
                        BT_LOGE("Cannot find variant field type: name=\"variant %s\"",
                                name);
                        ret = -EINVAL;
                        goto error;
                }
-
-               /* Make a copy of it */
-               variant_decl_copy = bt_field_type_copy(
-                       untagged_variant_decl);
-               if (!variant_decl_copy) {
-                       BT_LOGE_STR("Cannot create copy of variant field type.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               BT_MOVE(untagged_variant_decl, variant_decl_copy);
        } else {
                struct ctf_node *entry_node;
 
                if (name) {
-                       struct bt_field_type *evariant_decl =
-                               ctx_decl_scope_lookup_struct(ctx->current_scope,
-                                       name, 1);
-
-                       if (evariant_decl) {
-                               BT_PUT(evariant_decl);
+                       if (ctx_decl_scope_lookup_variant(ctx->current_scope,
+                                       name, 1, false)) {
                                BT_LOGE("Variant field type already declared in local scope: "
                                        "name=\"variant %s\"", name);
                                ret = -EINVAL;
@@ -2032,19 +2017,9 @@ int visit_variant_decl(struct ctx *ctx, const char *name,
                        }
                }
 
-               untagged_variant_decl = bt_field_type_variant_create(NULL,
-                       NULL);
-               if (!untagged_variant_decl) {
-                       BT_LOGE_STR("Cannot create empty variant field type.");
-                       ret = -ENOMEM;
-                       goto error;
-               }
-
-               ret = ctx_push_scope(ctx);
-               if (ret) {
-                       BT_LOGE_STR("Cannot push scope.");
-                       goto error;
-               }
+               untagged_variant_decl = ctf_field_type_variant_create();
+               BT_ASSERT(untagged_variant_decl);
+               _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
 
                bt_list_for_each_entry(entry_node, decl_list, siblings) {
                        ret = visit_variant_decl_entry(ctx, entry_node,
@@ -2077,7 +2052,8 @@ int visit_variant_decl(struct ctx *ctx, const char *name,
         * return untagged variant.
         */
        if (!tag) {
-               BT_MOVE(*variant_decl, untagged_variant_decl);
+               *variant_decl = untagged_variant_decl;
+               untagged_variant_decl = NULL;
        } else {
                /*
                 * At this point, we have a fresh untagged variant; nobody
@@ -2091,44 +2067,54 @@ int visit_variant_decl(struct ctx *ctx, const char *name,
                        goto error;
                }
 
-               ret = bt_field_type_variant_set_tag_name(
-                       untagged_variant_decl, tag_no_underscore);
+               g_string_assign(untagged_variant_decl->tag_ref,
+                       tag_no_underscore);
                free(tag_no_underscore);
-               if (ret) {
-                       BT_LOGE("Cannot set variant field type's tag name: "
-                               "tag-name=\"%s\"", tag);
-                       goto error;
-               }
-
-               BT_MOVE(*variant_decl, untagged_variant_decl);
+               *variant_decl = untagged_variant_decl;
+               untagged_variant_decl = NULL;
        }
 
        BT_ASSERT(!untagged_variant_decl);
        BT_ASSERT(*variant_decl);
-
        return 0;
 
 error:
-       BT_PUT(untagged_variant_decl);
-       BT_PUT(*variant_decl);
-
+       ctf_field_type_destroy((void *) untagged_variant_decl);
+       untagged_variant_decl = NULL;
+       ctf_field_type_destroy((void *) *variant_decl);
+       *variant_decl = NULL;
        return ret;
 }
 
+struct uori {
+       bool is_signed;
+       union {
+               uint64_t u;
+               uint64_t i;
+       } value;
+};
+
 static
 int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
-       struct bt_field_type *enum_decl, int64_t *last, bt_bool is_signed)
+               struct ctf_field_type_enum *enum_decl, struct uori *last)
 {
        int ret = 0;
        int nr_vals = 0;
        struct ctf_node *iter;
-       int64_t start = 0, end = 0;
+       struct uori start = {
+               .is_signed = false,
+               .value.u = 0,
+       };
+       struct uori end = {
+               .is_signed = false,
+               .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) {
-               int64_t *target;
+               struct uori *target;
 
                if (iter->type != NODE_UNARY_EXPRESSION) {
                        _BT_LOGE_NODE(iter,
@@ -2147,10 +2133,13 @@ int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
 
                switch (iter->u.unary_expression.type) {
                case UNARY_SIGNED_CONSTANT:
-                       *target = iter->u.unary_expression.u.signed_constant;
+                       target->is_signed = true;
+                       target->value.i =
+                               iter->u.unary_expression.u.signed_constant;
                        break;
                case UNARY_UNSIGNED_CONSTANT:
-                       *target = (int64_t)
+                       target->is_signed = false;
+                       target->value.u =
                                iter->u.unary_expression.u.unsigned_constant;
                        break;
                default:
@@ -2182,7 +2171,11 @@ int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
                end = start;
        }
 
-       *last = end + 1;
+       if (end.is_signed) {
+               last->value.i = end.value.i + 1;
+       } else {
+               last->value.u = end.value.u + 1;
+       }
 
        if (label[0] == '_') {
                /*
@@ -2196,23 +2189,8 @@ int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
                effective_label = &label[1];
        }
 
-       if (is_signed) {
-               ret = bt_field_type_enumeration_signed_add_mapping(enum_decl,
-                       effective_label, start, end);
-       } else {
-               ret = bt_field_type_enumeration_unsigned_add_mapping(enum_decl,
-                       effective_label, (uint64_t) start, (uint64_t) end);
-       }
-       if (ret) {
-               _BT_LOGE_NODE(enumerator,
-                       "Cannot add mapping to enumeration field type: "
-                       "label=\"%s\", ret=%d, "
-                       "start-value-unsigned=%" PRIu64 ", "
-                       "end-value-unsigned=%" PRIu64, label, ret,
-                       (uint64_t) start, (uint64_t) end);
-               goto error;
-       }
-
+       ctf_field_type_enum_append_mapping(enum_decl, effective_label,
+               start.value.u, end.value.u);
        return 0;
 
 error:
@@ -2221,21 +2199,19 @@ error:
 
 static
 int visit_enum_decl(struct ctx *ctx, const char *name,
-       struct ctf_node *container_type,
-       struct bt_list_head *enumerator_list,
-       int has_body,
-       struct bt_field_type **enum_decl)
+               struct ctf_node *container_type,
+               struct bt_list_head *enumerator_list,
+               int has_body, struct ctf_field_type_enum **enum_decl)
 {
        int ret = 0;
        GQuark qdummy_id;
-       _BT_FIELD_TYPE_INIT(integer_decl);
+       struct ctf_field_type_int *integer_decl = NULL;
 
+       BT_ASSERT(enum_decl);
        *enum_decl = NULL;
 
        /* For named enum (without body), lookup in declaration scope */
        if (!has_body) {
-               _BT_FIELD_TYPE_INIT(enum_decl_copy);
-
                if (!name) {
                        BT_LOGE_STR("Bodyless enumeration field type: missing name.");
                        ret = -EPERM;
@@ -2243,35 +2219,23 @@ int visit_enum_decl(struct ctx *ctx, const char *name,
                }
 
                *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope,
-                       name, -1);
+                       name, -1, true);
                if (!*enum_decl) {
                        BT_LOGE("Cannot find enumeration field type: "
                                "name=\"enum %s\"", name);
                        ret = -EINVAL;
                        goto error;
                }
-
-               /* Make a copy of it */
-               enum_decl_copy = bt_field_type_copy(*enum_decl);
-               if (!enum_decl_copy) {
-                       BT_LOGE_STR("Cannot create copy of enumeration field type.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               BT_PUT(*enum_decl);
-               BT_MOVE(*enum_decl, enum_decl_copy);
        } else {
                struct ctf_node *iter;
-               int64_t last_value = 0;
+               struct uori last_value = {
+                       .is_signed = false,
+                       .value.u = 0,
+               };
 
                if (name) {
-                       _BT_FIELD_TYPE_INIT(eenum_decl);
-
-                       eenum_decl = ctx_decl_scope_lookup_enum(
-                               ctx->current_scope, name, 1);
-                       if (eenum_decl) {
-                               BT_PUT(eenum_decl);
+                       if (ctx_decl_scope_lookup_enum(ctx->current_scope,
+                                       name, 1, false)) {
                                BT_LOGE("Enumeration field type already declared in local scope: "
                                        "name=\"enum %s\"", name);
                                ret = -EINVAL;
@@ -2280,8 +2244,8 @@ int visit_enum_decl(struct ctx *ctx, const char *name,
                }
 
                if (!container_type) {
-                       integer_decl = ctx_decl_scope_lookup_alias(
-                               ctx->current_scope, "int", -1);
+                       integer_decl = (void *) ctx_decl_scope_lookup_alias(
+                               ctx->current_scope, "int", -1, true);
                        if (!integer_decl) {
                                BT_LOGE_STR("Cannot find implicit `int` field type alias for enumeration field type.");
                                ret = -EINVAL;
@@ -2289,7 +2253,8 @@ int visit_enum_decl(struct ctx *ctx, const char *name,
                        }
                } else {
                        ret = visit_type_declarator(ctx, container_type,
-                               &qdummy_id, NULL, &integer_decl, NULL);
+                               &qdummy_id, NULL, (void *) &integer_decl,
+                               NULL);
                        if (ret) {
                                BT_ASSERT(!integer_decl);
                                ret = -EINVAL;
@@ -2299,26 +2264,24 @@ int visit_enum_decl(struct ctx *ctx, const char *name,
 
                BT_ASSERT(integer_decl);
 
-               if (!bt_field_type_is_integer(integer_decl)) {
+               if (integer_decl->base.base.id != CTF_FIELD_TYPE_ID_INT) {
                        BT_LOGE("Container field type for enumeration field type is not an integer field type: "
-                               "ft-id=%s",
-                               bt_common_field_type_id_string(
-                                       bt_field_type_get_type_id(integer_decl)));
+                               "ft-id=%d", integer_decl->base.base.id);
                        ret = -EINVAL;
                        goto error;
                }
 
-               *enum_decl = bt_field_type_enumeration_create(integer_decl);
-               if (!*enum_decl) {
-                       BT_LOGE_STR("Cannot create enumeration field type.");
-                       ret = -ENOMEM;
-                       goto error;
-               }
+               *enum_decl = ctf_field_type_enum_create();
+               BT_ASSERT(*enum_decl);
+               (*enum_decl)->base.base.base.alignment =
+                       integer_decl->base.base.alignment;
+               ctf_field_type_int_copy_content((void *) *enum_decl,
+                               (void *) integer_decl);
+               last_value.is_signed = (*enum_decl)->base.is_signed;
 
                bt_list_for_each_entry(iter, enumerator_list, siblings) {
                        ret = visit_enum_decl_entry(ctx, iter, *enum_decl,
-                               &last_value,
-                               bt_field_type_integer_is_signed(integer_decl));
+                               &last_value);
                        if (ret) {
                                _BT_LOGE_NODE(iter,
                                        "Cannot visit enumeration field type entry: "
@@ -2338,25 +2301,25 @@ int visit_enum_decl(struct ctx *ctx, const char *name,
                }
        }
 
-       BT_PUT(integer_decl);
-
-       return 0;
+       goto end;
 
 error:
-       BT_PUT(integer_decl);
-       BT_PUT(*enum_decl);
+       ctf_field_type_destroy((void *) *enum_decl);
+       *enum_decl = NULL;
 
+end:
+       ctf_field_type_destroy((void *) integer_decl);
+       integer_decl = NULL;
        return ret;
 }
 
 static
 int visit_type_specifier(struct ctx *ctx,
-       struct ctf_node *type_specifier_list,
-       struct bt_field_type **decl)
+               struct ctf_node *type_specifier_list,
+               struct ctf_field_type **decl)
 {
        int ret = 0;
        GString *str = NULL;
-       _BT_FIELD_TYPE_INIT(decl_copy);
 
        *decl = NULL;
        str = g_string_new("");
@@ -2367,7 +2330,8 @@ int visit_type_specifier(struct ctx *ctx,
                goto error;
        }
 
-       *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1);
+       *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1,
+               true);
        if (!*decl) {
                _BT_LOGE_NODE(type_specifier_list,
                        "Cannot find type alias: name=\"%s\"", str->str);
@@ -2375,46 +2339,35 @@ int visit_type_specifier(struct ctx *ctx,
                goto error;
        }
 
-       /* Make a copy of the type declaration */
-       decl_copy = bt_field_type_copy(*decl);
-       if (!decl_copy) {
-               _BT_LOGE_NODE(type_specifier_list,
-                       "Cannot create field type copy.");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       BT_MOVE(*decl, decl_copy);
-       (void) g_string_free(str, TRUE);
-       str = NULL;
-
-       return 0;
+       goto end;
 
 error:
+       ctf_field_type_destroy(*decl);
+       *decl = NULL;
+
+end:
        if (str) {
-               (void) g_string_free(str, TRUE);
+               g_string_free(str, TRUE);
        }
 
-       BT_PUT(*decl);
-
        return ret;
 }
 
 static
 int visit_integer_decl(struct ctx *ctx,
-       struct bt_list_head *expressions,
-       struct bt_field_type **integer_decl)
+               struct bt_list_head *expressions,
+               struct ctf_field_type_int **integer_decl)
 {
        int set = 0;
        int ret = 0;
-       bt_bool signedness = 0;
+       int signedness = 0;
        struct ctf_node *expression;
        uint64_t alignment = 0, size = 0;
-       struct bt_clock_class *mapped_clock = NULL;
-       enum bt_string_encoding encoding = BT_STRING_ENCODING_NONE;
-       enum bt_integer_base base = BT_INTEGER_BASE_DECIMAL;
-       enum bt_byte_order byte_order =
-               bt_trace_get_native_byte_order(ctx->trace);
+       struct bt_clock_class *mapped_clock_class = NULL;
+       enum ctf_encoding encoding = CTF_ENCODING_NONE;
+       enum bt_field_type_integer_preferred_display_base base =
+               BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
+       enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
 
        *integer_decl = NULL;
 
@@ -2463,7 +2416,7 @@ int visit_integer_decl(struct ctx *ctx,
                        }
 
                        byte_order = get_real_byte_order(ctx, right);
-                       if (byte_order == BT_BYTE_ORDER_UNKNOWN) {
+                       if (byte_order == -1) {
                                _BT_LOGE_NODE(right,
                                        "Invalid `byte_order` attribute in integer field type: "
                                        "ret=%d", ret);
@@ -2557,16 +2510,16 @@ int visit_integer_decl(struct ctx *ctx,
 
                                switch (constant) {
                                case 2:
-                                       base = BT_INTEGER_BASE_BINARY;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
                                        break;
                                case 8:
-                                       base = BT_INTEGER_BASE_OCTAL;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
                                        break;
                                case 10:
-                                       base = BT_INTEGER_BASE_DECIMAL;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
                                        break;
                                case 16:
-                                       base = BT_INTEGER_BASE_HEXADECIMAL;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
                                        break;
                                default:
                                        _BT_LOGE_NODE(right,
@@ -2594,20 +2547,20 @@ int visit_integer_decl(struct ctx *ctx,
                                                !strcmp(s_right, "d") ||
                                                !strcmp(s_right, "i") ||
                                                !strcmp(s_right, "u")) {
-                                       base = BT_INTEGER_BASE_DECIMAL;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
                                } else if (!strcmp(s_right, "hexadecimal") ||
                                                !strcmp(s_right, "hex") ||
                                                !strcmp(s_right, "x") ||
                                                !strcmp(s_right, "X") ||
                                                !strcmp(s_right, "p")) {
-                                       base = BT_INTEGER_BASE_HEXADECIMAL;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
                                } else if (!strcmp(s_right, "octal") ||
                                                !strcmp(s_right, "oct") ||
                                                !strcmp(s_right, "o")) {
-                                       base = BT_INTEGER_BASE_OCTAL;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
                                } else if (!strcmp(s_right, "binary") ||
                                                !strcmp(s_right, "b")) {
-                                       base = BT_INTEGER_BASE_BINARY;
+                                       base = BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
                                } else {
                                        _BT_LOGE_NODE(right,
                                                "Unexpected unary expression for integer field type's `base` attribute: "
@@ -2660,13 +2613,12 @@ int visit_integer_decl(struct ctx *ctx,
                        if (!strcmp(s_right, "UTF8") ||
                                        !strcmp(s_right, "utf8") ||
                                        !strcmp(s_right, "utf-8") ||
-                                       !strcmp(s_right, "UTF-8")) {
-                               encoding = BT_STRING_ENCODING_UTF8;
-                       } else if (!strcmp(s_right, "ASCII") ||
+                                       !strcmp(s_right, "UTF-8") ||
+                                       !strcmp(s_right, "ASCII") ||
                                        !strcmp(s_right, "ascii")) {
-                               encoding = BT_STRING_ENCODING_ASCII;
+                               encoding = CTF_ENCODING_UTF8;
                        } else if (!strcmp(s_right, "none")) {
-                               encoding = BT_STRING_ENCODING_NONE;
+                               encoding = CTF_ENCODING_NONE;
                        } else {
                                _BT_LOGE_NODE(right,
                                        "Invalid `encoding` attribute in integer field type: "
@@ -2720,9 +2672,10 @@ int visit_integer_decl(struct ctx *ctx,
                                continue;
                        }
 
-                       mapped_clock = bt_trace_get_clock_class_by_name(
-                               ctx->trace, clock_name);
-                       if (!mapped_clock) {
+                       mapped_clock_class =
+                               ctf_trace_class_borrow_clock_class_by_name(
+                                       ctx->ctf_tc, clock_name);
+                       if (!mapped_clock_class) {
                                _BT_LOGE_NODE(right,
                                        "Invalid `map` attribute in integer field type: "
                                        "cannot find clock class at this point: name=\"%s\"",
@@ -2756,57 +2709,33 @@ int visit_integer_decl(struct ctx *ctx,
                }
        }
 
-       *integer_decl = bt_field_type_integer_create((unsigned int) size);
-       if (!*integer_decl) {
-               BT_LOGE_STR("Cannot create integer field type.");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       ret = bt_field_type_integer_set_is_signed(*integer_decl, signedness);
-       ret |= bt_field_type_integer_set_base(*integer_decl, base);
-       ret |= bt_field_type_integer_set_encoding(*integer_decl, encoding);
-       ret |= bt_field_type_set_alignment(*integer_decl,
-               (unsigned int) alignment);
-       ret |= bt_field_type_set_byte_order(*integer_decl, byte_order);
-
-       if (mapped_clock) {
-               /* Move clock */
-               ret |= bt_field_type_integer_set_mapped_clock_class(
-                       *integer_decl, mapped_clock);
-               bt_put(mapped_clock);
-               mapped_clock = NULL;
-       }
-
-       if (ret) {
-               BT_LOGE_STR("Cannot configure integer field type.");
-               ret = -EINVAL;
-               goto error;
-       }
-
+       *integer_decl = ctf_field_type_int_create();
+       BT_ASSERT(*integer_decl);
+       (*integer_decl)->base.base.alignment = alignment;
+       (*integer_decl)->base.byte_order = byte_order;
+       (*integer_decl)->base.size = size;
+       (*integer_decl)->is_signed = (signedness > 0);
+       (*integer_decl)->disp_base = base;
+       (*integer_decl)->encoding = encoding;
+       (*integer_decl)->mapped_clock_class = bt_get(mapped_clock_class);
        return 0;
 
 error:
-       if (mapped_clock) {
-               bt_put(mapped_clock);
-       }
-
-       BT_PUT(*integer_decl);
-
+       ctf_field_type_destroy((void *) *integer_decl);
+       *integer_decl = NULL;
        return ret;
 }
 
 static
 int visit_floating_point_number_decl(struct ctx *ctx,
-       struct bt_list_head *expressions,
-       struct bt_field_type **float_decl)
+               struct bt_list_head *expressions,
+               struct ctf_field_type_float **float_decl)
 {
        int set = 0;
        int ret = 0;
        struct ctf_node *expression;
        uint64_t alignment = 1, exp_dig = 0, mant_dig = 0;
-       enum bt_byte_order byte_order =
-               bt_trace_get_native_byte_order(ctx->trace);
+       enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
 
        *float_decl = NULL;
 
@@ -2836,7 +2765,7 @@ int visit_floating_point_number_decl(struct ctx *ctx,
                        }
 
                        byte_order = get_real_byte_order(ctx, right);
-                       if (byte_order == BT_BYTE_ORDER_UNKNOWN) {
+                       if (byte_order == -1) {
                                _BT_LOGE_NODE(right,
                                        "Invalid `byte_order` attribute in floating point number field type: "
                                        "ret=%d", ret);
@@ -2943,6 +2872,24 @@ int visit_floating_point_number_decl(struct ctx *ctx,
                goto error;
        }
 
+       if (mant_dig != 24 && mant_dig != 53) {
+               BT_LOGE_STR("`mant_dig` attribute: expecting 24 or 53.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (mant_dig == 24 && exp_dig != 8) {
+               BT_LOGE_STR("`exp_dig` attribute: expecting 8 because `mant_dig` is 24.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (mant_dig == 53 && exp_dig != 11) {
+               BT_LOGE_STR("`exp_dig` attribute: expecting 11 because `mant_dig` is 53.");
+               ret = -EPERM;
+               goto error;
+       }
+
        if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) {
                if ((mant_dig + exp_dig) % CHAR_BIT) {
                        /* Bit-packed alignment */
@@ -2953,42 +2900,28 @@ int visit_floating_point_number_decl(struct ctx *ctx,
                }
        }
 
-       *float_decl = bt_field_type_floating_point_create();
-       if (!*float_decl) {
-               BT_LOGE_STR("Cannot create floating point number field type.");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       ret = bt_field_type_floating_point_set_exponent_digits(
-               *float_decl, exp_dig);
-       ret |= bt_field_type_floating_point_set_mantissa_digits(
-               *float_decl, mant_dig);
-       ret |= bt_field_type_set_byte_order(*float_decl, byte_order);
-       ret |= bt_field_type_set_alignment(*float_decl, alignment);
-       if (ret) {
-               BT_LOGE_STR("Cannot configure floating point number field type.");
-               ret = -EINVAL;
-               goto error;
-       }
-
+       *float_decl = ctf_field_type_float_create();
+       BT_ASSERT(*float_decl);
+       (*float_decl)->base.base.alignment = alignment;
+       (*float_decl)->base.byte_order = byte_order;
+       (*float_decl)->base.size = mant_dig + exp_dig;
        return 0;
 
 error:
-       BT_PUT(*float_decl);
-
+       ctf_field_type_destroy((void *) *float_decl);
+       *float_decl = NULL;
        return ret;
 }
 
 static
 int visit_string_decl(struct ctx *ctx,
-       struct bt_list_head *expressions,
-       struct bt_field_type **string_decl)
+               struct bt_list_head *expressions,
+               struct ctf_field_type_string **string_decl)
 {
        int set = 0;
        int ret = 0;
        struct ctf_node *expression;
-       enum bt_string_encoding encoding = BT_STRING_ENCODING_UTF8;
+       enum ctf_encoding encoding = CTF_ENCODING_UTF8;
 
        *string_decl = NULL;
 
@@ -3039,13 +2972,12 @@ int visit_string_decl(struct ctx *ctx,
                        if (!strcmp(s_right, "UTF8") ||
                                        !strcmp(s_right, "utf8") ||
                                        !strcmp(s_right, "utf-8") ||
-                                       !strcmp(s_right, "UTF-8")) {
-                               encoding = BT_STRING_ENCODING_UTF8;
-                       } else if (!strcmp(s_right, "ASCII") ||
+                                       !strcmp(s_right, "UTF-8") ||
+                                       !strcmp(s_right, "ASCII") ||
                                        !strcmp(s_right, "ascii")) {
-                               encoding = BT_STRING_ENCODING_ASCII;
+                               encoding = CTF_ENCODING_UTF8;
                        } else if (!strcmp(s_right, "none")) {
-                               encoding = BT_STRING_ENCODING_NONE;
+                               encoding = CTF_ENCODING_NONE;
                        } else {
                                _BT_LOGE_NODE(right,
                                        "Invalid `encoding` attribute in string field type: "
@@ -3066,32 +2998,20 @@ int visit_string_decl(struct ctx *ctx,
                }
        }
 
-       *string_decl = bt_field_type_string_create();
-       if (!*string_decl) {
-               BT_LOGE_STR("Cannot create string field type.");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       ret = bt_field_type_string_set_encoding(*string_decl, encoding);
-       if (ret) {
-               BT_LOGE_STR("Cannot configure string field type.");
-               ret = -EINVAL;
-               goto error;
-       }
-
+       *string_decl = ctf_field_type_string_create();
+       BT_ASSERT(*string_decl);
+       (*string_decl)->encoding = encoding;
        return 0;
 
 error:
-       BT_PUT(*string_decl);
-
+       ctf_field_type_destroy((void *) *string_decl);
+       *string_decl = NULL;
        return ret;
 }
 
 static
 int visit_type_specifier_list(struct ctx *ctx,
-       struct ctf_node *ts_list,
-       struct bt_field_type **decl)
+               struct ctf_node *ts_list, struct ctf_field_type **decl)
 {
        int ret = 0;
        struct ctf_node *first, *node;
@@ -3119,7 +3039,7 @@ int visit_type_specifier_list(struct ctx *ctx,
        switch (first->u.type_specifier.type) {
        case TYPESPEC_INTEGER:
                ret = visit_integer_decl(ctx, &node->u.integer.expressions,
-                       decl);
+                       (void *) decl);
                if (ret) {
                        BT_ASSERT(!*decl);
                        goto error;
@@ -3127,7 +3047,7 @@ int visit_type_specifier_list(struct ctx *ctx,
                break;
        case TYPESPEC_FLOATING_POINT:
                ret = visit_floating_point_number_decl(ctx,
-                       &node->u.floating_point.expressions, decl);
+                       &node->u.floating_point.expressions, (void *) decl);
                if (ret) {
                        BT_ASSERT(!*decl);
                        goto error;
@@ -3135,7 +3055,7 @@ int visit_type_specifier_list(struct ctx *ctx,
                break;
        case TYPESPEC_STRING:
                ret = visit_string_decl(ctx,
-                       &node->u.string.expressions, decl);
+                       &node->u.string.expressions, (void *) decl);
                if (ret) {
                        BT_ASSERT(!*decl);
                        goto error;
@@ -3145,7 +3065,7 @@ int visit_type_specifier_list(struct ctx *ctx,
                ret = visit_struct_decl(ctx, node->u._struct.name,
                        &node->u._struct.declaration_list,
                        node->u._struct.has_body,
-                       &node->u._struct.min_align, decl);
+                       &node->u._struct.min_align, (void *) decl);
                if (ret) {
                        BT_ASSERT(!*decl);
                        goto error;
@@ -3155,7 +3075,7 @@ int visit_type_specifier_list(struct ctx *ctx,
                ret = visit_variant_decl(ctx, node->u.variant.name,
                        node->u.variant.choice,
                        &node->u.variant.declaration_list,
-                       node->u.variant.has_body, decl);
+                       node->u.variant.has_body, (void *) decl);
                if (ret) {
                        BT_ASSERT(!*decl);
                        goto error;
@@ -3165,7 +3085,7 @@ int visit_type_specifier_list(struct ctx *ctx,
                ret = visit_enum_decl(ctx, node->u._enum.enum_id,
                        node->u._enum.container_type,
                        &node->u._enum.enumerator_list,
-                       node->u._enum.has_body, decl);
+                       node->u._enum.has_body, (void *) decl);
                if (ret) {
                        BT_ASSERT(!*decl);
                        goto error;
@@ -3203,23 +3123,21 @@ int visit_type_specifier_list(struct ctx *ctx,
        }
 
        BT_ASSERT(*decl);
-
        return 0;
 
 error:
-       BT_PUT(*decl);
-
+       ctf_field_type_destroy((void *) *decl);
+       *decl = NULL;
        return ret;
 }
 
 static
 int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
-       struct bt_event_class *event_class, int64_t *stream_id,
-       int *set)
+               struct ctf_event_class *event_class, uint64_t *stream_id,
+               int *set)
 {
        int ret = 0;
        char *left = NULL;
-       _BT_FIELD_TYPE_INIT(decl);
 
        switch (node->type) {
        case NODE_TYPEDEF:
@@ -3252,8 +3170,7 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                if (!strcmp(left, "name")) {
                        /* This is already known at this stage */
                        if (_IS_SET(set, _EVENT_NAME_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "name",
-                                       "event class");
+                               _BT_LOGE_DUP_ATTR(node, "name", "event class");
                                ret = -EPERM;
                                goto error;
                        }
@@ -3263,8 +3180,7 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                        int64_t id = -1;
 
                        if (_IS_SET(set, _EVENT_ID_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "id",
-                                       "event class");
+                               _BT_LOGE_DUP_ATTR(node, "id", "event class");
                                ret = -EPERM;
                                goto error;
                        }
@@ -3279,14 +3195,7 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                goto error;
                        }
 
-                       ret = bt_event_class_set_id(event_class, id);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set event class's ID: "
-                                       "id=%" PRId64, id);
-                               goto error;
-                       }
-
+                       event_class->id = id;
                        _SET(set, _EVENT_ID_SET);
                } else if (!strcmp(left, "stream_id")) {
                        if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
@@ -3297,7 +3206,8 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                        }
 
                        ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               (uint64_t *) stream_id);
+                               stream_id);
+
                        /*
                         * Only read "stream_id" if get_unary_unsigned()
                         * succeeded.
@@ -3322,23 +3232,14 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                _BT_LIST_FIRST_ENTRY(
                                        &node->u.ctf_expression.right,
                                        struct ctf_node, siblings),
-                               &decl);
+                               &event_class->spec_context_ft);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot create event class's context field type.");
                                goto error;
                        }
 
-                       BT_ASSERT(decl);
-                       ret = bt_event_class_set_context_field_type(
-                               event_class, decl);
-                       BT_PUT(decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set event class's context field type.");
-                               goto error;
-                       }
-
+                       BT_ASSERT(event_class->spec_context_ft);
                        _SET(set, _EVENT_CONTEXT_SET);
                } else if (!strcmp(left, "fields")) {
                        if (_IS_SET(set, _EVENT_FIELDS_SET)) {
@@ -3352,30 +3253,20 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                _BT_LIST_FIRST_ENTRY(
                                        &node->u.ctf_expression.right,
                                        struct ctf_node, siblings),
-                               &decl);
+                               &event_class->payload_ft);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot create event class's payload field type.");
                                goto error;
                        }
 
-                       BT_ASSERT(decl);
-                       ret = bt_event_class_set_payload_field_type(
-                               event_class, decl);
-                       BT_PUT(decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set event class's payload field type.");
-                               goto error;
-                       }
-
+                       BT_ASSERT(event_class->payload_ft);
                        _SET(set, _EVENT_FIELDS_SET);
                } else if (!strcmp(left, "loglevel")) {
                        uint64_t loglevel_value;
-                       enum bt_event_class_log_level log_level =
-                               BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED;
+                       enum bt_event_class_log_level log_level = -1;
 
-                       if (_IS_SET(set, _EVENT_LOGLEVEL_SET)) {
+                       if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) {
                                _BT_LOGE_DUP_ATTR(node, "loglevel",
                                        "event class");
                                ret = -EPERM;
@@ -3442,17 +3333,11 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                        "log-level=%" PRIu64, loglevel_value);
                        }
 
-                       if (log_level != BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) {
-                               ret = bt_event_class_set_log_level(
-                                       event_class, log_level);
-                               if (ret) {
-                                       _BT_LOGE_NODE(node,
-                                               "Cannot set event class's log level.");
-                                       goto error;
-                               }
+                       if (log_level != -1) {
+                               event_class->log_level = log_level;
                        }
 
-                       _SET(set, _EVENT_LOGLEVEL_SET);
+                       _SET(set, _EVENT_LOG_LEVEL_SET);
                } else if (!strcmp(left, "model.emf.uri")) {
                        char *right;
 
@@ -3476,13 +3361,8 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                _BT_LOGW_NODE(node,
                                        "Not setting event class's EMF URI because it's empty.");
                        } else {
-                               ret = bt_event_class_set_emf_uri(
-                                       event_class, right);
-                               if (ret) {
-                                       _BT_LOGE_NODE(node,
-                                               "Cannot set event class's EMF URI.");
-                                       goto error;
-                               }
+                               g_string_assign(event_class->emf_uri,
+                                       right);
                        }
 
                        g_free(right);
@@ -3502,15 +3382,14 @@ int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
                goto error;
        }
 
-       return 0;
+       goto end;
 
 error:
        if (left) {
                g_free(left);
        }
 
-       BT_PUT(decl);
-
+end:
        return ret;
 }
 
@@ -3556,93 +3435,6 @@ char *get_event_decl_name(struct ctx *ctx, struct ctf_node *node)
 
 error:
        g_free(left);
-
-       return NULL;
-}
-
-static
-int reset_event_decl_types(struct ctx *ctx,
-       struct bt_event_class *event_class)
-{
-       int ret = 0;
-
-       /* Context type. */
-       ret = bt_event_class_set_context_field_type(event_class, NULL);
-       if (ret) {
-               BT_LOGE("Cannot reset initial event class's context field type: "
-                       "event-name=\"%s\"",
-                       bt_event_class_get_name(event_class));
-               goto end;
-       }
-
-       /* Event payload. */
-       ret = bt_event_class_set_payload_field_type(event_class, NULL);
-       if (ret) {
-               BT_LOGE("Cannot reset initial event class's payload field type: "
-                       "event-name=\"%s\"",
-                       bt_event_class_get_name(event_class));
-               goto end;
-       }
-end:
-       return ret;
-}
-
-static
-int reset_stream_decl_types(struct ctx *ctx,
-       struct bt_stream_class *stream_class)
-{
-       int ret = 0;
-
-       /* Packet context. */
-       ret = bt_stream_class_set_packet_context_field_type(stream_class, NULL);
-       if (ret) {
-               BT_LOGE_STR("Cannot reset initial stream class's packet context field type.");
-               goto end;
-       }
-
-       /* Event header. */
-       ret = bt_stream_class_set_event_header_field_type(stream_class, NULL);
-       if (ret) {
-               BT_LOGE_STR("Cannot reset initial stream class's event header field type.");
-               goto end;
-       }
-
-       /* Event context. */
-       ret = bt_stream_class_set_event_context_field_type(stream_class, NULL);
-       if (ret) {
-               BT_LOGE_STR("Cannot reset initial stream class's event context field type.");
-               goto end;
-       }
-end:
-       return ret;
-}
-
-static
-struct bt_stream_class *create_reset_stream_class(struct ctx *ctx)
-{
-       int ret;
-       struct bt_stream_class *stream_class;
-
-       stream_class = bt_stream_class_create(NULL);
-       if (!stream_class) {
-               BT_LOGE_STR("Cannot create empty stream class.");
-               goto error;
-       }
-
-       /*
-        * Set packet context, event header, and event context to NULL to
-        * override the default ones.
-        */
-       ret = reset_stream_decl_types(ctx, stream_class);
-       if (ret) {
-               goto error;
-       }
-
-       return stream_class;
-
-error:
-       BT_PUT(stream_class);
-
        return NULL;
 }
 
@@ -3651,13 +3443,11 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
 {
        int ret = 0;
        int set = 0;
-       int64_t event_id;
        struct ctf_node *iter;
-       int64_t stream_id = -1;
+       uint64_t stream_id = 0;
        char *event_name = NULL;
-       struct bt_event_class *event_class = NULL;
-       struct bt_event_class *eevent_class;
-       struct bt_stream_class *stream_class = NULL;
+       struct ctf_event_class *event_class = NULL;
+       struct ctf_stream_class *stream_class = NULL;
        struct bt_list_head *decl_list = &node->u.event.declaration_list;
        bool pop_scope = false;
 
@@ -3674,25 +3464,10 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
                goto error;
        }
 
-       event_class = bt_event_class_create(event_name);
-
-       /*
-        * Unset context and fields to override the default ones.
-        */
-       ret = reset_event_decl_types(ctx, event_class);
-       if (ret) {
-               _BT_LOGE_NODE(node,
-                       "Cannot reset event class's field types: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       ret = ctx_push_scope(ctx);
-       if (ret) {
-               BT_LOGE_STR("Cannot push scope.");
-               goto error;
-       }
-
+       event_class = ctf_event_class_create();
+       BT_ASSERT(event_class);
+       g_string_assign(event_class->name, event_name);
+       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
        pop_scope = true;
 
        bt_list_for_each_entry(iter, decl_list, siblings) {
@@ -3706,71 +3481,25 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
        }
 
        if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) {
-               GList *keys = NULL;
-               int64_t *new_stream_id;
-               struct bt_stream_class *new_stream_class;
-               size_t stream_class_count =
-                       g_hash_table_size(ctx->stream_classes) +
-                       bt_trace_get_stream_class_count(ctx->trace);
-
                /*
                 * Allow missing stream_id if there is only a single
                 * stream class.
                 */
-               switch (stream_class_count) {
+               switch (ctx->ctf_tc->stream_classes->len) {
                case 0:
                        /* Create implicit stream class if there's none */
                        stream_id = 0;
-                       new_stream_class = create_reset_stream_class(ctx);
-                       if (!new_stream_class) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot create empty stream class.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       ret = bt_stream_class_set_id(new_stream_class,
-                               stream_id);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set stream class's ID: "
-                                       "id=0, ret=%d", ret);
-                               BT_PUT(new_stream_class);
-                               goto error;
-                       }
-
-                       new_stream_id = g_new0(int64_t, 1);
-                       if (!new_stream_id) {
-                               BT_LOGE_STR("Failed to allocate a int64_t.");
-                               ret = -ENOMEM;
-                               goto error;
-                       }
-
-                       *new_stream_id = stream_id;
-
-                       /* Move reference to visitor's context */
-                       g_hash_table_insert(ctx->stream_classes,
-                               new_stream_id, new_stream_class);
-                       new_stream_id = NULL;
-                       new_stream_class = NULL;
+                       stream_class = ctf_stream_class_create();
+                       BT_ASSERT(stream_class);
+                       stream_class->id = stream_id;
+                       g_ptr_array_add(ctx->ctf_tc->stream_classes,
+                               stream_class);
+                       stream_class = stream_class;
                        break;
                case 1:
                        /* Single stream class: get its ID */
-                       if (g_hash_table_size(ctx->stream_classes) == 1) {
-                               keys = g_hash_table_get_keys(ctx->stream_classes);
-                               stream_id = *((int64_t *) keys->data);
-                               g_list_free(keys);
-                       } else {
-                               BT_ASSERT(bt_trace_get_stream_class_count(
-                                       ctx->trace) == 1);
-                               stream_class =
-                                       bt_trace_get_stream_class_by_index(
-                                               ctx->trace, 0);
-                               BT_ASSERT(stream_class);
-                               stream_id = bt_stream_class_get_id(
-                                       stream_class);
-                               BT_PUT(stream_class);
-                       }
+                       stream_class = ctx->ctf_tc->stream_classes->pdata[0];
+                       stream_id = stream_class->id;
                        break;
                default:
                        _BT_LOGE_NODE(node,
@@ -3780,14 +3509,10 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
                }
        }
 
-       BT_ASSERT(stream_id >= 0);
-
        /* We have the stream ID now; get the stream class if found */
-       stream_class = g_hash_table_lookup(ctx->stream_classes, &stream_id);
-       bt_get(stream_class);
        if (!stream_class) {
-               stream_class = bt_trace_get_stream_class_by_id(ctx->trace,
-                       stream_id);
+               stream_class = ctf_trace_class_borrow_stream_class_by_id(
+                       ctx->ctf_tc, stream_id);
                if (!stream_class) {
                        _BT_LOGE_NODE(node,
                                "Cannot find stream class at this point: "
@@ -3801,8 +3526,7 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
 
        if (!_IS_SET(&set, _EVENT_ID_SET)) {
                /* Allow only one event without ID per stream */
-               if (bt_stream_class_get_event_class_count(stream_class) !=
-                               0) {
+               if (stream_class->event_classes->len != 0) {
                        _BT_LOGE_NODE(node,
                                "Missing `id` attribute in event class.");
                        ret = -EPERM;
@@ -3810,114 +3534,97 @@ int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
                }
 
                /* Automatic ID */
-               ret = bt_event_class_set_id(event_class, 0);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot set event class's ID: id=0, ret=%d",
-                               ret);
-                       goto error;
-               }
+               event_class->id = 0;
        }
 
-       event_id = bt_event_class_get_id(event_class);
-       if (event_id < 0) {
-               _BT_LOGE_NODE(node, "Cannot get event class's ID.");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       eevent_class = bt_stream_class_get_event_class_by_id(stream_class,
-               event_id);
-       if (eevent_class) {
-               BT_PUT(eevent_class);
+       if (ctf_stream_class_borrow_event_class_by_id(stream_class,
+                       event_class->id)) {
                _BT_LOGE_NODE(node,
                        "Duplicate event class (same ID) in the same stream class: "
-                       "id=%" PRId64, event_id);
+                       "id=%" PRId64, event_class->id);
                ret = -EEXIST;
                goto error;
        }
 
-       ret = bt_stream_class_add_event_class(stream_class, event_class);
-       BT_PUT(event_class);
-       if (ret) {
-               _BT_LOGE_NODE(node,
-                       "Cannot add event class to stream class: ret=%d", ret);
-               goto error;
-       }
-
+       ctf_stream_class_append_event_class(stream_class, event_class);
+       event_class = NULL;
        goto end;
 
 error:
-       bt_put(event_class);
+       ctf_event_class_destroy(event_class);
+       event_class = NULL;
+
+       if (ret >= 0) {
+               ret = -1;
+       }
 
 end:
        if (pop_scope) {
                ctx_pop_scope(ctx);
        }
 
-       g_free(event_name);
-       bt_put(stream_class);
+       if (event_name) {
+               g_free(event_name);
+       }
+
        return ret;
 }
 
 static
 int auto_map_field_to_trace_clock_class(struct ctx *ctx,
-               struct bt_field_type *ft)
+               struct ctf_field_type *ft)
 {
        struct bt_clock_class *clock_class_to_map_to = NULL;
-       struct bt_clock_class *mapped_clock_class = NULL;
+       struct ctf_field_type_int *int_ft = (void *) ft;
        int ret = 0;
-       int64_t clock_class_count;
+       uint64_t clock_class_count;
+
+       if (!ft) {
+               goto end;
+       }
 
-       if (!ft || !bt_field_type_is_integer(ft)) {
+       if (ft->id != CTF_FIELD_TYPE_ID_INT &&
+                       ft->id != CTF_FIELD_TYPE_ID_ENUM) {
                goto end;
        }
 
-       mapped_clock_class =
-               bt_field_type_integer_get_mapped_clock_class(ft);
-       if (mapped_clock_class) {
+       if (int_ft->mapped_clock_class) {
+               /* Already mapped */
                goto end;
        }
 
-       clock_class_count = bt_trace_get_clock_class_count(ctx->trace);
-       BT_ASSERT(clock_class_count >= 0);
+       clock_class_count = ctx->ctf_tc->clock_classes->len;
 
        switch (clock_class_count) {
        case 0:
                /*
-                * No clock class exists in the trace at this
-                * point. Create an implicit one at 1 GHz,
-                * named `default`, and use this clock class.
+                * No clock class exists in the trace at this point. Create an
+                * implicit one at 1 GHz, named `default`, and use this clock
+                * class.
                 */
-               clock_class_to_map_to = bt_clock_class_create("default",
-                       1000000000);
-               if (!clock_class_to_map_to) {
-                       BT_LOGE_STR("Cannot create a clock class.");
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = bt_trace_add_clock_class(ctx->trace,
-                       clock_class_to_map_to);
-               if (ret) {
-                       BT_LOGE_STR("Cannot add clock class to trace.");
-                       goto end;
-               }
+               clock_class_to_map_to = bt_clock_class_create();
+               BT_ASSERT(clock_class_to_map_to);
+               ret = bt_clock_class_set_frequency(clock_class_to_map_to,
+                       UINT64_C(1000000000));
+               BT_ASSERT(ret == 0);
+               ret = bt_clock_class_set_name(clock_class_to_map_to,
+                       "default");
+               BT_ASSERT(ret == 0);
+               g_ptr_array_add(ctx->ctf_tc->clock_classes,
+                       bt_get(clock_class_to_map_to));
                break;
        case 1:
                /*
-                * Only one clock class exists in the trace at
-                * this point: use this one.
+                * Only one clock class exists in the trace at this point: use
+                * this one.
                 */
                clock_class_to_map_to =
-                       bt_trace_get_clock_class_by_index(ctx->trace, 0);
-               BT_ASSERT(clock_class_to_map_to);
+                       bt_get(ctx->ctf_tc->clock_classes->pdata[0]);
                break;
        default:
                /*
-                * Timestamp field not mapped to a clock class
-                * and there's more than one clock class in the
-                * trace: this is an error.
+                * Timestamp field not mapped to a clock class and there's more
+                * than one clock class in the trace: this is an error.
                 */
                BT_LOGE_STR("Timestamp field found with no mapped clock class, "
                        "but there's more than one clock class in the trace at this point.");
@@ -3926,76 +3633,64 @@ int auto_map_field_to_trace_clock_class(struct ctx *ctx,
        }
 
        BT_ASSERT(clock_class_to_map_to);
-       ret = bt_field_type_integer_set_mapped_clock_class(ft,
-               clock_class_to_map_to);
-       if (ret) {
-               BT_LOGE("Cannot map field type's field to trace's clock class: "
-                       "clock-class-name=\"%s\", ret=%d",
-                       bt_clock_class_get_name(clock_class_to_map_to),
-                       ret);
-               goto end;
-       }
+       int_ft->mapped_clock_class = bt_get(clock_class_to_map_to);
 
 end:
        bt_put(clock_class_to_map_to);
-       bt_put(mapped_clock_class);
        return ret;
 }
 
 static
 int auto_map_fields_to_trace_clock_class(struct ctx *ctx,
-               struct bt_field_type *root_ft, const char *field_name)
+               struct ctf_field_type *root_ft, const char *field_name)
 {
        int ret = 0;
-       int64_t i, count;
+       uint64_t i, count;
+       struct ctf_field_type_struct *struct_ft = (void *) root_ft;
+       struct ctf_field_type_variant *var_ft = (void *) root_ft;
 
        if (!root_ft) {
                goto end;
        }
 
-       if (!bt_field_type_is_structure(root_ft) &&
-                       !bt_field_type_is_variant(root_ft)) {
+       if (root_ft->id != CTF_FIELD_TYPE_ID_STRUCT &&
+                       root_ft->id != CTF_FIELD_TYPE_ID_VARIANT) {
                goto end;
        }
 
-       if (bt_field_type_is_structure(root_ft)) {
-               count = bt_field_type_structure_get_field_count(root_ft);
+       if (root_ft->id == CTF_FIELD_TYPE_ID_STRUCT) {
+               count = struct_ft->members->len;
        } else {
-               count = bt_field_type_variant_get_field_count(root_ft);
+               count = var_ft->options->len;
        }
 
-       BT_ASSERT(count >= 0);
-
        for (i = 0; i < count; i++) {
-               _BT_FIELD_TYPE_INIT(ft);
-               const char *name;
+               struct ctf_named_field_type *named_ft = NULL;
 
-               if (bt_field_type_is_structure(root_ft)) {
-                       ret = bt_field_type_structure_get_field_by_index(
-                               root_ft, &name, &ft, i);
-               } else if (bt_field_type_is_variant(root_ft)) {
-                       ret = bt_field_type_variant_get_field_by_index(
-                               root_ft, &name, &ft, i);
+               if (root_ft->id == CTF_FIELD_TYPE_ID_STRUCT) {
+                       named_ft = ctf_field_type_struct_borrow_member_by_index(
+                               struct_ft, i);
+               } else if (root_ft->id == CTF_FIELD_TYPE_ID_VARIANT) {
+                       named_ft = ctf_field_type_variant_borrow_option_by_index(
+                               var_ft, i);
                }
 
-               BT_ASSERT(ret == 0);
-
-               if (strcmp(name, field_name) == 0) {
-                       ret = auto_map_field_to_trace_clock_class(ctx, ft);
+               if (strcmp(named_ft->name->str, field_name) == 0) {
+                       ret = auto_map_field_to_trace_clock_class(ctx,
+                               named_ft->ft);
                        if (ret) {
                                BT_LOGE("Cannot automatically map field to trace's clock class: "
                                        "field-name=\"%s\"", field_name);
-                               bt_put(ft);
                                goto end;
                        }
                }
 
-               ret = auto_map_fields_to_trace_clock_class(ctx, ft, field_name);
-               bt_put(ft);
+               ret = auto_map_fields_to_trace_clock_class(ctx, named_ft->ft,
+                       field_name);
                if (ret) {
                        BT_LOGE("Cannot automatically map structure or variant field type's fields to trace's clock class: "
                                "field-name=\"%s\", root-field-name=\"%s\"",
-                               field_name, name);
+                               field_name, named_ft->name->str);
                        goto end;
                }
        }
@@ -4006,11 +3701,10 @@ end:
 
 static
 int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
-       struct bt_stream_class *stream_class, int *set)
+               struct ctf_stream_class *stream_class, int *set)
 {
        int ret = 0;
        char *left = NULL;
-       _BT_FIELD_TYPE_INIT(decl);
 
        switch (node->type) {
        case NODE_TYPEDEF:
@@ -4042,7 +3736,6 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
 
                if (!strcmp(left, "id")) {
                        int64_t id;
-                       gpointer ptr;
 
                        if (_IS_SET(set, _STREAM_ID_SET)) {
                                _BT_LOGE_DUP_ATTR(node, "id",
@@ -4053,6 +3746,7 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
 
                        ret = get_unary_unsigned(&node->u.ctf_expression.right,
                                (uint64_t *) &id);
+
                        /* Only read "id" if get_unary_unsigned() succeeded. */
                        if (ret || (!ret && id < 0)) {
                                _BT_LOGE_NODE(node,
@@ -4061,8 +3755,8 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                goto error;
                        }
 
-                       ptr = g_hash_table_lookup(ctx->stream_classes, &id);
-                       if (ptr) {
+                       if (ctf_trace_class_borrow_stream_class_by_id(
+                                       ctx->ctf_tc, id)) {
                                _BT_LOGE_NODE(node,
                                        "Duplicate stream class (same ID): id=%" PRId64,
                                        id);
@@ -4070,14 +3764,7 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                goto error;
                        }
 
-                       ret = bt_stream_class_set_id(stream_class, id);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set stream class's ID: "
-                                       "id=%" PRId64 ", ret=%d", id, ret);
-                               goto error;
-                       }
-
+                       stream_class->id = id;
                        _SET(set, _STREAM_ID_SET);
                } else if (!strcmp(left, "event.header")) {
                        if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
@@ -4091,31 +3778,22 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                _BT_LIST_FIRST_ENTRY(
                                        &node->u.ctf_expression.right,
                                        struct ctf_node, siblings),
-                               &decl);
+                               &stream_class->event_header_ft);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot create stream class's event header field type.");
                                goto error;
                        }
 
-                       BT_ASSERT(decl);
+                       BT_ASSERT(stream_class->event_header_ft);
                        ret = auto_map_fields_to_trace_clock_class(ctx,
-                               decl, "timestamp");
+                               stream_class->event_header_ft, "timestamp");
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot automatically map specific event header field type fields named `timestamp` to trace's clock class.");
                                goto error;
                        }
 
-                       ret = bt_stream_class_set_event_header_field_type(
-                               stream_class, decl);
-                       BT_PUT(decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set stream class's event header field type.");
-                               goto error;
-                       }
-
                        _SET(set, _STREAM_EVENT_HEADER_SET);
                } else if (!strcmp(left, "event.context")) {
                        if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
@@ -4129,24 +3807,14 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                _BT_LIST_FIRST_ENTRY(
                                        &node->u.ctf_expression.right,
                                        struct ctf_node, siblings),
-                               &decl);
+                               &stream_class->event_common_context_ft);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot create stream class's event context field type.");
                                goto error;
                        }
 
-                       BT_ASSERT(decl);
-
-                       ret = bt_stream_class_set_event_context_field_type(
-                               stream_class, decl);
-                       BT_PUT(decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set stream class's event context field type.");
-                               goto error;
-                       }
-
+                       BT_ASSERT(stream_class->event_common_context_ft);
                        _SET(set, _STREAM_EVENT_CONTEXT_SET);
                } else if (!strcmp(left, "packet.context")) {
                        if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
@@ -4160,16 +3828,17 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
                                _BT_LIST_FIRST_ENTRY(
                                        &node->u.ctf_expression.right,
                                        struct ctf_node, siblings),
-                               &decl);
+                               &stream_class->packet_context_ft);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot create stream class's packet context field type.");
                                goto error;
                        }
 
-                       BT_ASSERT(decl);
+                       BT_ASSERT(stream_class->packet_context_ft);
                        ret = auto_map_fields_to_trace_clock_class(ctx,
-                               decl, "timestamp_begin");
+                               stream_class->packet_context_ft,
+                               "timestamp_begin");
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot automatically map specific packet context field type fields named `timestamp_begin` to trace's clock class.");
@@ -4177,22 +3846,14 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
                        }
 
                        ret = auto_map_fields_to_trace_clock_class(ctx,
-                               decl, "timestamp_end");
+                               stream_class->packet_context_ft,
+                               "timestamp_end");
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot automatically map specific packet context field type fields named `timestamp_end` to trace's clock class.");
                                goto error;
                        }
 
-                       ret = bt_stream_class_set_packet_context_field_type(
-                               stream_class, decl);
-                       BT_PUT(decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set stream class's packet context field type.");
-                               goto error;
-                       }
-
                        _SET(set, _STREAM_PACKET_CONTEXT_SET);
                } else {
                        _BT_LOGW_NODE(node,
@@ -4214,21 +3875,16 @@ int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
 
 error:
        g_free(left);
-       BT_PUT(decl);
-
        return ret;
 }
 
 static
 int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
 {
-       int64_t id;
-       int64_t *new_id;
        int set = 0;
        int ret = 0;
        struct ctf_node *iter;
-       struct bt_stream_class *stream_class = NULL;
-       struct bt_stream_class *existing_stream_class = NULL;
+       struct ctf_stream_class *stream_class = NULL;
        struct bt_list_head *decl_list = &node->u.stream.declaration_list;
 
        if (node->visited) {
@@ -4236,18 +3892,9 @@ int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
        }
 
        node->visited = TRUE;
-       stream_class = create_reset_stream_class(ctx);
-       if (!stream_class) {
-               _BT_LOGE_NODE(node, "Cannot create empty stream class.");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       ret = ctx_push_scope(ctx);
-       if (ret) {
-               BT_LOGE_STR("Cannot push scope.");
-               goto error;
-       }
+       stream_class = ctf_stream_class_create();
+       BT_ASSERT(stream_class);
+       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
 
        bt_list_for_each_entry(iter, decl_list, siblings) {
                ret = visit_stream_decl_entry(ctx, iter, stream_class, &set);
@@ -4263,42 +3910,35 @@ int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
        ctx_pop_scope(ctx);
 
        if (_IS_SET(&set, _STREAM_ID_SET)) {
-               /* Check that packet header has stream_id field */
-               _BT_FIELD_TYPE_INIT(stream_id_decl);
-               _BT_FIELD_TYPE_INIT(packet_header_decl);
+               /* Check that packet header has `stream_id` field */
+               struct ctf_named_field_type *named_ft = NULL;
 
-               packet_header_decl =
-                       bt_trace_get_packet_header_field_type(ctx->trace);
-               if (!packet_header_decl) {
+               if (!ctx->ctf_tc->packet_header_ft) {
                        _BT_LOGE_NODE(node,
                                "Stream class has a `id` attribute, "
                                "but trace has no packet header field type.");
                        goto error;
                }
 
-               stream_id_decl =
-                       bt_field_type_structure_get_field_type_by_name(
-                               packet_header_decl, "stream_id");
-               BT_PUT(packet_header_decl);
-               if (!stream_id_decl) {
+               named_ft = ctf_field_type_struct_borrow_member_by_name(
+                       (void *) ctx->ctf_tc->packet_header_ft, "stream_id");
+               if (!named_ft) {
                        _BT_LOGE_NODE(node,
                                "Stream class has a `id` attribute, "
                                "but trace's packet header field type has no `stream_id` field.");
                        goto error;
                }
 
-               if (!bt_field_type_is_integer(stream_id_decl)) {
-                       BT_PUT(stream_id_decl);
+               if (named_ft->ft->id != CTF_FIELD_TYPE_ID_INT &&
+                               named_ft->ft->id != CTF_FIELD_TYPE_ID_ENUM) {
                        _BT_LOGE_NODE(node,
                                "Stream class has a `id` attribute, "
                                "but trace's packet header field type's `stream_id` field is not an integer field type.");
                        goto error;
                }
-
-               BT_PUT(stream_id_decl);
        } else {
                /* Allow only _one_ ID-less stream */
-               if (g_hash_table_size(ctx->stream_classes) != 0) {
+               if (ctx->ctf_tc->stream_classes->len != 0) {
                        _BT_LOGE_NODE(node,
                                "Missing `id` attribute in stream class as there's more than one stream class in the trace.");
                        ret = -EPERM;
@@ -4306,52 +3946,31 @@ int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
                }
 
                /* Automatic ID: 0 */
-               ret = bt_stream_class_set_id(stream_class, 0);
-               BT_ASSERT(ret == 0);
-       }
-
-       id = bt_stream_class_get_id(stream_class);
-       if (id < 0) {
-               _BT_LOGE_NODE(node,
-                       "Cannot get stream class's ID.");
-               ret = -EINVAL;
-               goto error;
+               stream_class->id = 0;
        }
 
        /*
         * Make sure that this stream class's ID is currently unique in
         * the trace.
         */
-       existing_stream_class = bt_trace_get_stream_class_by_id(ctx->trace,
-               id);
-       if (g_hash_table_lookup(ctx->stream_classes, &id) ||
-                       existing_stream_class) {
+       if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc,
+                       stream_class->id)) {
                _BT_LOGE_NODE(node,
                        "Duplicate stream class (same ID): id=%" PRId64,
-                       id);
+                       stream_class->id);
                ret = -EINVAL;
                goto error;
        }
 
-       new_id = g_new0(int64_t, 1);
-       if (!new_id) {
-               BT_LOGE_STR("Failed to allocate a int64_t.");
-               ret = -ENOMEM;
-               goto error;
-       }
-       *new_id = id;
-
-       /* Move reference to visitor's context */
-       g_hash_table_insert(ctx->stream_classes, new_id,
-               stream_class);
+       g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class);
        stream_class = NULL;
        goto end;
 
 error:
-       bt_put(stream_class);
+       ctf_stream_class_destroy(stream_class);
+       stream_class = NULL;
 
 end:
-       bt_put(existing_stream_class);
        return ret;
 }
 
@@ -4360,7 +3979,7 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
 {
        int ret = 0;
        char *left = NULL;
-       _BT_FIELD_TYPE_INIT(packet_header_decl);
+       uint64_t val;
 
        switch (node->type) {
        case NODE_TYPEDEF:
@@ -4398,7 +4017,7 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
                        }
 
                        ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               &ctx->trace_major);
+                               &val);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Unexpected unary expression for trace's `major` attribute.");
@@ -4406,6 +4025,13 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
                                goto error;
                        }
 
+                       if (val != 1) {
+                               _BT_LOGE_NODE(node,
+                                       "Invalid trace's `minor` attribute: expecting 1.");
+                               goto error;
+                       }
+
+                       ctx->ctf_tc->major = val;
                        _SET(set, _TRACE_MAJOR_SET);
                } else if (!strcmp(left, "minor")) {
                        if (_IS_SET(set, _TRACE_MINOR_SET)) {
@@ -4415,7 +4041,7 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
                        }
 
                        ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               &ctx->trace_minor);
+                               &val);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Unexpected unary expression for trace's `minor` attribute.");
@@ -4423,6 +4049,13 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
                                goto error;
                        }
 
+                       if (val != 8) {
+                               _BT_LOGE_NODE(node,
+                                       "Invalid trace's `minor` attribute: expecting 8.");
+                               goto error;
+                       }
+
+                       ctx->ctf_tc->minor = val;
                        _SET(set, _TRACE_MINOR_SET);
                } else if (!strcmp(left, "uuid")) {
                        if (_IS_SET(set, _TRACE_UUID_SET)) {
@@ -4432,22 +4065,17 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
                        }
 
                        ret = get_unary_uuid(&node->u.ctf_expression.right,
-                               ctx->trace_uuid);
+                               ctx->ctf_tc->uuid);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Invalid trace's `uuid` attribute.");
                                goto error;
                        }
 
-                       ret = bt_trace_set_uuid(ctx->trace, ctx->trace_uuid);
-                       if (ret) {
-                               _BT_LOGE_NODE(node, "Cannot set trace's UUID.");
-                               goto error;
-                       }
-
+                       ctx->ctf_tc->is_uuid_set = true;
                        _SET(set, _TRACE_UUID_SET);
                } else if (!strcmp(left, "byte_order")) {
-                       /* Native byte order is already known at this stage */
+                       /* Default byte order is already known at this stage */
                        if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
                                _BT_LOGE_DUP_ATTR(node, "byte_order",
                                        "trace");
@@ -4455,6 +4083,7 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
                                goto error;
                        }
 
+                       BT_ASSERT(ctx->ctf_tc->default_byte_order != -1);
                        _SET(set, _TRACE_BYTE_ORDER_SET);
                } else if (!strcmp(left, "packet.header")) {
                        if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
@@ -4468,23 +4097,14 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
                                _BT_LIST_FIRST_ENTRY(
                                        &node->u.ctf_expression.right,
                                        struct ctf_node, siblings),
-                               &packet_header_decl);
+                               &ctx->ctf_tc->packet_header_ft);
                        if (ret) {
                                _BT_LOGE_NODE(node,
                                        "Cannot create trace's packet header field type.");
                                goto error;
                        }
 
-                       BT_ASSERT(packet_header_decl);
-                       ret = bt_trace_set_packet_header_field_type(ctx->trace,
-                               packet_header_decl);
-                       BT_PUT(packet_header_decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot set trace's packet header field type.");
-                               goto error;
-                       }
-
+                       BT_ASSERT(ctx->ctf_tc->packet_header_ft);
                        _SET(set, _TRACE_PACKET_HEADER_SET);
                } else {
                        _BT_LOGW_NODE(node,
@@ -4506,8 +4126,6 @@ int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
 
 error:
        g_free(left);
-       BT_PUT(packet_header_decl);
-
        return ret;
 }
 
@@ -4531,11 +4149,7 @@ int visit_trace_decl(struct ctx *ctx, struct ctf_node *node)
                goto error;
        }
 
-       ret = ctx_push_scope(ctx);
-       if (ret) {
-               BT_LOGE_STR("Cannot push scope.");
-               goto error;
-       }
+       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
 
        bt_list_for_each_entry(iter, decl_list, siblings) {
                ret = visit_trace_decl_entry(ctx, iter, &set);
@@ -4570,7 +4184,7 @@ int visit_trace_decl(struct ctx *ctx, struct ctf_node *node)
                goto error;
        }
 
-       ctx->is_trace_visited = TRUE;
+       ctx->is_trace_visited = true;
 
 end:
        return 0;
@@ -4630,20 +4244,14 @@ int visit_env(struct ctx *ctx, struct ctf_node *node)
                                        BT_LOGI("Detected LTTng trace from `%s` environment value: "
                                                "tracer-name=\"%s\"",
                                                left, right);
-                                       ctx->is_lttng = 1;
+                                       ctx->is_lttng = true;
                                }
                        }
 
-                       ret = bt_trace_set_environment_field_string(
-                               ctx->trace, left, right);
+                       ctf_trace_class_append_env_entry(ctx->ctf_tc,
+                               left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR,
+                               right, 0);
                        g_free(right);
-
-                       if (ret) {
-                               _BT_LOGE_NODE(entry_node,
-                                       "Cannot add string environment entry to trace: "
-                                       "name=\"%s\", ret=%d", left, ret);
-                               goto error;
-                       }
                } else if (is_unary_unsigned(right_head) ||
                                is_unary_signed(right_head)) {
                        int64_t v;
@@ -4662,14 +4270,9 @@ int visit_env(struct ctx *ctx, struct ctf_node *node)
                                goto error;
                        }
 
-                       ret = bt_trace_set_environment_field_integer(
-                               ctx->trace, left, v);
-                       if (ret) {
-                               _BT_LOGE_NODE(entry_node,
-                                       "Cannot add integer environment entry to trace: "
-                                       "name=\"%s\", ret=%d", left, ret);
-                               goto error;
-                       }
+                       ctf_trace_class_append_env_entry(ctx->ctf_tc,
+                               left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT,
+                               NULL, v);
                } else {
                        _BT_LOGW_NODE(entry_node,
                                "Environment entry has unknown type: "
@@ -4685,7 +4288,6 @@ end:
 
 error:
        g_free(left);
-
        return ret;
 }
 
@@ -4712,7 +4314,7 @@ int set_trace_byte_order(struct ctx *ctx, struct ctf_node *trace_node)
                        }
 
                        if (!strcmp(left, "byte_order")) {
-                               enum bt_byte_order bo;
+                               enum ctf_byte_order bo;
 
                                if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
                                        _BT_LOGE_DUP_ATTR(node, "byte_order",
@@ -4726,13 +4328,13 @@ int set_trace_byte_order(struct ctx *ctx, struct ctf_node *trace_node)
                                        &node->u.ctf_expression.right,
                                        struct ctf_node, siblings);
                                bo = byte_order_from_unary_expr(right_node);
-                               if (bo == BT_BYTE_ORDER_UNKNOWN) {
+                               if (bo == -1) {
                                        _BT_LOGE_NODE(node,
                                                "Invalid `byte_order` attribute in trace (`trace` block): "
                                                "expecting `le`, `be`, or `network`.");
                                        ret = -EINVAL;
                                        goto error;
-                               } else if (bo == BT_BYTE_ORDER_NATIVE) {
+                               } else if (bo == CTF_BYTE_ORDER_DEFAULT) {
                                        _BT_LOGE_NODE(node,
                                                "Invalid `byte_order` attribute in trace (`trace` block): "
                                                "cannot be set to `native` here.");
@@ -4740,15 +4342,7 @@ int set_trace_byte_order(struct ctx *ctx, struct ctf_node *trace_node)
                                        goto error;
                                }
 
-                               ctx->trace_bo = bo;
-                               ret = bt_trace_set_native_byte_order(
-                                       ctx->trace, bo);
-                               if (ret) {
-                                       _BT_LOGE_NODE(node,
-                                               "Cannot set trace's byte order: "
-                                               "ret=%d", ret);
-                                       goto error;
-                               }
+                               ctx->ctf_tc->default_byte_order = bo;
                        }
 
                        g_free(left);
@@ -4767,13 +4361,13 @@ int set_trace_byte_order(struct ctx *ctx, struct ctf_node *trace_node)
 
 error:
        g_free(left);
-
        return ret;
 }
 
 static
 int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
-       struct bt_clock_class *clock, int *set)
+       struct bt_clock_class *clock, int *set, int64_t *offset_seconds,
+       uint64_t *offset_cycles)
 {
        int ret = 0;
        char *left = NULL;
@@ -4822,7 +4416,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                g_free(right);
                _SET(set, _CLOCK_NAME_SET);
        } else if (!strcmp(left, "uuid")) {
-               unsigned char uuid[BABELTRACE_UUID_LEN];
+               uint8_t uuid[BABELTRACE_UUID_LEN];
 
                if (_IS_SET(set, _CLOCK_UUID_SET)) {
                        _BT_LOGE_DUP_ATTR(entry_node, "uuid", "clock class");
@@ -4875,7 +4469,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                g_free(right);
                _SET(set, _CLOCK_DESCRIPTION_SET);
        } else if (!strcmp(left, "freq")) {
-               uint64_t freq = -1ULL;
+               uint64_t freq = UINT64_C(-1);
 
                if (_IS_SET(set, _CLOCK_FREQ_SET)) {
                        _BT_LOGE_DUP_ATTR(entry_node, "freq", "clock class");
@@ -4892,7 +4486,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                        goto error;
                }
 
-               if (freq == -1ULL || freq == 0) {
+               if (freq == UINT64_C(-1) || freq == 0) {
                        _BT_LOGE_NODE(entry_node,
                                "Invalid clock class frequency: freq=%" PRIu64,
                                freq);
@@ -4936,8 +4530,6 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
 
                _SET(set, _CLOCK_PRECISION_SET);
        } else if (!strcmp(left, "offset_s")) {
-               int64_t offset_s;
-
                if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
                        _BT_LOGE_DUP_ATTR(entry_node, "offset_s",
                                "clock class");
@@ -4946,7 +4538,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                }
 
                ret = get_unary_signed(
-                       &entry_node->u.ctf_expression.right, &offset_s);
+                       &entry_node->u.ctf_expression.right, offset_seconds);
                if (ret) {
                        _BT_LOGE_NODE(entry_node,
                                "Unexpected unary expression for clock class's `offset_s` attribute.");
@@ -4954,25 +4546,16 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                        goto error;
                }
 
-               ret = bt_clock_class_set_offset_s(clock, offset_s);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot set clock class's offset in seconds.");
-                       goto error;
-               }
-
                _SET(set, _CLOCK_OFFSET_S_SET);
        } else if (!strcmp(left, "offset")) {
-               int64_t offset;
-
                if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
                        _BT_LOGE_DUP_ATTR(entry_node, "offset", "clock class");
                        ret = -EPERM;
                        goto error;
                }
 
-               ret = get_unary_signed(
-                       &entry_node->u.ctf_expression.right, &offset);
+               ret = get_unary_unsigned(
+                       &entry_node->u.ctf_expression.right, offset_cycles);
                if (ret) {
                        _BT_LOGE_NODE(entry_node,
                                "Unexpected unary expression for clock class's `offset` attribute.");
@@ -4980,13 +4563,6 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
                        goto error;
                }
 
-               ret = bt_clock_class_set_offset_cycles(clock, offset);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot set clock class's offset in cycles.");
-                       goto error;
-               }
-
                _SET(set, _CLOCK_OFFSET_SET);
        } else if (!strcmp(left, "absolute")) {
                struct ctf_node *right;
@@ -5025,22 +4601,20 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
 
        g_free(left);
        left = NULL;
-
        return 0;
 
 error:
        g_free(left);
-
        return ret;
 }
 
-static
-int64_t cycles_from_ns(uint64_t frequency, int64_t ns)
+static inline
+uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns)
 {
-       int64_t cycles;
+       uint64_t cycles;
 
        /* 1GHz */
-       if (frequency == 1000000000ULL) {
+       if (frequency == UINT64_C(1000000000)) {
                cycles = ns;
        } else {
                cycles = (uint64_t) (((double) ns * (double) frequency) / 1e9);
@@ -5050,35 +4624,73 @@ int64_t cycles_from_ns(uint64_t frequency, int64_t ns)
 }
 
 static
-int apply_clock_class_offset(struct ctx *ctx, struct bt_clock_class *clock)
+void calibrate_clock_class_offsets(int64_t *offset_seconds,
+               uint64_t *offset_cycles, uint64_t freq)
+{
+       if (*offset_cycles >= freq) {
+               const uint64_t s_in_offset_cycles = *offset_cycles / freq;
+
+               *offset_seconds += (int64_t) s_in_offset_cycles;
+               *offset_cycles -= (s_in_offset_cycles * freq);
+       }
+}
+
+static
+void apply_clock_class_offset(struct ctx *ctx, struct bt_clock_class *clock)
 {
        int ret;
        uint64_t freq;
-       int64_t offset_cycles;
-       int64_t offset_to_apply;
+       int64_t offset_s_to_apply = ctx->decoder_config.clock_class_offset_s;
+       uint64_t offset_ns_to_apply;
+       int64_t cur_offset_s;
+       uint64_t cur_offset_cycles;
 
-       freq = bt_clock_class_get_frequency(clock);
-       if (freq == -1ULL) {
-               BT_LOGE_STR("Cannot get clock class's frequency.");
-               ret = -1;
+       if (ctx->decoder_config.clock_class_offset_s == 0 &&
+                       ctx->decoder_config.clock_class_offset_ns == 0) {
                goto end;
        }
 
-       ret = bt_clock_class_get_offset_cycles(clock, &offset_cycles);
-       if (ret) {
-               BT_LOGE_STR("Cannot get clock class's offset in cycles.");
-               ret = -1;
-               goto end;
+       /* Transfer nanoseconds to seconds as much as possible */
+       if (ctx->decoder_config.clock_class_offset_ns < 0) {
+               const int64_t abs_ns = -ctx->decoder_config.clock_class_offset_ns;
+               const int64_t abs_extra_s = abs_ns / INT64_C(1000000000) + 1;
+               const int64_t extra_s = -abs_extra_s;
+               const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
+                       (extra_s * INT64_C(1000000000));
+
+               BT_ASSERT(offset_ns > 0);
+               offset_ns_to_apply = (uint64_t) offset_ns;
+               offset_s_to_apply += extra_s;
+       } else {
+               const int64_t extra_s = ctx->decoder_config.clock_class_offset_ns /
+                       INT64_C(1000000000);
+               const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
+                       (extra_s * INT64_C(1000000000));
+
+               BT_ASSERT(offset_ns >= 0);
+               offset_ns_to_apply = (uint64_t) offset_ns;
+               offset_s_to_apply += extra_s;
        }
 
-       offset_to_apply =
-               ctx->decoder_config.clock_class_offset_s * 1000000000LL +
-               ctx->decoder_config.clock_class_offset_ns;
-       offset_cycles += cycles_from_ns(freq, offset_to_apply);
-       ret = bt_clock_class_set_offset_cycles(clock, offset_cycles);
+       freq = bt_clock_class_get_frequency(clock);
+       bt_clock_class_get_offset(clock, &cur_offset_s, &cur_offset_cycles);
+
+       /* Apply offsets */
+       cur_offset_s += offset_s_to_apply;
+       cur_offset_cycles += cycles_from_ns(freq, offset_ns_to_apply);
+
+       /*
+        * Recalibrate offsets because the part in cycles can be greater
+        * than the frequency at this point.
+        */
+       calibrate_clock_class_offsets(&cur_offset_s, &cur_offset_cycles, freq);
+
+       /* Set final offsets */
+       ret = bt_clock_class_set_offset(clock, cur_offset_s, cur_offset_cycles);
+       BT_ASSERT(ret == 0);
 
 end:
-       return ret;
+       return;
 }
 
 static
@@ -5090,6 +4702,9 @@ int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
        struct ctf_node *entry_node;
        struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list;
        const char *clock_class_name;
+       int64_t offset_seconds = 0;
+       uint64_t offset_cycles = 0;
+       uint64_t freq;
 
        if (clock_node->visited) {
                return 0;
@@ -5098,21 +4713,30 @@ int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
        clock_node->visited = TRUE;
 
        /* CTF 1.8's default frequency for a clock class is 1 GHz */
-       clock = bt_clock_class_create(NULL, 1000000000);
+       clock = bt_clock_class_create();
        if (!clock) {
                _BT_LOGE_NODE(clock_node,
                        "Cannot create default clock class.");
                ret = -ENOMEM;
-               goto error;
+               goto end;
+       }
+
+       /* CTF: not absolute by default */
+       ret = bt_clock_class_set_is_absolute(clock, BT_FALSE);
+       if (ret) {
+               _BT_LOGE_NODE(clock_node,
+                       "Cannot set clock class's absolute flag.");
+               goto end;
        }
 
        bt_list_for_each_entry(entry_node, decl_list, siblings) {
-               ret = visit_clock_decl_entry(ctx, entry_node, clock, &set);
+               ret = visit_clock_decl_entry(ctx, entry_node, clock, &set,
+                       &offset_seconds, &offset_cycles);
                if (ret) {
                        _BT_LOGE_NODE(entry_node,
                                "Cannot visit clock class's entry: ret=%d",
                                ret);
-                       goto error;
+                       goto end;
                }
        }
 
@@ -5120,7 +4744,7 @@ int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
                _BT_LOGE_NODE(clock_node,
                        "Missing `name` attribute in clock class.");
                ret = -EPERM;
-               goto error;
+               goto end;
        }
 
        clock_class_name = bt_clock_class_get_name(clock);
@@ -5132,31 +4756,28 @@ int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
                 * it's a condition to be able to sort notifications
                 * from different sources.
                 */
-               ret = bt_clock_class_set_is_absolute(clock, 1);
+               ret = bt_clock_class_set_is_absolute(clock, BT_TRUE);
                if (ret) {
                        _BT_LOGE_NODE(clock_node,
                                "Cannot set clock class's absolute flag.");
-                       goto error;
+                       goto end;
                }
        }
 
-       ret = apply_clock_class_offset(ctx, clock);
-       if (ret) {
-               _BT_LOGE_NODE(clock_node,
-                       "Cannot apply clock class's custom offset.");
-               goto error;
-       }
-
-       ret = bt_trace_add_clock_class(ctx->trace, clock);
-       if (ret) {
-               _BT_LOGE_NODE(clock_node,
-                       "Cannot add clock class to trace.");
-               goto error;
-       }
+       /*
+        * Adjust offsets so that the part in cycles is less than the
+        * frequency (move to the part in seconds).
+        */
+       freq = bt_clock_class_get_frequency(clock);
+       calibrate_clock_class_offsets(&offset_seconds, &offset_cycles, freq);
+       BT_ASSERT(offset_cycles < bt_clock_class_get_frequency(clock));
+       ret = bt_clock_class_set_offset(clock, offset_seconds, offset_cycles);
+       BT_ASSERT(ret == 0);
+       apply_clock_class_offset(ctx, clock);
+       g_ptr_array_add(ctx->ctf_tc->clock_classes, bt_get(clock));
 
-error:
+end:
        BT_PUT(clock);
-
        return ret;
 }
 
@@ -5193,7 +4814,7 @@ int visit_root_decl(struct ctx *ctx, struct ctf_node *root_decl_node)
                break;
        case NODE_TYPE_SPECIFIER_LIST:
        {
-               _BT_FIELD_TYPE_INIT(decl);
+               struct ctf_field_type *decl = NULL;
 
                /*
                 * Just add the type specifier to the root
@@ -5208,7 +4829,8 @@ int visit_root_decl(struct ctx *ctx, struct ctf_node *root_decl_node)
                        goto end;
                }
 
-               BT_PUT(decl);
+               ctf_field_type_destroy(decl);
+               decl = NULL;
                break;
        }
        default:
@@ -5224,13 +4846,17 @@ end:
 }
 
 static
-int set_trace_name(struct ctx *ctx)
+int try_set_trace_class_name(struct ctx *ctx)
 {
-       GString *name;
+       GString *name = NULL;
        int ret = 0;
-       struct bt_value *value = NULL;
+       struct ctf_trace_class_env_entry *env_entry;
+
+       if (ctx->ctf_tc->name->len > 0) {
+               /* Already set */
+               goto end;
+       }
 
-       BT_ASSERT(bt_trace_get_stream_class_count(ctx->trace) == 0);
        name = g_string_new(NULL);
        if (!name) {
                BT_LOGE_STR("Failed to allocate a GString.");
@@ -5242,38 +4868,25 @@ int set_trace_name(struct ctx *ctx)
         * Check if we have a trace environment string value named `hostname`.
         * If so, use it as the trace name's prefix.
         */
-       value = bt_trace_get_environment_field_value_by_name(ctx->trace,
+       env_entry = ctf_trace_class_borrow_env_entry_by_name(ctx->ctf_tc,
                "hostname");
-       if (value && bt_value_is_string(value)) {
-               const char *hostname;
-
-               ret = bt_value_string_get(value, &hostname);
-               BT_ASSERT(ret == 0);
-               g_string_append(name, hostname);
+       if (env_entry &&
+                       env_entry->type == CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR) {
+               g_string_append(name, env_entry->value.str->str);
 
-               if (ctx->trace_name_suffix) {
+               if (ctx->trace_class_name_suffix) {
                        g_string_append_c(name, G_DIR_SEPARATOR);
                }
        }
 
-       if (ctx->trace_name_suffix) {
-               g_string_append(name, ctx->trace_name_suffix);
-       }
-
-       ret = bt_trace_set_name(ctx->trace, name->str);
-       if (ret) {
-               BT_LOGE("Cannot set trace's name: name=\"%s\"", name->str);
-               goto error;
+       if (ctx->trace_class_name_suffix) {
+               g_string_append(name, ctx->trace_class_name_suffix);
        }
 
+       g_string_assign(ctx->ctf_tc->name, name->str);
        goto end;
 
-error:
-       ret = -1;
-
 end:
-       bt_put(value);
-
        if (name) {
                g_string_free(name, TRUE);
        }
@@ -5281,77 +4894,20 @@ end:
        return ret;
 }
 
-static
-int move_ctx_stream_classes_to_trace(struct ctx *ctx)
-{
-       int ret = 0;
-       GHashTableIter iter;
-       gpointer key, stream_class;
-
-       if (g_hash_table_size(ctx->stream_classes) > 0 &&
-                       bt_trace_get_stream_class_count(ctx->trace) == 0) {
-               /*
-                * We're about to add the first stream class to the
-                * trace. This will freeze the trace, and after this
-                * we cannot set the name anymore. At this point,
-                * set the trace name.
-                */
-               ret = set_trace_name(ctx);
-               if (ret) {
-                       BT_LOGE_STR("Cannot set trace's name.");
-                       goto end;
-               }
-       }
-
-       g_hash_table_iter_init(&iter, ctx->stream_classes);
-
-       while (g_hash_table_iter_next(&iter, &key, &stream_class)) {
-               ret = bt_trace_add_stream_class(ctx->trace,
-                       stream_class);
-               if (ret) {
-                       int64_t id = bt_stream_class_get_id(stream_class);
-                       BT_LOGE("Cannot add stream class to trace: id=%" PRId64,
-                               id);
-                       goto end;
-               }
-       }
-
-       g_hash_table_remove_all(ctx->stream_classes);
-
-end:
-       return ret;
-}
-
 BT_HIDDEN
 struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(
                const struct ctf_metadata_decoder_config *decoder_config,
                const char *name)
 {
-       int ret;
        struct ctx *ctx = NULL;
-       struct bt_trace *trace;
-
-       trace = bt_trace_create();
-       if (!trace) {
-               BT_LOGE_STR("Cannot create empty trace.");
-               goto error;
-       }
-
-       /* Set packet header to NULL to override the default one */
-       ret = bt_trace_set_packet_header_field_type(trace, NULL);
-       if (ret) {
-               BT_LOGE_STR("Cannot reset initial trace's packet header field type.");
-               goto error;
-       }
 
        /* Create visitor's context */
-       ctx = ctx_create(trace, decoder_config, name);
+       ctx = ctx_create(decoder_config, name);
        if (!ctx) {
                BT_LOGE_STR("Cannot create visitor's context.");
                goto error;
        }
 
-       trace = NULL;
        goto end;
 
 error:
@@ -5359,7 +4915,6 @@ error:
        ctx = NULL;
 
 end:
-       bt_put(trace);
        return (void *) ctx;
 }
 
@@ -5370,7 +4925,7 @@ void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor)
 }
 
 BT_HIDDEN
-struct bt_trace *ctf_visitor_generate_ir_get_trace(
+struct bt_trace *ctf_visitor_generate_ir_get_ir_trace(
                struct ctf_visitor_generate_ir *visitor)
 {
        struct ctx *ctx = (void *) visitor;
@@ -5380,6 +4935,17 @@ struct bt_trace *ctf_visitor_generate_ir_get_trace(
        return bt_get(ctx->trace);
 }
 
+BT_HIDDEN
+struct ctf_trace_class *ctf_visitor_generate_ir_borrow_ctf_trace_class(
+               struct ctf_visitor_generate_ir *visitor)
+{
+       struct ctx *ctx = (void *) visitor;
+
+       BT_ASSERT(ctx);
+       BT_ASSERT(ctx->ctf_tc);
+       return ctx->ctf_tc;
+}
+
 BT_HIDDEN
 int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
                struct ctf_node *node)
@@ -5393,7 +4959,7 @@ int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
        case NODE_ROOT:
        {
                struct ctf_node *iter;
-               int got_trace_decl = FALSE;
+               bool got_trace_decl = false;
 
                /*
                 * The first thing we need is the native byte order of
@@ -5402,7 +4968,7 @@ int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
                 * have the native byte order yet, and we don't have any
                 * trace block yet, then fail with EINCOMPLETE.
                 */
-               if (ctx->trace_bo == BT_BYTE_ORDER_NATIVE) {
+               if (ctx->ctf_tc->default_byte_order == -1) {
                        bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
                                if (got_trace_decl) {
                                        _BT_LOGE_NODE(node,
@@ -5419,7 +4985,7 @@ int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
                                        goto end;
                                }
 
-                               got_trace_decl = TRUE;
+                               got_trace_decl = true;
                        }
 
                        if (!got_trace_decl) {
@@ -5429,10 +4995,10 @@ int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
                        }
                }
 
-               BT_ASSERT(ctx->trace_bo == BT_BYTE_ORDER_LITTLE_ENDIAN ||
-                       ctx->trace_bo == BT_BYTE_ORDER_BIG_ENDIAN);
+               BT_ASSERT(ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_LITTLE ||
+                       ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_BIG);
                BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
+                               ctx->current_scope->parent_scope == NULL);
 
                /* Environment */
                bt_list_for_each_entry(iter, &node->u.root.env, siblings) {
@@ -5542,10 +5108,67 @@ int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
                goto end;
        }
 
-       /* Move decoded stream classes to trace, if any */
-       ret = move_ctx_stream_classes_to_trace(ctx);
+       /* Update default clock classes */
+       ret = ctf_trace_class_update_default_clock_classes(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Set trace's name, if not already done */
+       ret = try_set_trace_class_name(ctx);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update trace class meanings */
+       ret = ctf_trace_class_update_meanings(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update text arrays and sequences */
+       ret = ctf_trace_class_update_text_array_sequence(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Resolve sequence lengths and variant tags */
+       ret = ctf_trace_class_resolve_field_types(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update "in IR" for field types */
+       ret = ctf_trace_class_update_in_ir(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update saved value indexes */
+       ret = ctf_trace_class_update_value_storing_indexes(ctx->ctf_tc);
        if (ret) {
-               BT_LOGE("Cannot move stream classes to trace: ret=%d", ret);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Validate what we have so far */
+       ret = ctf_trace_class_validate(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Copy new CTF metadata -> new IR metadata */
+       ret = ctf_trace_class_translate(ctx->trace, ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
        }
 
 end:
index 0c1d75728d3201a60c1953170c70a838c266aa8b..5927285901469f46a8153aef62ad4800202b7b91 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Babeltrace - CTF notification iterator
  *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -58,7 +58,7 @@ struct stack_entry {
         */
        struct bt_field *base;
 
-       /* index of next field to set */
+       /* Index of next field to set */
        size_t index;
 };
 
@@ -82,13 +82,13 @@ enum state {
        STATE_AFTER_STREAM_PACKET_CONTEXT,
        STATE_EMIT_NOTIF_NEW_STREAM,
        STATE_EMIT_NOTIF_NEW_PACKET,
-       STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN,
-       STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
-       STATE_AFTER_STREAM_EVENT_HEADER,
-       STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN,
-       STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
-       STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
-       STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
+       STATE_DSCOPE_EVENT_HEADER_BEGIN,
+       STATE_DSCOPE_EVENT_HEADER_CONTINUE,
+       STATE_AFTER_EVENT_HEADER,
+       STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN,
+       STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE,
+       STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
+       STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE,
        STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
        STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
        STATE_EMIT_NOTIF_EVENT,
@@ -97,45 +97,6 @@ enum state {
        STATE_SKIP_PACKET_PADDING,
 };
 
-struct trace_field_path_cache {
-       /*
-        * Indexes of the stream_id and stream_instance_id field in the packet
-        * header structure, -1 if unset.
-        */
-       int stream_id;
-       int stream_instance_id;
-};
-
-struct stream_class_field_path_cache {
-       /*
-        * Indexes of the v and id fields in the stream event header structure,
-        * -1 if unset.
-        */
-       int v;
-       int id;
-
-       /*
-        * index of the timestamp_end, packet_size and content_size fields in
-        * the stream packet context structure. Set to -1 if the fields were
-        * not found.
-        */
-       int timestamp_end;
-       int packet_size;
-       int content_size;
-};
-
-struct field_cb_override {
-       enum bt_btr_status (* func)(void *value,
-                       struct bt_field_type *type, void *data);
-       void *data;
-};
-
-/* Clock value: clock class and raw value */
-struct clock_value {
-       struct bt_clock_class *clock_class; /* Weak */
-       uint64_t raw_value;
-};
-
 /* CTF notification iterator */
 struct bt_notif_iter {
        /* Visit stack */
@@ -152,11 +113,17 @@ struct bt_notif_iter {
         */
        struct bt_field *cur_dscope_field;
 
-       /* Trace and classes (owned by this) */
+       /*
+        * True if we're done filling a string field from a text
+        * array/sequence payload.
+        */
+       bool done_filling_string;
+
+       /* Trace and classes */
        struct {
-               struct bt_trace *trace;
-               struct bt_stream_class *stream_class;
-               struct bt_event_class *event_class;
+               struct ctf_trace_class *tc;
+               struct ctf_stream_class *sc;
+               struct ctf_event_class *ec;
        } meta;
 
        /* Current packet header field wrapper (NULL if not created yet) */
@@ -171,12 +138,6 @@ struct bt_notif_iter {
        /* Current packet (NULL if not created yet) */
        struct bt_packet *packet;
 
-       /* Previous packet availability */
-       enum bt_packet_previous_packet_availability prev_packet_avail;
-
-       /* Previous packet (NULL if not available) */
-       struct bt_packet *prev_packet;
-
        /* Current stream (NULL if not set yet) */
        struct bt_stream *stream;
 
@@ -186,39 +147,16 @@ struct bt_notif_iter {
        /* Current event notification (NULL if not created yet) */
        struct bt_notification *event_notif;
 
-       /*
-        * Current `timestamp_end` field (to consider before switching
-        * packets). If it's set, it's a field which is within
-        * `dscopes.stream_packet_context` below, which is in `packet`
-        * above.
-        */
-       struct bt_field *cur_timestamp_end;
-
-       /* Database of current dynamic scopes (owned by this) */
+       /* Database of current dynamic scopes */
        struct {
                struct bt_field *trace_packet_header;
                struct bt_field *stream_packet_context;
-               struct bt_field *stream_event_header;
-               struct bt_field *stream_event_context;
-               struct bt_field *event_context;
+               struct bt_field *event_header;
+               struct bt_field *event_common_context;
+               struct bt_field *event_spec_context;
                struct bt_field *event_payload;
        } dscopes;
 
-       /*
-        * Special field overrides.
-        *
-        * Overrides are used to implement the behaviours of special fields such
-        * as "timestamp_end" (which must be ignored until the end of the
-        * packet), "id" (event id) which can be present multiple times and must
-        * be updated multiple time.
-        *
-        * This should be used to implement the behaviour of integer fields
-        * mapped to clocks and other "tagged" fields (in CTF 2).
-        *
-        * bt_field_type to struct field_cb_override
-        */
-       GHashTable *field_overrides;
-
        /* Current state */
        enum state state;
 
@@ -254,34 +192,39 @@ struct bt_notif_iter {
        bool stream_begin_emitted;
 
        /* Current packet size (bits) (-1 if unknown) */
-       int64_t cur_packet_size;
+       int64_t cur_exp_packet_total_size;
 
        /* Current content size (bits) (-1 if unknown) */
-       int64_t cur_content_size;
+       int64_t cur_exp_packet_content_size;
 
-       /*
-        * Offset, in the underlying media, of the current packet's start
-        * (-1 if unknown).
-        */
-       off_t cur_packet_offset;
+       /* Current stream class ID */
+       int64_t cur_stream_class_id;
 
-       /* bt_clock_class to uint64_t. */
-       GHashTable *clock_states;
+       /* Current event class ID */
+       int64_t cur_event_class_id;
 
-       /*
-        * Cache of the trace-constant field paths (event header type)
-        * associated to the current trace.
-        */
-       struct trace_field_path_cache trace_field_path_cache;
+       /* Current data stream ID */
+       int64_t cur_data_stream_id;
 
        /*
-        * Field path cache associated with the current stream class.
-        * Ownership of this structure belongs to the field_path_caches HT.
+        * Offset, in the underlying media, of the current packet's
+        * start (-1 if unknown).
         */
-       struct stream_class_field_path_cache *cur_sc_field_path_cache;
+       off_t cur_packet_offset;
+
+       /* Default clock's current value */
+       uint64_t default_clock_val;
 
-       /* bt_stream_class to struct stream_class_field_path_cache. */
-       GHashTable *sc_field_path_caches;
+       /* End of packet snapshots */
+       struct {
+               uint64_t discarded_events;
+               uint64_t packets;
+               uint64_t beginning_clock;
+               uint64_t end_clock;
+       } snapshots;
+
+       /* Stored values (for sequence lengths, variant tags) */
+       GArray *stored_values;
 };
 
 static inline
@@ -306,20 +249,20 @@ const char *state_string(enum state state)
                return "STATE_EMIT_NOTIF_NEW_PACKET";
        case STATE_EMIT_NOTIF_NEW_STREAM:
                return "STATE_EMIT_NOTIF_NEW_STREAM";
-       case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN:
-               return "STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN";
-       case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE:
-               return "STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE";
-       case STATE_AFTER_STREAM_EVENT_HEADER:
-               return "STATE_AFTER_STREAM_EVENT_HEADER";
-       case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN:
-               return "STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN";
-       case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE:
-               return "STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE";
-       case STATE_DSCOPE_EVENT_CONTEXT_BEGIN:
-               return "STATE_DSCOPE_EVENT_CONTEXT_BEGIN";
-       case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE:
-               return "STATE_DSCOPE_EVENT_CONTEXT_CONTINUE";
+       case STATE_DSCOPE_EVENT_HEADER_BEGIN:
+               return "STATE_DSCOPE_EVENT_HEADER_BEGIN";
+       case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
+               return "STATE_DSCOPE_EVENT_HEADER_CONTINUE";
+       case STATE_AFTER_EVENT_HEADER:
+               return "STATE_AFTER_EVENT_HEADER";
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
+               return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN";
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
+               return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE";
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
+               return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN";
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
+               return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE";
        case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
                return "STATE_DSCOPE_EVENT_PAYLOAD_BEGIN";
        case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
@@ -340,10 +283,6 @@ const char *state_string(enum state state)
 static
 int bt_notif_iter_switch_packet(struct bt_notif_iter *notit);
 
-static
-enum bt_btr_status btr_timestamp_end_cb(void *value,
-               struct bt_field_type *type, void *data);
-
 static
 struct stack *stack_new(struct bt_notif_iter *notit)
 {
@@ -362,11 +301,14 @@ struct stack *stack_new(struct bt_notif_iter *notit)
        }
 
        BT_LOGD("Created stack: notit-addr=%p, stack-addr=%p", notit, stack);
-       return stack;
+       goto end;
 
 error:
        g_free(stack);
-       return NULL;
+       stack = NULL;
+
+end:
+       return stack;
 }
 
 static
@@ -383,7 +325,7 @@ void stack_destroy(struct stack *stack)
 }
 
 static
-int stack_push(struct stack *stack, struct bt_field *base)
+void stack_push(struct stack *stack, struct bt_field *base)
 {
        struct stack_entry *entry;
 
@@ -401,7 +343,6 @@ int stack_push(struct stack *stack, struct bt_field *base)
        entry->base = base;
        entry->index = 0;
        stack->size++;
-       return 0;
 }
 
 static inline
@@ -448,6 +389,7 @@ static inline
 enum bt_notif_iter_status notif_iter_status_from_m_status(
                enum bt_notif_iter_medium_status m_status)
 {
+       /* They are the same */
        return (int) m_status;
 }
 
@@ -521,8 +463,9 @@ enum bt_notif_iter_status request_medium_bytes(
                 * in the middle of a packet header, packet context, or
                 * event.
                 */
-               if (notit->cur_packet_size >= 0) {
-                       if (packet_at(notit) == notit->cur_packet_size) {
+               if (notit->cur_exp_packet_total_size >= 0) {
+                       if (packet_at(notit) ==
+                                       notit->cur_exp_packet_total_size) {
                                goto end;
                        }
                } else {
@@ -542,7 +485,7 @@ enum bt_notif_iter_status request_medium_bytes(
                        "packet-cur=%zu, last-eh-at=%zu",
                        bt_notif_iter_medium_status_string(m_status),
                        state_string(notit->state),
-                       notit->cur_packet_size,
+                       notit->cur_exp_packet_total_size,
                        notit->buf.at, packet_at(notit),
                        notit->buf.last_eh_at);
                m_status = BT_NOTIF_ITER_MEDIUM_STATUS_ERROR;
@@ -561,7 +504,7 @@ enum bt_notif_iter_status buf_ensure_available_bits(
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
 
-       if (buf_available_bits(notit) == 0) {
+       if (unlikely(buf_available_bits(notit) == 0)) {
                /*
                 * This _cannot_ return BT_NOTIF_ITER_STATUS_OK
                 * _and_ no bits.
@@ -572,18 +515,10 @@ enum bt_notif_iter_status buf_ensure_available_bits(
        return status;
 }
 
-static inline
-void reset_clock_value(struct clock_value *cv)
-{
-       BT_ASSERT(cv);
-       cv->clock_class = NULL;
-       cv->raw_value = UINT64_C(-1);
-}
-
 static
 enum bt_notif_iter_status read_dscope_begin_state(
                struct bt_notif_iter *notit,
-               struct bt_field_type *dscope_field_type,
+               struct ctf_field_type *dscope_ft,
                enum state done_state, enum state continue_state,
                struct bt_field *dscope_field)
 {
@@ -593,8 +528,8 @@ enum bt_notif_iter_status read_dscope_begin_state(
 
        notit->cur_dscope_field = dscope_field;
        BT_LOGV("Starting BTR: notit-addr=%p, btr-addr=%p, ft-addr=%p",
-               notit, notit->btr, dscope_field_type);
-       consumed_bits = bt_btr_start(notit->btr, dscope_field_type,
+               notit, notit->btr, dscope_ft);
+       consumed_bits = bt_btr_start(notit->btr, dscope_ft,
                notit->buf.addr, notit->buf.at, packet_at(notit),
                notit->buf.sz, &btr_status);
        BT_LOGV("BTR consumed bits: size=%zu", consumed_bits);
@@ -650,7 +585,6 @@ enum bt_notif_iter_status read_dscope_continue_state(
                goto end;
        }
 
-
        consumed_bits = bt_btr_continue(notit->btr, notit->buf.addr,
                notit->buf.sz, &btr_status);
        BT_LOGV("BTR consumed bits: size=%zu", consumed_bits);
@@ -682,15 +616,15 @@ end:
 static
 void release_event_dscopes(struct bt_notif_iter *notit)
 {
-       notit->dscopes.stream_event_header = NULL;
+       notit->dscopes.event_header = NULL;
 
        if (notit->event_header_field) {
                bt_event_header_field_release(notit->event_header_field);
                notit->event_header_field = NULL;
        }
 
-       notit->dscopes.stream_event_context = NULL;
-       notit->dscopes.event_context = NULL;
+       notit->dscopes.event_common_context = NULL;
+       notit->dscopes.event_spec_context = NULL;
        notit->dscopes.event_payload = NULL;
 }
 
@@ -718,7 +652,7 @@ static
 enum bt_notif_iter_status read_packet_header_begin_state(
                struct bt_notif_iter *notit)
 {
-       struct bt_field_type *packet_header_type = NULL;
+       struct ctf_field_type *packet_header_ft = NULL;
        enum bt_notif_iter_status ret = BT_NOTIF_ITER_STATUS_OK;
 
        if (bt_notif_iter_switch_packet(notit)) {
@@ -728,40 +662,46 @@ enum bt_notif_iter_status read_packet_header_begin_state(
        }
 
        /* Packet header type is common to the whole trace. */
-       packet_header_type = bt_trace_borrow_packet_header_field_type(
-                       notit->meta.trace);
-       if (!packet_header_type) {
+       packet_header_ft = notit->meta.tc->packet_header_ft;
+       if (!packet_header_ft) {
                notit->state = STATE_AFTER_TRACE_PACKET_HEADER;
                goto end;
        }
 
-       /*
-        * Create free packet header field from trace. This field is
-        * going to be moved to the packet once we create it. We cannot
-        * create the packet now because:
-        *
-        * 1. A packet is created from a stream.
-        * 2. A stream is created from a stream class.
-        * 3. We need the packet header field's content to know the ID
-        *    of the stream class to select.
-        */
        BT_ASSERT(!notit->packet_header_field);
-       notit->packet_header_field = bt_trace_create_packet_header_field(
-               notit->meta.trace);
-       if (!notit->packet_header_field) {
-               BT_LOGE_STR("Cannot create packet header field wrapper from trace.");
-               ret = BT_NOTIF_ITER_STATUS_ERROR;
-               goto end;
+
+       if (packet_header_ft->in_ir) {
+               /*
+                * Create free packet header field from trace. This
+                * field is going to be moved to the packet once we
+                * create it. We cannot create the packet now because:
+                *
+                * 1. A packet is created from a stream.
+                * 2. A stream is created from a stream class.
+                * 3. We need the packet header field's content to know
+                *    the ID of the stream class to select.
+                */
+               notit->packet_header_field = bt_packet_header_field_create(
+                       notit->meta.tc->ir_tc);
+               if (!notit->packet_header_field) {
+                       BT_LOGE_STR("Cannot create packet header field wrapper from trace.");
+                       ret = BT_NOTIF_ITER_STATUS_ERROR;
+                       goto end;
+               }
+
+               notit->dscopes.trace_packet_header =
+                       bt_packet_header_field_borrow_field(notit->packet_header_field);
+               BT_ASSERT(notit->dscopes.trace_packet_header);
        }
 
-       notit->dscopes.trace_packet_header =
-               bt_packet_header_field_borrow_field(notit->packet_header_field);
-       BT_ASSERT(notit->dscopes.trace_packet_header);
+       notit->cur_stream_class_id = -1;
+       notit->cur_event_class_id = -1;
+       notit->cur_data_stream_id = -1;
        BT_LOGV("Decoding packet header field:"
                "notit-addr=%p, trace-addr=%p, trace-name=\"%s\", ft-addr=%p",
-               notit, notit->meta.trace,
-               bt_trace_get_name(notit->meta.trace), packet_header_type);
-       ret = read_dscope_begin_state(notit, packet_header_type,
+               notit, notit->meta.tc,
+               notit->meta.tc->name->str, packet_header_ft);
+       ret = read_dscope_begin_state(notit, packet_header_ft,
                STATE_AFTER_TRACE_PACKET_HEADER,
                STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
                notit->dscopes.trace_packet_header);
@@ -769,9 +709,9 @@ enum bt_notif_iter_status read_packet_header_begin_state(
                BT_LOGW("Cannot decode packet header field: "
                        "notit-addr=%p, trace-addr=%p, "
                        "trace-name=\"%s\", ft-addr=%p",
-                       notit, notit->meta.trace,
-                       bt_trace_get_name(notit->meta.trace),
-                       packet_header_type);
+                       notit, notit->meta.tc,
+                       notit->meta.tc->name->str,
+                       packet_header_ft);
        }
 
 end:
@@ -783,314 +723,76 @@ enum bt_notif_iter_status read_packet_header_continue_state(
                struct bt_notif_iter *notit)
 {
        return read_dscope_continue_state(notit,
-                       STATE_AFTER_TRACE_PACKET_HEADER);
-}
-
-static
-struct stream_class_field_path_cache *
-create_stream_class_field_path_cache_entry(
-               struct bt_notif_iter *notit,
-               struct bt_stream_class *stream_class)
-{
-       int v = -1;
-       int id = -1;
-       int timestamp_end = -1;
-       int packet_size = -1;
-       int content_size = -1;
-       struct stream_class_field_path_cache *cache_entry = g_new0(
-                       struct stream_class_field_path_cache, 1);
-       struct bt_field_type *event_header = NULL, *packet_context = NULL;
-
-       if (!cache_entry) {
-               BT_LOGE_STR("Failed to allocate one stream class field path cache.");
-               goto end;
-       }
-
-       event_header = bt_stream_class_borrow_event_header_field_type(
-               stream_class);
-       if (event_header && bt_field_type_is_structure(event_header)) {
-               int i, count;
-
-               count = bt_field_type_structure_get_field_count(
-                       event_header);
-               BT_ASSERT(count >= 0);
-
-               for (i = 0; i < count; i++) {
-                       int ret;
-                       const char *name;
-
-                       ret = bt_field_type_structure_borrow_field_by_index(
-                                       event_header, &name, NULL, i);
-                       if (ret) {
-                               BT_LOGE("Cannot get event header structure field type's field: "
-                                       "notit-addr=%p, stream-class-addr=%p, "
-                                       "stream-class-name=\"%s\", "
-                                       "stream-class-id=%" PRId64 ", "
-                                       "ft-addr=%p, index=%d",
-                                       notit, stream_class,
-                                       bt_stream_class_get_name(stream_class),
-                                       bt_stream_class_get_id(stream_class),
-                                       event_header, i);
-                               goto error;
-                       }
-
-                       if (v != -1 && id != -1) {
-                               break;
-                       }
-
-                       if (v == -1 && strcmp(name, "v") == 0) {
-                               v = i;
-                       } else if (id == -1 && !strcmp(name, "id")) {
-                               id = i;
-                       }
-               }
-       }
-
-       packet_context = bt_stream_class_borrow_packet_context_field_type(
-                       stream_class);
-       if (packet_context && bt_field_type_is_structure(packet_context)) {
-               int i, count;
-
-               count = bt_field_type_structure_get_field_count(
-                       packet_context);
-               BT_ASSERT(count >= 0);
-
-               for (i = 0; i < count; i++) {
-                       int ret;
-                       const char *name;
-                       struct bt_field_type *field_type;
-
-                       if (timestamp_end != -1 && packet_size != -1 &&
-                                       content_size != -1) {
-                               break;
-                       }
-
-                       ret = bt_field_type_structure_borrow_field_by_index(
-                                       packet_context, &name, &field_type, i);
-                       if (ret) {
-                               BT_LOGE("Cannot get packet context structure field type's field: "
-                                       "notit-addr=%p, stream-class-addr=%p, "
-                                       "stream-class-name=\"%s\", "
-                                       "stream-class-id=%" PRId64 ", "
-                                       "ft-addr=%p, index=%d",
-                                       notit, stream_class,
-                                       bt_stream_class_get_name(stream_class),
-                                       bt_stream_class_get_id(stream_class),
-                                       event_header, i);
-                               goto error;
-                       }
-
-                       if (timestamp_end == -1 &&
-                                       strcmp(name, "timestamp_end") == 0) {
-                               struct field_cb_override *override = g_new0(
-                                               struct field_cb_override, 1);
-
-                               if (!override) {
-                                       goto error;
-                               }
-
-                               override->func = btr_timestamp_end_cb;
-                               override->data = notit;
-                               g_hash_table_insert(notit->field_overrides,
-                                       field_type, override);
-                               timestamp_end = i;
-                       } else if (packet_size == -1 &&
-                                       !strcmp(name, "packet_size")) {
-                               packet_size = i;
-                       } else if (content_size == -1 &&
-                                       !strcmp(name, "content_size")) {
-                               content_size = i;
-                       }
-               }
-       }
-
-       cache_entry->v = v;
-       cache_entry->id = id;
-       cache_entry->timestamp_end = timestamp_end;
-       cache_entry->packet_size = packet_size;
-       cache_entry->content_size = content_size;
-
-end:
-       return cache_entry;
-
-error:
-       g_free(cache_entry);
-       cache_entry = NULL;
-       goto end;
-}
-
-static
-struct stream_class_field_path_cache *get_stream_class_field_path_cache(
-               struct bt_notif_iter *notit,
-               struct bt_stream_class *stream_class)
-{
-       bool cache_entry_found;
-       struct stream_class_field_path_cache *cache_entry;
-
-       cache_entry_found = g_hash_table_lookup_extended(
-                       notit->sc_field_path_caches,
-                       stream_class, NULL, (gpointer) &cache_entry);
-       if (unlikely(!cache_entry_found)) {
-               cache_entry = create_stream_class_field_path_cache_entry(notit,
-                       stream_class);
-               g_hash_table_insert(notit->sc_field_path_caches,
-                       stream_class, (gpointer) cache_entry);
-       }
-
-       return cache_entry;
+               STATE_AFTER_TRACE_PACKET_HEADER);
 }
 
 static inline
-enum bt_notif_iter_status set_current_stream_class(
-               struct bt_notif_iter *notit)
+enum bt_notif_iter_status set_current_stream_class(struct bt_notif_iter *notit)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field_type *packet_header_type = NULL;
-       struct bt_field_type *stream_id_field_type = NULL;
-       struct bt_stream_class *new_stream_class = NULL;
-       uint64_t stream_id;
-
-       /* Clear the current stream class field path cache. */
-       notit->cur_sc_field_path_cache = NULL;
-
-       /* Is there any "stream_id" field in the packet header? */
-       packet_header_type = bt_trace_borrow_packet_header_field_type(
-               notit->meta.trace);
-       if (!packet_header_type) {
+       struct ctf_stream_class *new_stream_class = NULL;
+
+       if (notit->cur_stream_class_id == -1) {
                /*
-                * No packet header, therefore no `stream_id` field,
-                * therefore only one stream class.
+                * No current stream class ID field, therefore only one
+                * stream class.
                 */
-               goto single_stream_class;
-       }
-
-       BT_ASSERT(bt_field_type_is_structure(packet_header_type));
-
-       // TODO: optimalize!
-       stream_id_field_type =
-               bt_field_type_structure_borrow_field_type_by_name(
-                       packet_header_type, "stream_id");
-       if (stream_id_field_type) {
-               /* Find appropriate stream class using current stream ID */
-               int ret;
-               struct bt_field *stream_id_field = NULL;
-
-               BT_ASSERT(notit->dscopes.trace_packet_header);
+               if (notit->meta.tc->stream_classes->len != 1) {
+                       BT_LOGW("Need exactly one stream class since there's "
+                               "no stream class ID field: "
+                               "notit-addr=%p, trace-name=\"%s\"",
+                               notit, notit->meta.tc->name->str);
+                       status = BT_NOTIF_ITER_STATUS_ERROR;
+                       goto end;
+               }
 
-               // TODO: optimalize!
-               stream_id_field = bt_field_structure_borrow_field_by_name(
-                               notit->dscopes.trace_packet_header, "stream_id");
-               BT_ASSERT(stream_id_field);
-               ret = bt_field_integer_unsigned_get_value(
-                               stream_id_field, &stream_id);
-               BT_ASSERT(!ret);
-       } else {
-single_stream_class:
-               /* Only one stream: pick the first stream class */
-               BT_ASSERT(bt_trace_get_stream_class_count(
-                               notit->meta.trace) == 1);
-               stream_id = 0;
+               new_stream_class = notit->meta.tc->stream_classes->pdata[0];
+               notit->cur_stream_class_id = new_stream_class->id;
+               goto end;
        }
 
-       BT_LOGV("Found stream class ID to use: notit-addr=%p, "
-               "stream-class-id=%" PRIu64 ", "
-               "trace-addr=%p, trace-name=\"%s\"",
-               notit, stream_id, notit->meta.trace,
-               bt_trace_get_name(notit->meta.trace));
-
-       new_stream_class = bt_trace_borrow_stream_class_by_id(
-               notit->meta.trace, stream_id);
+       new_stream_class = ctf_trace_class_borrow_stream_class_by_id(
+               notit->meta.tc, notit->cur_stream_class_id);
        if (!new_stream_class) {
                BT_LOGW("No stream class with ID of stream class ID to use in trace: "
                        "notit-addr=%p, stream-class-id=%" PRIu64 ", "
                        "trace-addr=%p, trace-name=\"%s\"",
-                       notit, stream_id, notit->meta.trace,
-                       bt_trace_get_name(notit->meta.trace));
+                       notit, notit->cur_stream_class_id, notit->meta.tc,
+                       notit->meta.tc->name->str);
                status = BT_NOTIF_ITER_STATUS_ERROR;
                goto end;
        }
 
-       if (notit->meta.stream_class) {
-               if (new_stream_class != notit->meta.stream_class) {
+       if (notit->meta.sc) {
+               if (new_stream_class != notit->meta.sc) {
                        BT_LOGW("Two packets refer to two different stream classes within the same packet sequence: "
                                "notit-addr=%p, prev-stream-class-addr=%p, "
-                               "prev-stream-class-name=\"%s\", "
                                "prev-stream-class-id=%" PRId64 ", "
                                "next-stream-class-addr=%p, "
-                               "next-stream-class-name=\"%s\", "
                                "next-stream-class-id=%" PRId64 ", "
                                "trace-addr=%p, trace-name=\"%s\"",
-                               notit, notit->meta.stream_class,
-                               bt_stream_class_get_name(notit->meta.stream_class),
-                               bt_stream_class_get_id(notit->meta.stream_class),
+                               notit, notit->meta.sc,
+                               notit->meta.sc->id,
                                new_stream_class,
-                               bt_stream_class_get_name(new_stream_class),
-                               bt_stream_class_get_id(new_stream_class),
-                               notit->meta.trace,
-                               bt_trace_get_name(notit->meta.trace));
+                               new_stream_class->id,
+                               notit->meta.tc,
+                               notit->meta.tc->name->str);
                        status = BT_NOTIF_ITER_STATUS_ERROR;
                        goto end;
                }
        } else {
-               notit->meta.stream_class = new_stream_class;
+               notit->meta.sc = new_stream_class;
        }
 
        BT_LOGV("Set current stream class: "
                "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-class-id=%" PRId64,
-               notit, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class));
-
-       /*
-        * Retrieve (or lazily create) the current stream class field path
-        * cache.
-        */
-       notit->cur_sc_field_path_cache = get_stream_class_field_path_cache(
-               notit, notit->meta.stream_class);
-       if (!notit->cur_sc_field_path_cache) {
-               BT_LOGW("Cannot retrieve stream class field path from cache: "
-                       "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", stream-class-id=%" PRId64,
-                       notit, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class));
-               status = BT_NOTIF_ITER_STATUS_ERROR;
-               goto end;
-       }
+               "stream-class-id=%" PRId64,
+               notit, notit->meta.sc, notit->meta.sc->id);
 
 end:
        return status;
 }
 
-static inline
-uint64_t get_cur_stream_instance_id(struct bt_notif_iter *notit)
-{
-       struct bt_field *stream_instance_id_field = NULL;
-       uint64_t stream_instance_id = -1ULL;
-       int ret;
-
-       if (!notit->dscopes.trace_packet_header) {
-               goto end;
-       }
-
-       stream_instance_id_field = bt_field_structure_borrow_field_by_name(
-               notit->dscopes.trace_packet_header, "stream_instance_id");
-       if (!stream_instance_id_field) {
-               goto end;
-       }
-
-       ret = bt_field_integer_unsigned_get_value(stream_instance_id_field,
-               &stream_instance_id);
-       if (ret) {
-               stream_instance_id = -1ULL;
-               goto end;
-       }
-
-end:
-       return stream_instance_id;
-}
-
 static inline
 enum bt_notif_iter_status set_current_stream(struct bt_notif_iter *notit)
 {
@@ -1098,23 +800,23 @@ enum bt_notif_iter_status set_current_stream(struct bt_notif_iter *notit)
        struct bt_stream *stream = NULL;
 
        BT_LOGV("Calling user function (get stream): notit-addr=%p, "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64,
-               notit, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class));
+               "stream-class-addr=%p, stream-class-id=%" PRId64,
+               notit, notit->meta.sc,
+               notit->meta.sc->id);
        stream = bt_get(notit->medium.medops.borrow_stream(
-               notit->meta.stream_class, get_cur_stream_instance_id(notit),
+               notit->meta.sc->ir_sc, notit->cur_data_stream_id,
                notit->medium.data));
        BT_LOGV("User function returned: stream-addr=%p", stream);
        if (!stream) {
-               BT_LOGW_STR("User function failed to return a stream object for the given stream class.");
+               BT_LOGW_STR("User function failed to return a stream object "
+                       "for the given stream class.");
                status = BT_NOTIF_ITER_STATUS_ERROR;
                goto end;
        }
 
        if (notit->stream && stream != notit->stream) {
-               BT_LOGW("User function returned a different stream than the previous one for the same sequence of packets.");
+               BT_LOGW("User function returned a different stream than the "
+                       "previous one for the same sequence of packets.");
                status = BT_NOTIF_ITER_STATUS_ERROR;
                goto end;
        }
@@ -1137,25 +839,20 @@ enum bt_notif_iter_status set_current_packet(struct bt_notif_iter *notit)
        BT_LOGV("Creating packet from stream: "
                "notit-addr=%p, stream-addr=%p, "
                "stream-class-addr=%p, "
-               "stream-class-name=\"%s\", "
                "stream-class-id=%" PRId64,
-               notit, notit->stream, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class));
+               notit, notit->stream, notit->meta.sc,
+               notit->meta.sc->id);
 
        /* Create packet */
        BT_ASSERT(notit->stream);
-       packet = bt_packet_create(notit->stream, notit->prev_packet_avail,
-               notit->prev_packet);
+       packet = bt_packet_create(notit->stream);
        if (!packet) {
                BT_LOGE("Cannot create packet from stream: "
                        "notit-addr=%p, stream-addr=%p, "
                        "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
                        "stream-class-id=%" PRId64,
-                       notit, notit->stream, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class));
+                       notit, notit->stream, notit->meta.sc,
+                       notit->meta.sc->id);
                goto error;
        }
 
@@ -1192,64 +889,61 @@ enum bt_notif_iter_status read_packet_context_begin_state(
                struct bt_notif_iter *notit)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field_type *packet_context_type;
+       struct ctf_field_type *packet_context_ft;
 
-       BT_ASSERT(notit->meta.stream_class);
-       packet_context_type = bt_stream_class_borrow_packet_context_field_type(
-               notit->meta.stream_class);
-       if (!packet_context_type) {
+       BT_ASSERT(notit->meta.sc);
+       packet_context_ft = notit->meta.sc->packet_context_ft;
+       if (!packet_context_ft) {
                BT_LOGV("No packet packet context field type in stream class: continuing: "
                        "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", stream-class-id=%" PRId64,
-                       notit, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class));
+                       "stream-class-id=%" PRId64,
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id);
                notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
                goto end;
        }
 
-       /*
-        * Create free packet context field from stream class. This
-        * field is going to be moved to the packet once we create it.
-        * We cannot create the packet now because a packet is created
-        * from a stream, and this API must be able to return the packet
-        * header and context fields without creating a stream
-        * (bt_notif_iter_get_packet_header_context_fields()).
-        */
        BT_ASSERT(!notit->packet_context_field);
-       notit->packet_context_field =
-               bt_stream_class_create_packet_context_field(
-                       notit->meta.stream_class);
-       if (!notit->packet_context_field) {
-               BT_LOGE_STR("Cannot create packet context field wrapper from stream class.");
-               status = BT_NOTIF_ITER_STATUS_ERROR;
-               goto end;
+
+       if (packet_context_ft->in_ir) {
+               /*
+                * Create free packet context field from stream class.
+                * This field is going to be moved to the packet once we
+                * create it. We cannot create the packet now because a
+                * packet is created from a stream, and this API must be
+                * able to return the packet header and context fields
+                * without creating a stream
+                * (bt_notif_iter_borrow_packet_header_context_fields()).
+                */
+               notit->packet_context_field =
+                       bt_packet_context_field_create(notit->meta.sc->ir_sc);
+               if (!notit->packet_context_field) {
+                       BT_LOGE_STR("Cannot create packet context field wrapper from stream class.");
+                       status = BT_NOTIF_ITER_STATUS_ERROR;
+                       goto end;
+               }
+
+               notit->dscopes.stream_packet_context =
+                       bt_packet_context_field_borrow_field(notit->packet_context_field);
+               BT_ASSERT(notit->dscopes.stream_packet_context);
        }
 
-       notit->dscopes.stream_packet_context =
-               bt_packet_context_field_borrow_field(notit->packet_context_field);
-       BT_ASSERT(notit->dscopes.stream_packet_context);
        BT_LOGV("Decoding packet context field: "
                "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
-               "ft-addr=%p",
-               notit, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class),
-               packet_context_type);
-       status = read_dscope_begin_state(notit, packet_context_type,
+               "stream-class-id=%" PRId64 ", ft-addr=%p",
+               notit, notit->meta.sc,
+               notit->meta.sc->id, packet_context_ft);
+       status = read_dscope_begin_state(notit, packet_context_ft,
                STATE_AFTER_STREAM_PACKET_CONTEXT,
                STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
                notit->dscopes.stream_packet_context);
        if (status < 0) {
                BT_LOGW("Cannot decode packet context field: "
                        "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
                        "stream-class-id=%" PRId64 ", ft-addr=%p",
-                       notit, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class),
-                       packet_context_type);
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id,
+                       packet_context_ft);
        }
 
 end:
@@ -1264,113 +958,47 @@ enum bt_notif_iter_status read_packet_context_continue_state(
                        STATE_AFTER_STREAM_PACKET_CONTEXT);
 }
 
-static inline
-uint64_t get_field_raw_clock_value(struct bt_field *base_field,
-               const char *field_name, struct bt_clock_class **user_cc)
-{
-       struct bt_field *field;
-       struct bt_field_type *ft;
-       struct bt_clock_class *clock_class = NULL;
-       uint64_t val = UINT64_C(-1);
-       int ret;
-
-       field = bt_field_structure_borrow_field_by_name(base_field, field_name);
-       if (!field) {
-               goto end;
-       }
-
-       ft = bt_field_borrow_type(field);
-       BT_ASSERT(ft);
-
-       if (!bt_field_type_is_integer(ft)) {
-               goto end;
-       }
-
-       clock_class = bt_field_type_integer_borrow_mapped_clock_class(ft);
-       if (!clock_class) {
-               goto end;
-       }
-
-       ret = bt_field_integer_unsigned_get_value(field, &val);
-       BT_ASSERT(ret == 0);
-
-end:
-       *user_cc = clock_class;
-       return val;
-}
-
 static
 enum bt_notif_iter_status set_current_packet_content_sizes(
                struct bt_notif_iter *notit)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field *packet_size_field = NULL;
-       struct bt_field *content_size_field = NULL;
-       uint64_t content_size = -1ULL, packet_size = -1ULL;
 
-       if (!notit->dscopes.stream_packet_context) {
-               goto end;
-       }
-
-       packet_size_field = bt_field_structure_borrow_field_by_name(
-               notit->dscopes.stream_packet_context, "packet_size");
-       content_size_field = bt_field_structure_borrow_field_by_name(
-               notit->dscopes.stream_packet_context, "content_size");
-       if (packet_size_field) {
-               int ret = bt_field_integer_unsigned_get_value(
-                       packet_size_field, &packet_size);
-
-               BT_ASSERT(ret == 0);
-               if (packet_size == 0) {
-                       BT_LOGW("Invalid packet size: packet context field indicates packet size is zero: "
-                               "notit-addr=%p, packet-context-field-addr=%p",
-                               notit, notit->dscopes.stream_packet_context);
-                       status = BT_NOTIF_ITER_STATUS_ERROR;
-                       goto end;
-               } else if ((packet_size % 8) != 0) {
-                       BT_LOGW("Invalid packet size: packet context field indicates packet size is not a multiple of 8: "
+       if (notit->cur_exp_packet_total_size == -1) {
+               if (notit->cur_exp_packet_content_size != -1) {
+                       BT_LOGW("Content size is set, but packet size is not: "
                                "notit-addr=%p, packet-context-field-addr=%p, "
-                               "packet-size=%" PRIu64,
+                               "packet-size=%" PRId64 ", content-size=%" PRId64,
                                notit, notit->dscopes.stream_packet_context,
-                               packet_size);
+                               notit->cur_exp_packet_total_size,
+                               notit->cur_exp_packet_content_size);
                        status = BT_NOTIF_ITER_STATUS_ERROR;
                        goto end;
                }
-       }
-
-       if (content_size_field) {
-               int ret = bt_field_integer_unsigned_get_value(
-                       content_size_field, &content_size);
-
-               BT_ASSERT(ret == 0);
        } else {
-               content_size = packet_size;
+               if (notit->cur_exp_packet_content_size == -1) {
+                       notit->cur_exp_packet_content_size =
+                               notit->cur_exp_packet_total_size;
+               }
        }
 
-       if (content_size > packet_size) {
-               BT_LOGW("Invalid packet or content size: packet context field indicates content size is greater than packet size: "
+       if (notit->cur_exp_packet_content_size >
+                       notit->cur_exp_packet_total_size) {
+               BT_LOGW("Invalid packet or content size: "
+                       "content size is greater than packet size: "
                        "notit-addr=%p, packet-context-field-addr=%p, "
-                       "packet-size=%" PRIu64 ", content-size=%" PRIu64,
+                       "packet-size=%" PRId64 ", content-size=%" PRId64,
                        notit, notit->dscopes.stream_packet_context,
-                       packet_size, content_size);
+                       notit->cur_exp_packet_total_size,
+                       notit->cur_exp_packet_content_size);
                status = BT_NOTIF_ITER_STATUS_ERROR;
                goto end;
        }
 
-       if (packet_size != -1ULL) {
-               notit->cur_packet_size = packet_size;
-       } else {
-               /*
-                * Use the content size as packet size indicator if the
-                * packet size field is missing. This means there is no
-                * padding in this stream.
-                */
-               notit->cur_packet_size = content_size;
-       }
-       notit->cur_content_size = content_size;
        BT_LOGV("Set current packet and content sizes: "
                "notit-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64,
-               notit, packet_size, content_size);
+               notit, notit->cur_exp_packet_total_size,
+               notit->cur_exp_packet_content_size);
 end:
        return status;
 }
@@ -1401,72 +1029,99 @@ enum bt_notif_iter_status read_event_header_begin_state(
                struct bt_notif_iter *notit)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field_type *event_header_type = NULL;
+       struct ctf_field_type *event_header_ft = NULL;
 
        /* Reset the position of the last event header */
        notit->buf.last_eh_at = notit->buf.at;
+       notit->cur_event_class_id = -1;
 
        /* Check if we have some content left */
-       if (notit->cur_content_size >= 0) {
-               if (packet_at(notit) == notit->cur_content_size) {
+       if (notit->cur_exp_packet_content_size >= 0) {
+               if (unlikely(packet_at(notit) ==
+                               notit->cur_exp_packet_content_size)) {
                        /* No more events! */
                        BT_LOGV("Reached end of packet: notit-addr=%p, "
                                "cur=%zu", notit, packet_at(notit));
                        notit->state = STATE_EMIT_NOTIF_END_OF_PACKET;
                        goto end;
-               } else if (packet_at(notit) > notit->cur_content_size) {
+               } else if (unlikely(packet_at(notit) >
+                               notit->cur_exp_packet_content_size)) {
                        /* That's not supposed to happen */
                        BT_LOGV("Before decoding event header field: cursor is passed the packet's content: "
                                "notit-addr=%p, content-size=%" PRId64 ", "
-                               "cur=%zu", notit, notit->cur_content_size,
+                               "cur=%zu", notit,
+                               notit->cur_exp_packet_content_size,
                                packet_at(notit));
                        status = BT_NOTIF_ITER_STATUS_ERROR;
                        goto end;
                }
+       } else {
+               /*
+                * "Infinite" content: we're done when the medium has
+                * nothing else for us.
+                */
+               status = buf_ensure_available_bits(notit);
+               if (status != BT_NOTIF_ITER_STATUS_OK) {
+                       /*
+                        * If this function returns
+                        * `BT_NOTIF_ITER_STATUS_EOF`:
+                        *
+                        * 1. bt_notif_iter_get_next_notification()
+                        *    emits a "packet end" notification. This
+                        *    resets the current packet. The state
+                        *    remains unchanged otherwise.
+                        * 2. This function is called again. It returns
+                        *    `BT_NOTIF_ITER_STATUS_EOF` again.
+                        * 3. bt_notif_iter_get_next_notification()
+                        *    emits a "stream end" notification because
+                        *    there's no current packet. It sets the
+                        *    current state to `STATE_DONE`.
+                        */
+                       goto end;
+               }
        }
 
        release_event_dscopes(notit);
-       BT_ASSERT(notit->meta.stream_class);
-       event_header_type = bt_stream_class_borrow_event_header_field_type(
-               notit->meta.stream_class);
-       if (!event_header_type) {
-               notit->state = STATE_AFTER_STREAM_EVENT_HEADER;
+       BT_ASSERT(notit->meta.sc);
+       event_header_ft = notit->meta.sc->event_header_ft;
+       if (!event_header_ft) {
+               notit->state = STATE_AFTER_EVENT_HEADER;
                goto end;
        }
 
-       BT_ASSERT(!notit->event_header_field);
-       notit->event_header_field = bt_stream_class_create_event_header_field(
-               notit->meta.stream_class);
-       if (!notit->event_header_field) {
-               BT_LOGE_STR("Cannot create event header field wrapper from trace.");
-               status = BT_NOTIF_ITER_STATUS_ERROR;
-               goto end;
+       if (event_header_ft->in_ir) {
+               BT_ASSERT(!notit->event_header_field);
+               notit->event_header_field = bt_event_header_field_create(
+                       notit->meta.sc->ir_sc);
+               if (!notit->event_header_field) {
+                       BT_LOGE_STR("Cannot create event header field wrapper from trace.");
+                       status = BT_NOTIF_ITER_STATUS_ERROR;
+                       goto end;
+               }
+
+               notit->dscopes.event_header =
+                       bt_event_header_field_borrow_field(notit->event_header_field);
+               BT_ASSERT(notit->dscopes.event_header);
        }
 
-       notit->dscopes.stream_event_header =
-               bt_event_header_field_borrow_field(notit->event_header_field);
-       BT_ASSERT(notit->dscopes.stream_event_header);
        BT_LOGV("Decoding event header field: "
                "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
+               "stream-class-id=%" PRId64 ", "
                "ft-addr=%p",
-               notit, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class),
-               event_header_type);
-       status = read_dscope_begin_state(notit, event_header_type,
-               STATE_AFTER_STREAM_EVENT_HEADER,
-               STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
-               notit->dscopes.stream_event_header);
+               notit, notit->meta.sc,
+               notit->meta.sc->id,
+               event_header_ft);
+       status = read_dscope_begin_state(notit, event_header_ft,
+               STATE_AFTER_EVENT_HEADER,
+               STATE_DSCOPE_EVENT_HEADER_CONTINUE,
+               notit->dscopes.event_header);
        if (status < 0) {
                BT_LOGW("Cannot decode event header field: "
                        "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
                        "stream-class-id=%" PRId64 ", ft-addr=%p",
-                       notit, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class),
-                       event_header_type);
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id,
+                       event_header_ft);
        }
 
 end:
@@ -1478,142 +1133,55 @@ enum bt_notif_iter_status read_event_header_continue_state(
                struct bt_notif_iter *notit)
 {
        return read_dscope_continue_state(notit,
-               STATE_AFTER_STREAM_EVENT_HEADER);
+               STATE_AFTER_EVENT_HEADER);
 }
 
 static inline
 enum bt_notif_iter_status set_current_event_class(struct bt_notif_iter *notit)
 {
-       /*
-        * The assert() calls in this function are okay because it is
-        * assumed here that all the metadata objects have been
-        * validated for CTF correctness before decoding actual streams.
-        */
-
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field_type *event_header_type;
-       struct bt_field_type *id_field_type = NULL;
-       struct bt_field_type *v_field_type = NULL;
-       uint64_t event_id = -1ULL;
-       int ret;
 
-       event_header_type = bt_stream_class_borrow_event_header_field_type(
-               notit->meta.stream_class);
-       if (!event_header_type) {
-               /*
-                * No event header, therefore no event class ID field,
-                * therefore only one event class.
-                */
-               goto single_event_class;
-       }
+       struct ctf_event_class *new_event_class = NULL;
 
-       /* Is there any "id"/"v" field in the event header? */
-       BT_ASSERT(bt_field_type_is_structure(event_header_type));
-       id_field_type = bt_field_type_structure_borrow_field_type_by_name(
-               event_header_type, "id");
-       v_field_type = bt_field_type_structure_borrow_field_type_by_name(
-               event_header_type, "v");
-       BT_ASSERT(notit->dscopes.stream_event_header);
-       if (v_field_type) {
+       if (notit->cur_event_class_id == -1) {
                /*
-                *  _   _____ _____
-                * | | |_   _|_   _| __   __ _
-                * | |   | |   | || '_ \ / _` |
-                * | |___| |   | || | | | (_| |  S P E C I A L
-                * |_____|_|   |_||_| |_|\__, |  C A S E â„¢
-                *                       |___/
+                * No current event class ID field, therefore only one
+                * event class.
                 */
-               struct bt_field *v_field = NULL;
-               struct bt_field *v_struct_field = NULL;
-               struct bt_field *v_struct_id_field = NULL;
-
-               // TODO: optimalize!
-               v_field = bt_field_structure_borrow_field_by_name(
-                       notit->dscopes.stream_event_header, "v");
-               BT_ASSERT(v_field);
-
-               v_struct_field =
-                       bt_field_variant_borrow_current_field(v_field);
-               if (!v_struct_field) {
-                       goto end_v_field_type;
-               }
-
-               // TODO: optimalize!
-               v_struct_id_field = bt_field_structure_borrow_field_by_name(
-                       v_struct_field, "id");
-               if (!v_struct_id_field) {
-                       goto end_v_field_type;
-               }
-
-               if (bt_field_is_integer(v_struct_id_field)) {
-                       ret = bt_field_integer_unsigned_get_value(
-                               v_struct_id_field, &event_id);
-                       if (ret) {
-                               BT_LOGV("Cannot get value of unsigned integer field (`id`): continuing: "
-                                       "notit=%p, field-addr=%p",
-                                       notit, v_struct_id_field);
-                               event_id = -1ULL;
-                       }
-               }
-       }
-
-end_v_field_type:
-       if (id_field_type && event_id == -1ULL) {
-               /* Check "id" field */
-               struct bt_field *id_field = NULL;
-               int ret_get_value = 0;
-
-               // TODO: optimalize!
-               id_field = bt_field_structure_borrow_field_by_name(
-                       notit->dscopes.stream_event_header, "id");
-               if (!id_field) {
-                       goto check_event_id;
+               if (notit->meta.sc->event_classes->len != 1) {
+                       BT_LOGW("Need exactly one event class since there's "
+                               "no event class ID field: "
+                               "notit-addr=%p, trace-name=\"%s\"",
+                               notit, notit->meta.tc->name->str);
+                       status = BT_NOTIF_ITER_STATUS_ERROR;
+                       goto end;
                }
 
-               ret_get_value = bt_field_integer_unsigned_get_value(
-                       id_field, &event_id);
-               BT_ASSERT(ret_get_value == 0);
-       }
-
-check_event_id:
-       if (event_id == -1ULL) {
-single_event_class:
-               /* Event ID not found: single event? */
-               BT_ASSERT(bt_stream_class_get_event_class_count(
-                       notit->meta.stream_class) == 1);
-               event_id = 0;
+               new_event_class = notit->meta.sc->event_classes->pdata[0];
+               notit->cur_event_class_id = new_event_class->id;
+               goto end;
        }
 
-       BT_LOGV("Found event class ID to use: notit-addr=%p, "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64 ", "
-               "event-class-id=%" PRIu64,
-               notit, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class),
-               event_id);
-       notit->meta.event_class = bt_stream_class_borrow_event_class_by_id(
-               notit->meta.stream_class, event_id);
-       if (!notit->meta.event_class) {
+       new_event_class = ctf_stream_class_borrow_event_class_by_id(
+               notit->meta.sc, notit->cur_event_class_id);
+       if (!new_event_class) {
                BT_LOGW("No event class with ID of event class ID to use in stream class: "
-                       "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", "
-                       "event-class-id=%" PRIu64,
-                       notit, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class),
-                       event_id);
+                       "notit-addr=%p, stream-class-id=%" PRIu64 ", "
+                       "event-class-id=%" PRIu64 ", "
+                       "trace-addr=%p, trace-name=\"%s\"",
+                       notit, notit->meta.sc->id, notit->cur_event_class_id,
+                       notit->meta.tc, notit->meta.tc->name->str);
                status = BT_NOTIF_ITER_STATUS_ERROR;
                goto end;
        }
 
+       notit->meta.ec = new_event_class;
        BT_LOGV("Set current event class: "
                "notit-addr=%p, event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               notit, notit->meta.event_class,
-               bt_event_class_get_name(notit->meta.event_class),
-               bt_event_class_get_id(notit->meta.event_class));
+               "event-class-id=%" PRId64 ", "
+               "event-class-name=\"%s\"",
+               notit, notit->meta.ec, notit->meta.ec->id,
+               notit->meta.ec->name->str);
 
 end:
        return status;
@@ -1626,22 +1194,22 @@ enum bt_notif_iter_status set_current_event_notification(
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
        struct bt_notification *notif = NULL;
 
-       BT_ASSERT(notit->meta.event_class);
+       BT_ASSERT(notit->meta.ec);
        BT_ASSERT(notit->packet);
        BT_LOGV("Creating event notification from event class and packet: "
                "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p",
-               notit, notit->meta.event_class,
-               bt_event_class_get_name(notit->meta.event_class),
+               notit, notit->meta.ec,
+               notit->meta.ec->name->str,
                notit->packet);
        BT_ASSERT(notit->notif_iter);
        notif = bt_notification_event_create(notit->notif_iter,
-               notit->meta.event_class, notit->packet);
+               notit->meta.ec->ir_ec, notit->packet);
        if (!notif) {
                BT_LOGE("Cannot create event notification: "
                        "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", "
                        "packet-addr=%p",
-                       notit, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
+                       notit, notit->meta.ec,
+                       notit->meta.ec->name->str,
                        notit->packet);
                goto error;
        }
@@ -1682,7 +1250,6 @@ enum bt_notif_iter_status after_event_header_state(
                BT_ASSERT(notit->event);
                ret = bt_event_move_header(notit->event,
                        notit->event_header_field);
-
                if (ret) {
                        status = BT_NOTIF_ITER_STATUS_ERROR;
                        goto end;
@@ -1691,60 +1258,58 @@ enum bt_notif_iter_status after_event_header_state(
                notit->event_header_field = NULL;
 
                /*
-                * At this point notit->dscopes.stream_event_header has
+                * At this point notit->dscopes.event_header has
                 * the same value as the event header field within
                 * notit->event.
                 */
-               BT_ASSERT(bt_event_borrow_header(notit->event) ==
-                       notit->dscopes.stream_event_header);
+               BT_ASSERT(bt_event_borrow_header_field(notit->event) ==
+                       notit->dscopes.event_header);
        }
 
-       notit->state = STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN;
+       notit->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN;
 
 end:
        return status;
 }
 
 static
-enum bt_notif_iter_status read_stream_event_context_begin_state(
+enum bt_notif_iter_status read_event_common_context_begin_state(
                struct bt_notif_iter *notit)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field_type *stream_event_context_type;
+       struct ctf_field_type *event_common_context_ft;
 
-       stream_event_context_type =
-               bt_stream_class_borrow_event_context_field_type(
-                       notit->meta.stream_class);
-       if (!stream_event_context_type) {
-               notit->state = STATE_DSCOPE_EVENT_CONTEXT_BEGIN;
+       event_common_context_ft = notit->meta.sc->event_common_context_ft;
+       if (!event_common_context_ft) {
+               notit->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN;
                goto end;
        }
 
-       BT_ASSERT(!notit->dscopes.stream_event_context);
-       notit->dscopes.stream_event_context =
-               bt_event_borrow_stream_event_context(notit->event);
-       BT_ASSERT(notit->dscopes.stream_event_context);
-       BT_LOGV("Decoding stream event context field: "
+       if (event_common_context_ft->in_ir) {
+               BT_ASSERT(!notit->dscopes.event_common_context);
+               notit->dscopes.event_common_context =
+                       bt_event_borrow_common_context_field(notit->event);
+               BT_ASSERT(notit->dscopes.event_common_context);
+       }
+
+       BT_LOGV("Decoding event common context field: "
                "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
+               "stream-class-id=%" PRId64 ", "
                "ft-addr=%p",
-               notit, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class),
-               stream_event_context_type);
-       status = read_dscope_begin_state(notit, stream_event_context_type,
-               STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
-               STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
-               notit->dscopes.stream_event_context);
+               notit, notit->meta.sc,
+               notit->meta.sc->id,
+               event_common_context_ft);
+       status = read_dscope_begin_state(notit, event_common_context_ft,
+               STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
+               STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE,
+               notit->dscopes.event_common_context);
        if (status < 0) {
-               BT_LOGW("Cannot decode stream event context field: "
+               BT_LOGW("Cannot decode event common context field: "
                        "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
                        "stream-class-id=%" PRId64 ", ft-addr=%p",
-                       notit, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class),
-                       stream_event_context_type);
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id,
+                       event_common_context_ft);
        }
 
 end:
@@ -1752,51 +1317,54 @@ end:
 }
 
 static
-enum bt_notif_iter_status read_stream_event_context_continue_state(
+enum bt_notif_iter_status read_event_common_context_continue_state(
                struct bt_notif_iter *notit)
 {
        return read_dscope_continue_state(notit,
-               STATE_DSCOPE_EVENT_CONTEXT_BEGIN);
+               STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN);
 }
 
 static
-enum bt_notif_iter_status read_event_context_begin_state(
+enum bt_notif_iter_status read_event_spec_context_begin_state(
                struct bt_notif_iter *notit)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field_type *event_context_type;
+       struct ctf_field_type *event_spec_context_ft;
 
-       event_context_type = bt_event_class_borrow_context_field_type(
-               notit->meta.event_class);
-       if (!event_context_type) {
+       event_spec_context_ft = notit->meta.ec->spec_context_ft;
+       if (!event_spec_context_ft) {
                notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
                goto end;
        }
 
-       BT_ASSERT(!notit->dscopes.event_context);
-       notit->dscopes.event_context = bt_event_borrow_context(notit->event);
-       BT_ASSERT(notit->dscopes.event_context);
-       BT_LOGV("Decoding event context field: "
+       if (event_spec_context_ft->in_ir) {
+               BT_ASSERT(!notit->dscopes.event_spec_context);
+               notit->dscopes.event_spec_context = bt_event_borrow_specific_context_field(
+                       notit->event);
+               BT_ASSERT(notit->dscopes.event_spec_context);
+       }
+
+       BT_LOGV("Decoding event specific context field: "
                "notit-addr=%p, event-class-addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
                "ft-addr=%p",
-               notit, notit->meta.event_class,
-               bt_event_class_get_name(notit->meta.event_class),
-               bt_event_class_get_id(notit->meta.event_class),
-               event_context_type);
-       status = read_dscope_begin_state(notit, event_context_type,
+               notit, notit->meta.ec,
+               notit->meta.ec->name->str,
+               notit->meta.ec->id,
+               event_spec_context_ft);
+       status = read_dscope_begin_state(notit, event_spec_context_ft,
                STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
-               STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
-               notit->dscopes.event_context);
+               STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE,
+               notit->dscopes.event_spec_context);
        if (status < 0) {
-               BT_LOGW("Cannot decode event context field: "
+               BT_LOGW("Cannot decode event specific context field: "
                        "notit-addr=%p, event-class-addr=%p, "
                        "event-class-name=\"%s\", "
                        "event-class-id=%" PRId64 ", ft-addr=%p",
-                       notit, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class),
-                       event_context_type);
+                       notit, notit->meta.ec,
+                       notit->meta.ec->name->str,
+                       notit->meta.ec->id,
+                       event_spec_context_ft);
        }
 
 end:
@@ -1804,7 +1372,7 @@ end:
 }
 
 static
-enum bt_notif_iter_status read_event_context_continue_state(
+enum bt_notif_iter_status read_event_spec_context_continue_state(
                struct bt_notif_iter *notit)
 {
        return read_dscope_continue_state(notit,
@@ -1816,27 +1384,30 @@ enum bt_notif_iter_status read_event_payload_begin_state(
                struct bt_notif_iter *notit)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
-       struct bt_field_type *event_payload_type;
+       struct ctf_field_type *event_payload_ft;
 
-       event_payload_type = bt_event_class_borrow_payload_field_type(
-               notit->meta.event_class);
-       if (!event_payload_type) {
+       event_payload_ft = notit->meta.ec->payload_ft;
+       if (!event_payload_ft) {
                notit->state = STATE_EMIT_NOTIF_EVENT;
                goto end;
        }
 
-       BT_ASSERT(!notit->dscopes.event_payload);
-       notit->dscopes.event_payload = bt_event_borrow_payload(notit->event);
-       BT_ASSERT(notit->dscopes.event_payload);
+       if (event_payload_ft->in_ir) {
+               BT_ASSERT(!notit->dscopes.event_payload);
+               notit->dscopes.event_payload = bt_event_borrow_payload_field(
+                       notit->event);
+               BT_ASSERT(notit->dscopes.event_payload);
+       }
+
        BT_LOGV("Decoding event payload field: "
                "notit-addr=%p, event-class-addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
                "ft-addr=%p",
-               notit, notit->meta.event_class,
-               bt_event_class_get_name(notit->meta.event_class),
-               bt_event_class_get_id(notit->meta.event_class),
-               event_payload_type);
-       status = read_dscope_begin_state(notit, event_payload_type,
+               notit, notit->meta.ec,
+               notit->meta.ec->name->str,
+               notit->meta.ec->id,
+               event_payload_ft);
+       status = read_dscope_begin_state(notit, event_payload_ft,
                STATE_EMIT_NOTIF_EVENT,
                STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
                notit->dscopes.event_payload);
@@ -1845,10 +1416,10 @@ enum bt_notif_iter_status read_event_payload_begin_state(
                        "notit-addr=%p, event-class-addr=%p, "
                        "event-class-name=\"%s\", "
                        "event-class-id=%" PRId64 ", ft-addr=%p",
-                       notit, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class),
-                       event_payload_type);
+                       notit, notit->meta.ec,
+                       notit->meta.ec->name->str,
+                       notit->meta.ec->id,
+                       event_payload_ft);
        }
 
 end:
@@ -1869,8 +1440,8 @@ enum bt_notif_iter_status skip_packet_padding_state(
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
        size_t bits_to_skip;
 
-       BT_ASSERT(notit->cur_packet_size > 0);
-       bits_to_skip = notit->cur_packet_size - packet_at(notit);
+       BT_ASSERT(notit->cur_exp_packet_total_size > 0);
+       bits_to_skip = notit->cur_exp_packet_total_size - packet_at(notit);
        if (bits_to_skip == 0) {
                notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
                goto end;
@@ -1888,7 +1459,8 @@ enum bt_notif_iter_status skip_packet_padding_state(
                BT_LOGV("Skipping %zu bits of padding: notit-addr=%p, size=%zu",
                        bits_to_consume, notit, bits_to_consume);
                buf_consume_bits(notit, bits_to_consume);
-               bits_to_skip = notit->cur_packet_size - packet_at(notit);
+               bits_to_skip = notit->cur_exp_packet_total_size -
+                       packet_at(notit);
                if (bits_to_skip == 0) {
                        notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
                        goto end;
@@ -1935,28 +1507,28 @@ enum bt_notif_iter_status handle_state(struct bt_notif_iter *notit)
                notit->state = STATE_EMIT_NOTIF_NEW_PACKET;
                break;
        case STATE_EMIT_NOTIF_NEW_PACKET:
-               notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
+               notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
                break;
-       case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN:
+       case STATE_DSCOPE_EVENT_HEADER_BEGIN:
                status = read_event_header_begin_state(notit);
                break;
-       case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE:
+       case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
                status = read_event_header_continue_state(notit);
                break;
-       case STATE_AFTER_STREAM_EVENT_HEADER:
+       case STATE_AFTER_EVENT_HEADER:
                status = after_event_header_state(notit);
                break;
-       case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN:
-               status = read_stream_event_context_begin_state(notit);
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
+               status = read_event_common_context_begin_state(notit);
                break;
-       case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE:
-               status = read_stream_event_context_continue_state(notit);
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
+               status = read_event_common_context_continue_state(notit);
                break;
-       case STATE_DSCOPE_EVENT_CONTEXT_BEGIN:
-               status = read_event_context_begin_state(notit);
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
+               status = read_event_spec_context_begin_state(notit);
                break;
-       case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE:
-               status = read_event_context_continue_state(notit);
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
+               status = read_event_spec_context_continue_state(notit);
                break;
        case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
                status = read_event_payload_begin_state(notit);
@@ -1965,7 +1537,7 @@ enum bt_notif_iter_status handle_state(struct bt_notif_iter *notit)
                status = read_event_payload_continue_state(notit);
                break;
        case STATE_EMIT_NOTIF_EVENT:
-               notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
+               notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
                break;
        case STATE_SKIP_PACKET_PADDING:
                status = skip_packet_padding_state(notit);
@@ -1995,11 +1567,9 @@ void bt_notif_iter_reset(struct bt_notif_iter *notit)
        BT_ASSERT(notit);
        BT_LOGD("Resetting notification iterator: addr=%p", notit);
        stack_clear(notit->stack);
-       notit->meta.stream_class = NULL;
-       notit->meta.event_class = NULL;
+       notit->meta.sc = NULL;
+       notit->meta.ec = NULL;
        BT_PUT(notit->packet);
-       notit->prev_packet_avail = BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE;
-       BT_PUT(notit->prev_packet);
        BT_PUT(notit->stream);
        BT_PUT(notit->event_notif);
        release_all_dscopes(notit);
@@ -2026,11 +1596,13 @@ void bt_notif_iter_reset(struct bt_notif_iter *notit)
        notit->buf.last_eh_at = SIZE_MAX;
        notit->buf.packet_offset = 0;
        notit->state = STATE_INIT;
-       notit->cur_content_size = -1;
-       notit->cur_packet_size = -1;
+       notit->cur_exp_packet_content_size = -1;
+       notit->cur_exp_packet_total_size = -1;
        notit->cur_packet_offset = -1;
+       notit->cur_stream_class_id = -1;
+       notit->cur_event_class_id = -1;
+       notit->cur_data_stream_id = -1;
        notit->stream_begin_emitted = false;
-       notit->cur_timestamp_end = NULL;
 }
 
 static
@@ -2045,18 +1617,17 @@ int bt_notif_iter_switch_packet(struct bt_notif_iter *notit)
         */
        BT_ASSERT(notit);
 
-       if (notit->cur_packet_size != -1) {
-               notit->cur_packet_offset += notit->cur_packet_size;
+       if (notit->cur_exp_packet_total_size != -1) {
+               notit->cur_packet_offset += notit->cur_exp_packet_total_size;
        }
 
        BT_LOGV("Switching packet: notit-addr=%p, cur=%zu, "
                "packet-offset=%" PRId64, notit, notit->buf.at,
                notit->cur_packet_offset);
        stack_clear(notit->stack);
-       notit->meta.event_class = NULL;
+       notit->meta.ec = NULL;
        BT_PUT(notit->packet);
        BT_PUT(notit->event_notif);
-       notit->cur_timestamp_end = NULL;
        release_all_dscopes(notit);
        notit->cur_dscope_field = NULL;
 
@@ -2083,9 +1654,15 @@ int bt_notif_iter_switch_packet(struct bt_notif_iter *notit)
                        notit->buf.addr, notit->buf.sz);
        }
 
-       notit->cur_content_size = -1;
-       notit->cur_packet_size = -1;
-       notit->cur_sc_field_path_cache = NULL;
+       notit->cur_exp_packet_content_size = -1;
+       notit->cur_exp_packet_total_size = -1;
+       notit->cur_stream_class_id = -1;
+       notit->cur_event_class_id = -1;
+       notit->cur_data_stream_id = -1;
+       notit->snapshots.discarded_events = UINT64_C(-1);
+       notit->snapshots.packets = UINT64_C(-1);
+       notit->snapshots.beginning_clock = UINT64_C(-1);
+       notit->snapshots.end_clock = UINT64_C(-1);
 
 end:
        return ret;
@@ -2096,234 +1673,217 @@ struct bt_field *borrow_next_field(struct bt_notif_iter *notit)
 {
        struct bt_field *next_field = NULL;
        struct bt_field *base_field;
-       struct bt_field_type *base_type;
+       struct bt_field_type *base_ft;
        size_t index;
 
        BT_ASSERT(!stack_empty(notit->stack));
        index = stack_top(notit->stack)->index;
        base_field = stack_top(notit->stack)->base;
        BT_ASSERT(base_field);
-       base_type = bt_field_borrow_type(base_field);
-       BT_ASSERT(base_type);
+       base_ft = bt_field_borrow_type(base_field);
+       BT_ASSERT(base_ft);
 
-       switch (bt_field_type_get_type_id(base_type)) {
-       case BT_FIELD_TYPE_ID_STRUCT:
+       switch (bt_field_type_get_type_id(base_ft)) {
+       case BT_FIELD_TYPE_ID_STRUCTURE:
        {
-               next_field = bt_field_structure_borrow_field_by_index(
+               BT_ASSERT(index <
+                       bt_field_type_structure_get_member_count(
+                               bt_field_borrow_type(base_field)));
+               next_field = bt_field_structure_borrow_member_field_by_index(
                        base_field, index);
                break;
        }
-       case BT_FIELD_TYPE_ID_ARRAY:
-               next_field = bt_field_array_borrow_field(base_field, index);
-               break;
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               next_field = bt_field_sequence_borrow_field(base_field, index);
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
+               BT_ASSERT(index < bt_field_array_get_length(base_field));
+               next_field = bt_field_array_borrow_element_field_by_index(
+                       base_field, index);
                break;
        case BT_FIELD_TYPE_ID_VARIANT:
-               next_field = bt_field_variant_borrow_current_field(base_field);
+               BT_ASSERT(index == 0);
+               next_field = bt_field_variant_borrow_selected_option_field(
+                       base_field);
                break;
        default:
-               BT_LOGF("Unknown base field type ID: "
-                       "notit-addr=%p, ft-addr=%p, ft-id=%s",
-                       notit, base_type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(base_type)));
                abort();
        }
 
+       BT_ASSERT(next_field);
        return next_field;
 }
 
 static
-void update_clock_state(uint64_t *state, struct bt_field *value_field,
-               struct bt_field_type *value_type)
+void update_default_clock(struct bt_notif_iter *notit, uint64_t new_val,
+               uint64_t new_val_size)
 {
-       uint64_t requested_new_value;
-       uint64_t requested_new_value_mask;
+       uint64_t new_val_mask;
        uint64_t cur_value_masked;
-       int requested_new_value_size;
-       int ret;
 
-       BT_ASSERT(value_type);
-       BT_ASSERT(bt_field_type_is_integer(value_type));
-       requested_new_value_size =
-                       bt_field_type_integer_get_size(value_type);
-       BT_ASSERT(requested_new_value_size > 0);
-       ret = bt_field_integer_unsigned_get_value(value_field,
-                       &requested_new_value);
-       BT_ASSERT(!ret);
+       BT_ASSERT(new_val_size > 0);
 
        /*
         * Special case for a 64-bit new value, which is the limit
         * of a clock value as of this version: overwrite the
         * current value directly.
         */
-       if (requested_new_value_size == 64) {
-               *state = requested_new_value;
+       if (new_val_size == 64) {
+               notit->default_clock_val = new_val;
                goto end;
        }
 
-       requested_new_value_mask = (1ULL << requested_new_value_size) - 1;
-       cur_value_masked = *state & requested_new_value_mask;
+       new_val_mask = (1ULL << new_val_size) - 1;
+       cur_value_masked = notit->default_clock_val & new_val_mask;
 
-       if (requested_new_value < cur_value_masked) {
+       if (new_val < cur_value_masked) {
                /*
                 * It looks like a wrap happened on the number of bits
                 * of the requested new value. Assume that the clock
                 * value wrapped only one time.
                 */
-               *state += requested_new_value_mask + 1;
+               notit->default_clock_val += new_val_mask + 1;
        }
 
        /* Clear the low bits of the current clock value. */
-       *state &= ~requested_new_value_mask;
+       notit->default_clock_val &= ~new_val_mask;
 
        /* Set the low bits of the current clock value. */
-       *state |= requested_new_value;
+       notit->default_clock_val |= new_val;
 
 end:
-       BT_LOGV("Updated clock's value from integer field's value: "
-               "value=%" PRIu64, *state);
+       BT_LOGV("Updated default clock's value from integer field's value: "
+               "value=%" PRIu64, notit->default_clock_val);
 }
 
 static
-enum bt_btr_status update_clock(struct bt_notif_iter *notit,
-               struct bt_field *int_field)
+enum bt_btr_status btr_unsigned_int_cb(uint64_t value,
+               struct ctf_field_type *ft, void *data)
 {
-       gboolean clock_class_found;
-       uint64_t *clock_state = NULL;
-       struct bt_field_type *int_field_type = NULL;
-       enum bt_btr_status ret = BT_BTR_STATUS_OK;
-       struct bt_clock_class *clock_class = NULL;
+       struct bt_notif_iter *notit = data;
+       enum bt_btr_status status = BT_BTR_STATUS_OK;
+       struct bt_field *field = NULL;
+       struct ctf_field_type_int *int_ft = (void *) ft;
 
-       int_field_type = bt_field_borrow_type(int_field);
-       BT_ASSERT(int_field_type);
-
-       if (bt_field_type_is_enumeration(int_field_type)) {
-               int_field_type =
-                       bt_field_type_enumeration_borrow_container_field_type(
-                               int_field_type);
-       }
+       BT_LOGV("Unsigned integer function called from BTR: "
+               "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
+               "ft-id=%d, ft-in-ir=%d, value=%" PRIu64,
+               notit, notit->btr, ft, ft->id, ft->in_ir, value);
 
-       clock_class = bt_field_type_integer_borrow_mapped_clock_class(
-               int_field_type);
-       if (likely(!clock_class)) {
-               goto end;
+       if (likely(int_ft->meaning == CTF_FIELD_TYPE_MEANING_NONE)) {
+               goto update_def_clock;
        }
 
-       clock_class_found = g_hash_table_lookup_extended(notit->clock_states,
-               clock_class, NULL, (gpointer) &clock_state);
-       if (!clock_class_found) {
-               clock_state = g_new0(uint64_t, 1);
-               if (!clock_state) {
-                       BT_LOGE_STR("Failed to allocate a uint64_t.");
-                       ret = BT_BTR_STATUS_ENOMEM;
+       switch (int_ft->meaning) {
+       case CTF_FIELD_TYPE_MEANING_EVENT_CLASS_ID:
+               notit->cur_event_class_id = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_DATA_STREAM_ID:
+               notit->cur_data_stream_id = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_PACKET_BEGINNING_TIME:
+               notit->snapshots.beginning_clock = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_PACKET_END_TIME:
+               notit->snapshots.end_clock = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_STREAM_CLASS_ID:
+               notit->cur_stream_class_id = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_MAGIC:
+               if (value != 0xc1fc1fc1) {
+                       BT_LOGW("Invalid CTF magic number: notit-addr=%p, "
+                               "magic=%" PRIx64, notit, value);
+                       status = BT_BTR_STATUS_ERROR;
                        goto end;
                }
 
-               g_hash_table_insert(notit->clock_states, clock_class,
-                       clock_state);
+               break;
+       case CTF_FIELD_TYPE_MEANING_PACKET_COUNTER_SNAPSHOT:
+               notit->snapshots.packets = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT:
+               notit->snapshots.discarded_events = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_EXP_PACKET_TOTAL_SIZE:
+               notit->cur_exp_packet_total_size = value;
+               break;
+       case CTF_FIELD_TYPE_MEANING_EXP_PACKET_CONTENT_SIZE:
+               notit->cur_exp_packet_content_size = value;
+               break;
+       default:
+               abort();
        }
 
-       /* Update the clock's state. */
-       BT_LOGV("Updating notification iterator's clock's value from integer field: "
-               "notit-addr=%p, clock-class-addr=%p, "
-               "clock-class-name=\"%s\", value=%" PRIu64,
-               notit, clock_class,
-               bt_clock_class_get_name(clock_class), *clock_state);
-       update_clock_state(clock_state, int_field, int_field_type);
-
-end:
-       return ret;
-}
+update_def_clock:
+       if (unlikely(int_ft->mapped_clock_class)) {
+               update_default_clock(notit, value, int_ft->base.size);
+       }
 
-static
-enum bt_btr_status btr_unsigned_int_common(uint64_t value,
-               struct bt_field_type *type, void *data,
-               struct bt_field **out_field)
-{
-       enum bt_btr_status status = BT_BTR_STATUS_OK;
-       struct bt_field *field = NULL;
-       struct bt_notif_iter *notit = data;
-       int ret;
+       if (unlikely(int_ft->storing_index >= 0)) {
+               g_array_index(notit->stored_values, uint64_t,
+                       (uint64_t) int_ft->storing_index) = value;
+       }
 
-       BT_LOGV("Common unsigned integer function called from BTR: "
-               "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s, value=%" PRIu64,
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)),
-               value);
-       field = borrow_next_field(notit);
-       if (!field) {
-               BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
-               status = BT_BTR_STATUS_ERROR;
+       if (unlikely(!ft->in_ir)) {
                goto end;
        }
 
-       BT_ASSERT(bt_field_is_integer(field) || bt_field_is_enumeration(field));
-       ret = bt_field_integer_unsigned_set_value(field, value);
-       BT_ASSERT(ret == 0);
+       field = borrow_next_field(notit);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_type(field) == ft->ir_ft);
+       BT_ASSERT(bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_UNSIGNED_INTEGER ||
+               bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION);
+       bt_field_unsigned_integer_set_value(field, value);
        stack_top(notit->stack)->index++;
-       *out_field = field;
 
 end:
        return status;
 }
 
 static
-enum bt_btr_status btr_timestamp_end_cb(void *value,
-               struct bt_field_type *type, void *data)
+enum bt_btr_status btr_unsigned_int_char_cb(uint64_t value,
+               struct ctf_field_type *ft, void *data)
 {
-       enum bt_btr_status status;
-       struct bt_field *field = NULL;
+       int ret;
        struct bt_notif_iter *notit = data;
-       uint64_t uvalue = *((uint64_t *) value);
+       enum bt_btr_status status = BT_BTR_STATUS_OK;
+       struct bt_field *string_field = NULL;
+       struct ctf_field_type_int *int_ft = (void *) ft;
+       char str[2] = {'\0', '\0'};
 
-       BT_LOGV("`timestamp_end` unsigned integer function called from BTR: "
+       BT_LOGV("Unsigned integer character function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s",
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)));
-
-       status = btr_unsigned_int_common(uvalue, type, data, &field);
+               "ft-id=%d, ft-in-ir=%d, value=%" PRIu64,
+               notit, notit->btr, ft, ft->id, ft->in_ir, value);
+       BT_ASSERT(int_ft->meaning == CTF_FIELD_TYPE_MEANING_NONE);
+       BT_ASSERT(!int_ft->mapped_clock_class);
+       BT_ASSERT(int_ft->storing_index < 0);
 
-       /* Set as the current packet's end timestamp field */
-       notit->cur_timestamp_end = field;
-       return status;
-}
-
-static
-enum bt_btr_status btr_unsigned_int_cb(uint64_t value,
-               struct bt_field_type *type, void *data)
-{
-       struct bt_notif_iter *notit = data;
-       enum bt_btr_status status = BT_BTR_STATUS_OK;
-       struct bt_field *field = NULL;
-       struct field_cb_override *override;
+       if (unlikely(!ft->in_ir)) {
+               goto end;
+       }
 
-       BT_LOGV("Unsigned integer function called from BTR: "
-               "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s, value=%" PRIu64,
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)),
-               value);
-       override = g_hash_table_lookup(notit->field_overrides, type);
-       if (unlikely(override)) {
-               /* Override function logs errors */
-               status = override->func(&value, type, override->data);
+       if (notit->done_filling_string) {
                goto end;
        }
 
-       status = btr_unsigned_int_common(value, type, data, &field);
-       if (status != BT_BTR_STATUS_OK) {
-               /* btr_unsigned_int_common() logs errors */
+       if (value == 0) {
+               notit->done_filling_string = true;
                goto end;
        }
 
-       status = update_clock(notit, field);
+       string_field = stack_top(notit->stack)->base;
+       BT_ASSERT(bt_field_get_type_id(string_field) == BT_FIELD_TYPE_ID_STRING);
+
+       /* Append character */
+       str[0] = (char) value;
+       ret = bt_field_string_append_with_length(string_field, str, 1);
+       if (ret) {
+               BT_LOGE("Cannot append character to string field's value: "
+                       "notit-addr=%p, field-addr=%p, ret=%d",
+                       notit, string_field, ret);
+               status = BT_BTR_STATUS_ERROR;
+               goto end;
+       }
 
 end:
        return status;
@@ -2331,30 +1891,34 @@ end:
 
 static
 enum bt_btr_status btr_signed_int_cb(int64_t value,
-               struct bt_field_type *type, void *data)
+               struct ctf_field_type *ft, void *data)
 {
        enum bt_btr_status status = BT_BTR_STATUS_OK;
        struct bt_field *field = NULL;
        struct bt_notif_iter *notit = data;
-       int ret;
+       struct ctf_field_type_int *int_ft = (void *) ft;
 
        BT_LOGV("Signed integer function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s, value=%" PRId64,
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)),
-               value);
-       field = borrow_next_field(notit);
-       if (!field) {
-               BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
-               status = BT_BTR_STATUS_ERROR;
+               "ft-id=%d, ft-in-ir=%d, value=%" PRId64,
+               notit, notit->btr, ft, ft->id, ft->in_ir, value);
+       BT_ASSERT(int_ft->meaning == CTF_FIELD_TYPE_MEANING_NONE);
+
+       if (unlikely(int_ft->storing_index >= 0)) {
+               g_array_index(notit->stored_values, uint64_t,
+                       (uint64_t) int_ft->storing_index) = (uint64_t) value;
+       }
+
+       if (unlikely(!ft->in_ir)) {
                goto end;
        }
 
-       BT_ASSERT(bt_field_is_integer(field) || bt_field_is_enumeration(field));
-       ret = bt_field_integer_signed_set_value(field, value);
-       BT_ASSERT(ret == 0);
+       field = borrow_next_field(notit);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_type(field) == ft->ir_ft);
+       BT_ASSERT(bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_SIGNED_INTEGER ||
+               bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_SIGNED_ENUMERATION);
+       bt_field_signed_integer_set_value(field, value);
        stack_top(notit->stack)->index++;
 
 end:
@@ -2363,80 +1927,59 @@ end:
 
 static
 enum bt_btr_status btr_floating_point_cb(double value,
-               struct bt_field_type *type, void *data)
+               struct ctf_field_type *ft, void *data)
 {
        enum bt_btr_status status = BT_BTR_STATUS_OK;
        struct bt_field *field = NULL;
        struct bt_notif_iter *notit = data;
-       int ret;
 
        BT_LOGV("Floating point number function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s, value=%f",
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)),
-               value);
+               "ft-id=%d, ft-in-ir=%d, value=%f",
+               notit, notit->btr, ft, ft->id, ft->in_ir, value);
+       BT_ASSERT(ft->in_ir);
        field = borrow_next_field(notit);
-       if (!field) {
-               BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
-
-       ret = bt_field_floating_point_set_value(field, value);
-       BT_ASSERT(!ret);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_type(field) == ft->ir_ft);
+       BT_ASSERT(bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_REAL);
+       bt_field_real_set_value(field, value);
        stack_top(notit->stack)->index++;
-
-end:
        return status;
 }
 
 static
 enum bt_btr_status btr_string_begin_cb(
-               struct bt_field_type *type, void *data)
+               struct ctf_field_type *ft, void *data)
 {
-       enum bt_btr_status status = BT_BTR_STATUS_OK;
        struct bt_field *field = NULL;
        struct bt_notif_iter *notit = data;
        int ret;
 
        BT_LOGV("String (beginning) function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s",
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)));
-       field = borrow_next_field(notit);
-       if (!field) {
-               BT_LOGW("Cannot get next field: notit-addr=%p", notit);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
+               "ft-id=%d, ft-in-ir=%d",
+               notit, notit->btr, ft, ft->id, ft->in_ir);
 
+       BT_ASSERT(ft->in_ir);
+       field = borrow_next_field(notit);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_type(field) == ft->ir_ft);
+       BT_ASSERT(bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_STRING);
        ret = bt_field_string_clear(field);
        BT_ASSERT(ret == 0);
 
        /*
-        * Push on stack. Not a compound type per se, but we know that only
-        * btr_string_cb() may be called between this call and a subsequent
-        * call to btr_string_end_cb().
+        * Push on stack. Not a compound type per se, but we know that
+        * only btr_string_cb() may be called between this call and a
+        * subsequent call to btr_string_end_cb().
         */
-       ret = stack_push(notit->stack, field);
-       if (ret) {
-               BT_LOGE("Cannot push string field on stack: "
-                       "notit-addr=%p, field-addr=%p", notit, field);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return status;
+       stack_push(notit->stack, field);
+       return BT_BTR_STATUS_OK;
 }
 
 static
 enum bt_btr_status btr_string_cb(const char *value,
-               size_t len, struct bt_field_type *type, void *data)
+               size_t len, struct ctf_field_type *ft, void *data)
 {
        enum bt_btr_status status = BT_BTR_STATUS_OK;
        struct bt_field *field = NULL;
@@ -2445,16 +1988,15 @@ enum bt_btr_status btr_string_cb(const char *value,
 
        BT_LOGV("String (substring) function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s, string-length=%zu",
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)),
+               "ft-id=%d, ft-in-ir=%d, string-length=%zu",
+               notit, notit->btr, ft, ft->id, ft->in_ir,
                len);
+       BT_ASSERT(ft->in_ir);
        field = stack_top(notit->stack)->base;
        BT_ASSERT(field);
 
        /* Append current substring */
-       ret = bt_field_string_append_len(field, value, len);
+       ret = bt_field_string_append_with_length(field, value, len);
        if (ret) {
                BT_LOGE("Cannot append substring to string field's value: "
                        "notit-addr=%p, field-addr=%p, string-length=%zu, "
@@ -2469,16 +2011,15 @@ end:
 
 static
 enum bt_btr_status btr_string_end_cb(
-               struct bt_field_type *type, void *data)
+               struct ctf_field_type *ft, void *data)
 {
        struct bt_notif_iter *notit = data;
 
        BT_LOGV("String (end) function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s",
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)));
+               "ft-id=%d, ft-in-ir=%d",
+               notit, notit->btr, ft, ft->id, ft->in_ir);
+       BT_ASSERT(ft->in_ir);
 
        /* Pop string field */
        stack_pop(notit->stack);
@@ -2489,19 +2030,19 @@ enum bt_btr_status btr_string_end_cb(
 }
 
 enum bt_btr_status btr_compound_begin_cb(
-               struct bt_field_type *type, void *data)
+               struct ctf_field_type *ft, void *data)
 {
-       enum bt_btr_status status = BT_BTR_STATUS_OK;
        struct bt_notif_iter *notit = data;
        struct bt_field *field;
-       int ret;
 
        BT_LOGV("Compound (beginning) function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s",
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)));
+               "ft-id=%d, ft-in-ir=%d",
+               notit, notit->btr, ft, ft->id, ft->in_ir);
+
+       if (!ft->in_ir) {
+               goto end;
+       }
 
        /* Borrow field */
        if (stack_empty(notit->stack)) {
@@ -2509,290 +2050,203 @@ enum bt_btr_status btr_compound_begin_cb(
                field = notit->cur_dscope_field;
        } else {
                field = borrow_next_field(notit);
-               if (!field) {
-                       BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
-                       status = BT_BTR_STATUS_ERROR;
-                       goto end;
-               }
+               BT_ASSERT(field);
        }
 
        /* Push field */
        BT_ASSERT(field);
-       ret = stack_push(notit->stack, field);
-       if (ret) {
-               BT_LOGE("Cannot push compound field onto the stack: "
-                       "notit-addr=%p, ft-addr=%p, ft-id=%s, ret=%d",
-                       notit, type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(type)),
-                       ret);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
+       BT_ASSERT(bt_field_borrow_type(field) == ft->ir_ft);
+       stack_push(notit->stack, field);
+
+       /*
+        * Change BTR "unsigned int" callback if it's a text
+        * array/sequence.
+        */
+       if (ft->id == CTF_FIELD_TYPE_ID_ARRAY ||
+                       ft->id == CTF_FIELD_TYPE_ID_SEQUENCE) {
+               struct ctf_field_type_array_base *array_ft = (void *) ft;
+
+               if (array_ft->is_text) {
+                       int ret;
+
+                       BT_ASSERT(bt_field_get_type_id(field) ==
+                               BT_FIELD_TYPE_ID_STRING);
+                       notit->done_filling_string = false;
+                       ret = bt_field_string_clear(field);
+                       BT_ASSERT(ret == 0);
+                       bt_btr_set_unsigned_int_cb(notit->btr,
+                               btr_unsigned_int_char_cb);
+               }
        }
 
 end:
-       return status;
+       return BT_BTR_STATUS_OK;
 }
 
 enum bt_btr_status btr_compound_end_cb(
-               struct bt_field_type *type, void *data)
+               struct ctf_field_type *ft, void *data)
 {
        struct bt_notif_iter *notit = data;
 
        BT_LOGV("Compound (end) function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
-               "ft-id=%s",
-               notit, notit->btr, type,
-               bt_common_field_type_id_string(
-                       bt_field_type_get_type_id(type)));
-       BT_ASSERT(!stack_empty(notit->stack));
-
-       /* Pop stack */
-       stack_pop(notit->stack);
-
-       /* If the stack is not empty, increment the base's index */
-       if (!stack_empty(notit->stack)) {
-               stack_top(notit->stack)->index++;
-       }
-
-       return BT_BTR_STATUS_OK;
-}
-
-static
-struct bt_field *resolve_field(struct bt_notif_iter *notit,
-               struct bt_field_path *path)
-{
-       struct bt_field *field = NULL;
-       unsigned int i;
-
-       if (BT_LOG_ON_VERBOSE) {
-               GString *gstr = bt_field_path_string(path);
-
-               BT_LOGV("Resolving field path: notit-addr=%p, field-path=\"%s\"",
-                       notit, gstr ? gstr->str : NULL);
-
-               if (gstr) {
-                       g_string_free(gstr, TRUE);
-               }
-       }
-
-       switch (bt_field_path_get_root_scope(path)) {
-       case BT_SCOPE_TRACE_PACKET_HEADER:
-               field = notit->dscopes.trace_packet_header;
-               break;
-       case BT_SCOPE_STREAM_PACKET_CONTEXT:
-               field = notit->dscopes.stream_packet_context;
-               break;
-       case BT_SCOPE_STREAM_EVENT_HEADER:
-               field = notit->dscopes.stream_event_header;
-               break;
-       case BT_SCOPE_STREAM_EVENT_CONTEXT:
-               field = notit->dscopes.stream_event_context;
-               break;
-       case BT_SCOPE_EVENT_CONTEXT:
-               field = notit->dscopes.event_context;
-               break;
-       case BT_SCOPE_EVENT_FIELDS:
-               field = notit->dscopes.event_payload;
-               break;
-       default:
-               BT_LOGF("Cannot resolve field path: unknown scope: "
-                       "notit-addr=%p, root-scope=%s",
-                       notit, bt_common_scope_string(
-                               bt_field_path_get_root_scope(path)));
-               abort();
-       }
+               "ft-id=%d, ft-in-ir=%d",
+               notit, notit->btr, ft, ft->id, ft->in_ir);
 
-       if (!field) {
-               BT_LOGW("Cannot resolve field path: root field not found: "
-                       "notit-addr=%p, root-scope=%s",
-                       notit, bt_common_scope_string(
-                               bt_field_path_get_root_scope(path)));
+       if (!ft->in_ir) {
                goto end;
        }
 
-       for (i = 0; i < bt_field_path_get_index_count(path); ++i) {
-               struct bt_field *next_field = NULL;
-               struct bt_field_type *field_type;
-               int index = bt_field_path_get_index(path, i);
-
-               field_type = bt_field_borrow_type(field);
-               BT_ASSERT(field_type);
+       BT_ASSERT(!stack_empty(notit->stack));
+       BT_ASSERT(bt_field_borrow_type(stack_top(notit->stack)->base) ==
+               ft->ir_ft);
 
-               if (bt_field_type_is_structure(field_type)) {
-                       next_field = bt_field_structure_borrow_field_by_index(
-                               field, index);
-               } else if (bt_field_type_is_variant(field_type)) {
-                       next_field =
-                               bt_field_variant_borrow_current_field(field);
+       /*
+        * Reset BTR "unsigned int" callback if it's a text
+        * array/sequence.
+        */
+       if (ft->id == CTF_FIELD_TYPE_ID_ARRAY ||
+                       ft->id == CTF_FIELD_TYPE_ID_SEQUENCE) {
+               struct ctf_field_type_array_base *array_ft = (void *) ft;
+
+               if (array_ft->is_text) {
+                       BT_ASSERT(bt_field_get_type_id(
+                               stack_top(notit->stack)->base) ==
+                                       BT_FIELD_TYPE_ID_STRING);
+                       bt_btr_set_unsigned_int_cb(notit->btr,
+                               btr_unsigned_int_cb);
                }
+       }
 
-               field = NULL;
-
-               if (!next_field) {
-                       BT_LOGW("Cannot find next field: "
-                               "notit-addr=%p, ft-addr=%p, ft-id=%s, index=%d",
-                               notit, field_type,
-                               bt_common_field_type_id_string(
-                                       bt_field_type_get_type_id(field_type)),
-                               index);
-                       goto end;
-               }
+       /* Pop stack */
+       stack_pop(notit->stack);
 
-               /* Move next field -> field */
-               field = next_field;
+       /* If the stack is not empty, increment the base's index */
+       if (!stack_empty(notit->stack)) {
+               stack_top(notit->stack)->index++;
        }
 
 end:
-       return field;
+       return BT_BTR_STATUS_OK;
 }
 
 static
-int64_t btr_get_sequence_length_cb(struct bt_field_type *type, void *data)
+int64_t btr_get_sequence_length_cb(struct ctf_field_type *ft, void *data)
 {
-       int64_t ret = -1;
-       int iret;
        struct bt_field *seq_field;
-       struct bt_field_path *field_path;
        struct bt_notif_iter *notit = data;
-       struct bt_field *length_field = NULL;
-       uint64_t length;
-
-       field_path = bt_field_type_sequence_borrow_length_field_path(type);
-       BT_ASSERT(field_path);
-       length_field = resolve_field(notit, field_path);
-       if (!length_field) {
-               BT_LOGW("Cannot resolve sequence field type's length field path: "
-                       "notit-addr=%p, ft-addr=%p",
-                       notit, type);
-               goto end;
-       }
-
-       iret = bt_field_integer_unsigned_get_value(length_field, &length);
-       if (iret) {
-               BT_LOGE("Cannot get value of sequence length field: "
-                       "notit-addr=%p, field-addr=%p",
-                       notit, length_field);
-               goto end;
-       }
+       struct ctf_field_type_sequence *seq_ft = (void *) ft;
+       int64_t length = -1;
+       int ret;
 
+       length = (uint64_t) g_array_index(notit->stored_values, uint64_t,
+               seq_ft->stored_length_index);
        seq_field = stack_top(notit->stack)->base;
-       iret = bt_field_sequence_set_length(seq_field, length);
-       if (iret) {
-               BT_LOGE("Cannot set sequence field's length field: "
-                       "notit-addr=%p, seq-field-addr=%p, "
-                       "length=%" PRIu64,
-                       notit, seq_field, length);
-               goto end;
+       BT_ASSERT(seq_field);
+       ret = bt_field_dynamic_array_set_length(seq_field, (uint64_t) length);
+       if (ret) {
+               BT_LOGE("Cannot set dynamic array field's length field: "
+                       "notit-addr=%p, field-addr=%p, "
+                       "length=%" PRIu64, notit, seq_field, length);
        }
 
-       ret = (int64_t) length;
-
-end:
-       return ret;
+       return length;
 }
 
 static
-struct bt_field_type *btr_borrow_variant_field_type_cb(
-               struct bt_field_type *type, void *data)
+struct ctf_field_type *btr_borrow_variant_selected_field_type_cb(
+               struct ctf_field_type *ft, void *data)
 {
        int ret;
-       struct bt_field_path *path;
+       uint64_t i;
+       int64_t option_index = -1;
        struct bt_notif_iter *notit = data;
-       struct bt_field *var_field;
-       struct bt_field *tag_field = NULL;
-       struct bt_field_type *tag_ft = NULL;
-       struct bt_field_type *tag_int_ft = NULL;
-       struct bt_field *selected_field = NULL;
-       struct bt_field_type *selected_field_type = NULL;
-
-       path = bt_field_type_variant_borrow_tag_field_path(type);
-       BT_ASSERT(path);
-       tag_field = resolve_field(notit, path);
-       if (!tag_field) {
-               BT_LOGW("Cannot resolve variant field type's tag field path: "
-                       "notit-addr=%p, ft-addr=%p",
-                       notit, type);
-               goto end;
-       }
+       struct ctf_field_type_variant *var_ft = (void *) ft;
+       struct ctf_named_field_type *selected_option = NULL;
+       struct ctf_field_type *ret_ft = NULL;
+       union {
+               uint64_t u;
+               int64_t i;
+       } tag;
+
+       /* Get variant's tag */
+       tag.u = g_array_index(notit->stored_values, uint64_t,
+               var_ft->stored_tag_index);
 
        /*
-        * We found the enumeration tag field instance which should be
-        * able to select a current field for this variant. This
-        * callback function we're in is called _after_
-        * compound_begin(), so the current stack top's base field is
-        * the variant field in question. We set the variant field's tag
-        * here and then get the current (selected) field thanks to this
-        * tag field's value. This current field will also provide us
-        * with its type. Then, this current field will remain the
-        * current selected one until the next callback function call
-        * which is used to fill it.
+        * Check each range to find the selected option's index.
         */
-       var_field = stack_top(notit->stack)->base;
-       tag_ft = bt_field_borrow_type(tag_field);
-       tag_int_ft = bt_field_type_enumeration_borrow_container_field_type(
-               tag_ft);
-
-       if (bt_field_type_integer_is_signed(tag_int_ft)) {
-               int64_t tag_value;
-
-               ret = bt_field_integer_signed_get_value(tag_field, &tag_value);
-               BT_ASSERT(ret == 0);
-               ret = bt_field_variant_set_tag_signed(var_field, tag_value);
-               BT_ASSERT(ret == 0);
+       if (var_ft->tag_ft->base.is_signed) {
+               for (i = 0; i < var_ft->ranges->len; i++) {
+                       struct ctf_field_type_variant_range *range =
+                               ctf_field_type_variant_borrow_range_by_index(
+                                       var_ft, i);
+
+                       if (tag.i >= range->range.lower.i &&
+                                       tag.i <= range->range.upper.i) {
+                               option_index = (int64_t) range->option_index;
+                               break;
+                       }
+               }
        } else {
-               uint64_t tag_value;
-
-               ret = bt_field_integer_unsigned_get_value(tag_field,
-                       &tag_value);
-               BT_ASSERT(ret == 0);
-               ret = bt_field_variant_set_tag_unsigned(var_field, tag_value);
-               BT_ASSERT(ret == 0);
+               for (i = 0; i < var_ft->ranges->len; i++) {
+                       struct ctf_field_type_variant_range *range =
+                               ctf_field_type_variant_borrow_range_by_index(
+                                       var_ft, i);
+
+                       if (tag.u >= range->range.lower.u &&
+                                       tag.u <= range->range.upper.u) {
+                               option_index = (int64_t) range->option_index;
+                               break;
+                       }
+               }
        }
 
-       selected_field = bt_field_variant_borrow_current_field(var_field);
-       if (!selected_field) {
-               BT_LOGW("Cannot borrow variant field's current field: "
-                       "notit-addr=%p, var-field-addr=%p",
-                       notit, var_field);
+       if (option_index < 0) {
+               BT_LOGW("Cannot find variant field type's option: "
+                       "notit-addr=%p, var-ft-addr=%p, u-tag=%" PRIu64 ", "
+                       "i-tag=%" PRId64, notit, var_ft, tag.u, tag.i);
                goto end;
        }
 
-       selected_field_type = bt_field_borrow_type(selected_field);
+       selected_option = ctf_field_type_variant_borrow_option_by_index(
+               var_ft, (uint64_t) option_index);
 
-end:
-       return selected_field_type;
-}
-
-static
-int set_event_clocks(struct bt_notif_iter *notit)
-{
-       int ret;
-       GHashTableIter iter;
-       struct bt_clock_class *clock_class;
-       uint64_t *clock_state;
-
-       g_hash_table_iter_init(&iter, notit->clock_states);
+       if (selected_option->ft->in_ir) {
+               struct bt_field *var_field = stack_top(notit->stack)->base;
 
-       while (g_hash_table_iter_next(&iter, (gpointer) &clock_class,
-                       (gpointer) &clock_state)) {
-               ret = bt_event_set_clock_value(notit->event, clock_class,
-                       *clock_state, BT_TRUE);
+               ret = bt_field_variant_select_option_field(var_field,
+                       option_index);
                if (ret) {
-                       BT_LOGE("Cannot set event's default clock value: "
-                               "notit-addr=%p, clock-class-addr=%p, "
-                               "clock-class-name=\"%s\"",
-                               notit, clock_class,
-                               bt_clock_class_get_name(clock_class));
-                       ret = -1;
+                       BT_LOGW("Cannot select variant field's option field: "
+                               "notit-addr=%p, var-field-addr=%p, "
+                               "opt-index=%" PRId64, notit, var_field,
+                               option_index);
                        goto end;
                }
        }
 
-       ret = 0;
+       ret_ft = selected_option->ft;
 
 end:
-       return ret;
+       return ret_ft;
+}
+
+static
+void set_event_default_clock_value(struct bt_notif_iter *notit)
+{
+       struct bt_event *event = bt_notification_event_borrow_event(
+               notit->event_notif);
+       struct bt_stream_class *sc = notit->meta.sc->ir_sc;
+
+       BT_ASSERT(event);
+
+       if (bt_stream_class_borrow_default_clock_class(sc)) {
+               int ret = bt_event_set_default_clock_value(event,
+                       notit->default_clock_val);
+
+               BT_ASSERT(ret == 0);
+       }
 }
 
 static
@@ -2854,6 +2308,7 @@ void notify_new_packet(struct bt_notif_iter *notit,
        int ret;
        enum bt_notif_iter_status status;
        struct bt_notification *notif = NULL;
+       struct bt_stream_class *sc;
 
        status = set_current_packet(notit);
        if (status != BT_NOTIF_ITER_STATUS_OK) {
@@ -2861,9 +2316,39 @@ void notify_new_packet(struct bt_notif_iter *notit,
        }
 
        BT_ASSERT(notit->packet);
+       sc = notit->meta.sc->ir_sc;
+       BT_ASSERT(sc);
+
+       if (bt_stream_class_packets_have_discarded_event_counter_snapshot(sc)) {
+               BT_ASSERT(notit->snapshots.discarded_events != UINT64_C(-1));
+               ret = bt_packet_set_discarded_event_counter_snapshot(
+                       notit->packet, notit->snapshots.discarded_events);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (bt_stream_class_packets_have_packet_counter_snapshot(sc)) {
+               BT_ASSERT(notit->snapshots.packets != UINT64_C(-1));
+               ret = bt_packet_set_packet_counter_snapshot(
+                       notit->packet, notit->snapshots.packets);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (bt_stream_class_packets_have_default_beginning_clock_value(sc)) {
+               BT_ASSERT(notit->snapshots.beginning_clock != UINT64_C(-1));
+               ret = bt_packet_set_default_beginning_clock_value(
+                       notit->packet, notit->snapshots.beginning_clock);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (bt_stream_class_packets_have_default_end_clock_value(sc)) {
+               BT_ASSERT(notit->snapshots.end_clock != UINT64_C(-1));
+               ret = bt_packet_set_default_end_clock_value(
+                       notit->packet, notit->snapshots.end_clock);
+               BT_ASSERT(ret == 0);
+       }
 
        if (notit->packet_header_field) {
-               ret = bt_packet_move_header(notit->packet,
+               ret = bt_packet_move_header_field(notit->packet,
                        notit->packet_header_field);
                if (ret) {
                        goto end;
@@ -2876,12 +2361,12 @@ void notify_new_packet(struct bt_notif_iter *notit,
                 * the same value as the packet header field within
                 * notit->packet.
                 */
-               BT_ASSERT(bt_packet_borrow_header(notit->packet) ==
+               BT_ASSERT(bt_packet_borrow_header_field(notit->packet) ==
                        notit->dscopes.trace_packet_header);
        }
 
        if (notit->packet_context_field) {
-               ret = bt_packet_move_context(notit->packet,
+               ret = bt_packet_move_context_field(notit->packet,
                        notit->packet_context_field);
                if (ret) {
                        goto end;
@@ -2894,7 +2379,7 @@ void notify_new_packet(struct bt_notif_iter *notit,
                 * the same value as the packet header field within
                 * notit->packet.
                 */
-               BT_ASSERT(bt_packet_borrow_context(notit->packet) ==
+               BT_ASSERT(bt_packet_borrow_context_field(notit->packet) ==
                        notit->dscopes.stream_packet_context);
        }
 
@@ -2924,6 +2409,11 @@ void notify_end_of_packet(struct bt_notif_iter *notit,
                return;
        }
 
+       /* Update default clock from packet's end time */
+       if (notit->snapshots.end_clock != UINT64_C(-1)) {
+               notit->default_clock_val = notit->snapshots.end_clock;
+       }
+
        BT_ASSERT(notit->notif_iter);
        notif = bt_notification_packet_end_create(notit->notif_iter,
                notit->packet);
@@ -2935,61 +2425,12 @@ void notify_end_of_packet(struct bt_notif_iter *notit,
 
        }
 
-       BT_MOVE(notit->prev_packet, notit->packet);
-       notit->prev_packet_avail =
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_AVAILABLE;
+       BT_PUT(notit->packet);
        *notification = notif;
 }
 
-static
-void init_trace_field_path_cache(struct bt_trace *trace,
-               struct trace_field_path_cache *trace_field_path_cache)
-{
-       int stream_id = -1;
-       int stream_instance_id = -1;
-       int i, count;
-       struct bt_field_type *packet_header = NULL;
-
-       packet_header = bt_trace_borrow_packet_header_field_type(trace);
-       if (!packet_header) {
-               goto end;
-       }
-
-       if (!bt_field_type_is_structure(packet_header)) {
-               goto end;
-       }
-
-       count = bt_field_type_structure_get_field_count(packet_header);
-       BT_ASSERT(count >= 0);
-
-       for (i = 0; (i < count && (stream_id == -1 || stream_instance_id == -1)); i++) {
-               int ret;
-               const char *field_name;
-
-               ret = bt_field_type_structure_borrow_field_by_index(
-                       packet_header, &field_name, NULL, i);
-               if (ret) {
-                       BT_LOGE("Cannot get structure field's field: "
-                               "field-addr=%p, index=%d",
-                               packet_header, i);
-                       goto end;
-               }
-
-               if (stream_id == -1 && !strcmp(field_name, "stream_id")) {
-                       stream_id = i;
-               } else if (stream_instance_id == -1 &&
-                               !strcmp(field_name, "stream_instance_id")) {
-                       stream_instance_id = i;
-               }
-       }
-
-end:
-       trace_field_path_cache->stream_id = stream_id;
-       trace_field_path_cache->stream_instance_id = stream_instance_id;
-}
-
 BT_HIDDEN
-struct bt_notif_iter *bt_notif_iter_create(struct bt_trace *trace,
+struct bt_notif_iter *bt_notif_iter_create(struct ctf_trace_class *tc,
                size_t max_request_sz,
                struct bt_notif_iter_medium_ops medops, void *data)
 {
@@ -3007,33 +2448,29 @@ struct bt_notif_iter *bt_notif_iter_create(struct bt_trace *trace,
                },
                .query = {
                        .get_sequence_length = btr_get_sequence_length_cb,
-                       .borrow_variant_field_type = btr_borrow_variant_field_type_cb,
+                       .borrow_variant_selected_field_type = btr_borrow_variant_selected_field_type_cb,
                },
        };
 
-       BT_ASSERT(trace);
+       BT_ASSERT(tc);
        BT_ASSERT(medops.request_bytes);
        BT_ASSERT(medops.borrow_stream);
        BT_LOGD("Creating CTF plugin notification iterator: "
                "trace-addr=%p, trace-name=\"%s\", max-request-size=%zu, "
-               "data=%p",
-               trace, bt_trace_get_name(trace), max_request_sz, data);
+               "data=%p", tc, tc->name->str, max_request_sz, data);
        notit = g_new0(struct bt_notif_iter, 1);
        if (!notit) {
                BT_LOGE_STR("Failed to allocate one CTF plugin notification iterator.");
                goto end;
        }
-       notit->clock_states = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL, g_free);
-       if (!notit->clock_states) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               goto error;
-       }
-       notit->meta.trace = trace;
+       notit->meta.tc = tc;
        notit->medium.medops = medops;
        notit->medium.max_request_sz = max_request_sz;
        notit->medium.data = data;
        notit->stack = stack_new(notit);
+       notit->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t));
+       g_array_set_size(notit->stored_values, tc->stored_value_count);
+
        if (!notit->stack) {
                BT_LOGE_STR("Failed to create field stack.");
                goto error;
@@ -3046,25 +2483,10 @@ struct bt_notif_iter *bt_notif_iter_create(struct bt_trace *trace,
        }
 
        bt_notif_iter_reset(notit);
-       init_trace_field_path_cache(trace, &notit->trace_field_path_cache);
-       notit->sc_field_path_caches = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL, g_free);
-       if (!notit->sc_field_path_caches) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               goto error;
-       }
-
-       notit->field_overrides = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL, g_free);
-       if (!notit->field_overrides) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               goto error;
-       }
-
        BT_LOGD("Created CTF plugin notification iterator: "
                "trace-addr=%p, trace-name=\"%s\", max-request-size=%zu, "
                "data=%p, notit-addr=%p",
-               trace, bt_trace_get_name(trace), max_request_sz, data,
+               tc, tc->name->str, max_request_sz, data,
                notit);
        notit->cur_packet_offset = 0;
 
@@ -3080,7 +2502,6 @@ error:
 void bt_notif_iter_destroy(struct bt_notif_iter *notit)
 {
        BT_PUT(notit->packet);
-       BT_PUT(notit->prev_packet);
        BT_PUT(notit->stream);
        release_all_dscopes(notit);
 
@@ -3096,16 +2517,8 @@ void bt_notif_iter_destroy(struct bt_notif_iter *notit)
                bt_btr_destroy(notit->btr);
        }
 
-       if (notit->clock_states) {
-               g_hash_table_destroy(notit->clock_states);
-       }
-
-       if (notit->sc_field_path_caches) {
-               g_hash_table_destroy(notit->sc_field_path_caches);
-       }
-
-       if (notit->field_overrides) {
-               g_hash_table_destroy(notit->field_overrides);
+       if (notit->stored_values) {
+               g_array_free(notit->stored_values, TRUE);
        }
 
        g_free(notit);
@@ -3116,7 +2529,6 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                struct bt_private_connection_private_notification_iterator *notif_iter,
                struct bt_notification **notification)
 {
-       int ret;
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
 
        BT_ASSERT(notit);
@@ -3173,14 +2585,17 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                case STATE_EMIT_NOTIF_NEW_STREAM:
                        /* notify_new_stream() logs errors */
                        notify_new_stream(notit, notification);
+
                        if (!*notification) {
                                status = BT_NOTIF_ITER_STATUS_ERROR;
                        }
+
                        notit->stream_begin_emitted = true;
                        goto end;
                case STATE_EMIT_NOTIF_NEW_PACKET:
                        /* notify_new_packet() logs errors */
                        notify_new_packet(notit, notification);
+
                        if (!*notification) {
                                status = BT_NOTIF_ITER_STATUS_ERROR;
                        }
@@ -3188,32 +2603,14 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                        goto end;
                case STATE_EMIT_NOTIF_EVENT:
                        BT_ASSERT(notit->event_notif);
-                       ret = set_event_clocks(notit);
-                       if (ret) {
-                               status = BT_NOTIF_ITER_STATUS_ERROR;
-                               goto end;
-                       }
-
+                       set_event_default_clock_value(notit);
                        *notification = notit->event_notif;
                        notit->event_notif = NULL;
                        goto end;
                case STATE_EMIT_NOTIF_END_OF_PACKET:
-                       /* Update clock with timestamp_end field. */
-                       if (notit->cur_timestamp_end) {
-                               enum bt_btr_status btr_status;
-
-                               btr_status = update_clock(notit,
-                                       notit->cur_timestamp_end);
-                               if (btr_status != BT_BTR_STATUS_OK) {
-                                       BT_LOGW("Cannot update stream's clock value: "
-                                               "notit-addr=%p", notit);
-                                       status = BT_NOTIF_ITER_STATUS_ERROR;
-                                       goto end;
-                               }
-                       }
-
                        /* notify_end_of_packet() logs errors */
                        notify_end_of_packet(notit, notification);
+
                        if (!*notification) {
                                status = BT_NOTIF_ITER_STATUS_ERROR;
                        }
@@ -3338,8 +2735,7 @@ enum bt_notif_iter_status bt_notif_iter_seek(
        }
 
        medium_status = notit->medium.medops.seek(
-                       BT_NOTIF_ITER_SEEK_WHENCE_SET, offset,
-                       notit->medium.data);
+               BT_NOTIF_ITER_SEEK_WHENCE_SET, offset, notit->medium.data);
        if (medium_status != BT_NOTIF_ITER_MEDIUM_STATUS_OK) {
                if (medium_status == BT_NOTIF_ITER_MEDIUM_STATUS_EOF) {
                        ret = BT_NOTIF_ITER_STATUS_EOF;
@@ -3351,13 +2747,13 @@ enum bt_notif_iter_status bt_notif_iter_seek(
 
        bt_notif_iter_reset(notit);
        notit->cur_packet_offset = offset;
+
 end:
        return ret;
 }
 
 BT_HIDDEN
-off_t bt_notif_iter_get_current_packet_offset(
-               struct bt_notif_iter *notit)
+off_t bt_notif_iter_get_current_packet_offset(struct bt_notif_iter *notit)
 {
        BT_ASSERT(notit);
        return notit->cur_packet_offset;
@@ -3368,5 +2764,36 @@ off_t bt_notif_iter_get_current_packet_size(
                struct bt_notif_iter *notit)
 {
        BT_ASSERT(notit);
-       return notit->cur_packet_size;
+       return notit->cur_exp_packet_total_size;
+}
+
+BT_HIDDEN
+void bt_notif_trace_class_changed(struct bt_notif_iter *notit)
+{
+       if (notit->meta.tc->stored_value_count > notit->stored_values->len) {
+               g_array_set_size(notit->stored_values,
+                       notit->meta.tc->stored_value_count);
+       }
+}
+
+BT_HIDDEN
+enum bt_notif_iter_status bt_notif_iter_get_packet_properties(
+               struct bt_notif_iter *notit,
+               struct bt_notif_iter_packet_properties *props)
+{
+       BT_ASSERT(notit);
+       BT_ASSERT(props);
+
+       props->exp_packet_total_size =
+               (uint64_t) notit->cur_exp_packet_total_size;
+       props->exp_packet_content_size =
+               (uint64_t) notit->cur_exp_packet_content_size;
+       BT_ASSERT(props->stream_class_id >= 0);
+       props->stream_class_id = (uint64_t) notit->cur_stream_class_id;
+       props->data_stream_id = notit->cur_data_stream_id;
+       props->snapshots.discarded_events = notit->snapshots.discarded_events;
+       props->snapshots.packets = notit->snapshots.packets;
+       props->snapshots.beginning_clock = notit->snapshots.beginning_clock;
+       props->snapshots.end_clock = notit->snapshots.end_clock;
+       return BT_NOTIF_ITER_STATUS_OK;
 }
index fe6f7c54ce8aebfe21a36cff485db3e0b43154a5..a504da948d2dd56e1f1f92a45a5471b602474dcd 100644 (file)
@@ -32,6 +32,8 @@
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/babeltrace-internal.h>
 
+#include "../metadata/ctf-meta.h"
+
 /**
  * @file ctf-notif-iter.h
  *
@@ -228,38 +230,12 @@ struct bt_notif_iter_medium_ops {
         */
        struct bt_stream * (* borrow_stream)(
                        struct bt_stream_class *stream_class,
-                       uint64_t stream_id, void *data);
+                       int64_t stream_id, void *data);
 };
 
 /** CTF notification iterator. */
 struct bt_notif_iter;
 
-// TODO: Replace by the real thing
-enum bt_notif_iter_notif_type {
-       BT_NOTIF_ITER_NOTIF_NEW_PACKET,
-       BT_NOTIF_ITER_NOTIF_END_OF_PACKET,
-       BT_NOTIF_ITER_NOTIF_EVENT,
-};
-
-struct bt_notif_iter_notif {
-       enum bt_notif_iter_notif_type type;
-};
-
-struct bt_notif_iter_notif_new_packet {
-       struct bt_notif_iter_notif base;
-       struct bt_packet *packet;
-};
-
-struct bt_notif_iter_notif_end_of_packet {
-       struct bt_notif_iter_notif base;
-       struct bt_packet *packet;
-};
-
-struct bt_notif_iter_notif_event {
-       struct bt_notif_iter_notif base;
-       struct bt_event *event;
-};
-
 /**
  * Creates a CTF notification iterator.
  *
@@ -277,7 +253,7 @@ struct bt_notif_iter_notif_event {
  *                             success, or \c NULL on error
  */
 BT_HIDDEN
-struct bt_notif_iter *bt_notif_iter_create(struct bt_trace *trace,
+struct bt_notif_iter *bt_notif_iter_create(struct ctf_trace_class *tc,
        size_t max_request_sz, struct bt_notif_iter_medium_ops medops,
        void *medops_data);
 
@@ -332,6 +308,25 @@ enum bt_notif_iter_status bt_notif_iter_borrow_packet_header_context_fields(
                struct bt_field **packet_header_field,
                struct bt_field **packet_context_field);
 
+struct bt_notif_iter_packet_properties {
+       uint64_t exp_packet_total_size;
+       uint64_t exp_packet_content_size;
+       uint64_t stream_class_id;
+       int64_t data_stream_id;
+
+       struct {
+               uint64_t discarded_events;
+               uint64_t packets;
+               uint64_t beginning_clock;
+               uint64_t end_clock;
+       } snapshots;
+};
+
+BT_HIDDEN
+enum bt_notif_iter_status bt_notif_iter_get_packet_properties(
+               struct bt_notif_iter *notit,
+               struct bt_notif_iter_packet_properties *props);
+
 BT_HIDDEN
 void bt_notif_iter_set_medops_data(struct bt_notif_iter *notit,
                void *medops_data);
@@ -362,6 +357,13 @@ off_t bt_notif_iter_get_current_packet_size(
 BT_HIDDEN
 void bt_notif_iter_reset(struct bt_notif_iter *notit);
 
+/*
+ * Notify the iterator that the trace class changed somehow (new
+ * stream/event classes).
+ */
+BT_HIDDEN
+void bt_notif_trace_class_changed(struct bt_notif_iter *notit);
+
 static inline
 const char *bt_notif_iter_medium_status_string(
                enum bt_notif_iter_medium_status status)
index 10662a80c8881803cba65251d648645989fc42ec..dd65f9412fba87d18c157eaba611c5dbad1b8987 100644 (file)
 #include "logging.h"
 
 #include "utils.h"
-
-struct bt_stream_class *ctf_utils_borrow_stream_class_from_packet_header(
-               struct bt_trace *trace,
-               struct bt_field *packet_header_field)
-{
-       struct bt_field *stream_id_field = NULL;
-       struct bt_stream_class *stream_class = NULL;
-       uint64_t stream_id = -1ULL;
-       int ret;
-
-       if (!packet_header_field) {
-               goto single_stream_class;
-       }
-
-       stream_id_field = bt_field_structure_borrow_field_by_name(
-               packet_header_field, "stream_id");
-       if (!stream_id_field) {
-               goto single_stream_class;
-       }
-
-       ret = bt_field_integer_unsigned_get_value(stream_id_field,
-               &stream_id);
-       if (ret) {
-               stream_id = -1ULL;
-       }
-
-       if (stream_id == -1ULL) {
-single_stream_class:
-               /* Single stream class */
-               if (bt_trace_get_stream_class_count(trace) == 0) {
-                       goto end;
-               }
-
-               stream_class = bt_trace_borrow_stream_class_by_index(trace, 0);
-       } else {
-               stream_class = bt_trace_borrow_stream_class_by_id(trace,
-                       stream_id);
-       }
-
-end:
-       return stream_class;
-}
index 179c97bcb05338a705a18da947f11e1bb73bd23d..2d07ad2f326cc47383aed5f652ea57c3efcae255 100644 (file)
@@ -28,8 +28,4 @@
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/babeltrace-internal.h>
 
-struct bt_stream_class *ctf_utils_borrow_stream_class_from_packet_header(
-               struct bt_trace *trace,
-               struct bt_field *packet_header_field);
-
 #endif /* CTF_UTILS_H */
index 2af4d177173b63a8ea6683bb1e0ad7a6bb1d91b9..3657199044a4ae10c944074ad7c723d1e7d871b8 100644 (file)
@@ -174,7 +174,7 @@ end:
 
 static
 struct bt_stream *medop_borrow_stream(
-               struct bt_stream_class *stream_class, uint64_t stream_id,
+               struct bt_stream_class *stream_class, int64_t stream_id,
                void *data)
 {
        struct ctf_fs_ds_file *ds_file = data;
@@ -290,113 +290,11 @@ struct ctf_fs_ds_index_entry *ctf_fs_ds_index_add_new_entry(
                        index->entries->len - 1);
 }
 
-static
-struct bt_clock_class *borrow_field_mapped_clock_class(
-               struct bt_field *field)
-{
-       struct bt_field_type *field_type;
-       struct bt_clock_class *clock_class = NULL;
-
-       field_type = bt_field_borrow_type(field);
-       if (!field_type) {
-               goto end;
-       }
-
-       clock_class = bt_field_type_integer_borrow_mapped_clock_class(
-               field_type);
-       if (!clock_class) {
-               goto end;
-       }
-
-end:
-       return clock_class;
-}
-
-static
-int borrow_packet_bounds_from_packet_context(
-               struct bt_field *packet_context,
-               struct bt_clock_class **_timestamp_begin_cc,
-               struct bt_field **_timestamp_begin,
-               struct bt_clock_class **_timestamp_end_cc,
-               struct bt_field **_timestamp_end)
-{
-       int ret = 0;
-       struct bt_clock_class *timestamp_begin_cc = NULL;
-       struct bt_clock_class *timestamp_end_cc = NULL;
-       struct bt_field *timestamp_begin = NULL;
-       struct bt_field *timestamp_end = NULL;
-
-       timestamp_begin = bt_field_structure_borrow_field_by_name(
-                       packet_context, "timestamp_begin");
-       if (!timestamp_begin) {
-               BT_LOGD_STR("Cannot retrieve timestamp_begin field in packet context.");
-               ret = -1;
-               goto end;
-       }
-
-       timestamp_begin_cc = borrow_field_mapped_clock_class(timestamp_begin);
-       if (!timestamp_begin_cc) {
-               BT_LOGD_STR("Cannot retrieve the clock mapped to timestamp_begin.");
-       }
-
-       timestamp_end = bt_field_structure_borrow_field_by_name(
-                       packet_context, "timestamp_end");
-       if (!timestamp_end) {
-               BT_LOGD_STR("Cannot retrieve timestamp_end field in packet context.");
-               ret = -1;
-               goto end;
-       }
-
-       timestamp_end_cc = borrow_field_mapped_clock_class(timestamp_end);
-       if (!timestamp_end_cc) {
-               BT_LOGD_STR("Cannot retrieve the clock mapped to timestamp_end.");
-       }
-
-       if (_timestamp_begin_cc) {
-               *_timestamp_begin_cc = timestamp_begin_cc;
-       }
-       if (_timestamp_begin) {
-               *_timestamp_begin = timestamp_begin;
-       }
-       if (_timestamp_end_cc) {
-               *_timestamp_end_cc = timestamp_end_cc;
-       }
-       if (_timestamp_end) {
-               *_timestamp_end = timestamp_end;
-       }
-end:
-       return ret;
-}
-
-static
-int borrow_ds_file_packet_bounds_clock_classes(struct ctf_fs_ds_file *ds_file,
-               struct bt_clock_class **timestamp_begin_cc,
-               struct bt_clock_class **timestamp_end_cc)
-{
-       struct bt_field *packet_context = NULL;
-       int ret = ctf_fs_ds_file_borrow_packet_header_context_fields(ds_file,
-               NULL, &packet_context);
-
-       if (ret || !packet_context) {
-               BT_LOGD("Cannot retrieve packet context field: ds-file-path=\"%s\"",
-                       ds_file->file->path->str);
-               ret = -1;
-               goto end;
-       }
-
-       ret = borrow_packet_bounds_from_packet_context(packet_context,
-                       timestamp_begin_cc, NULL,
-                       timestamp_end_cc, NULL);
-
-end:
-       return ret;
-}
-
 static
 int convert_cycles_to_ns(struct bt_clock_class *clock_class,
                uint64_t cycles, int64_t *ns)
 {
-       return bt_clock_class_cycles_to_ns(clock_class, cycles, ns);
+       return bt_clock_class_cycles_to_ns_from_origin(clock_class, cycles, ns);
 }
 
 static
@@ -418,17 +316,27 @@ struct ctf_fs_ds_index *build_index_from_idx_file(
        size_t file_index_entry_size;
        size_t file_entry_count;
        size_t i;
-       struct bt_clock_class *timestamp_begin_cc = NULL;
-       struct bt_clock_class *timestamp_end_cc = NULL;
+       struct ctf_stream_class *sc;
+       struct bt_notif_iter_packet_properties props;
 
        BT_LOGD("Building index from .idx file of stream file %s",
                        ds_file->file->path->str);
 
-       ret = borrow_ds_file_packet_bounds_clock_classes(ds_file,
-                       &timestamp_begin_cc, &timestamp_end_cc);
+       ret = bt_notif_iter_borrow_packet_header_context_fields(
+               ds_file->notif_iter, NULL, NULL);
        if (ret) {
-               BT_LOGD_STR("Cannot get clock classes of \"timestamp_begin\" "
-                               "and \"timestamp_end\" fields");
+               BT_LOGD_STR("Cannot borrow first packet's header and context "
+                       "fields.");
+               goto error;
+       }
+
+       ret = bt_notif_iter_get_packet_properties(ds_file->notif_iter, &props);
+       BT_ASSERT(ret == 0);
+       sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
+               props.stream_class_id);
+       BT_ASSERT(sc);
+       if (!sc->default_clock_class) {
+               BT_LOGD_STR("Cannot find stream class's default clock class.");
                goto error;
        }
 
@@ -535,14 +443,14 @@ struct ctf_fs_ds_index *build_index_from_idx_file(
                }
 
                /* Convert the packet's bound to nanoseconds since Epoch. */
-               ret = convert_cycles_to_ns(timestamp_begin_cc,
+               ret = convert_cycles_to_ns(sc->default_clock_class,
                                index_entry->timestamp_begin,
                                &index_entry->timestamp_begin_ns);
                if (ret) {
                        BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch during index parsing");
                        goto error;
                }
-               ret = convert_cycles_to_ns(timestamp_end_cc,
+               ret = convert_cycles_to_ns(sc->default_clock_class,
                                index_entry->timestamp_end,
                                &index_entry->timestamp_end_ns);
                if (ret) {
@@ -581,52 +489,32 @@ error:
 
 static
 int init_index_entry(struct ctf_fs_ds_index_entry *entry,
-               struct bt_field *packet_context, off_t packet_size,
-               off_t packet_offset)
+               struct ctf_fs_ds_file *ds_file,
+               struct bt_notif_iter_packet_properties *props,
+               off_t packet_size, off_t packet_offset)
 {
        int ret;
-       struct bt_field *timestamp_begin = NULL;
-       struct bt_field *timestamp_end = NULL;
-       struct bt_clock_class *timestamp_begin_cc = NULL;
-       struct bt_clock_class *timestamp_end_cc = NULL;
-
-       ret = borrow_packet_bounds_from_packet_context(packet_context,
-                       &timestamp_begin_cc, &timestamp_begin,
-                       &timestamp_end_cc, &timestamp_end);
-       if (ret || !timestamp_begin_cc || !timestamp_begin ||
-                       !timestamp_end_cc || ! timestamp_end) {
-               BT_LOGD_STR("Failed to determine time bound fields of packet.");
-               goto end;
-       }
+       struct ctf_stream_class *sc;
 
+       sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
+               props->stream_class_id);
+       BT_ASSERT(sc);
        BT_ASSERT(packet_offset >= 0);
        entry->offset = packet_offset;
-
        BT_ASSERT(packet_size >= 0);
        entry->packet_size = packet_size;
 
-       ret = bt_field_integer_unsigned_get_value(timestamp_begin,
-                       &entry->timestamp_begin);
-       if (ret) {
-               goto end;
-       }
-       ret = bt_field_integer_unsigned_get_value(timestamp_end,
-                       &entry->timestamp_end);
-       if (ret) {
-               goto end;
-       }
-
        /* Convert the packet's bound to nanoseconds since Epoch. */
-       ret = convert_cycles_to_ns(timestamp_begin_cc,
-                                  entry->timestamp_begin,
+       ret = convert_cycles_to_ns(sc->default_clock_class,
+                                  props->snapshots.beginning_clock,
                                   &entry->timestamp_begin_ns);
        if (ret) {
                BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
                goto end;
        }
 
-       ret = convert_cycles_to_ns(timestamp_end_cc,
-                                  entry->timestamp_end,
+       ret = convert_cycles_to_ns(sc->default_clock_class,
+                                  props->snapshots.end_clock,
                                   &entry->timestamp_end_ns);
        if (ret) {
                BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
@@ -655,12 +543,12 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
        do {
                off_t current_packet_offset;
                off_t next_packet_offset;
-               off_t current_packet_size, current_packet_size_bytes;
+               off_t current_packet_size_bytes;
                struct ctf_fs_ds_index_entry *entry;
-               struct bt_field *packet_context = NULL;
+               struct bt_notif_iter_packet_properties props;
 
                iter_status = bt_notif_iter_borrow_packet_header_context_fields(
-                       ds_file->notif_iter, NULL, &packet_context);
+                       ds_file->notif_iter, NULL, NULL);
                if (iter_status != BT_NOTIF_ITER_STATUS_OK) {
                        if (iter_status == BT_NOTIF_ITER_STATUS_EOF) {
                                break;
@@ -668,6 +556,10 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
                        goto error;
                }
 
+               ret = bt_notif_iter_get_packet_properties(ds_file->notif_iter,
+                       &props);
+               BT_ASSERT(ret == 0);
+
                current_packet_offset =
                        bt_notif_iter_get_current_packet_offset(
                                ds_file->notif_iter);
@@ -676,15 +568,8 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
                        goto error;
                }
 
-               current_packet_size = bt_notif_iter_get_current_packet_size(
-                       ds_file->notif_iter);
-               if (current_packet_size < 0) {
-                       BT_LOGE("Cannot get packet size: packet-offset=%jd",
-                                       current_packet_offset);
-                       goto error;
-               }
                current_packet_size_bytes =
-                       ((current_packet_size + 7) & ~7) / CHAR_BIT;
+                       ((props.exp_packet_total_size + 7) & ~7) / CHAR_BIT;
 
                if (current_packet_offset + current_packet_size_bytes >
                                ds_file->file->size) {
@@ -710,9 +595,8 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
                        goto error;
                }
 
-               ret = init_index_entry(entry, packet_context,
-                       current_packet_size_bytes,
-                       current_packet_offset);
+               ret = init_index_entry(entry, ds_file, &props,
+                       current_packet_size_bytes, current_packet_offset);
                if (ret) {
                        goto error;
                }
@@ -756,7 +640,7 @@ struct ctf_fs_ds_file *ctf_fs_ds_file_create(
        }
 
        ds_file->stream = bt_get(stream);
-       ds_file->cc_prio_map = bt_get(ctf_fs_trace->cc_prio_map);
+       ds_file->metadata = ctf_fs_trace->metadata;
        g_string_assign(ds_file->file->path, path);
        ret = ctf_fs_file_open(ds_file->file, "rb");
        if (ret) {
@@ -849,7 +733,6 @@ enum bt_notification_iterator_status ctf_fs_ds_file_next(
                status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
                break;
        }
-
        return status;
 }
 
index 13c6e8409bc504af3281f4b360c15c3d8f3bdbef..075b8293ab7ca59a3469ace1c9f2cf96d640b6a6 100644 (file)
@@ -81,10 +81,15 @@ struct ctf_fs_ds_file_info {
        GString *path;
 
        /* Guaranteed to be set, as opposed to the index. */
-       uint64_t begin_ns;
+       int64_t begin_ns;
 };
 
+struct ctf_fs_metadata;
+
 struct ctf_fs_ds_file {
+       /* Weak */
+       struct ctf_fs_metadata *metadata;
+
        /* Weak */
        struct bt_private_connection_private_notification_iterator *pc_notif_iter;
 
index 59a7bcab592000f46a80bc3b0b09a9cbdf772286..fa341ea1e02b6e8a10f32614240f62dbcd8a21c5 100644 (file)
@@ -258,7 +258,7 @@ enum bt_notification_iterator_status ctf_fs_iterator_init(
 
        notif_iter_data->pc_notif_iter = it;
        notif_iter_data->notif_iter = bt_notif_iter_create(
-               port_data->ds_file_group->ctf_fs_trace->metadata->trace,
+               port_data->ds_file_group->ctf_fs_trace->metadata->tc,
                bt_common_get_page_size() * 8,
                ctf_fs_ds_file_medops, NULL);
        if (!notif_iter_data->notif_iter) {
@@ -332,7 +332,6 @@ void ctf_fs_trace_destroy(struct ctf_fs_trace *ctf_fs_trace)
                g_free(ctf_fs_trace->metadata);
        }
 
-       bt_put(ctf_fs_trace->cc_prio_map);
        g_free(ctf_fs_trace);
 }
 
@@ -456,83 +455,6 @@ end:
        return ret;
 }
 
-static
-uint64_t get_packet_header_stream_instance_id(struct ctf_fs_trace *ctf_fs_trace,
-               struct bt_field *packet_header_field)
-{
-       struct bt_field *stream_instance_id_field = NULL;
-       uint64_t stream_instance_id = -1ULL;
-       int ret;
-
-       if (!packet_header_field) {
-               goto end;
-       }
-
-       stream_instance_id_field = bt_field_structure_borrow_field_by_name(
-               packet_header_field, "stream_instance_id");
-       if (!stream_instance_id_field) {
-               goto end;
-       }
-
-       ret = bt_field_integer_unsigned_get_value(stream_instance_id_field,
-               &stream_instance_id);
-       if (ret) {
-               stream_instance_id = -1ULL;
-               goto end;
-       }
-
-end:
-       return stream_instance_id;
-}
-
-uint64_t get_packet_context_timestamp_begin_ns(
-               struct ctf_fs_trace *ctf_fs_trace,
-               struct bt_field *packet_context_field)
-{
-       int ret;
-       struct bt_field *timestamp_begin_field = NULL;
-       struct bt_field_type *timestamp_begin_ft = NULL;
-       uint64_t timestamp_begin_raw_value = -1ULL;
-       uint64_t timestamp_begin_ns = -1ULL;
-       int64_t timestamp_begin_ns_signed;
-       struct bt_clock_class *timestamp_begin_clock_class = NULL;
-
-       if (!packet_context_field) {
-               goto end;
-       }
-
-       timestamp_begin_field = bt_field_structure_borrow_field_by_name(
-               packet_context_field, "timestamp_begin");
-       if (!timestamp_begin_field) {
-               goto end;
-       }
-
-       timestamp_begin_ft = bt_field_borrow_type(timestamp_begin_field);
-       BT_ASSERT(timestamp_begin_ft);
-       timestamp_begin_clock_class =
-               bt_field_type_integer_borrow_mapped_clock_class(timestamp_begin_ft);
-       if (!timestamp_begin_clock_class) {
-               goto end;
-       }
-
-       ret = bt_field_integer_unsigned_get_value(timestamp_begin_field,
-               &timestamp_begin_raw_value);
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_clock_class_cycles_to_ns(timestamp_begin_clock_class,
-               timestamp_begin_raw_value, &timestamp_begin_ns_signed);
-       if (ret) {
-               goto end;
-       }
-
-       timestamp_begin_ns = (uint64_t) timestamp_begin_ns_signed;
-
-end:
-       return timestamp_begin_ns;
-}
-
 static
 void ctf_fs_ds_file_info_destroy(struct ctf_fs_ds_file_info *ds_file_info)
 {
@@ -550,7 +472,7 @@ void ctf_fs_ds_file_info_destroy(struct ctf_fs_ds_file_info *ds_file_info)
 
 static
 struct ctf_fs_ds_file_info *ctf_fs_ds_file_info_create(const char *path,
-               uint64_t begin_ns, struct ctf_fs_ds_index *index)
+               int64_t begin_ns, struct ctf_fs_ds_index *index)
 {
        struct ctf_fs_ds_file_info *ds_file_info;
 
@@ -647,7 +569,7 @@ void array_insert(GPtrArray *array, gpointer element, size_t pos)
 static
 int ctf_fs_ds_file_group_add_ds_file_info(
                struct ctf_fs_ds_file_group *ds_file_group,
-               const char *path, uint64_t begin_ns,
+               const char *path, int64_t begin_ns,
                struct ctf_fs_ds_index *index)
 {
        struct ctf_fs_ds_file_info *ds_file_info;
@@ -687,11 +609,9 @@ static
 int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
                struct bt_graph *graph, const char *path)
 {
-       struct bt_field *packet_header_field = NULL;
-       struct bt_field *packet_context_field = NULL;
        struct bt_stream_class *stream_class = NULL;
-       uint64_t stream_instance_id = -1ULL;
-       uint64_t begin_ns = -1ULL;
+       int64_t stream_instance_id = -1;
+       int64_t begin_ns = -1;
        struct ctf_fs_ds_file_group *ds_file_group = NULL;
        bool add_group = false;
        int ret;
@@ -699,8 +619,10 @@ int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
        struct ctf_fs_ds_file *ds_file = NULL;
        struct ctf_fs_ds_index *index = NULL;
        struct bt_notif_iter *notif_iter = NULL;
+       struct ctf_stream_class *sc = NULL;
+       struct bt_notif_iter_packet_properties props;
 
-       notif_iter = bt_notif_iter_create(ctf_fs_trace->metadata->trace,
+       notif_iter = bt_notif_iter_create(ctf_fs_trace->metadata->tc,
                bt_common_get_page_size() * 8, ctf_fs_ds_file_medops, NULL);
        if (!notif_iter) {
                BT_LOGE_STR("Cannot create a CTF notification iterator.");
@@ -714,21 +636,32 @@ int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
        }
 
        ret = ctf_fs_ds_file_borrow_packet_header_context_fields(ds_file,
-               &packet_header_field, &packet_context_field);
+               NULL, NULL);
        if (ret) {
                BT_LOGE("Cannot get stream file's first packet's header and context fields (`%s`).",
                        path);
                goto error;
        }
 
-       stream_instance_id = get_packet_header_stream_instance_id(ctf_fs_trace,
-               packet_header_field);
-       begin_ns = get_packet_context_timestamp_begin_ns(ctf_fs_trace,
-               packet_context_field);
-       stream_class = ctf_utils_borrow_stream_class_from_packet_header(
-               ctf_fs_trace->metadata->trace, packet_header_field);
-       if (!stream_class) {
-               goto error;
+       ret = bt_notif_iter_get_packet_properties(ds_file->notif_iter, &props);
+       BT_ASSERT(ret == 0);
+       sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
+               props.stream_class_id);
+       BT_ASSERT(sc);
+       stream_class = sc->ir_sc;
+       BT_ASSERT(stream_class);
+       stream_instance_id = props.data_stream_id;
+
+       if (props.snapshots.beginning_clock != UINT64_C(-1)) {
+               BT_ASSERT(sc->default_clock_class);
+               ret = bt_clock_class_cycles_to_ns_from_origin(
+                       sc->default_clock_class,
+                       props.snapshots.beginning_clock, &begin_ns);
+               if (ret) {
+                       BT_LOGE("Cannot convert clock cycles to nanoseconds from origin (`%s`).",
+                               path);
+                       goto error;
+               }
        }
 
        index = ctf_fs_ds_file_build_index(ds_file);
@@ -737,16 +670,16 @@ int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
                        ds_file->file->path->str);
        }
 
-       if (begin_ns == -1ULL) {
+       if (begin_ns == -1) {
                /*
                 * No beggining timestamp to sort the stream files
                 * within a stream file group, so consider that this
                 * file must be the only one within its group.
                 */
-               stream_instance_id = -1ULL;
+               stream_instance_id = -1;
        }
 
-       if (stream_instance_id == -1ULL) {
+       if (stream_instance_id == -1) {
                /*
                 * No stream instance ID or no beginning timestamp:
                 * create a unique stream file group for this stream
@@ -772,8 +705,8 @@ int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
                goto end;
        }
 
-       BT_ASSERT(stream_instance_id != -1ULL);
-       BT_ASSERT(begin_ns != -1ULL);
+       BT_ASSERT(stream_instance_id != -1);
+       BT_ASSERT(begin_ns != -1);
 
        /* Find an existing stream file group with this ID */
        for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
@@ -922,27 +855,37 @@ int create_ds_file_groups(struct ctf_fs_trace *ctf_fs_trace,
                        goto error;
                }
 
-               if (ds_file_group->stream_id == -1ULL) {
+               if (ds_file_group->stream_id == UINT64_C(-1)) {
                        /* No stream ID: use 0 */
-                       ds_file_group->stream = bt_stream_create(
-                               ds_file_group->stream_class, name->str,
+                       ds_file_group->stream = bt_stream_create_with_id(
+                               ds_file_group->stream_class,
                                ctf_fs_trace->next_stream_id);
                        ctf_fs_trace->next_stream_id++;
                } else {
                        /* Specific stream ID */
-                       ds_file_group->stream = bt_stream_create(
-                               ds_file_group->stream_class, name->str,
-                               ds_file_group->stream_id);
+                       ds_file_group->stream = bt_stream_create_with_id(
+                               ds_file_group->stream_class,
+                               (uint64_t) ds_file_group->stream_id);
                }
 
-               g_string_free(name, TRUE);
-
                if (!ds_file_group->stream) {
                        BT_LOGE("Cannot create stream for DS file group: "
                                "addr=%p, stream-name=\"%s\"",
                                ds_file_group, name->str);
+                       g_string_free(name, TRUE);
+                       goto error;
+               }
+
+               ret = bt_stream_set_name(ds_file_group->stream, name->str);
+               if (ret) {
+                       BT_LOGE("Cannot set stream's name: "
+                               "addr=%p, stream-name=\"%s\"",
+                               ds_file_group->stream, name->str);
+                       g_string_free(name, TRUE);
                        goto error;
                }
+
+               g_string_free(name, TRUE);
        }
 
        goto end;
@@ -991,6 +934,7 @@ struct ctf_fs_trace *ctf_fs_trace_create(const char *path, const char *name,
                goto error;
        }
 
+       ctf_fs_metadata_init(ctf_fs_trace->metadata);
        ctf_fs_trace->ds_file_groups = g_ptr_array_new_with_free_func(
                (GDestroyNotify) ctf_fs_ds_file_group_destroy);
        if (!ctf_fs_trace->ds_file_groups) {
@@ -1012,13 +956,14 @@ struct ctf_fs_trace *ctf_fs_trace_create(const char *path, const char *name,
         * trace needs. There won't be any more. Therefore it is safe to
         * make this trace static.
         */
-       (void) bt_trace_set_is_static(ctf_fs_trace->metadata->trace);
+       (void) bt_trace_make_static(ctf_fs_trace->metadata->trace);
 
        goto end;
 
 error:
        ctf_fs_trace_destroy(ctf_fs_trace);
        ctf_fs_trace = NULL;
+
 end:
        return ctf_fs_trace;
 }
index 101d427e704a11bc233e2ad4a74604b283361013..c72be5e03dd3000b065ef1521384be843d7a5cfc 100644 (file)
@@ -33,6 +33,7 @@
 #include <babeltrace/babeltrace.h>
 #include "data-stream-file.h"
 #include "metadata.h"
+#include "../common/metadata/decoder.h"
 
 BT_HIDDEN
 extern bool ctf_fs_debug;
@@ -48,9 +49,17 @@ struct ctf_fs_file {
 };
 
 struct ctf_fs_metadata {
+       /* Owned by this */
+       struct ctf_metadata_decoder *decoder;
+
        /* Owned by this */
        struct bt_trace *trace;
 
+       /* Weak (owned by `decoder` above) */
+       struct ctf_trace_class *tc;
+
+       /* Owned by this */
+
        /* Owned by this */
        char *text;
 
@@ -76,9 +85,6 @@ struct ctf_fs_trace {
        /* Owned by this */
        struct ctf_fs_metadata *metadata;
 
-       /* Owned by this */
-       struct bt_clock_class_priority_map *cc_prio_map;
-
        /* Array of struct ctf_fs_ds_file_group *, owned by this */
        GPtrArray *ds_file_groups;
 
index 619e75a02380dc27812cad89cc123d598cab4037..e949374d6320dbfa2005961ae111eaa32df05c2f 100644 (file)
@@ -91,7 +91,6 @@ int ctf_fs_metadata_set_trace(struct ctf_fs_trace *ctf_fs_trace,
 {
        int ret = 0;
        struct ctf_fs_file *file = NULL;
-       struct ctf_metadata_decoder *metadata_decoder = NULL;
        struct ctf_metadata_decoder_config decoder_config = {
                .clock_class_offset_s = config ? config->clock_class_offset_s : 0,
                .clock_class_offset_ns = config ? config->clock_class_offset_ns : 0,
@@ -104,28 +103,32 @@ int ctf_fs_metadata_set_trace(struct ctf_fs_trace *ctf_fs_trace,
                goto end;
        }
 
-       metadata_decoder = ctf_metadata_decoder_create(
+       ctf_fs_trace->metadata->decoder = ctf_metadata_decoder_create(
                config ? &decoder_config : NULL,
                ctf_fs_trace->name->str);
-       if (!metadata_decoder) {
+       if (!ctf_fs_trace->metadata->decoder) {
                BT_LOGE("Cannot create metadata decoder object");
                ret = -1;
                goto end;
        }
 
-       ret = ctf_metadata_decoder_decode(metadata_decoder, file->fp);
+       ret = ctf_metadata_decoder_decode(ctf_fs_trace->metadata->decoder,
+               file->fp);
        if (ret) {
                BT_LOGE("Cannot decode metadata file");
                goto end;
        }
 
-       ctf_fs_trace->metadata->trace = ctf_metadata_decoder_get_trace(
-               metadata_decoder);
+       ctf_fs_trace->metadata->trace = ctf_metadata_decoder_get_ir_trace(
+               ctf_fs_trace->metadata->decoder);
        BT_ASSERT(ctf_fs_trace->metadata->trace);
+       ctf_fs_trace->metadata->tc =
+               ctf_metadata_decoder_borrow_ctf_trace_class(
+                       ctf_fs_trace->metadata->decoder);
+       BT_ASSERT(ctf_fs_trace->metadata->tc);
 
 end:
        ctf_fs_file_destroy(file);
-       ctf_metadata_decoder_destroy(metadata_decoder);
        return ret;
 }
 
@@ -144,4 +147,8 @@ void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata)
        if (metadata->trace) {
                BT_PUT(metadata->trace);
        }
+
+       if (metadata->decoder) {
+               ctf_metadata_decoder_destroy(metadata->decoder);
+       }
 }
index ba5546af9a7e97dcfe5a7e27da984eff591616f8..86dec73633d1fcf08c6c2281d1d30663ae1e0b44 100644 (file)
@@ -76,94 +76,6 @@ struct dmesg_component {
        struct bt_clock_class_priority_map *cc_prio_map;
 };
 
-static
-struct bt_field_type *create_packet_header_ft(void)
-{
-       struct bt_field_type *root_ft = NULL;
-       struct bt_field_type *ft = NULL;
-       int ret;
-
-       root_ft = bt_field_type_structure_create();
-       if (!root_ft) {
-               BT_LOGE_STR("Cannot create an empty structure field type object.");
-               goto error;
-       }
-
-       ft = bt_field_type_integer_create(32);
-       if (!ft) {
-               BT_LOGE_STR("Cannot create an integer field type object.");
-               goto error;
-       }
-
-       ret = bt_field_type_structure_add_field(root_ft, ft, "magic");
-       if (ret) {
-               BT_LOGE("Cannot add `magic` field type to structure field type: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       BT_PUT(ft);
-       ft = bt_field_type_integer_create(8);
-       if (!ft) {
-               BT_LOGE_STR("Cannot create an integer field type object.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_PUT(root_ft);
-
-end:
-       bt_put(ft);
-       return root_ft;
-}
-
-static
-struct bt_field_type *create_event_header_ft(
-               struct bt_clock_class *clock_class)
-{
-       struct bt_field_type *root_ft = NULL;
-       struct bt_field_type *ft = NULL;
-       int ret;
-
-       root_ft = bt_field_type_structure_create();
-       if (!root_ft) {
-               BT_LOGE_STR("Cannot create an empty structure field type object.");
-               goto error;
-       }
-
-       ft = bt_field_type_integer_create(64);
-       if (!ft) {
-               BT_LOGE_STR("Cannot create an integer field type object.");
-               goto error;
-       }
-
-       ret = bt_field_type_integer_set_mapped_clock_class(ft, clock_class);
-       if (ret) {
-               BT_LOGE("Cannot map integer field type to clock class: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       ret = bt_field_type_structure_add_field(root_ft,
-               ft, "timestamp");
-       if (ret) {
-               BT_LOGE("Cannot add `timestamp` field type to structure field type: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_PUT(root_ft);
-
-end:
-       bt_put(ft);
-       return root_ft;
-}
-
 static
 struct bt_field_type *create_event_payload_ft(void)
 {
@@ -183,10 +95,9 @@ struct bt_field_type *create_event_payload_ft(void)
                goto error;
        }
 
-       ret = bt_field_type_structure_add_field(root_ft,
-               ft, "str");
+       ret = bt_field_type_structure_append_member(root_ft, "str", ft);
        if (ret) {
-               BT_LOGE("Cannot add `str` field type to structure field type: "
+               BT_LOGE("Cannot add `str` member to structure field type: "
                        "ret=%d", ret);
                goto error;
        }
@@ -201,12 +112,6 @@ end:
        return root_ft;
 }
 
-static
-struct bt_clock_class *create_clock_class(void)
-{
-       return bt_clock_class_create("the_clock", 1000000000);
-}
-
 static
 int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
 {
@@ -221,18 +126,6 @@ int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
                goto error;
        }
 
-       ft = create_packet_header_ft();
-       if (!ft) {
-               BT_LOGE_STR("Cannot create packet header field type.");
-               goto error;
-       }
-
-       ret = bt_trace_set_packet_header_field_type(dmesg_comp->trace, ft);
-       if (ret) {
-               BT_LOGE_STR("Cannot set trace's packet header field type.");
-               goto error;
-       }
-
        if (dmesg_comp->params.read_from_stdin) {
                trace_name = "STDIN";
        } else {
@@ -253,48 +146,40 @@ int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
                }
        }
 
-       dmesg_comp->stream_class = bt_stream_class_create(NULL);
+       dmesg_comp->stream_class = bt_stream_class_create(dmesg_comp->trace);
        if (!dmesg_comp->stream_class) {
-               BT_LOGE_STR("Cannot create an empty stream class object.");
+               BT_LOGE_STR("Cannot create a stream class object.");
                goto error;
        }
 
        if (has_ts) {
-               dmesg_comp->clock_class = create_clock_class();
+               dmesg_comp->clock_class = bt_clock_class_create();
                if (!dmesg_comp->clock_class) {
                        BT_LOGE_STR("Cannot create clock class.");
                        goto error;
                }
 
-               ret = bt_trace_add_clock_class(dmesg_comp->trace,
-                       dmesg_comp->clock_class);
-               if (ret) {
-                       BT_LOGE_STR("Cannot add clock class to trace.");
-                       goto error;
-               }
-
-               bt_put(ft);
-               ft = create_event_header_ft(dmesg_comp->clock_class);
-               if (!ft) {
-                       BT_LOGE_STR("Cannot create event header field type.");
-                       goto error;
-               }
-
-               ret = bt_stream_class_set_event_header_field_type(
-                       dmesg_comp->stream_class, ft);
+               ret = bt_stream_class_set_default_clock_class(
+                       dmesg_comp->stream_class, dmesg_comp->clock_class);
                if (ret) {
-                       BT_LOGE_STR("Cannot set stream class's event header field type.");
+                       BT_LOGE_STR("Cannot set stream class's default clock class.");
                        goto error;
                }
        }
 
-       dmesg_comp->event_class = bt_event_class_create("string");
+       dmesg_comp->event_class = bt_event_class_create(
+               dmesg_comp->stream_class);
        if (!dmesg_comp->event_class) {
-               BT_LOGE_STR("Cannot create an empty event class object.");
+               BT_LOGE_STR("Cannot create an event class object.");
+               goto error;
+       }
+
+       ret = bt_event_class_set_name(dmesg_comp->event_class, "string");
+       if (ret) {
+               BT_LOGE_STR("Cannot set event class's name.");
                goto error;
        }
 
-       bt_put(ft);
        ft = create_event_payload_ft();
        if (!ft) {
                BT_LOGE_STR("Cannot create event payload field type.");
@@ -307,20 +192,6 @@ int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
                goto error;
        }
 
-       ret = bt_stream_class_add_event_class(dmesg_comp->stream_class,
-               dmesg_comp->event_class);
-       if (ret) {
-               BT_LOGE("Cannot add event class to stream class: ret=%d", ret);
-               goto error;
-       }
-
-       ret = bt_trace_add_stream_class(dmesg_comp->trace,
-               dmesg_comp->stream_class);
-       if (ret) {
-               BT_LOGE("Cannot add event class to stream class: ret=%d", ret);
-               goto error;
-       }
-
        goto end;
 
 error:
@@ -394,58 +265,24 @@ end:
        return ret;
 }
 
-static
-int fill_packet_header_field(struct bt_packet *packet)
-{
-       struct bt_field *ph = NULL;
-       struct bt_field *magic = NULL;
-       int ret;
-
-       ph = bt_packet_borrow_header(packet);
-       BT_ASSERT(ph);
-       magic = bt_field_structure_borrow_field_by_name(ph, "magic");
-       if (!magic) {
-               BT_LOGE_STR("Cannot borrow `magic` field from structure field.");
-               goto error;
-       }
-
-       ret = bt_field_integer_unsigned_set_value(magic, 0xc1fc1fc1);
-       BT_ASSERT(ret == 0);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
 static
 int create_packet_and_stream(struct dmesg_component *dmesg_comp)
 {
        int ret = 0;
 
-       dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class,
-               NULL, 0);
+       dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class);
        if (!dmesg_comp->stream) {
                BT_LOGE_STR("Cannot create stream object.");
                goto error;
        }
 
-       dmesg_comp->packet = bt_packet_create(dmesg_comp->stream,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
+       dmesg_comp->packet = bt_packet_create(dmesg_comp->stream);
        if (!dmesg_comp->packet) {
                BT_LOGE_STR("Cannot create packet object.");
                goto error;
        }
 
-       ret = fill_packet_header_field(dmesg_comp->packet);
-       if (ret) {
-               BT_LOGE_STR("Cannot fill packet header field.");
-               goto error;
-       }
-
-       ret = bt_trace_set_is_static(dmesg_comp->trace);
+       ret = bt_trace_make_static(dmesg_comp->trace);
        if (ret) {
                BT_LOGE_STR("Cannot make trace static.");
                goto error;
@@ -595,8 +432,6 @@ struct bt_notification *create_init_event_notif_from_line(
        unsigned long sec, usec, msec;
        unsigned int year, mon, mday, hour, min;
        uint64_t ts = 0;
-       struct bt_field *eh_field = NULL;
-       struct bt_field *ts_field = NULL;
        int ret = 0;
        struct dmesg_component *dmesg_comp = notif_iter->dmesg_comp;
 
@@ -673,19 +508,7 @@ skip_ts:
        BT_ASSERT(event);
 
        if (dmesg_comp->clock_class) {
-               ret = bt_event_set_clock_value(event,
-                       dmesg_comp->clock_class, ts, BT_TRUE);
-               BT_ASSERT(ret == 0);
-               eh_field = bt_event_borrow_header(event);
-               BT_ASSERT(eh_field);
-               ts_field = bt_field_structure_borrow_field_by_name(eh_field,
-                       "timestamp");
-               if (!ts_field) {
-                       BT_LOGE_STR("Cannot borrow `timestamp` field from event header structure field.");
-                       goto error;
-               }
-
-               ret = bt_field_integer_unsigned_set_value(ts_field, ts);
+               ret = bt_event_set_default_clock_value(event, ts);
                BT_ASSERT(ret == 0);
        }
 
@@ -706,9 +529,10 @@ int fill_event_payload_from_line(const char *line, struct bt_event *event)
        size_t len;
        int ret;
 
-       ep_field = bt_event_borrow_payload(event);
+       ep_field = bt_event_borrow_payload_field(event);
        BT_ASSERT(ep_field);
-       str_field = bt_field_structure_borrow_field_by_name(ep_field, "str");
+       str_field = bt_field_structure_borrow_member_field_by_index(ep_field,
+               0);
        if (!str_field) {
                BT_LOGE_STR("Cannot borrow `timestamp` field from event payload structure field.");
                goto error;
@@ -726,7 +550,7 @@ int fill_event_payload_from_line(const char *line, struct bt_event *event)
                goto error;
        }
 
-       ret = bt_field_string_append_len(str_field, line, len);
+       ret = bt_field_string_append_with_length(str_field, line, len);
        if (ret) {
                BT_LOGE("Cannot append value to string field object: "
                        "len=%zu", len);
index c5f57ae3a62dc45d9416fb2128f6b32d5ec9f34a..a4ace53420145cfe112b253178a32e53e0c7fac5 100644 (file)
@@ -84,23 +84,17 @@ static
 void print_timestamp_cycles(struct pretty_component *pretty,
                struct bt_event *event)
 {
-       int ret;
        struct bt_clock_value *clock_value;
        uint64_t cycles;
+       enum bt_clock_value_status cv_status;
 
-       clock_value = bt_event_borrow_default_clock_value(event);
-       if (!clock_value) {
+       cv_status = bt_event_borrow_default_clock_value(event, &clock_value);
+       if (cv_status != BT_CLOCK_VALUE_STATUS_KNOWN || !clock_value) {
                g_string_append(pretty->string, "????????????????????");
                return;
        }
 
-       ret = bt_clock_value_get_value(clock_value, &cycles);
-       if (ret) {
-               // TODO: log, this is unexpected
-               g_string_append(pretty->string, "Error");
-               return;
-       }
-
+       cycles = bt_clock_value_get_value(clock_value);
        g_string_append_printf(pretty->string, "%020" PRIu64, cycles);
 
        if (pretty->last_cycles_timestamp != -1ULL) {
@@ -124,7 +118,7 @@ void print_timestamp_wall(struct pretty_component *pretty,
                return;
        }
 
-       ret = bt_clock_value_get_value_ns_from_epoch(clock_value, &ts_nsec);
+       ret = bt_clock_value_get_ns_from_origin(clock_value, &ts_nsec);
        if (ret) {
                // TODO: log, this is unexpected
                g_string_append(pretty->string, "Error");
@@ -234,6 +228,7 @@ enum bt_component_status print_event_timestamp(struct pretty_component *pretty,
        struct bt_stream_class *stream_class = NULL;
        struct bt_trace *trace = NULL;
        struct bt_clock_value *clock_value = NULL;
+       enum bt_clock_value_status cv_status;
 
        stream = bt_event_borrow_stream(event);
        if (!stream) {
@@ -252,8 +247,8 @@ enum bt_component_status print_event_timestamp(struct pretty_component *pretty,
                goto end;
        }
 
-       clock_value = bt_event_borrow_default_clock_value(event);
-       if (!clock_value) {
+       cv_status = bt_event_borrow_default_clock_value(event, &clock_value);
+       if (cv_status != BT_CLOCK_VALUE_STATUS_KNOWN || !clock_value) {
                /* No default clock value: skip the timestamp without an error */
                goto end;
        }
@@ -269,9 +264,9 @@ enum bt_component_status print_event_timestamp(struct pretty_component *pretty,
        if (pretty->options.print_timestamp_cycles) {
                print_timestamp_cycles(pretty, event);
        } else {
-               struct bt_clock_value *clock_value =
-                       bt_event_borrow_default_clock_value(event);
-
+               clock_value = NULL;
+               cv_status = bt_event_borrow_default_clock_value(event,
+                       &clock_value);
                print_timestamp_wall(pretty, clock_value);
        }
        if (pretty->use_colors) {
@@ -330,6 +325,7 @@ enum bt_component_status print_event_header(struct pretty_component *pretty,
        struct bt_stream_class *stream_class = NULL;
        struct bt_trace *trace_class = NULL;
        int dom_print = 0;
+       enum bt_property_availability prop_avail;
 
        event_class = bt_event_borrow_class(event);
        if (!event_class) {
@@ -372,7 +368,7 @@ enum bt_component_status print_event_header(struct pretty_component *pretty,
        if (pretty->options.print_trace_hostname_field) {
                struct bt_value *hostname_str;
 
-               hostname_str = bt_trace_borrow_environment_field_value_by_name(
+               hostname_str = bt_trace_borrow_environment_entry_value_by_name(
                        trace_class, "hostname");
                if (hostname_str) {
                        const char *str;
@@ -393,7 +389,7 @@ enum bt_component_status print_event_header(struct pretty_component *pretty,
        if (pretty->options.print_trace_domain_field) {
                struct bt_value *domain_str;
 
-               domain_str = bt_trace_borrow_environment_field_value_by_name(
+               domain_str = bt_trace_borrow_environment_entry_value_by_name(
                        trace_class, "domain");
                if (domain_str) {
                        const char *str;
@@ -416,7 +412,7 @@ enum bt_component_status print_event_header(struct pretty_component *pretty,
        if (pretty->options.print_trace_procname_field) {
                struct bt_value *procname_str;
 
-               procname_str = bt_trace_borrow_environment_field_value_by_name(
+               procname_str = bt_trace_borrow_environment_entry_value_by_name(
                        trace_class, "procname");
                if (procname_str) {
                        const char *str;
@@ -440,7 +436,7 @@ enum bt_component_status print_event_header(struct pretty_component *pretty,
        if (pretty->options.print_trace_vpid_field) {
                struct bt_value *vpid_value;
 
-               vpid_value = bt_trace_borrow_environment_field_value_by_name(
+               vpid_value = bt_trace_borrow_environment_entry_value_by_name(
                        trace_class, "vpid");
                if (vpid_value) {
                        int64_t value;
@@ -482,13 +478,12 @@ enum bt_component_status print_event_header(struct pretty_component *pretty,
                enum bt_event_class_log_level log_level;
                const char *log_level_str = NULL;
 
-               log_level = bt_event_class_get_log_level(event_class);
-               BT_ASSERT(log_level != BT_EVENT_CLASS_LOG_LEVEL_UNKNOWN);
-               if (log_level != BT_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) {
+               prop_avail = bt_event_class_get_log_level(event_class,
+                       &log_level);
+               if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
                        log_level_str = log_level_names[log_level];
-               }
+                       BT_ASSERT(log_level_str);
 
-               if (log_level_str) {
                        if (!pretty->start_line) {
                                g_string_append(pretty->string, ", ");
                        }
@@ -554,10 +549,7 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
                struct bt_field *field)
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
-       struct bt_field_type *field_type = NULL;
-       enum bt_integer_base base;
-       enum bt_string_encoding encoding;
-       int signedness;
+       enum bt_field_type_integer_preferred_display_base base;
        struct bt_field_type *int_ft;
        union {
                uint64_t u;
@@ -566,54 +558,14 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
        bool rst_color = false;
        enum bt_field_type_id ft_id;
 
-       field_type = bt_field_borrow_type(field);
-       if (!field_type) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
+       int_ft = bt_field_borrow_type(field);
+       BT_ASSERT(int_ft);
        ft_id = bt_field_get_type_id(field);
-
-       switch (ft_id) {
-       case BT_FIELD_TYPE_ID_INTEGER:
-               int_ft = field_type;
-               break;
-       case BT_FIELD_TYPE_ID_ENUM:
-               int_ft = bt_field_type_enumeration_borrow_container_field_type(
-                       field_type);
-               break;
-       default:
-               abort();
-       }
-
-       signedness = bt_field_type_integer_is_signed(int_ft);
-       if (signedness < 0) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-       if (!signedness) {
-               ret = bt_field_integer_unsigned_get_value(field, &v.u);
+       if (ft_id == BT_FIELD_TYPE_ID_UNSIGNED_INTEGER ||
+                       ft_id == BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION) {
+               v.u = bt_field_unsigned_integer_get_value(field);
        } else {
-               ret = bt_field_integer_signed_get_value(field, &v.s);
-       }
-
-       if (ret < 0) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       encoding = bt_field_type_integer_get_encoding(int_ft);
-       switch (encoding) {
-       case BT_STRING_ENCODING_UTF8:
-       case BT_STRING_ENCODING_ASCII:
-               g_string_append_c(pretty->tmp_string, (int) v.u);
-               goto end;
-       case BT_STRING_ENCODING_NONE:
-       case BT_STRING_ENCODING_UNKNOWN:
-               break;
-       default:
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
+               v.s = bt_field_signed_integer_get_value(field);
        }
 
        if (pretty->use_colors) {
@@ -621,17 +573,13 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
                rst_color = true;
        }
 
-       base = bt_field_type_integer_get_base(int_ft);
+       base = bt_field_type_integer_get_preferred_display_base(int_ft);
        switch (base) {
-       case BT_INTEGER_BASE_BINARY:
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
        {
                int bitnr, len;
 
-               len = bt_field_type_integer_get_size(int_ft);
-               if (len < 0) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
+               len = bt_field_type_integer_get_field_value_range(int_ft);
                g_string_append(pretty->string, "0b");
                v.u = _bt_piecewise_lshift(v.u, 64 - len);
                for (bitnr = 0; bitnr < len; bitnr++) {
@@ -640,16 +588,14 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
                }
                break;
        }
-       case BT_INTEGER_BASE_OCTAL:
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
        {
-               if (signedness) {
+               if (ft_id == BT_FIELD_TYPE_ID_SIGNED_INTEGER ||
+                               ft_id == BT_FIELD_TYPE_ID_SIGNED_ENUMERATION) {
                        int len;
 
-                       len = bt_field_type_integer_get_size(int_ft);
-                       if (len < 0) {
-                               ret = BT_COMPONENT_STATUS_ERROR;
-                               goto end;
-                       }
+                       len = bt_field_type_integer_get_field_value_range(
+                               int_ft);
                        if (len < 64) {
                                size_t rounded_len;
 
@@ -663,23 +609,19 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
                g_string_append_printf(pretty->string, "0%" PRIo64, v.u);
                break;
        }
-       case BT_INTEGER_BASE_DECIMAL:
-       case BT_INTEGER_BASE_UNSPECIFIED:
-               if (!signedness) {
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
+               if (ft_id == BT_FIELD_TYPE_ID_UNSIGNED_INTEGER ||
+                               ft_id == BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION) {
                        g_string_append_printf(pretty->string, "%" PRIu64, v.u);
                } else {
                        g_string_append_printf(pretty->string, "%" PRId64, v.s);
                }
                break;
-       case BT_INTEGER_BASE_HEXADECIMAL:
+       case BT_FIELD_TYPE_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
        {
                int len;
 
-               len = bt_field_type_integer_get_size(int_ft);
-               if (len < 0) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
+               len = bt_field_type_integer_get_field_value_range(int_ft);
                if (len < 64) {
                        /* Round length to the nearest nibble */
                        uint8_t rounded_len = ((len + 3) & ~0x3);
@@ -775,30 +717,36 @@ enum bt_component_status print_enum(struct pretty_component *pretty,
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field_type *enumeration_field_type = NULL;
-       struct bt_field_type *container_field_type = NULL;
-       struct bt_field_type_enumeration_mapping_iterator *iter = NULL;
-       int nr_mappings = 0;
+       bt_field_type_enumeration_mapping_label_array label_array;
+       uint64_t label_count;
+       uint64_t i;
 
        enumeration_field_type = bt_field_borrow_type(field);
        if (!enumeration_field_type) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       container_field_type =
-               bt_field_type_enumeration_borrow_container_field_type(
-                       enumeration_field_type);
-       if (!container_field_type) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
+
+       switch (bt_field_get_type_id(field)) {
+       case BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION:
+               ret = bt_field_unsigned_enumeration_get_mapping_labels(field,
+                       &label_array, &label_count);
+               break;
+       case BT_FIELD_TYPE_ID_SIGNED_ENUMERATION:
+               ret = bt_field_signed_enumeration_get_mapping_labels(field,
+                       &label_array, &label_count);
+               break;
+       default:
+               abort();
        }
-       iter = bt_field_enumeration_get_mappings(field);
-       if (!iter) {
+
+       if (ret) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
+
        g_string_append(pretty->string, "( ");
-       ret = bt_field_type_enumeration_mapping_iterator_next(iter);
-       if (ret) {
+       if (label_count == 0) {
                if (pretty->use_colors) {
                        g_string_append(pretty->string, COLOR_UNKNOWN);
                }
@@ -808,16 +756,12 @@ enum bt_component_status print_enum(struct pretty_component *pretty,
                }
                goto skip_loop;
        }
-       for (;;) {
-               const char *mapping_name;
+       for (i = 0; i < label_count; i++) {
+               const char *mapping_name = label_array[i];
 
-               if (bt_field_type_enumeration_mapping_iterator_signed_get(
-                               iter, &mapping_name, NULL, NULL) < 0) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-               if (nr_mappings++)
+               if (i == 0) {
                        g_string_append(pretty->string, ", ");
+               }
                if (pretty->use_colors) {
                        g_string_append(pretty->string, COLOR_ENUM_MAPPING_NAME);
                }
@@ -825,9 +769,6 @@ enum bt_component_status print_enum(struct pretty_component *pretty,
                if (pretty->use_colors) {
                        g_string_append(pretty->string, COLOR_RST);
                }
-               if (bt_field_type_enumeration_mapping_iterator_next(iter) < 0) {
-                       break;
-               }
        }
 skip_loop:
        g_string_append(pretty->string, " : container = ");
@@ -837,7 +778,6 @@ skip_loop:
        }
        g_string_append(pretty->string, " )");
 end:
-       bt_put(iter);
        return ret;
 }
 
@@ -864,7 +804,7 @@ static
 enum bt_component_status print_struct_field(struct pretty_component *pretty,
                struct bt_field *_struct,
                struct bt_field_type *struct_type,
-               int i, bool print_names, int *nr_printed_fields,
+               uint64_t i, bool print_names, uint64_t *nr_printed_fields,
                GQuark *filter_fields, int filter_array_len)
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
@@ -872,16 +812,14 @@ enum bt_component_status print_struct_field(struct pretty_component *pretty,
        struct bt_field *field = NULL;
        struct bt_field_type *field_type = NULL;;
 
-       field = bt_field_structure_borrow_field_by_index(_struct, i);
+       field = bt_field_structure_borrow_member_field_by_index(_struct, i);
        if (!field) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       if (bt_field_type_structure_borrow_field_by_index(struct_type,
-                       &field_name, &field_type, i) < 0) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
+
+       bt_field_type_structure_borrow_member_by_index(struct_type, i,
+               &field_name, &field_type);
 
        if (filter_fields && !filter_field_name(pretty, field_name,
                                filter_fields, filter_array_len)) {
@@ -911,14 +849,14 @@ enum bt_component_status print_struct(struct pretty_component *pretty,
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field_type *struct_type = NULL;
-       int nr_fields, i, nr_printed_fields;
+       uint64_t nr_fields, i, nr_printed_fields;
 
        struct_type = bt_field_borrow_type(_struct);
        if (!struct_type) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       nr_fields = bt_field_type_structure_get_field_count(struct_type);
+       nr_fields = bt_field_type_structure_get_member_count(struct_type);
        if (nr_fields < 0) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
@@ -943,31 +881,22 @@ end:
 
 static
 enum bt_component_status print_array_field(struct pretty_component *pretty,
-               struct bt_field *array, uint64_t i,
-               bool is_string, bool print_names)
+               struct bt_field *array, uint64_t i, bool print_names)
 {
-       enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field *field = NULL;
 
-       if (!is_string) {
-               if (i != 0) {
-                       g_string_append(pretty->string, ", ");
-               } else {
-                       g_string_append(pretty->string, " ");
-               }
-               if (print_names) {
-                       g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
-               }
+       if (i != 0) {
+               g_string_append(pretty->string, ", ");
+       } else {
+               g_string_append(pretty->string, " ");
        }
-       field = bt_field_array_borrow_field(array, i);
-       if (!field) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
+       if (print_names) {
+               g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
        }
-       ret = print_field(pretty, field, print_names, NULL, 0);
 
-end:
-       return ret;
+       field = bt_field_array_borrow_element_field_by_index(array, i);
+       BT_ASSERT(field);
+       return print_field(pretty, field, print_names, NULL, 0);
 }
 
 static
@@ -975,77 +904,26 @@ enum bt_component_status print_array(struct pretty_component *pretty,
                struct bt_field *array, bool print_names)
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
-       struct bt_field_type *array_type = NULL, *field_type = NULL;
-       enum bt_field_type_id type_id;
-       int64_t len;
+       struct bt_field_type *array_type = NULL;
+       uint64_t len;
        uint64_t i;
-       bool is_string = false;
 
        array_type = bt_field_borrow_type(array);
        if (!array_type) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       field_type = bt_field_type_array_borrow_element_field_type(array_type);
-       if (!field_type) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-       len = bt_field_type_array_get_length(array_type);
-       if (len < 0) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-       type_id = bt_field_type_get_type_id(field_type);
-       if (type_id == BT_FIELD_TYPE_ID_INTEGER) {
-               enum bt_string_encoding encoding;
-
-               encoding = bt_field_type_integer_get_encoding(field_type);
-               if (encoding == BT_STRING_ENCODING_UTF8
-                               || encoding == BT_STRING_ENCODING_ASCII) {
-                       int integer_len, integer_alignment;
-
-                       integer_len = bt_field_type_integer_get_size(field_type);
-                       if (integer_len < 0) {
-                               return BT_COMPONENT_STATUS_ERROR;
-                       }
-                       integer_alignment = bt_field_type_get_alignment(field_type);
-                       if (integer_alignment < 0) {
-                               return BT_COMPONENT_STATUS_ERROR;
-                       }
-                       if (integer_len == CHAR_BIT
-                                       && integer_alignment == CHAR_BIT) {
-                               is_string = true;
-                       }
-               }
-       }
-
-       if (is_string) {
-               g_string_assign(pretty->tmp_string, "");
-       } else {
-               g_string_append(pretty->string, "[");
-       }
-
+       len = bt_field_array_get_length(array);
+       g_string_append(pretty->string, "[");
        pretty->depth++;
        for (i = 0; i < len; i++) {
-               ret = print_array_field(pretty, array, i, is_string, print_names);
+               ret = print_array_field(pretty, array, i, print_names);
                if (ret != BT_COMPONENT_STATUS_OK) {
                        goto end;
                }
        }
        pretty->depth--;
-
-       if (is_string) {
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_STRING_VALUE);
-               }
-               print_escape_string(pretty, pretty->tmp_string->str);
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_RST);
-               }
-       } else {
-               g_string_append(pretty->string, " ]");
-       }
+       g_string_append(pretty->string, " ]");
 
 end:
        return ret;
@@ -1053,31 +931,22 @@ end:
 
 static
 enum bt_component_status print_sequence_field(struct pretty_component *pretty,
-               struct bt_field *seq, uint64_t i,
-               bool is_string, bool print_names)
+               struct bt_field *seq, uint64_t i, bool print_names)
 {
-       enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field *field = NULL;
 
-       if (!is_string) {
-               if (i != 0) {
-                       g_string_append(pretty->string, ", ");
-               } else {
-                       g_string_append(pretty->string, " ");
-               }
-               if (print_names) {
-                       g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
-               }
+       if (i != 0) {
+               g_string_append(pretty->string, ", ");
+       } else {
+               g_string_append(pretty->string, " ");
        }
-       field = bt_field_sequence_borrow_field(seq, i);
-       if (!field) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
+       if (print_names) {
+               g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
        }
-       ret = print_field(pretty, field, print_names, NULL, 0);
 
-end:
-       return ret;
+       field = bt_field_array_borrow_element_field_by_index(seq, i);
+       BT_ASSERT(field);
+       return print_field(pretty, field, print_names, NULL, 0);
 }
 
 static
@@ -1085,80 +954,26 @@ enum bt_component_status print_sequence(struct pretty_component *pretty,
                struct bt_field *seq, bool print_names)
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
-       struct bt_field_type *seq_type = NULL, *field_type = NULL;
-       enum bt_field_type_id type_id;
-       int64_t len;
+       uint64_t len;
        uint64_t i;
-       bool is_string = false;
 
-       seq_type = bt_field_borrow_type(seq);
-       if (!seq_type) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-       len = bt_field_sequence_get_length(seq);
+       len = bt_field_array_get_length(seq);
        if (len < 0) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       field_type = bt_field_type_sequence_borrow_element_field_type(seq_type);
-       if (!field_type) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-       type_id = bt_field_type_get_type_id(field_type);
-       if (type_id == BT_FIELD_TYPE_ID_INTEGER) {
-               enum bt_string_encoding encoding;
-
-               encoding = bt_field_type_integer_get_encoding(field_type);
-               if (encoding == BT_STRING_ENCODING_UTF8
-                               || encoding == BT_STRING_ENCODING_ASCII) {
-                       int integer_len, integer_alignment;
 
-                       integer_len = bt_field_type_integer_get_size(field_type);
-                       if (integer_len < 0) {
-                               ret = BT_COMPONENT_STATUS_ERROR;
-                               goto end;
-                       }
-                       integer_alignment = bt_field_type_get_alignment(field_type);
-                       if (integer_alignment < 0) {
-                               ret = BT_COMPONENT_STATUS_ERROR;
-                               goto end;
-                       }
-                       if (integer_len == CHAR_BIT
-                                       && integer_alignment == CHAR_BIT) {
-                               is_string = true;
-                       }
-               }
-       }
-
-       if (is_string) {
-               g_string_assign(pretty->tmp_string, "");
-       } else {
-               g_string_append(pretty->string, "[");
-       }
+       g_string_append(pretty->string, "[");
 
        pretty->depth++;
        for (i = 0; i < len; i++) {
-               ret = print_sequence_field(pretty, seq, i,
-                       is_string, print_names);
+               ret = print_sequence_field(pretty, seq, i, print_names);
                if (ret != BT_COMPONENT_STATUS_OK) {
                        goto end;
                }
        }
        pretty->depth--;
-
-       if (is_string) {
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_STRING_VALUE);
-               }
-               print_escape_string(pretty, pretty->tmp_string->str);
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_RST);
-               }
-       } else {
-               g_string_append(pretty->string, " ]");
-       }
+       g_string_append(pretty->string, " ]");
 
 end:
        return ret;
@@ -1171,76 +986,13 @@ enum bt_component_status print_variant(struct pretty_component *pretty,
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field *field = NULL;
 
-       field = bt_field_variant_borrow_current_field(variant);
-       if (!field) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
+       field = bt_field_variant_borrow_selected_option_field(variant);
+       BT_ASSERT(field);
        g_string_append(pretty->string, "{ ");
        pretty->depth++;
        if (print_names) {
-               int iret;
-               struct bt_field_type *var_ft;
-               struct bt_field_type *tag_ft;
-               struct bt_field_type *container_ft;
-               const char *tag_choice;
-               bt_bool is_signed;
-               struct bt_field_type_enumeration_mapping_iterator *iter;
-
-               var_ft = bt_field_borrow_type(variant);
-               tag_ft = bt_field_type_variant_borrow_tag_field_type(
-                       var_ft);
-               container_ft =
-                       bt_field_type_enumeration_borrow_container_field_type(
-                               tag_ft);
-               is_signed = bt_field_type_integer_is_signed(container_ft);
-
-               if (is_signed) {
-                       int64_t tag;
-
-                       iret = bt_field_variant_get_tag_signed(variant, &tag);
-                       if (iret) {
-                               ret = BT_COMPONENT_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       iter = bt_field_type_enumeration_signed_find_mappings_by_value(
-                               tag_ft, tag);
-               } else {
-                       uint64_t tag;
-
-                       iret = bt_field_variant_get_tag_unsigned(variant, &tag);
-                       if (iret) {
-                               ret = BT_COMPONENT_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       iter = bt_field_type_enumeration_unsigned_find_mappings_by_value(
-                               tag_ft, tag);
-               }
-
-               if (!iter) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               iret = bt_field_type_enumeration_mapping_iterator_next(
-                       iter);
-               if (!iter || ret) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               iret =
-                       bt_field_type_enumeration_mapping_iterator_signed_get(
-                               iter, &tag_choice, NULL, NULL);
-               if (iret) {
-                       bt_put(iter);
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-               print_field_name_equal(pretty, tag_choice);
-               bt_put(iter);
+               // TODO: find tag's name using field path
+               // print_field_name_equal(pretty, tag_choice);
        }
        ret = print_field(pretty, field, print_names, NULL, 0);
        if (ret != BT_COMPONENT_STATUS_OK) {
@@ -1262,15 +1014,14 @@ enum bt_component_status print_field(struct pretty_component *pretty,
 
        type_id = bt_field_get_type_id(field);
        switch (type_id) {
-       case BT_FIELD_TYPE_ID_INTEGER:
+       case BT_FIELD_TYPE_ID_UNSIGNED_INTEGER:
+       case BT_FIELD_TYPE_ID_SIGNED_INTEGER:
                return print_integer(pretty, field);
-       case BT_FIELD_TYPE_ID_FLOAT:
+       case BT_FIELD_TYPE_ID_REAL:
        {
                double v;
 
-               if (bt_field_floating_point_get_value(field, &v)) {
-                       return BT_COMPONENT_STATUS_ERROR;
-               }
+               v = bt_field_real_get_value(field);
                if (pretty->use_colors) {
                        g_string_append(pretty->string, COLOR_NUMBER_VALUE);
                }
@@ -1280,7 +1031,8 @@ enum bt_component_status print_field(struct pretty_component *pretty,
                }
                return BT_COMPONENT_STATUS_OK;
        }
-       case BT_FIELD_TYPE_ID_ENUM:
+       case BT_FIELD_TYPE_ID_UNSIGNED_ENUMERATION:
+       case BT_FIELD_TYPE_ID_SIGNED_ENUMERATION:
                return print_enum(pretty, field);
        case BT_FIELD_TYPE_ID_STRING:
        {
@@ -1300,14 +1052,14 @@ enum bt_component_status print_field(struct pretty_component *pretty,
                }
                return BT_COMPONENT_STATUS_OK;
        }
-       case BT_FIELD_TYPE_ID_STRUCT:
+       case BT_FIELD_TYPE_ID_STRUCTURE:
                return print_struct(pretty, field, print_names, filter_fields,
                                filter_array_len);
        case BT_FIELD_TYPE_ID_VARIANT:
                return print_variant(pretty, field, print_names);
-       case BT_FIELD_TYPE_ID_ARRAY:
+       case BT_FIELD_TYPE_ID_STATIC_ARRAY:
                return print_array(pretty, field, print_names);
-       case BT_FIELD_TYPE_ID_SEQUENCE:
+       case BT_FIELD_TYPE_ID_DYNAMIC_ARRAY:
                return print_sequence(pretty, field, print_names);
        default:
                // TODO: log instead
@@ -1329,7 +1081,7 @@ enum bt_component_status print_stream_packet_context(struct pretty_component *pr
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       main_field = bt_packet_borrow_context(packet);
+       main_field = bt_packet_borrow_context_field(packet);
        if (!main_field) {
                goto end;
        }
@@ -1356,7 +1108,7 @@ enum bt_component_status print_event_header_raw(struct pretty_component *pretty,
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field *main_field = NULL;
 
-       main_field = bt_event_borrow_header(event);
+       main_field = bt_event_borrow_header_field(event);
        if (!main_field) {
                goto end;
        }
@@ -1381,7 +1133,7 @@ enum bt_component_status print_stream_event_context(struct pretty_component *pre
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field *main_field = NULL;
 
-       main_field = bt_event_borrow_stream_event_context(event);
+       main_field = bt_event_borrow_common_context_field(event);
        if (!main_field) {
                goto end;
        }
@@ -1406,7 +1158,7 @@ enum bt_component_status print_event_context(struct pretty_component *pretty,
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field *main_field = NULL;
 
-       main_field = bt_event_borrow_context(event);
+       main_field = bt_event_borrow_specific_context_field(event);
        if (!main_field) {
                goto end;
        }
@@ -1431,7 +1183,7 @@ enum bt_component_status print_event_payload(struct pretty_component *pretty,
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field *main_field = NULL;
 
-       main_field = bt_event_borrow_payload(event);
+       main_field = bt_event_borrow_payload_field(event);
        if (!main_field) {
                goto end;
        }
@@ -1524,6 +1276,7 @@ enum bt_component_status print_discarded_elements_msg(
                struct pretty_component *pretty, struct bt_packet *packet,
                uint64_t count, const char *elem_type)
 {
+#if 0
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_stream *stream = NULL;
        struct bt_stream_class *stream_class = NULL;
@@ -1635,12 +1388,15 @@ enum bt_component_status print_discarded_elements_msg(
        }
 
        return ret;
+#endif
+       return 0;
 }
 
 BT_HIDDEN
 enum bt_component_status pretty_print_packet(struct pretty_component *pretty,
                struct bt_notification *packet_beginning_notif)
 {
+#if 0
        struct bt_packet *packet = bt_notification_packet_begin_borrow_packet(
                packet_beginning_notif);
        uint64_t count;
@@ -1668,4 +1424,6 @@ enum bt_component_status pretty_print_packet(struct pretty_component *pretty,
 
 end:
        return status;
+#endif
+       return 0;
 }
index f3740a354b1ed5eac7363e1cc11d4f074572943a..c75b5d9bbfd801b47dfea8366d923913a92f56f2 100644 (file)
@@ -607,6 +607,7 @@ int get_notif_ts_ns(struct muxer_comp *muxer_comp,
        int ret = 0;
        const unsigned char *cc_uuid;
        const char *cc_name;
+       enum bt_clock_value_status cv_status = BT_CLOCK_VALUE_STATUS_KNOWN;
 
        BT_ASSERT(notif);
        BT_ASSERT(ts_ns);
@@ -620,7 +621,8 @@ int get_notif_ts_ns(struct muxer_comp *muxer_comp,
        case BT_NOTIFICATION_TYPE_EVENT:
                event = bt_notification_event_borrow_event(notif);
                BT_ASSERT(event);
-               clock_value = bt_event_borrow_default_clock_value(event);
+               cv_status = bt_event_borrow_default_clock_value(event,
+                       &clock_value);
                break;
 
        case BT_NOTIFICATION_TYPE_INACTIVITY:
@@ -635,6 +637,12 @@ int get_notif_ts_ns(struct muxer_comp *muxer_comp,
                goto end;
        }
 
+       if (cv_status != BT_CLOCK_VALUE_STATUS_KNOWN) {
+               BT_LOGE_STR("Unsupported unknown clock value.");
+               ret = -1;
+               goto end;
+       }
+
        /*
         * If the clock value is missing, then we consider that this
         * notification has no time. In this case it's always the
@@ -647,7 +655,7 @@ int get_notif_ts_ns(struct muxer_comp *muxer_comp,
                goto end;
        }
 
-       clock_class = bt_clock_value_borrow_class(clock_value);
+       clock_class = bt_clock_value_borrow_clock_class(clock_value);
        BT_ASSERT(clock_class);
        cc_uuid = bt_clock_class_get_uuid(clock_class);
        cc_name = bt_clock_class_get_name(clock_class);
@@ -800,7 +808,7 @@ int get_notif_ts_ns(struct muxer_comp *muxer_comp,
                }
        }
 
-       ret = bt_clock_value_get_value_ns_from_epoch(clock_value, ts_ns);
+       ret = bt_clock_value_get_ns_from_origin(clock_value, ts_ns);
        if (ret) {
                BT_LOGE("Cannot get nanoseconds from Epoch of clock value: "
                        "clock-value-addr=%p", clock_value);
index 298f24bd5d28926e127acfd2e970f63971b793e2..b2b34642e07fea6c54d8beced4bf5faa73f9a581 100644 (file)
@@ -21,24 +21,17 @@ test_bt_values_LDADD = $(COMMON_TEST_LDADD)
 
 test_ctf_ir_ref_LDADD = $(COMMON_TEST_LDADD)
 
-test_bt_ctf_field_type_validation_LDADD = $(COMMON_TEST_LDADD)
-
-test_ir_visit_LDADD = $(COMMON_TEST_LDADD)
-
 test_graph_topo_LDADD = $(COMMON_TEST_LDADD)
 
 test_bt_notification_iterator_LDADD = $(COMMON_TEST_LDADD)
 
 noinst_PROGRAMS = test_bitfield test_ctf_writer test_bt_values \
-       test_ctf_ir_ref test_bt_ctf_field_type_validation test_ir_visit \
-       test_graph_topo test_bt_notification_iterator
+       test_ctf_ir_ref test_graph_topo test_bt_notification_iterator
 
 test_bitfield_SOURCES = test_bitfield.c
 test_ctf_writer_SOURCES = test_ctf_writer.c
 test_bt_values_SOURCES = test_bt_values.c
 test_ctf_ir_ref_SOURCES = test_ctf_ir_ref.c
-test_bt_ctf_field_type_validation_SOURCES = test_bt_ctf_field_type_validation.c
-test_ir_visit_SOURCES = test_ir_visit.c
 test_graph_topo_SOURCES = test_graph_topo.c
 test_bt_notification_iterator_SOURCES = test_bt_notification_iterator.c
 
diff --git a/tests/lib/test_bt_ctf_field_type_validation.c b/tests/lib/test_bt_ctf_field_type_validation.c
deleted file mode 100644 (file)
index b31b619..0000000
+++ /dev/null
@@ -1,2949 +0,0 @@
-/*
- * test_bt_field_type_validation.c
- *
- * Babeltrace CTF IR field type validation test
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <babeltrace/ref.h>
-#include <babeltrace/ctf-ir/field-types.h>
-#include <babeltrace/ctf-ir/field-path.h>
-#include <babeltrace/ctf-ir/event.h>
-#include <babeltrace/ctf-ir/event-class.h>
-#include <babeltrace/ctf-ir/stream-class.h>
-#include <babeltrace/ctf-ir/trace.h>
-#include <babeltrace/assert-internal.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdarg.h>
-#include <glib.h>
-#include "tap/tap.h"
-
-static
-struct bt_field_type *get_good_packet_header_field_type(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         magic:
-           class: int
-           size: 32
-         uuid:
-           class: array
-           length: 16
-           element-type:
-             class: int
-             size: 8
-         stream_id:
-           class: int
-           size: 32
-         iron:
-           class: struct
-           fields:
-             listen:
-               class: string
-             dust:
-               class: int
-               size: 23
-             parallel:
-               class: enum
-               value-type:
-                 class: int
-                 size: 10
-               members:
-                 - RED
-                 - BLUE
-                 - YELLOW
-             fire:
-               class: struct
-               fields:
-                 word:
-                   class: int
-                   size: 17
-                 rabbit:
-                   class: string
-                 keen:
-                   class: array
-                   length: word
-                   element-type:
-                     class: variant
-                     tag: iron.parallel
-                     types:
-                       RED:
-                         class: string
-                       BLUE:
-                         class: array
-                         length: magic
-                         element-type:
-                           class: int
-                           size: 5
-                       YELLOW:
-                         class: struct
-             report:
-               class: array
-               length: trace.packet.header.iron.dust
-               element-type:
-                 class: string
-             group:
-               class: array
-               length: trace.packet.header.stream_id
-               element-type:
-                 class: string
-         serious:
-           class: int
-           size: 1
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_magic = NULL;
-       struct bt_field_type *root_uuid = NULL;
-       struct bt_field_type *root_uuid_elem = NULL;
-       struct bt_field_type *root_stream_id = NULL;
-       struct bt_field_type *root_iron = NULL;
-       struct bt_field_type *root_iron_listen = NULL;
-       struct bt_field_type *root_iron_dust = NULL;
-       struct bt_field_type *root_iron_parallel = NULL;
-       struct bt_field_type *root_iron_parallel_int = NULL;
-       struct bt_field_type *root_iron_fire = NULL;
-       struct bt_field_type *root_iron_fire_word = NULL;
-       struct bt_field_type *root_iron_fire_rabbit = NULL;
-       struct bt_field_type *root_iron_fire_keen = NULL;
-       struct bt_field_type *root_iron_fire_keen_elem = NULL;
-       struct bt_field_type *root_iron_fire_keen_elem_RED = NULL;
-       struct bt_field_type *root_iron_fire_keen_elem_BLUE = NULL;
-       struct bt_field_type *root_iron_fire_keen_elem_BLUE_elem = NULL;
-       struct bt_field_type *root_iron_fire_keen_elem_YELLOW = NULL;
-       struct bt_field_type *root_iron_report = NULL;
-       struct bt_field_type *root_iron_report_elem = NULL;
-       struct bt_field_type *root_iron_group = NULL;
-       struct bt_field_type *root_iron_group_elem = NULL;
-       struct bt_field_type *root_serious = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_magic = bt_field_type_integer_create(32);
-       BT_ASSERT(root_magic);
-       ret = bt_field_type_integer_set_is_signed(root_magic, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_magic, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_magic, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_magic, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_magic, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_magic, "magic");
-       BT_ASSERT(ret == 0);
-       root_uuid_elem = bt_field_type_integer_create(8);
-       BT_ASSERT(root_uuid_elem);
-       ret = bt_field_type_integer_set_is_signed(root_uuid_elem, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_uuid_elem, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_uuid_elem, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_uuid_elem, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_uuid_elem, 8);
-       BT_ASSERT(ret == 0);
-       root_uuid = bt_field_type_array_create(root_uuid_elem, 16);
-       BT_ASSERT(root_uuid);
-       ret = bt_field_type_structure_add_field(root, root_uuid, "uuid");
-       BT_ASSERT(ret == 0);
-       root_stream_id = bt_field_type_integer_create(32);
-       BT_ASSERT(root_stream_id);
-       ret = bt_field_type_integer_set_is_signed(root_stream_id, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_stream_id, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_stream_id, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_stream_id, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_stream_id, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_stream_id, "stream_id");
-       BT_ASSERT(ret == 0);
-       root_iron = bt_field_type_structure_create();
-       BT_ASSERT(root_iron);
-       ret = bt_field_type_set_alignment(root_iron, 8);
-       BT_ASSERT(ret == 0);
-       root_iron_listen = bt_field_type_string_create();
-       BT_ASSERT(root_iron_listen);
-       ret = bt_field_type_string_set_encoding(root_iron_listen, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_iron, root_iron_listen, "listen");
-       BT_ASSERT(ret == 0);
-       root_iron_dust = bt_field_type_integer_create(23);
-       BT_ASSERT(root_iron_dust);
-       ret = bt_field_type_integer_set_is_signed(root_iron_dust, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_iron_dust, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_iron_dust, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_iron_dust, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_iron_dust, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_iron, root_iron_dust, "dust");
-       BT_ASSERT(ret == 0);
-       root_iron_parallel_int = bt_field_type_integer_create(10);
-       BT_ASSERT(root_iron_parallel_int);
-       ret = bt_field_type_integer_set_is_signed(root_iron_parallel_int, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_iron_parallel_int, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_iron_parallel_int, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_iron_parallel_int, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_iron_parallel_int, 1);
-       BT_ASSERT(ret == 0);
-       root_iron_parallel = bt_field_type_enumeration_create(root_iron_parallel_int);
-       BT_ASSERT(root_iron_parallel);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_iron_parallel, "RED", 0, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_iron_parallel, "BLUE", 1, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_iron_parallel, "YELLOW", 2, 2);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_iron, root_iron_parallel, "parallel");
-       BT_ASSERT(ret == 0);
-       root_iron_fire = bt_field_type_structure_create();
-       BT_ASSERT(root_iron_fire);
-       ret = bt_field_type_set_alignment(root_iron_fire, 8);
-       BT_ASSERT(ret == 0);
-       root_iron_fire_word = bt_field_type_integer_create(17);
-       BT_ASSERT(root_iron_fire_word);
-       ret = bt_field_type_integer_set_is_signed(root_iron_fire_word, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_iron_fire_word, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_iron_fire_word, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_iron_fire_word, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_iron_fire_word, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_iron_fire, root_iron_fire_word, "word");
-       BT_ASSERT(ret == 0);
-       root_iron_fire_rabbit = bt_field_type_string_create();
-       BT_ASSERT(root_iron_fire_rabbit);
-       ret = bt_field_type_string_set_encoding(root_iron_fire_rabbit, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_iron_fire, root_iron_fire_rabbit, "rabbit");
-       BT_ASSERT(ret == 0);
-       root_iron_fire_keen_elem = bt_field_type_variant_create(NULL, "iron.parallel");
-       BT_ASSERT(root_iron_fire_keen_elem);
-       root_iron_fire_keen_elem_RED = bt_field_type_string_create();
-       BT_ASSERT(root_iron_fire_keen_elem_RED);
-       ret = bt_field_type_string_set_encoding(root_iron_fire_keen_elem_RED, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_variant_add_field(root_iron_fire_keen_elem, root_iron_fire_keen_elem_RED, "RED");
-       BT_ASSERT(ret == 0);
-       root_iron_fire_keen_elem_BLUE_elem = bt_field_type_integer_create(5);
-       BT_ASSERT(root_iron_fire_keen_elem_BLUE_elem);
-       ret = bt_field_type_integer_set_is_signed(root_iron_fire_keen_elem_BLUE_elem, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_iron_fire_keen_elem_BLUE_elem, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_iron_fire_keen_elem_BLUE_elem, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_iron_fire_keen_elem_BLUE_elem, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_iron_fire_keen_elem_BLUE_elem, 1);
-       BT_ASSERT(ret == 0);
-       root_iron_fire_keen_elem_BLUE = bt_field_type_sequence_create(root_iron_fire_keen_elem_BLUE_elem, "magic");
-       BT_ASSERT(root_iron_fire_keen_elem_BLUE);
-       ret = bt_field_type_variant_add_field(root_iron_fire_keen_elem, root_iron_fire_keen_elem_BLUE, "BLUE");
-       BT_ASSERT(ret == 0);
-       root_iron_fire_keen_elem_YELLOW = bt_field_type_structure_create();
-       BT_ASSERT(root_iron_fire_keen_elem_YELLOW);
-       ret = bt_field_type_set_alignment(root_iron_fire_keen_elem_YELLOW, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_variant_add_field(root_iron_fire_keen_elem, root_iron_fire_keen_elem_YELLOW, "YELLOW");
-       BT_ASSERT(ret == 0);
-       root_iron_fire_keen = bt_field_type_sequence_create(root_iron_fire_keen_elem, "word");
-       BT_ASSERT(root_iron_fire_keen);
-       ret = bt_field_type_structure_add_field(root_iron_fire, root_iron_fire_keen, "keen");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_iron, root_iron_fire, "fire");
-       BT_ASSERT(ret == 0);
-       root_iron_report_elem = bt_field_type_string_create();
-       BT_ASSERT(root_iron_report_elem);
-       ret = bt_field_type_string_set_encoding(root_iron_report_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_iron_report = bt_field_type_sequence_create(root_iron_report_elem, "trace.packet.header.iron.dust");
-       BT_ASSERT(root_iron_report);
-       ret = bt_field_type_structure_add_field(root_iron, root_iron_report, "report");
-       BT_ASSERT(ret == 0);
-       root_iron_group_elem = bt_field_type_string_create();
-       BT_ASSERT(root_iron_group_elem);
-       ret = bt_field_type_string_set_encoding(root_iron_group_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_iron_group = bt_field_type_sequence_create(root_iron_group_elem, "trace.packet.header.stream_id");
-       BT_ASSERT(root_iron_group);
-       ret = bt_field_type_structure_add_field(root_iron, root_iron_group, "group");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_iron, "iron");
-       BT_ASSERT(ret == 0);
-       root_serious = bt_field_type_integer_create(1);
-       BT_ASSERT(root_serious);
-       ret = bt_field_type_integer_set_is_signed(root_serious, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_serious, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_serious, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_serious, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_serious, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_serious, "serious");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_magic);
-       BT_PUT(root_uuid);
-       BT_PUT(root_uuid_elem);
-       BT_PUT(root_stream_id);
-       BT_PUT(root_iron);
-       BT_PUT(root_iron_listen);
-       BT_PUT(root_iron_dust);
-       BT_PUT(root_iron_parallel);
-       BT_PUT(root_iron_parallel_int);
-       BT_PUT(root_iron_fire);
-       BT_PUT(root_iron_fire_word);
-       BT_PUT(root_iron_fire_rabbit);
-       BT_PUT(root_iron_fire_keen);
-       BT_PUT(root_iron_fire_keen_elem);
-       BT_PUT(root_iron_fire_keen_elem_RED);
-       BT_PUT(root_iron_fire_keen_elem_BLUE);
-       BT_PUT(root_iron_fire_keen_elem_BLUE_elem);
-       BT_PUT(root_iron_fire_keen_elem_YELLOW);
-       BT_PUT(root_iron_report);
-       BT_PUT(root_iron_report_elem);
-       BT_PUT(root_iron_group);
-       BT_PUT(root_iron_group_elem);
-       BT_PUT(root_serious);
-
-       return root;
-}
-
-static
-struct bt_field_type *get_good_packet_context_field_type(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         placid:
-           class: int
-           size: 32
-         meow:
-           class: string
-         serious:
-           class: int
-           size: 11
-         naive:
-           class: array
-           length: 17
-           element-type:
-             class: array
-             length: placid
-             element-type:
-               class: string
-         clover:
-           class: struct
-           fields:
-             oval:
-               class: int
-               size: 17
-             whole:
-               class: variant
-               tag: iron.parallel
-               types:
-                 BLUE:
-                   class: array
-                   length: trace.packet.header.iron.fire.word
-                   element-type:
-                     class: string
-                 RED:
-                   class: int
-                   size: 44
-                 YELLOW:
-                   class: string
-             egg:
-               class: array
-               length: stream.packet.context.clover.oval
-               element-type:
-                 class: int
-                 size: 55
-             square:
-               class: enum
-               value-type:
-                 class: int
-                 size: 12
-               members:
-                 - YOUNG
-                 - OLD
-             useful:
-               class: array
-               length: serious
-               element-type:
-                 class: int
-                 size: 2
-         tart:
-           class: string
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_placid = NULL;
-       struct bt_field_type *root_meow = NULL;
-       struct bt_field_type *root_serious = NULL;
-       struct bt_field_type *root_naive = NULL;
-       struct bt_field_type *root_naive_elem = NULL;
-       struct bt_field_type *root_naive_elem_elem = NULL;
-       struct bt_field_type *root_clover = NULL;
-       struct bt_field_type *root_clover_oval = NULL;
-       struct bt_field_type *root_clover_whole = NULL;
-       struct bt_field_type *root_clover_whole_BLUE = NULL;
-       struct bt_field_type *root_clover_whole_BLUE_elem = NULL;
-       struct bt_field_type *root_clover_whole_RED = NULL;
-       struct bt_field_type *root_clover_whole_YELLOW = NULL;
-       struct bt_field_type *root_clover_egg = NULL;
-       struct bt_field_type *root_clover_egg_elem = NULL;
-       struct bt_field_type *root_clover_square = NULL;
-       struct bt_field_type *root_clover_square_int = NULL;
-       struct bt_field_type *root_clover_useful = NULL;
-       struct bt_field_type *root_clover_useful_elem = NULL;
-       struct bt_field_type *root_tart = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_placid = bt_field_type_integer_create(32);
-       BT_ASSERT(root_placid);
-       ret = bt_field_type_integer_set_is_signed(root_placid, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_placid, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_placid, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_placid, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_placid, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_placid, "placid");
-       BT_ASSERT(ret == 0);
-       root_meow = bt_field_type_string_create();
-       BT_ASSERT(root_meow);
-       ret = bt_field_type_string_set_encoding(root_meow, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_meow, "meow");
-       BT_ASSERT(ret == 0);
-       root_serious = bt_field_type_integer_create(11);
-       BT_ASSERT(root_serious);
-       ret = bt_field_type_integer_set_is_signed(root_serious, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_serious, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_serious, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_serious, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_serious, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_serious, "serious");
-       BT_ASSERT(ret == 0);
-       root_naive_elem_elem = bt_field_type_string_create();
-       BT_ASSERT(root_naive_elem_elem);
-       ret = bt_field_type_string_set_encoding(root_naive_elem_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_naive_elem = bt_field_type_sequence_create(root_naive_elem_elem, "placid");
-       BT_ASSERT(root_naive_elem);
-       root_naive = bt_field_type_array_create(root_naive_elem, 17);
-       BT_ASSERT(root_naive);
-       ret = bt_field_type_structure_add_field(root, root_naive, "naive");
-       BT_ASSERT(ret == 0);
-       root_clover = bt_field_type_structure_create();
-       BT_ASSERT(root_clover);
-       ret = bt_field_type_set_alignment(root_clover, 1);
-       BT_ASSERT(ret == 0);
-       root_clover_oval = bt_field_type_integer_create(17);
-       BT_ASSERT(root_clover_oval);
-       ret = bt_field_type_integer_set_is_signed(root_clover_oval, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_clover_oval, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_clover_oval, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_clover_oval, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_clover_oval, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_clover, root_clover_oval, "oval");
-       BT_ASSERT(ret == 0);
-       root_clover_whole = bt_field_type_variant_create(NULL, "iron.parallel");
-       BT_ASSERT(root_clover_whole);
-       root_clover_whole_BLUE_elem = bt_field_type_string_create();
-       BT_ASSERT(root_clover_whole_BLUE_elem);
-       ret = bt_field_type_string_set_encoding(root_clover_whole_BLUE_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_clover_whole_BLUE = bt_field_type_sequence_create(root_clover_whole_BLUE_elem, "trace.packet.header.iron.fire.word");
-       BT_ASSERT(root_clover_whole_BLUE);
-       ret = bt_field_type_variant_add_field(root_clover_whole, root_clover_whole_BLUE, "BLUE");
-       BT_ASSERT(ret == 0);
-       root_clover_whole_RED = bt_field_type_integer_create(44);
-       BT_ASSERT(root_clover_whole_RED);
-       ret = bt_field_type_integer_set_is_signed(root_clover_whole_RED, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_clover_whole_RED, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_clover_whole_RED, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_clover_whole_RED, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_clover_whole_RED, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_variant_add_field(root_clover_whole, root_clover_whole_RED, "RED");
-       BT_ASSERT(ret == 0);
-       root_clover_whole_YELLOW = bt_field_type_string_create();
-       BT_ASSERT(root_clover_whole_YELLOW);
-       ret = bt_field_type_string_set_encoding(root_clover_whole_YELLOW, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_variant_add_field(root_clover_whole, root_clover_whole_YELLOW, "YELLOW");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_clover, root_clover_whole, "whole");
-       BT_ASSERT(ret == 0);
-       root_clover_egg_elem = bt_field_type_integer_create(55);
-       BT_ASSERT(root_clover_egg_elem);
-       ret = bt_field_type_integer_set_is_signed(root_clover_egg_elem, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_clover_egg_elem, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_clover_egg_elem, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_clover_egg_elem, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_clover_egg_elem, 1);
-       BT_ASSERT(ret == 0);
-       root_clover_egg = bt_field_type_sequence_create(root_clover_egg_elem, "stream.packet.context.clover.oval");
-       BT_ASSERT(root_clover_egg);
-       ret = bt_field_type_structure_add_field(root_clover, root_clover_egg, "egg");
-       BT_ASSERT(ret == 0);
-       root_clover_square_int = bt_field_type_integer_create(12);
-       BT_ASSERT(root_clover_square_int);
-       ret = bt_field_type_integer_set_is_signed(root_clover_square_int, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_clover_square_int, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_clover_square_int, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_clover_square_int, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_clover_square_int, 1);
-       BT_ASSERT(ret == 0);
-       root_clover_square = bt_field_type_enumeration_create(root_clover_square_int);
-       BT_ASSERT(root_clover_square);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_clover_square, "YOUNG", 0, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_clover_square, "OLD", 1, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_clover, root_clover_square, "square");
-       BT_ASSERT(ret == 0);
-       root_clover_useful_elem = bt_field_type_integer_create(2);
-       BT_ASSERT(root_clover_useful_elem);
-       ret = bt_field_type_integer_set_is_signed(root_clover_useful_elem, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_clover_useful_elem, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_clover_useful_elem, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_clover_useful_elem, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_clover_useful_elem, 1);
-       BT_ASSERT(ret == 0);
-       root_clover_useful = bt_field_type_sequence_create(root_clover_useful_elem, "serious");
-       BT_ASSERT(root_clover_useful);
-       ret = bt_field_type_structure_add_field(root_clover, root_clover_useful, "useful");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_clover, "clover");
-       BT_ASSERT(ret == 0);
-       root_tart = bt_field_type_string_create();
-       BT_ASSERT(root_tart);
-       ret = bt_field_type_string_set_encoding(root_tart, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_tart, "tart");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_placid);
-       BT_PUT(root_meow);
-       BT_PUT(root_serious);
-       BT_PUT(root_naive);
-       BT_PUT(root_naive_elem);
-       BT_PUT(root_naive_elem_elem);
-       BT_PUT(root_clover);
-       BT_PUT(root_clover_oval);
-       BT_PUT(root_clover_whole);
-       BT_PUT(root_clover_whole_BLUE);
-       BT_PUT(root_clover_whole_BLUE_elem);
-       BT_PUT(root_clover_whole_RED);
-       BT_PUT(root_clover_whole_YELLOW);
-       BT_PUT(root_clover_egg);
-       BT_PUT(root_clover_egg_elem);
-       BT_PUT(root_clover_square);
-       BT_PUT(root_clover_square_int);
-       BT_PUT(root_clover_useful);
-       BT_PUT(root_clover_useful_elem);
-       BT_PUT(root_tart);
-
-       return root;
-}
-
-
-static
-struct bt_field_type *get_good_event_header_field_type(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         id:
-           class: int
-           size: 17
-         timestamp:
-           class: int
-           size: 64
-         action:
-           class: struct
-           fields:
-             special:
-               class: int
-               size: 17
-             lucky:
-               class: array
-               length: stream.packet.context.placid
-               element-type:
-                 class: string
-             dream:
-               class: string
-             grandiose:
-               class: array
-               length: trace.packet.header.serious
-               element-type:
-                 class: int
-                 size: 3
-         stiff:
-           class: array
-           length: clover.whole.RED
-           element-type:
-             class: string
-         fruit:
-           class: struct
-           fields:
-             apple:
-               class: array
-               length: action.special
-               element-type:
-                 class: int
-                 size: 5
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_id = NULL;
-       struct bt_field_type *root_timestamp = NULL;
-       struct bt_field_type *root_action = NULL;
-       struct bt_field_type *root_action_special = NULL;
-       struct bt_field_type *root_action_lucky = NULL;
-       struct bt_field_type *root_action_lucky_elem = NULL;
-       struct bt_field_type *root_action_dream = NULL;
-       struct bt_field_type *root_action_grandiose = NULL;
-       struct bt_field_type *root_action_grandiose_elem = NULL;
-       struct bt_field_type *root_stiff = NULL;
-       struct bt_field_type *root_stiff_elem = NULL;
-       struct bt_field_type *root_fruit = NULL;
-       struct bt_field_type *root_fruit_apple = NULL;
-       struct bt_field_type *root_fruit_apple_elem = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_id = bt_field_type_integer_create(17);
-       BT_ASSERT(root_id);
-       ret = bt_field_type_integer_set_is_signed(root_id, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_id, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_id, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_id, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_id, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_id, "id");
-       BT_ASSERT(ret == 0);
-       root_timestamp = bt_field_type_integer_create(64);
-       BT_ASSERT(root_timestamp);
-       ret = bt_field_type_integer_set_is_signed(root_timestamp, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_timestamp, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_timestamp, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_timestamp, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_timestamp, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_timestamp, "timestamp");
-       BT_ASSERT(ret == 0);
-       root_action = bt_field_type_structure_create();
-       BT_ASSERT(root_action);
-       ret = bt_field_type_set_alignment(root_action, 8);
-       BT_ASSERT(ret == 0);
-       root_action_special = bt_field_type_integer_create(17);
-       BT_ASSERT(root_action_special);
-       ret = bt_field_type_integer_set_is_signed(root_action_special, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_action_special, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_action_special, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_action_special, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_action_special, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_action, root_action_special, "special");
-       BT_ASSERT(ret == 0);
-       root_action_lucky_elem = bt_field_type_string_create();
-       BT_ASSERT(root_action_lucky_elem);
-       ret = bt_field_type_string_set_encoding(root_action_lucky_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_action_lucky = bt_field_type_sequence_create(root_action_lucky_elem, "stream.packet.context.placid");
-       BT_ASSERT(root_action_lucky);
-       ret = bt_field_type_structure_add_field(root_action, root_action_lucky, "lucky");
-       BT_ASSERT(ret == 0);
-       root_action_dream = bt_field_type_string_create();
-       BT_ASSERT(root_action_dream);
-       ret = bt_field_type_string_set_encoding(root_action_dream, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_action, root_action_dream, "dream");
-       BT_ASSERT(ret == 0);
-       root_action_grandiose_elem = bt_field_type_integer_create(3);
-       BT_ASSERT(root_action_grandiose_elem);
-       ret = bt_field_type_integer_set_is_signed(root_action_grandiose_elem, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_action_grandiose_elem, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_action_grandiose_elem, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_action_grandiose_elem, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_action_grandiose_elem, 1);
-       BT_ASSERT(ret == 0);
-       root_action_grandiose = bt_field_type_sequence_create(root_action_grandiose_elem, "trace.packet.header.serious");
-       BT_ASSERT(root_action_grandiose);
-       ret = bt_field_type_structure_add_field(root_action, root_action_grandiose, "grandiose");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_action, "action");
-       BT_ASSERT(ret == 0);
-       root_stiff_elem = bt_field_type_string_create();
-       BT_ASSERT(root_stiff_elem);
-       ret = bt_field_type_string_set_encoding(root_stiff_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_stiff = bt_field_type_sequence_create(root_stiff_elem, "clover.whole.RED");
-       BT_ASSERT(root_stiff);
-       ret = bt_field_type_structure_add_field(root, root_stiff, "stiff");
-       BT_ASSERT(ret == 0);
-       root_fruit = bt_field_type_structure_create();
-       BT_ASSERT(root_fruit);
-       ret = bt_field_type_set_alignment(root_fruit, 1);
-       BT_ASSERT(ret == 0);
-       root_fruit_apple_elem = bt_field_type_integer_create(5);
-       BT_ASSERT(root_fruit_apple_elem);
-       ret = bt_field_type_integer_set_is_signed(root_fruit_apple_elem, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_fruit_apple_elem, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_fruit_apple_elem, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_fruit_apple_elem, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_fruit_apple_elem, 1);
-       BT_ASSERT(ret == 0);
-       root_fruit_apple = bt_field_type_sequence_create(root_fruit_apple_elem, "action.special");
-       BT_ASSERT(root_fruit_apple);
-       ret = bt_field_type_structure_add_field(root_fruit, root_fruit_apple, "apple");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_fruit, "fruit");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_id);
-       BT_PUT(root_timestamp);
-       BT_PUT(root_action);
-       BT_PUT(root_action_special);
-       BT_PUT(root_action_lucky);
-       BT_PUT(root_action_lucky_elem);
-       BT_PUT(root_action_dream);
-       BT_PUT(root_action_grandiose);
-       BT_PUT(root_action_grandiose_elem);
-       BT_PUT(root_stiff);
-       BT_PUT(root_stiff_elem);
-       BT_PUT(root_fruit);
-       BT_PUT(root_fruit_apple);
-       BT_PUT(root_fruit_apple_elem);
-
-       return root;
-}
-
-static
-struct bt_field_type *get_good_stream_event_context_field_type(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         face:
-           class: struct
-           fields:
-             branch:
-               class: array
-               length: serious
-               element-type:
-                 class: string
-             income:
-               class: array
-               length: magic
-               element-type:
-                 class: string
-             magic:
-               class: int
-               size: 23
-             lucky:
-               class: array
-               length: magic
-               element-type:
-                 class: string
-         cats:
-           class: int
-           size: 5
-         dream:
-           class: array
-           length: stream.packet.context.placid
-           element-type:
-             class: array
-             length: trace.packet.header.iron.dust
-             element-type:
-               class: array
-               length: stream.event.context.face.magic
-               element-type:
-                 class: string
-         stream_id:
-           class: int
-           size: 9
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_face = NULL;
-       struct bt_field_type *root_face_branch = NULL;
-       struct bt_field_type *root_face_branch_elem = NULL;
-       struct bt_field_type *root_face_income = NULL;
-       struct bt_field_type *root_face_income_elem = NULL;
-       struct bt_field_type *root_face_magic = NULL;
-       struct bt_field_type *root_face_lucky = NULL;
-       struct bt_field_type *root_face_lucky_elem = NULL;
-       struct bt_field_type *root_cats = NULL;
-       struct bt_field_type *root_dream = NULL;
-       struct bt_field_type *root_dream_elem = NULL;
-       struct bt_field_type *root_dream_elem_elem = NULL;
-       struct bt_field_type *root_dream_elem_elem_elem = NULL;
-       struct bt_field_type *root_stream_id = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_face = bt_field_type_structure_create();
-       BT_ASSERT(root_face);
-       ret = bt_field_type_set_alignment(root_face, 8);
-       BT_ASSERT(ret == 0);
-       root_face_branch_elem = bt_field_type_string_create();
-       BT_ASSERT(root_face_branch_elem);
-       ret = bt_field_type_string_set_encoding(root_face_branch_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_face_branch = bt_field_type_sequence_create(root_face_branch_elem, "serious");
-       BT_ASSERT(root_face_branch);
-       ret = bt_field_type_structure_add_field(root_face, root_face_branch, "branch");
-       BT_ASSERT(ret == 0);
-       root_face_income_elem = bt_field_type_string_create();
-       BT_ASSERT(root_face_income_elem);
-       ret = bt_field_type_string_set_encoding(root_face_income_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_face_income = bt_field_type_sequence_create(root_face_income_elem, "magic");
-       BT_ASSERT(root_face_income);
-       ret = bt_field_type_structure_add_field(root_face, root_face_income, "income");
-       BT_ASSERT(ret == 0);
-       root_face_magic = bt_field_type_integer_create(23);
-       BT_ASSERT(root_face_magic);
-       ret = bt_field_type_integer_set_is_signed(root_face_magic, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_face_magic, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_face_magic, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_face_magic, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_face_magic, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_face, root_face_magic, "magic");
-       BT_ASSERT(ret == 0);
-       root_face_lucky_elem = bt_field_type_string_create();
-       BT_ASSERT(root_face_lucky_elem);
-       ret = bt_field_type_string_set_encoding(root_face_lucky_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_face_lucky = bt_field_type_sequence_create(root_face_lucky_elem, "magic");
-       BT_ASSERT(root_face_lucky);
-       ret = bt_field_type_structure_add_field(root_face, root_face_lucky, "lucky");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_face, "face");
-       BT_ASSERT(ret == 0);
-       root_cats = bt_field_type_integer_create(5);
-       BT_ASSERT(root_cats);
-       ret = bt_field_type_integer_set_is_signed(root_cats, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_cats, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_cats, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_cats, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_cats, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_cats, "cats");
-       BT_ASSERT(ret == 0);
-       root_dream_elem_elem_elem = bt_field_type_string_create();
-       BT_ASSERT(root_dream_elem_elem_elem);
-       ret = bt_field_type_string_set_encoding(root_dream_elem_elem_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_dream_elem_elem = bt_field_type_sequence_create(root_dream_elem_elem_elem, "stream.event.context.face.magic");
-       BT_ASSERT(root_dream_elem_elem);
-       root_dream_elem = bt_field_type_sequence_create(root_dream_elem_elem, "trace.packet.header.iron.dust");
-       BT_ASSERT(root_dream_elem);
-       root_dream = bt_field_type_sequence_create(root_dream_elem, "stream.packet.context.placid");
-       BT_ASSERT(root_dream);
-       ret = bt_field_type_structure_add_field(root, root_dream, "dream");
-       BT_ASSERT(ret == 0);
-       root_stream_id = bt_field_type_integer_create(9);
-       BT_ASSERT(root_stream_id);
-       ret = bt_field_type_integer_set_is_signed(root_stream_id, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_stream_id, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_stream_id, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_stream_id, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_stream_id, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_stream_id, "stream_id");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_face);
-       BT_PUT(root_face_branch);
-       BT_PUT(root_face_branch_elem);
-       BT_PUT(root_face_income);
-       BT_PUT(root_face_income_elem);
-       BT_PUT(root_face_magic);
-       BT_PUT(root_face_lucky);
-       BT_PUT(root_face_lucky_elem);
-       BT_PUT(root_cats);
-       BT_PUT(root_dream);
-       BT_PUT(root_dream_elem);
-       BT_PUT(root_dream_elem_elem);
-       BT_PUT(root_dream_elem_elem_elem);
-       BT_PUT(root_stream_id);
-
-       return root;
-}
-
-static
-struct bt_field_type *get_good_event_context_field_type(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         film:
-           class: int
-           size: 19
-         berry:
-           class: struct
-           fields:
-             pine:
-               class: array
-               length: stream_id
-               element-type:
-                 class: string
-             porter:
-               class: array
-               length: face.magic
-               element-type:
-                 class: string
-             mice:
-               class: array
-               length: action.special
-               element-type:
-                 class: string
-             third:
-               class: int
-               size: 18
-             guard:
-               class: array
-               length: clover.oval
-               element-type:
-                 class: string
-             one:
-               class: array
-               length: iron.fire.word
-               element-type:
-                 class: string
-         cats:
-           class: int
-           size: 55
-         loud:
-           class: struct
-           fields:
-             toys:
-               class: array
-               length: trace.packet.header.iron.fire.word
-               element-type:
-                 class: string
-             spoon:
-               class: array
-               length: stream.packet.context.clover.oval
-               element-type:
-                 class: string
-             turkey:
-               class: array
-               length: stream.event.header.action.special
-               element-type:
-                 class: string
-             inform:
-               class: array
-               length: stream.event.context.face.magic
-               element-type:
-                 class: string
-             odd:
-               class: array
-               length: berry.third
-               element-type:
-                 class: string
-             amuck:
-               class: array
-               length: event.context.film
-               element-type:
-                 class: string
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_film = NULL;
-       struct bt_field_type *root_berry = NULL;
-       struct bt_field_type *root_berry_pine = NULL;
-       struct bt_field_type *root_berry_pine_elem = NULL;
-       struct bt_field_type *root_berry_porter = NULL;
-       struct bt_field_type *root_berry_porter_elem = NULL;
-       struct bt_field_type *root_berry_mice = NULL;
-       struct bt_field_type *root_berry_mice_elem = NULL;
-       struct bt_field_type *root_berry_third = NULL;
-       struct bt_field_type *root_berry_guard = NULL;
-       struct bt_field_type *root_berry_guard_elem = NULL;
-       struct bt_field_type *root_berry_one = NULL;
-       struct bt_field_type *root_berry_one_elem = NULL;
-       struct bt_field_type *root_cats = NULL;
-       struct bt_field_type *root_loud = NULL;
-       struct bt_field_type *root_loud_toys = NULL;
-       struct bt_field_type *root_loud_toys_elem = NULL;
-       struct bt_field_type *root_loud_spoon = NULL;
-       struct bt_field_type *root_loud_spoon_elem = NULL;
-       struct bt_field_type *root_loud_turkey = NULL;
-       struct bt_field_type *root_loud_turkey_elem = NULL;
-       struct bt_field_type *root_loud_inform = NULL;
-       struct bt_field_type *root_loud_inform_elem = NULL;
-       struct bt_field_type *root_loud_odd = NULL;
-       struct bt_field_type *root_loud_odd_elem = NULL;
-       struct bt_field_type *root_loud_amuck = NULL;
-       struct bt_field_type *root_loud_amuck_elem = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_film = bt_field_type_integer_create(19);
-       BT_ASSERT(root_film);
-       ret = bt_field_type_integer_set_is_signed(root_film, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_film, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_film, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_film, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_film, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_film, "film");
-       BT_ASSERT(ret == 0);
-       root_berry = bt_field_type_structure_create();
-       BT_ASSERT(root_berry);
-       ret = bt_field_type_set_alignment(root_berry, 8);
-       BT_ASSERT(ret == 0);
-       root_berry_pine_elem = bt_field_type_string_create();
-       BT_ASSERT(root_berry_pine_elem);
-       ret = bt_field_type_string_set_encoding(root_berry_pine_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_berry_pine = bt_field_type_sequence_create(root_berry_pine_elem, "stream_id");
-       BT_ASSERT(root_berry_pine);
-       ret = bt_field_type_structure_add_field(root_berry, root_berry_pine, "pine");
-       BT_ASSERT(ret == 0);
-       root_berry_porter_elem = bt_field_type_string_create();
-       BT_ASSERT(root_berry_porter_elem);
-       ret = bt_field_type_string_set_encoding(root_berry_porter_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_berry_porter = bt_field_type_sequence_create(root_berry_porter_elem, "face.magic");
-       BT_ASSERT(root_berry_porter);
-       ret = bt_field_type_structure_add_field(root_berry, root_berry_porter, "porter");
-       BT_ASSERT(ret == 0);
-       root_berry_mice_elem = bt_field_type_string_create();
-       BT_ASSERT(root_berry_mice_elem);
-       ret = bt_field_type_string_set_encoding(root_berry_mice_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_berry_mice = bt_field_type_sequence_create(root_berry_mice_elem, "action.special");
-       BT_ASSERT(root_berry_mice);
-       ret = bt_field_type_structure_add_field(root_berry, root_berry_mice, "mice");
-       BT_ASSERT(ret == 0);
-       root_berry_third = bt_field_type_integer_create(18);
-       BT_ASSERT(root_berry_third);
-       ret = bt_field_type_integer_set_is_signed(root_berry_third, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_berry_third, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_berry_third, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_berry_third, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_berry_third, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root_berry, root_berry_third, "third");
-       BT_ASSERT(ret == 0);
-       root_berry_guard_elem = bt_field_type_string_create();
-       BT_ASSERT(root_berry_guard_elem);
-       ret = bt_field_type_string_set_encoding(root_berry_guard_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_berry_guard = bt_field_type_sequence_create(root_berry_guard_elem, "clover.oval");
-       BT_ASSERT(root_berry_guard);
-       ret = bt_field_type_structure_add_field(root_berry, root_berry_guard, "guard");
-       BT_ASSERT(ret == 0);
-       root_berry_one_elem = bt_field_type_string_create();
-       BT_ASSERT(root_berry_one_elem);
-       ret = bt_field_type_string_set_encoding(root_berry_one_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_berry_one = bt_field_type_sequence_create(root_berry_one_elem, "iron.fire.word");
-       BT_ASSERT(root_berry_one);
-       ret = bt_field_type_structure_add_field(root_berry, root_berry_one, "one");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_berry, "berry");
-       BT_ASSERT(ret == 0);
-       root_cats = bt_field_type_integer_create(55);
-       BT_ASSERT(root_cats);
-       ret = bt_field_type_integer_set_is_signed(root_cats, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_cats, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_cats, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_cats, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_cats, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_cats, "cats");
-       BT_ASSERT(ret == 0);
-       root_loud = bt_field_type_structure_create();
-       BT_ASSERT(root_loud);
-       ret = bt_field_type_set_alignment(root_loud, 8);
-       BT_ASSERT(ret == 0);
-       root_loud_toys_elem = bt_field_type_string_create();
-       BT_ASSERT(root_loud_toys_elem);
-       ret = bt_field_type_string_set_encoding(root_loud_toys_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_loud_toys = bt_field_type_sequence_create(root_loud_toys_elem, "trace.packet.header.iron.fire.word");
-       BT_ASSERT(root_loud_toys);
-       ret = bt_field_type_structure_add_field(root_loud, root_loud_toys, "toys");
-       BT_ASSERT(ret == 0);
-       root_loud_spoon_elem = bt_field_type_string_create();
-       BT_ASSERT(root_loud_spoon_elem);
-       ret = bt_field_type_string_set_encoding(root_loud_spoon_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_loud_spoon = bt_field_type_sequence_create(root_loud_spoon_elem, "stream.packet.context.clover.oval");
-       BT_ASSERT(root_loud_spoon);
-       ret = bt_field_type_structure_add_field(root_loud, root_loud_spoon, "spoon");
-       BT_ASSERT(ret == 0);
-       root_loud_turkey_elem = bt_field_type_string_create();
-       BT_ASSERT(root_loud_turkey_elem);
-       ret = bt_field_type_string_set_encoding(root_loud_turkey_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_loud_turkey = bt_field_type_sequence_create(root_loud_turkey_elem, "stream.event.header.action.special");
-       BT_ASSERT(root_loud_turkey);
-       ret = bt_field_type_structure_add_field(root_loud, root_loud_turkey, "turkey");
-       BT_ASSERT(ret == 0);
-       root_loud_inform_elem = bt_field_type_string_create();
-       BT_ASSERT(root_loud_inform_elem);
-       ret = bt_field_type_string_set_encoding(root_loud_inform_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_loud_inform = bt_field_type_sequence_create(root_loud_inform_elem, "stream.event.context.face.magic");
-       BT_ASSERT(root_loud_inform);
-       ret = bt_field_type_structure_add_field(root_loud, root_loud_inform, "inform");
-       BT_ASSERT(ret == 0);
-       root_loud_odd_elem = bt_field_type_string_create();
-       BT_ASSERT(root_loud_odd_elem);
-       ret = bt_field_type_string_set_encoding(root_loud_odd_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_loud_odd = bt_field_type_sequence_create(root_loud_odd_elem, "berry.third");
-       BT_ASSERT(root_loud_odd);
-       ret = bt_field_type_structure_add_field(root_loud, root_loud_odd, "odd");
-       BT_ASSERT(ret == 0);
-       root_loud_amuck_elem = bt_field_type_string_create();
-       BT_ASSERT(root_loud_amuck_elem);
-       ret = bt_field_type_string_set_encoding(root_loud_amuck_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_loud_amuck = bt_field_type_sequence_create(root_loud_amuck_elem, "event.context.film");
-       BT_ASSERT(root_loud_amuck);
-       ret = bt_field_type_structure_add_field(root_loud, root_loud_amuck, "amuck");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_loud, "loud");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_film);
-       BT_PUT(root_berry);
-       BT_PUT(root_berry_pine);
-       BT_PUT(root_berry_pine_elem);
-       BT_PUT(root_berry_porter);
-       BT_PUT(root_berry_porter_elem);
-       BT_PUT(root_berry_mice);
-       BT_PUT(root_berry_mice_elem);
-       BT_PUT(root_berry_third);
-       BT_PUT(root_berry_guard);
-       BT_PUT(root_berry_guard_elem);
-       BT_PUT(root_berry_one);
-       BT_PUT(root_berry_one_elem);
-       BT_PUT(root_cats);
-       BT_PUT(root_loud);
-       BT_PUT(root_loud_toys);
-       BT_PUT(root_loud_toys_elem);
-       BT_PUT(root_loud_spoon);
-       BT_PUT(root_loud_spoon_elem);
-       BT_PUT(root_loud_turkey);
-       BT_PUT(root_loud_turkey_elem);
-       BT_PUT(root_loud_inform);
-       BT_PUT(root_loud_inform_elem);
-       BT_PUT(root_loud_odd);
-       BT_PUT(root_loud_odd_elem);
-       BT_PUT(root_loud_amuck);
-       BT_PUT(root_loud_amuck_elem);
-
-       return root;
-}
-
-static
-struct bt_field_type *get_good_event_payload_field_type(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         splendid:
-           class: int
-           size: 12
-         relative:
-           class: struct
-           fields:
-             equal:
-               class: array
-               length: splendid
-               element-type:
-                 class: string
-             amuck:
-               class: array
-               length: cats
-               element-type:
-                 class: string
-             push:
-               class: array
-               length: berry.third
-               element-type:
-                 class: string
-             brick:
-               class: array
-               length: face.magic
-               element-type:
-                 class: string
-             amuck:
-               class: array
-               length: id
-               element-type:
-                 class: string
-             crush:
-               class: array
-               length: serious
-               element-type:
-                 class: string
-             canvas:
-               class: array
-               length: iron.dust
-               element-type:
-                 class: string
-         absolute:
-           class: struct
-           fields:
-             equal:
-               class: array
-               length: event.fields.splendid
-               element-type:
-                 class: string
-             amuck:
-               class: array
-               length: event.context.cats
-               element-type:
-                 class: string
-             push:
-               class: array
-               length: event.context.berry.third
-               element-type:
-                 class: string
-             brick:
-               class: array
-               length: stream.event.context.face.magic
-               element-type:
-                 class: string
-             amuck:
-               class: array
-               length: stream.event.header.id
-               element-type:
-                 class: string
-             crush:
-               class: array
-               length: stream.packet.context.serious
-               element-type:
-                 class: string
-             canvas:
-               class: array
-               length: trace.packet.header.iron.dust
-               element-type:
-                 class: string
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_splendid = NULL;
-       struct bt_field_type *root_relative = NULL;
-       struct bt_field_type *root_relative_equal = NULL;
-       struct bt_field_type *root_relative_equal_elem = NULL;
-       struct bt_field_type *root_relative_amuck = NULL;
-       struct bt_field_type *root_relative_amuck_elem = NULL;
-       struct bt_field_type *root_relative_push = NULL;
-       struct bt_field_type *root_relative_push_elem = NULL;
-       struct bt_field_type *root_relative_brick = NULL;
-       struct bt_field_type *root_relative_brick_elem = NULL;
-       struct bt_field_type *root_relative_crush = NULL;
-       struct bt_field_type *root_relative_crush_elem = NULL;
-       struct bt_field_type *root_relative_canvas = NULL;
-       struct bt_field_type *root_relative_canvas_elem = NULL;
-       struct bt_field_type *root_absolute = NULL;
-       struct bt_field_type *root_absolute_equal = NULL;
-       struct bt_field_type *root_absolute_equal_elem = NULL;
-       struct bt_field_type *root_absolute_amuck = NULL;
-       struct bt_field_type *root_absolute_amuck_elem = NULL;
-       struct bt_field_type *root_absolute_push = NULL;
-       struct bt_field_type *root_absolute_push_elem = NULL;
-       struct bt_field_type *root_absolute_brick = NULL;
-       struct bt_field_type *root_absolute_brick_elem = NULL;
-       struct bt_field_type *root_absolute_crush = NULL;
-       struct bt_field_type *root_absolute_crush_elem = NULL;
-       struct bt_field_type *root_absolute_canvas = NULL;
-       struct bt_field_type *root_absolute_canvas_elem = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_splendid = bt_field_type_integer_create(12);
-       BT_ASSERT(root_splendid);
-       ret = bt_field_type_integer_set_is_signed(root_splendid, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_splendid, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_splendid, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_splendid, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_splendid, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_splendid, "splendid");
-       BT_ASSERT(ret == 0);
-       root_relative = bt_field_type_structure_create();
-       BT_ASSERT(root_relative);
-       ret = bt_field_type_set_alignment(root_relative, 8);
-       BT_ASSERT(ret == 0);
-       root_relative_equal_elem = bt_field_type_string_create();
-       BT_ASSERT(root_relative_equal_elem);
-       ret = bt_field_type_string_set_encoding(root_relative_equal_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_relative_equal = bt_field_type_sequence_create(root_relative_equal_elem, "splendid");
-       BT_ASSERT(root_relative_equal);
-       ret = bt_field_type_structure_add_field(root_relative, root_relative_equal, "equal");
-       BT_ASSERT(ret == 0);
-       root_relative_amuck_elem = bt_field_type_string_create();
-       BT_ASSERT(root_relative_amuck_elem);
-       ret = bt_field_type_string_set_encoding(root_relative_amuck_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_relative_amuck = bt_field_type_sequence_create(root_relative_amuck_elem, "id");
-       BT_ASSERT(root_relative_amuck);
-       ret = bt_field_type_structure_add_field(root_relative, root_relative_amuck, "amuck");
-       BT_ASSERT(ret == 0);
-       root_relative_push_elem = bt_field_type_string_create();
-       BT_ASSERT(root_relative_push_elem);
-       ret = bt_field_type_string_set_encoding(root_relative_push_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_relative_push = bt_field_type_sequence_create(root_relative_push_elem, "berry.third");
-       BT_ASSERT(root_relative_push);
-       ret = bt_field_type_structure_add_field(root_relative, root_relative_push, "push");
-       BT_ASSERT(ret == 0);
-       root_relative_brick_elem = bt_field_type_string_create();
-       BT_ASSERT(root_relative_brick_elem);
-       ret = bt_field_type_string_set_encoding(root_relative_brick_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_relative_brick = bt_field_type_sequence_create(root_relative_brick_elem, "face.magic");
-       BT_ASSERT(root_relative_brick);
-       ret = bt_field_type_structure_add_field(root_relative, root_relative_brick, "brick");
-       BT_ASSERT(ret == 0);
-       root_relative_crush_elem = bt_field_type_string_create();
-       BT_ASSERT(root_relative_crush_elem);
-       ret = bt_field_type_string_set_encoding(root_relative_crush_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_relative_crush = bt_field_type_sequence_create(root_relative_crush_elem, "serious");
-       BT_ASSERT(root_relative_crush);
-       ret = bt_field_type_structure_add_field(root_relative, root_relative_crush, "crush");
-       BT_ASSERT(ret == 0);
-       root_relative_canvas_elem = bt_field_type_string_create();
-       BT_ASSERT(root_relative_canvas_elem);
-       ret = bt_field_type_string_set_encoding(root_relative_canvas_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_relative_canvas = bt_field_type_sequence_create(root_relative_canvas_elem, "iron.dust");
-       BT_ASSERT(root_relative_canvas);
-       ret = bt_field_type_structure_add_field(root_relative, root_relative_canvas, "canvas");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_relative, "relative");
-       BT_ASSERT(ret == 0);
-       root_absolute = bt_field_type_structure_create();
-       BT_ASSERT(root_absolute);
-       ret = bt_field_type_set_alignment(root_absolute, 8);
-       BT_ASSERT(ret == 0);
-       root_absolute_equal_elem = bt_field_type_string_create();
-       BT_ASSERT(root_absolute_equal_elem);
-       ret = bt_field_type_string_set_encoding(root_absolute_equal_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_absolute_equal = bt_field_type_sequence_create(root_absolute_equal_elem, "event.fields.splendid");
-       BT_ASSERT(root_absolute_equal);
-       ret = bt_field_type_structure_add_field(root_absolute, root_absolute_equal, "equal");
-       BT_ASSERT(ret == 0);
-       root_absolute_amuck_elem = bt_field_type_string_create();
-       BT_ASSERT(root_absolute_amuck_elem);
-       ret = bt_field_type_string_set_encoding(root_absolute_amuck_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_absolute_amuck = bt_field_type_sequence_create(root_absolute_amuck_elem, "stream.event.header.id");
-       BT_ASSERT(root_absolute_amuck);
-       ret = bt_field_type_structure_add_field(root_absolute, root_absolute_amuck, "amuck");
-       BT_ASSERT(ret == 0);
-       root_absolute_push_elem = bt_field_type_string_create();
-       BT_ASSERT(root_absolute_push_elem);
-       ret = bt_field_type_string_set_encoding(root_absolute_push_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_absolute_push = bt_field_type_sequence_create(root_absolute_push_elem, "event.context.berry.third");
-       BT_ASSERT(root_absolute_push);
-       ret = bt_field_type_structure_add_field(root_absolute, root_absolute_push, "push");
-       BT_ASSERT(ret == 0);
-       root_absolute_brick_elem = bt_field_type_string_create();
-       BT_ASSERT(root_absolute_brick_elem);
-       ret = bt_field_type_string_set_encoding(root_absolute_brick_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_absolute_brick = bt_field_type_sequence_create(root_absolute_brick_elem, "stream.event.context.face.magic");
-       BT_ASSERT(root_absolute_brick);
-       ret = bt_field_type_structure_add_field(root_absolute, root_absolute_brick, "brick");
-       BT_ASSERT(ret == 0);
-       root_absolute_crush_elem = bt_field_type_string_create();
-       BT_ASSERT(root_absolute_crush_elem);
-       ret = bt_field_type_string_set_encoding(root_absolute_crush_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_absolute_crush = bt_field_type_sequence_create(root_absolute_crush_elem, "stream.packet.context.serious");
-       BT_ASSERT(root_absolute_crush);
-       ret = bt_field_type_structure_add_field(root_absolute, root_absolute_crush, "crush");
-       BT_ASSERT(ret == 0);
-       root_absolute_canvas_elem = bt_field_type_string_create();
-       BT_ASSERT(root_absolute_canvas_elem);
-       ret = bt_field_type_string_set_encoding(root_absolute_canvas_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_absolute_canvas = bt_field_type_sequence_create(root_absolute_canvas_elem, "trace.packet.header.iron.dust");
-       BT_ASSERT(root_absolute_canvas);
-       ret = bt_field_type_structure_add_field(root_absolute, root_absolute_canvas, "canvas");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_absolute, "absolute");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_splendid);
-       BT_PUT(root_relative);
-       BT_PUT(root_relative_equal);
-       BT_PUT(root_relative_equal_elem);
-       BT_PUT(root_relative_amuck);
-       BT_PUT(root_relative_amuck_elem);
-       BT_PUT(root_relative_push);
-       BT_PUT(root_relative_push_elem);
-       BT_PUT(root_relative_brick);
-       BT_PUT(root_relative_brick_elem);
-       BT_PUT(root_relative_crush);
-       BT_PUT(root_relative_crush_elem);
-       BT_PUT(root_relative_canvas);
-       BT_PUT(root_relative_canvas_elem);
-       BT_PUT(root_absolute);
-       BT_PUT(root_absolute_equal);
-       BT_PUT(root_absolute_equal_elem);
-       BT_PUT(root_absolute_amuck);
-       BT_PUT(root_absolute_amuck_elem);
-       BT_PUT(root_absolute_push);
-       BT_PUT(root_absolute_push_elem);
-       BT_PUT(root_absolute_brick);
-       BT_PUT(root_absolute_brick_elem);
-       BT_PUT(root_absolute_crush);
-       BT_PUT(root_absolute_crush_elem);
-       BT_PUT(root_absolute_canvas);
-       BT_PUT(root_absolute_canvas_elem);
-
-       return root;
-}
-
-static
-struct bt_field_type *get_child_ft(struct bt_field_type *parent_ft,
-               const char *name)
-{
-       struct bt_field_type *ft = NULL;
-
-       switch (bt_field_type_get_type_id(parent_ft)) {
-       case BT_FIELD_TYPE_ID_STRUCT:
-               ft = bt_field_type_structure_get_field_type_by_name(
-                       parent_ft, name);
-               break;
-
-       case BT_FIELD_TYPE_ID_VARIANT:
-               ft = bt_field_type_variant_get_field_type_by_name(
-                       parent_ft, name);
-               break;
-
-       case BT_FIELD_TYPE_ID_ARRAY:
-               ft = bt_field_type_array_get_element_field_type(parent_ft);
-               break;
-
-       case BT_FIELD_TYPE_ID_SEQUENCE:
-               ft = bt_field_type_sequence_get_element_field_type(parent_ft);
-               break;
-
-       case BT_FIELD_TYPE_ID_ENUM:
-               ft = bt_field_type_enumeration_get_container_field_type(
-                       parent_ft);
-               break;
-
-       default:
-               break;
-       }
-
-       BT_ASSERT(ft);
-
-       return ft;
-}
-
-static
-struct bt_field_type *get_ft(struct bt_field_type *root_ft, ...)
-{
-       struct bt_field_type *child_ft = NULL;
-       struct bt_field_type *ft = root_ft;
-       va_list ap;
-
-       va_start(ap, root_ft);
-       bt_get(ft);
-
-       while (true) {
-               const char *field_name = va_arg(ap, const char *);
-
-               if (field_name == NULL) {
-                       break;
-               }
-
-               child_ft = get_child_ft(ft, field_name);
-
-               if (!child_ft) {
-                       BT_PUT(ft);
-                       goto end;
-               }
-
-               BT_MOVE(ft, child_ft);
-       }
-
-end:
-       va_end(ap);
-
-       return ft;
-}
-
-#define FIELD_PATH_END -2
-
-static
-int validate_field_path(struct bt_field_type *field_type, int int_root, ...)
-{
-       enum bt_scope root = int_root;
-       int ret = 0;
-       int len;
-       int expected_index;
-       int actual_index;
-       int i = 0;
-       struct bt_field_path *field_path = NULL;
-       va_list ap;
-
-       va_start(ap, int_root);
-       if (bt_field_type_is_sequence(field_type)) {
-               field_path = bt_field_type_sequence_get_length_field_path(
-                               field_type);
-       } else if (bt_field_type_is_variant(field_type)) {
-               field_path = bt_field_type_variant_get_tag_field_path(
-                               field_type);
-       }
-
-       if (!field_path) {
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_field_path_get_root_scope(field_path) != root) {
-               ret = -1;
-               goto end;
-       }
-
-       len = bt_field_path_get_index_count(field_path);
-
-       while (true) {
-               expected_index = va_arg(ap, int);
-
-               if (expected_index == FIELD_PATH_END) {
-                       break;
-               }
-
-               if (i == len) {
-                       break;
-               }
-
-               actual_index = bt_field_path_get_index(field_path, i);
-
-               if (actual_index == INT_MIN) {
-                       ret = -1;
-                       goto end;
-               }
-
-               i++;
-       }
-
-       if (i != len || expected_index != FIELD_PATH_END) {
-               ret = -1;
-       }
-
-end:
-       BT_PUT(field_path);
-       va_end(ap);
-
-       return ret;
-}
-
-static
-void validate_test_pass(struct bt_trace *trace)
-{
-       struct bt_stream_class *sc;
-       struct bt_event_class *ec;
-       struct bt_field_type *ph;
-       struct bt_field_type *pc;
-       struct bt_field_type *eh;
-       struct bt_field_type *sec;
-       struct bt_field_type *ectx;
-       struct bt_field_type *ep;
-       struct bt_field_type *ft_src = NULL;
-       struct bt_field_type *ft_target = NULL;
-       struct bt_field_type *ft_tag = NULL;
-
-       sc = bt_trace_get_stream_class_by_index(trace, 0);
-       BT_ASSERT(sc);
-       ec = bt_stream_class_get_event_class_by_index(sc, 0);
-       BT_ASSERT(ec);
-
-       ph = bt_trace_get_packet_header_field_type(trace);
-       ok(ph, "Trace packet header still exists after successful validation");
-       pc = bt_stream_class_get_packet_context_field_type(sc);
-       ok(pc, "Stream packet context still exists after successful validation");
-       eh = bt_stream_class_get_event_header_field_type(sc);
-       ok(eh, "Stream event header still exists after successful validation");
-       sec = bt_stream_class_get_event_context_field_type(sc);
-       ok(sec, "Stream event context still exists after successful validation");
-       ectx = bt_event_class_get_context_field_type(ec);
-       ok(ectx, "Event context still exists after successful validation");
-       ep = bt_event_class_get_payload_field_type(ec);
-       ok(ep, "Event payload still exists after successful validation");
-
-       /* trace.packet.header.iron.fire.keen */
-       ft_src = get_ft(ph, "iron", "fire", "keen", NULL);
-       ok(!validate_field_path(ft_src, BT_SCOPE_TRACE_PACKET_HEADER,
-               3, 3, 0, FIELD_PATH_END),
-               "trace.packet.header.iron.fire.keen has the correct field path");
-       BT_PUT(ft_src);
-
-       /* trace.packet.header.iron.fire.keen.[element] */
-       ft_src = get_ft(ph, "iron", "fire", "keen", "", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 2, FIELD_PATH_END),
-               "trace.packet.header.iron.fire.keen.[element] has the correct field path");
-       ft_target = get_ft(ph, "iron", "parallel", NULL);
-       ft_tag = bt_field_type_variant_get_tag_field_type(ft_src);
-       ok(ft_tag == ft_target,
-               "trace.packet.header.iron.fire.keen.[element] has the correct tag type");
-       BT_PUT(ft_src);
-       BT_PUT(ft_target);
-       BT_PUT(ft_tag);
-
-       /* trace.packet.header.iron.fire.keen.[element].BLUE */
-       ft_src = get_ft(ph, "iron", "fire", "keen", "", "BLUE", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 0, FIELD_PATH_END),
-               "trace.packet.header.iron.fire.keen.[element].BLUE has the correct field path");
-       BT_PUT(ft_src);
-
-       /* trace.packet.header.iron.report */
-       ft_src = get_ft(ph, "iron", "report", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 1, FIELD_PATH_END),
-               "trace.packet.header.iron.report has the correct field path");
-       BT_PUT(ft_src);
-
-       /* trace.packet.header.iron.group */
-       ft_src = get_ft(ph, "iron", "group", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 2, FIELD_PATH_END),
-               "trace.packet.header.iron.group has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.packet.context.naive.[element] */
-       ft_src = get_ft(pc, "naive", "", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 0, FIELD_PATH_END),
-               "stream.packet.context.naive.[element] has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.packet.context.clover.whole */
-       ft_src = get_ft(pc, "clover", "whole", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 2, FIELD_PATH_END),
-               "stream.packet.context.clover.whole has the correct field path");
-       ft_target = get_ft(ph, "iron", "parallel", NULL);
-       ft_tag = bt_field_type_variant_get_tag_field_type(ft_src);
-       ok(ft_tag == ft_target,
-               "stream.packet.context.clover.whole has the correct tag type");
-       BT_PUT(ft_src);
-       BT_PUT(ft_target);
-       BT_PUT(ft_tag);
-
-       /* stream.packet.context.clover.whole.BLUE */
-       ft_src = get_ft(pc, "clover", "whole", "BLUE", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 3, 0, FIELD_PATH_END),
-               "stream.packet.context.clover.whole.BLUE has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.packet.context.clover.egg */
-       ft_src = get_ft(pc, "clover", "egg", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 4, 0, FIELD_PATH_END),
-               "stream.packet.context.clover.egg has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.packet.context.clover.useful */
-       ft_src = get_ft(pc, "clover", "useful", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 2, FIELD_PATH_END),
-               "stream.packet.context.clover.useful has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.header.action.lucky */
-       ft_src = get_ft(eh, "action", "lucky", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 0, FIELD_PATH_END),
-               "stream.event.header.action.lucky has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.header.stiff */
-       ft_src = get_ft(eh, "stiff", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 4, 1, 1, FIELD_PATH_END),
-               "stream.event.header.stiff has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.header.fruit.apple */
-       ft_src = get_ft(eh, "fruit", "apple", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_HEADER, 2, 0, FIELD_PATH_END),
-               "stream.event.header.fruit.apple has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.context.face.branch */
-       ft_src = get_ft(sec, "face", "branch", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 2, FIELD_PATH_END),
-               "stream.event.context.face.branch has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.context.face.income */
-       ft_src = get_ft(sec, "face", "income", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 0, FIELD_PATH_END),
-               "stream.event.context.face.income has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.context.face.lucky */
-       ft_src = get_ft(sec, "face", "lucky", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_CONTEXT, 0, 2, FIELD_PATH_END),
-               "stream.event.context.face.lucky has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.context.dream */
-       ft_src = get_ft(sec, "dream", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 0, FIELD_PATH_END),
-               "stream.event.context.dream has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.context.dream.[element] */
-       ft_src = get_ft(sec, "dream", "", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 1, FIELD_PATH_END),
-               "stream.event.context.dream.[element] has the correct field path");
-       BT_PUT(ft_src);
-
-       /* stream.event.context.dream.[element].[element] */
-       ft_src = get_ft(sec, "dream", "", "", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_CONTEXT, 0, 2, FIELD_PATH_END),
-               "stream.event.context.dream.[element].[element] has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.berry.porter */
-       ft_src = get_ft(ectx, "berry", "porter", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_CONTEXT, 0, 2, FIELD_PATH_END),
-               "event.context.berry.porter has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.berry.porter */
-       ft_src = get_ft(ectx, "berry", "porter", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_CONTEXT, 0, 2, FIELD_PATH_END),
-               "event.context.berry.porter has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.berry.mice */
-       ft_src = get_ft(ectx, "berry", "mice", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_HEADER, 2, 0, FIELD_PATH_END),
-               "event.context.berry.mice has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.berry.guard */
-       ft_src = get_ft(ectx, "berry", "guard", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 4, 0, FIELD_PATH_END),
-               "event.context.berry.guard has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.berry.one */
-       ft_src = get_ft(ectx, "berry", "one", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 3, 0, FIELD_PATH_END),
-               "event.context.berry.one has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.loud.toys */
-       ft_src = get_ft(ectx, "loud", "toys", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 3, 0, FIELD_PATH_END),
-               "event.context.loud.toys has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.loud.spoon */
-       ft_src = get_ft(ectx, "loud", "spoon", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 4, 0, FIELD_PATH_END),
-               "event.context.loud.spoon has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.loud.turkey */
-       ft_src = get_ft(ectx, "loud", "turkey", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_HEADER, 2, 0, FIELD_PATH_END),
-               "event.context.loud.turkey has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.loud.inform */
-       ft_src = get_ft(ectx, "loud", "inform", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_CONTEXT, 0, 2, FIELD_PATH_END),
-               "event.context.loud.inform has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.loud.odd */
-       ft_src = get_ft(ectx, "loud", "odd", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_EVENT_CONTEXT, 1, 3, FIELD_PATH_END),
-               "event.context.loud.odd has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.context.loud.amuck */
-       ft_src = get_ft(ectx, "loud", "amuck", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_EVENT_CONTEXT, 0, FIELD_PATH_END),
-               "event.context.loud.amuck has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.relative.equal */
-       ft_src = get_ft(ep, "relative", "equal", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_EVENT_FIELDS, 0, FIELD_PATH_END),
-               "event.fields.relative.equal has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.relative.amuck */
-       ft_src = get_ft(ep, "relative", "amuck", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_HEADER, 0, FIELD_PATH_END),
-               "event.fields.relative.amuck has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.relative.push */
-       ft_src = get_ft(ep, "relative", "push", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_EVENT_CONTEXT, 1, 3, FIELD_PATH_END),
-               "event.fields.relative.push has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.relative.brick */
-       ft_src = get_ft(ep, "relative", "brick", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_CONTEXT, 0, 2, FIELD_PATH_END),
-               "event.fields.relative.brick has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.relative.crush */
-       ft_src = get_ft(ep, "relative", "crush", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 2, FIELD_PATH_END),
-               "event.fields.relative.crush has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.relative.canvas */
-       ft_src = get_ft(ep, "relative", "canvas", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 1, FIELD_PATH_END),
-               "event.fields.relative.canvas has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.absolute.equal */
-       ft_src = get_ft(ep, "absolute", "equal", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_EVENT_FIELDS, 0, FIELD_PATH_END),
-               "event.fields.absolute.equal has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.absolute.amuck */
-       ft_src = get_ft(ep, "absolute", "amuck", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_HEADER, 0, FIELD_PATH_END),
-               "event.fields.absolute.amuck has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.absolute.push */
-       ft_src = get_ft(ep, "absolute", "push", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_EVENT_CONTEXT, 1, 3, FIELD_PATH_END),
-               "event.fields.absolute.push has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.absolute.brick */
-       ft_src = get_ft(ep, "absolute", "brick", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_EVENT_CONTEXT, 0, 2, FIELD_PATH_END),
-               "event.fields.absolute.brick has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.absolute.crush */
-       ft_src = get_ft(ep, "absolute", "crush", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_STREAM_PACKET_CONTEXT, 2, FIELD_PATH_END),
-               "event.fields.absolute.crush has the correct field path");
-       BT_PUT(ft_src);
-
-       /* event.fields.absolute.canvas */
-       ft_src = get_ft(ep, "absolute", "canvas", NULL);
-       ok(!validate_field_path(ft_src,
-               BT_SCOPE_TRACE_PACKET_HEADER, 3, 1, FIELD_PATH_END),
-               "event.fields.absolute.canvas has the correct field path");
-       BT_PUT(ft_src);
-
-       BT_PUT(ft_src);
-       BT_PUT(ft_target);
-       BT_PUT(ph);
-       BT_PUT(pc);
-       BT_PUT(eh);
-       BT_PUT(sec);
-       BT_PUT(ectx);
-       BT_PUT(ep);
-       BT_PUT(sc);
-       BT_PUT(ec);
-}
-
-static
-void test_pass(void)
-{
-       int ret;
-       struct bt_trace *trace;
-       struct bt_stream_class *sc;
-       struct bt_event_class *ec;
-       struct bt_field_type *ph;
-       struct bt_field_type *pc;
-       struct bt_field_type *eh;
-       struct bt_field_type *sec;
-       struct bt_field_type *ectx;
-       struct bt_field_type *ep;
-
-       trace = bt_trace_create();
-       BT_ASSERT(trace);
-       sc = bt_stream_class_create("nice_piece_of_stream_class");
-       BT_ASSERT(sc);
-       ec = bt_event_class_create("oh_what_an_event_class");
-       BT_ASSERT(ec);
-
-       ph = get_good_packet_header_field_type();
-       BT_ASSERT(ph);
-       pc = get_good_packet_context_field_type();
-       BT_ASSERT(pc);
-       eh = get_good_event_header_field_type();
-       BT_ASSERT(eh);
-       sec = get_good_stream_event_context_field_type();
-       BT_ASSERT(sec);
-       ectx = get_good_event_context_field_type();
-       BT_ASSERT(ec);
-       ep = get_good_event_payload_field_type();
-       BT_ASSERT(ep);
-
-       ret = bt_trace_set_packet_header_field_type(trace, ph);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_set_packet_context_field_type(sc, pc);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_set_event_header_field_type(sc, eh);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_set_event_context_field_type(sc, sec);
-       BT_ASSERT(ret == 0);
-       ret = bt_event_class_set_context_field_type(ec, ectx);
-       BT_ASSERT(ret == 0);
-       ret = bt_event_class_set_payload_field_type(ec, ep);
-       BT_ASSERT(ret == 0);
-
-       ret = bt_stream_class_add_event_class(sc, ec);
-       BT_ASSERT(ret == 0);
-
-       /* Validation happens here */
-       ret = bt_trace_add_stream_class(trace, sc);
-       ok(ret == 0, "Valid type system is considered valid");
-
-       validate_test_pass(trace);
-
-       BT_PUT(ph);
-       BT_PUT(pc);
-       BT_PUT(eh);
-       BT_PUT(sec);
-       BT_PUT(ectx);
-       BT_PUT(ep);
-       BT_PUT(trace);
-       BT_PUT(sc);
-       BT_PUT(ec);
-}
-
-static
-int try_add_event_class_to_trace(struct bt_field_type *ectx,
-               struct bt_field_type *ep)
-{
-       int ret;
-       struct bt_trace *trace;
-       struct bt_stream_class *sc;
-       struct bt_event_class *ec;
-
-       trace = bt_trace_create();
-       BT_ASSERT(trace);
-       sc = bt_stream_class_create("sc");
-       BT_ASSERT(sc);
-       ec = bt_event_class_create("ec");
-       BT_ASSERT(ec);
-
-       if (ectx) {
-               ret = bt_event_class_set_context_field_type(ec, ectx);
-               BT_ASSERT(ret == 0);
-       }
-
-       if (ep) {
-               ret = bt_event_class_set_payload_field_type(ec, ep);
-               BT_ASSERT(ret == 0);
-       }
-
-       ret = bt_stream_class_add_event_class(sc, ec);
-       BT_ASSERT(ret == 0);
-       ret = bt_trace_add_stream_class(trace, sc);
-       BT_PUT(ec);
-       BT_PUT(sc);
-       BT_PUT(trace);
-       return ret;
-}
-
-static
-struct bt_field_type *test_fail_unavailable_root_get_event_payload(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: int
-           size: 32
-         b:
-           class: array
-           length: stream.event.context.lol
-           element-type:
-             class: string
-         c:
-           class: string
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_b = NULL;
-       struct bt_field_type *root_b_elem = NULL;
-       struct bt_field_type *root_c = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_integer_create(32);
-       BT_ASSERT(root_a);
-       ret = bt_field_type_integer_set_is_signed(root_a, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_a, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_a, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_a, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_a, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_b_elem = bt_field_type_string_create();
-       BT_ASSERT(root_b_elem);
-       ret = bt_field_type_string_set_encoding(root_b_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_b = bt_field_type_sequence_create(root_b_elem, "stream.event.context.lol");
-       BT_ASSERT(root_b);
-       ret = bt_field_type_structure_add_field(root, root_b, "b");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_b);
-       BT_PUT(root_b_elem);
-       BT_PUT(root_c);
-
-       return root;
-}
-
-static
-void test_fail_unavailable_root(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_unavailable_root_get_event_payload();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep),
-               "Sequence FT with length in unavailable root is invalid");
-
-       BT_PUT(ep);
-}
-
-static
-struct bt_field_type *test_fail_target_is_root_get_event_payload(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: int
-           size: 32
-         b:
-           class: array
-           length: event.fields
-           element-type:
-             class: string
-         c:
-           class: string
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_b = NULL;
-       struct bt_field_type *root_b_elem = NULL;
-       struct bt_field_type *root_c = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_integer_create(32);
-       BT_ASSERT(root_a);
-       ret = bt_field_type_integer_set_is_signed(root_a, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_a, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_a, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_a, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_a, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_b_elem = bt_field_type_string_create();
-       BT_ASSERT(root_b_elem);
-       ret = bt_field_type_string_set_encoding(root_b_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_b = bt_field_type_sequence_create(root_b_elem, "event.fields");
-       BT_ASSERT(root_b);
-       ret = bt_field_type_structure_add_field(root, root_b, "b");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_b);
-       BT_PUT(root_b_elem);
-       BT_PUT(root_c);
-
-       return root;
-}
-
-static
-void test_fail_target_is_root(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_target_is_root_get_event_payload();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep),
-               "Sequence FT with root as its length is invalid");
-       BT_PUT(ep);
-}
-
-static
-struct bt_field_type *test_fail_target_is_after_source_get_ep(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: int
-           size: 32
-         b:
-           class: array
-           length: d
-           element-type:
-             class: string
-         c:
-           class: string
-         d:
-           class: int
-           size: 17
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_b = NULL;
-       struct bt_field_type *root_b_elem = NULL;
-       struct bt_field_type *root_c = NULL;
-       struct bt_field_type *root_d = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_integer_create(32);
-       BT_ASSERT(root_a);
-       ret = bt_field_type_integer_set_is_signed(root_a, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_a, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_a, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_a, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_a, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_b_elem = bt_field_type_string_create();
-       BT_ASSERT(root_b_elem);
-       ret = bt_field_type_string_set_encoding(root_b_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_b = bt_field_type_sequence_create(root_b_elem, "d");
-       BT_ASSERT(root_b);
-       ret = bt_field_type_structure_add_field(root, root_b, "b");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-       root_d = bt_field_type_integer_create(17);
-       BT_ASSERT(root_d);
-       ret = bt_field_type_integer_set_is_signed(root_d, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_d, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_d, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_d, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_d, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_d, "d");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_b);
-       BT_PUT(root_b_elem);
-       BT_PUT(root_c);
-       BT_PUT(root_d);
-
-       return root;
-}
-
-static
-void test_fail_target_is_after_source(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_target_is_after_source_get_ep();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep),
-               "Sequence FT with length after it is invalid");
-       BT_PUT(ep);
-}
-
-static
-struct bt_field_type *test_fail_target_is_ancestor_of_source_get_ep(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: int
-           size: 32
-         z:
-           class: struct
-           fields:
-             b:
-               class: array
-               length: z
-               element-type:
-                 class: string
-         c:
-           class: string
-         d:
-           class: int
-           size: 17
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_z = NULL;
-       struct bt_field_type *root_z_b = NULL;
-       struct bt_field_type *root_z_b_elem = NULL;
-       struct bt_field_type *root_c = NULL;
-       struct bt_field_type *root_d = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_integer_create(32);
-       BT_ASSERT(root_a);
-       ret = bt_field_type_integer_set_is_signed(root_a, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_a, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_a, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_a, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_a, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_z = bt_field_type_structure_create();
-       BT_ASSERT(root_z);
-       ret = bt_field_type_set_alignment(root_z, 8);
-       BT_ASSERT(ret == 0);
-       root_z_b_elem = bt_field_type_string_create();
-       BT_ASSERT(root_z_b_elem);
-       ret = bt_field_type_string_set_encoding(root_z_b_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_z_b = bt_field_type_sequence_create(root_z_b_elem, "z");
-       BT_ASSERT(root_z_b);
-       ret = bt_field_type_structure_add_field(root_z, root_z_b, "b");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_z, "z");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-       root_d = bt_field_type_integer_create(17);
-       BT_ASSERT(root_d);
-       ret = bt_field_type_integer_set_is_signed(root_d, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_d, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_d, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_d, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_d, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_d, "d");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_z);
-       BT_PUT(root_z_b);
-       BT_PUT(root_z_b_elem);
-       BT_PUT(root_c);
-       BT_PUT(root_d);
-
-       return root;
-}
-
-static
-void test_fail_target_is_ancestor_of_source(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_target_is_ancestor_of_source_get_ep();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep),
-               "Sequence FT with ancestor as its length is invalid");
-       BT_PUT(ep);
-}
-
-static
-struct bt_field_type *test_fail_target_is_source_get_event_payload(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: int
-           size: 32
-         b:
-           class: array
-           length: event.fields.b
-           element-type:
-             class: string
-         c:
-           class: string
-         d:
-           class: int
-           size: 17
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_b = NULL;
-       struct bt_field_type *root_b_elem = NULL;
-       struct bt_field_type *root_c = NULL;
-       struct bt_field_type *root_d = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_integer_create(32);
-       BT_ASSERT(root_a);
-       ret = bt_field_type_integer_set_is_signed(root_a, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_a, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_a, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_a, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_a, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_b_elem = bt_field_type_string_create();
-       BT_ASSERT(root_b_elem);
-       ret = bt_field_type_string_set_encoding(root_b_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_b = bt_field_type_sequence_create(root_b_elem, "event.fields.b");
-       BT_ASSERT(root_b);
-       ret = bt_field_type_structure_add_field(root, root_b, "b");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-       root_d = bt_field_type_integer_create(17);
-       BT_ASSERT(root_d);
-       ret = bt_field_type_integer_set_is_signed(root_d, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_d, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_d, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_d, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_d, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_d, "d");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_b);
-       BT_PUT(root_b_elem);
-       BT_PUT(root_c);
-       BT_PUT(root_d);
-
-       return root;
-}
-
-static
-void test_fail_target_is_source(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_target_is_source_get_event_payload();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep),
-               "Sequence FT with itself as its length is invalid");
-       BT_PUT(ep);
-}
-
-static
-struct bt_field_type *test_fail_variant_tag_is_not_enum_get_ep(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: int
-           size: 32
-         b:
-           class: variant
-           tag: a
-           types:
-             HELLO:
-               class: string
-         c:
-           class: string
-         d:
-           class: int
-           size: 17
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_b = NULL;
-       struct bt_field_type *root_b_HELLO = NULL;
-       struct bt_field_type *root_c = NULL;
-       struct bt_field_type *root_d = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_integer_create(32);
-       BT_ASSERT(root_a);
-       ret = bt_field_type_integer_set_is_signed(root_a, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_a, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_a, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_a, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_a, 8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_b = bt_field_type_variant_create(NULL, "a");
-       BT_ASSERT(root_b);
-       root_b_HELLO = bt_field_type_string_create();
-       BT_ASSERT(root_b_HELLO);
-       ret = bt_field_type_string_set_encoding(root_b_HELLO, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_variant_add_field(root_b, root_b_HELLO, "HELLO");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_b, "b");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-       root_d = bt_field_type_integer_create(17);
-       BT_ASSERT(root_d);
-       ret = bt_field_type_integer_set_is_signed(root_d, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_d, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_d, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_d, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_d, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_d, "d");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_b);
-       BT_PUT(root_b_HELLO);
-       BT_PUT(root_c);
-       BT_PUT(root_d);
-
-       return root;
-}
-
-static
-void test_fail_variant_tag_is_not_enum(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_variant_tag_is_not_enum_get_ep();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep),
-               "Variant FT with non-enum FT as its tag FT is invalid");
-       BT_PUT(ep);
-}
-
-static
-struct bt_field_type *test_fail_variant_tag_mismatch_mappings_get_ep(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: enum
-           value-type:
-             class: int
-             size: 16
-           members:
-             - GLASS
-             - OF
-             - WATER
-         b:
-           class: variant
-           tag: a
-           types:
-             GLASS:
-               class: string
-             OF:
-               class: int
-               size: 2
-         c:
-           class: string
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_a_int = NULL;
-       struct bt_field_type *root_b = NULL;
-       struct bt_field_type *root_b_GLASS = NULL;
-       struct bt_field_type *root_b_OF = NULL;
-       struct bt_field_type *root_c = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a_int = bt_field_type_integer_create(16);
-       BT_ASSERT(root_a_int);
-       ret = bt_field_type_integer_set_is_signed(root_a_int, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_a_int, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_a_int, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_a_int, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_a_int, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_enumeration_create(root_a_int);
-       BT_ASSERT(root_a);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_a, "GLASS", 0, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_a, "OF", 1, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_enumeration_unsigned_add_mapping(root_a, "WATER", 2, 2);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_b = bt_field_type_variant_create(NULL, "a");
-       BT_ASSERT(root_b);
-       root_b_GLASS = bt_field_type_string_create();
-       BT_ASSERT(root_b_GLASS);
-       ret = bt_field_type_string_set_encoding(root_b_GLASS, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_variant_add_field(root_b, root_b_GLASS, "GLASS");
-       BT_ASSERT(ret == 0);
-       root_b_OF = bt_field_type_integer_create(2);
-       BT_ASSERT(root_b_OF);
-       ret = bt_field_type_integer_set_is_signed(root_b_OF, 0);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_base(root_b_OF, 10);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_encoding(root_b_OF, BT_STRING_ENCODING_NONE);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_byte_order(root_b_OF, BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_set_alignment(root_b_OF, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_variant_add_field(root_b, root_b_OF, "OF");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_b, "b");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_a_int);
-       BT_PUT(root_b);
-       BT_PUT(root_b_GLASS);
-       BT_PUT(root_b_OF);
-       BT_PUT(root_c);
-
-       return root;
-}
-
-static
-void test_fail_variant_tag_mismatch_mappings(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_variant_tag_mismatch_mappings_get_ep();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep) == 0,
-               "Variant FT with mismatching tag FT is valid");
-       BT_PUT(ep);
-}
-
-static
-struct bt_field_type *test_fail_sequence_tag_is_not_int_get_ep(void)
-{
-       /*
-       Generated by bt-ctfirtg using the following input:
-
-       class: struct
-       fields:
-         a:
-           class: string
-         b:
-           class: array
-           length: a
-           element-type:
-             class: string
-         c:
-           class: string
-
-       */
-
-       struct bt_field_type *root = NULL;
-       struct bt_field_type *root_a = NULL;
-       struct bt_field_type *root_b = NULL;
-       struct bt_field_type *root_b_elem = NULL;
-       struct bt_field_type *root_c = NULL;
-
-       int ret;
-       root = bt_field_type_structure_create();
-       BT_ASSERT(root);
-       ret = bt_field_type_set_alignment(root, 8);
-       BT_ASSERT(ret == 0);
-       root_a = bt_field_type_string_create();
-       BT_ASSERT(root_a);
-       ret = bt_field_type_string_set_encoding(root_a, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_a, "a");
-       BT_ASSERT(ret == 0);
-       root_b_elem = bt_field_type_string_create();
-       BT_ASSERT(root_b_elem);
-       ret = bt_field_type_string_set_encoding(root_b_elem, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       root_b = bt_field_type_sequence_create(root_b_elem, "a");
-       BT_ASSERT(root_b);
-       ret = bt_field_type_structure_add_field(root, root_b, "b");
-       BT_ASSERT(ret == 0);
-       root_c = bt_field_type_string_create();
-       BT_ASSERT(root_c);
-       ret = bt_field_type_string_set_encoding(root_c, BT_STRING_ENCODING_UTF8);
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_structure_add_field(root, root_c, "c");
-       BT_ASSERT(ret == 0);
-
-       BT_PUT(root_a);
-       BT_PUT(root_b);
-       BT_PUT(root_b_elem);
-       BT_PUT(root_c);
-
-       return root;
-}
-
-static
-void test_fail_sequence_tag_is_not_int(void)
-{
-       struct bt_field_type *ep;
-
-       ep = test_fail_sequence_tag_is_not_int_get_ep();
-       BT_ASSERT(ep);
-       ok(try_add_event_class_to_trace(NULL, ep),
-               "Sequence FT with non-enum length FT is invalid");
-       BT_PUT(ep);
-}
-
-static
-void test_fail(void)
-{
-       test_fail_unavailable_root();
-       test_fail_target_is_root();
-       test_fail_target_is_after_source();
-       test_fail_target_is_ancestor_of_source();
-       test_fail_target_is_source();
-       test_fail_variant_tag_is_not_enum();
-       test_fail_variant_tag_mismatch_mappings();
-       test_fail_sequence_tag_is_not_int();
-}
-
-int main(void)
-{
-       plan_no_plan();
-
-       test_pass();
-       test_fail();
-
-       return 0;
-}
index f954aa6b0183289ea9eb9a3b60dc81d413b01c03..3cfa474597cebdb0cb8fb791330b246b6a64adb4 100644 (file)
@@ -40,7 +40,6 @@
 #include <babeltrace/graph/connection.h>
 #include <babeltrace/graph/graph.h>
 #include <babeltrace/graph/notification-event.h>
-#include <babeltrace/graph/notification-inactivity.h>
 #include <babeltrace/graph/notification-iterator.h>
 #include <babeltrace/graph/notification-packet.h>
 #include <babeltrace/graph/notification-stream.h>
@@ -69,7 +68,6 @@ enum test {
 enum test_event_type {
        TEST_EV_TYPE_NOTIF_UNEXPECTED,
        TEST_EV_TYPE_NOTIF_EVENT,
-       TEST_EV_TYPE_NOTIF_INACTIVITY,
        TEST_EV_TYPE_NOTIF_STREAM_BEGIN,
        TEST_EV_TYPE_NOTIF_PACKET_BEGIN,
        TEST_EV_TYPE_NOTIF_PACKET_END,
@@ -116,7 +114,6 @@ enum {
        SEQ_EVENT_STREAM1_PACKET2 = -15,
        SEQ_EVENT_STREAM2_PACKET1 = -16,
        SEQ_EVENT_STREAM2_PACKET2 = -17,
-       SEQ_INACTIVITY = -18,
 };
 
 struct src_iter_user_data {
@@ -170,9 +167,6 @@ void print_test_event(FILE *fp, const struct test_event *event)
        case TEST_EV_TYPE_NOTIF_EVENT:
                fprintf(fp, "TEST_EV_TYPE_NOTIF_EVENT");
                break;
-       case TEST_EV_TYPE_NOTIF_INACTIVITY:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_INACTIVITY");
-               break;
        case TEST_EV_TYPE_NOTIF_STREAM_BEGIN:
                fprintf(fp, "TEST_EV_TYPE_NOTIF_STREAM_BEGIN");
                break;
@@ -279,59 +273,30 @@ bool compare_test_events(const struct test_event *expected_events)
 static
 void init_static_data(void)
 {
-       int ret;
        struct bt_trace *trace;
-       struct bt_field_type *empty_struct_ft;
 
        /* Test events */
        test_events = g_array_new(FALSE, TRUE, sizeof(struct test_event));
        BT_ASSERT(test_events);
 
        /* Metadata */
-       empty_struct_ft = bt_field_type_structure_create();
-       BT_ASSERT(empty_struct_ft);
        trace = bt_trace_create();
        BT_ASSERT(trace);
-       ret = bt_trace_set_packet_header_field_type(trace, empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       src_stream_class = bt_stream_class_create("my-stream-class");
+       src_stream_class = bt_stream_class_create(trace);
        BT_ASSERT(src_stream_class);
-       ret = bt_stream_class_set_packet_context_field_type(src_stream_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_set_event_header_field_type(src_stream_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_set_event_context_field_type(src_stream_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       src_event_class = bt_event_class_create("my-event-class");
-       ret = bt_event_class_set_context_field_type(src_event_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_event_class_set_payload_field_type(src_event_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_add_event_class(src_stream_class,
-               src_event_class);
-       BT_ASSERT(ret == 0);
-       ret = bt_trace_add_stream_class(trace, src_stream_class);
-       BT_ASSERT(ret == 0);
-       src_stream1 = bt_stream_create(src_stream_class, "stream-1", 0);
+       src_event_class = bt_event_class_create(src_stream_class);
+       BT_ASSERT(src_event_class);
+       src_stream1 = bt_stream_create(src_stream_class);
        BT_ASSERT(src_stream1);
-       src_stream2 = bt_stream_create(src_stream_class, "stream-2", 1);
+       src_stream2 = bt_stream_create(src_stream_class);
        BT_ASSERT(src_stream2);
-       src_stream1_packet1 = bt_packet_create(src_stream1,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
+       src_stream1_packet1 = bt_packet_create(src_stream1);
        BT_ASSERT(src_stream1_packet1);
-       src_stream1_packet2 = bt_packet_create(src_stream1,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
+       src_stream1_packet2 = bt_packet_create(src_stream1);
        BT_ASSERT(src_stream1_packet2);
-       src_stream2_packet1 = bt_packet_create(src_stream2,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
+       src_stream2_packet1 = bt_packet_create(src_stream2);
        BT_ASSERT(src_stream2_packet1);
-       src_stream2_packet2 = bt_packet_create(src_stream2,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
+       src_stream2_packet2 = bt_packet_create(src_stream2);
        BT_ASSERT(src_stream2_packet2);
 
        if (debug) {
@@ -344,7 +309,6 @@ void init_static_data(void)
        }
 
        bt_put(trace);
-       bt_put(empty_struct_ft);
 }
 
 static
@@ -410,9 +374,6 @@ void src_iter_next_seq_one(struct src_iter_user_data *user_data,
        struct bt_packet *event_packet = NULL;
 
        switch (user_data->seq[user_data->at]) {
-       case SEQ_INACTIVITY:
-               *notif = bt_notification_inactivity_create(cur_notif_iter);
-               break;
        case SEQ_STREAM1_BEGIN:
                *notif = bt_notification_stream_begin_create(cur_notif_iter,
                        src_stream1);
@@ -564,9 +525,6 @@ void append_test_events_from_notification(struct bt_notification *notification)
                BT_ASSERT(test_event.packet);
                break;
        }
-       case BT_NOTIFICATION_TYPE_INACTIVITY:
-               test_event.type = TEST_EV_TYPE_NOTIF_INACTIVITY;
-               break;
        case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
                test_event.type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN;
                test_event.stream =
index 64d25e2be0ed72cf84273577bcaa80d12a7098bb..e618a2692b566557e2438597b022a79006187db7 100644 (file)
@@ -39,7 +39,7 @@
 #include <babeltrace/assert-internal.h>
 #include "common.h"
 
-#define NR_TESTS 41
+#define NR_TESTS 37
 
 struct user {
        struct bt_trace *tc;
@@ -83,51 +83,32 @@ static struct bt_field_type *create_integer_struct(void)
        struct bt_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL;
 
        structure = bt_field_type_structure_create();
-       if (!structure) {
-               goto error;
-       }
-
-       ui8 = bt_field_type_integer_create(8);
-       if (!ui8) {
-               diag("Failed to create uint8_t type");
-               goto error;
-       }
-       ret = bt_field_type_structure_add_field(structure, ui8,
-                       "payload_8");
-       if (ret) {
-               diag("Failed to add uint8_t to structure");
-               goto error;
-       }
-       ui16 = bt_field_type_integer_create(16);
-       if (!ui16) {
-               diag("Failed to create uint16_t type");
-               goto error;
-       }
-       ret = bt_field_type_structure_add_field(structure, ui16,
-                       "payload_16");
-       if (ret) {
-               diag("Failed to add uint16_t to structure");
-               goto error;
-       }
-       ui32 = bt_field_type_integer_create(32);
-       if (!ui32) {
-               diag("Failed to create uint32_t type");
-               goto error;
-       }
-       ret = bt_field_type_structure_add_field(structure, ui32,
-                       "payload_32");
-       if (ret) {
-               diag("Failed to add uint32_t to structure");
-               goto error;
-       }
-end:
+       BT_ASSERT(structure);
+       ui8 = bt_field_type_unsigned_integer_create();
+       BT_ASSERT(ui8);
+       ret = bt_field_type_integer_set_field_value_range(ui8, 8);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_structure_append_member(structure,
+               "payload_8", ui8);
+       BT_ASSERT(ret == 0);
+       ui16 = bt_field_type_unsigned_integer_create();
+       BT_ASSERT(ui16);
+       ret = bt_field_type_integer_set_field_value_range(ui16, 16);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_structure_append_member(structure,
+               "payload_16", ui16);
+       BT_ASSERT(ret == 0);
+       ui32 = bt_field_type_unsigned_integer_create();
+       BT_ASSERT(ui32);
+       ret = bt_field_type_integer_set_field_value_range(ui32, 32);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_structure_append_member(structure,
+               "payload_32", ui32);
+       BT_ASSERT(ret == 0);
        BT_PUT(ui8);
        BT_PUT(ui16);
        BT_PUT(ui32);
        return structure;
-error:
-       BT_PUT(structure);
-       goto end;
 }
 
 static struct bt_ctf_field_type *create_writer_integer_struct(void)
@@ -137,51 +118,26 @@ static struct bt_ctf_field_type *create_writer_integer_struct(void)
        struct bt_ctf_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL;
 
        structure = bt_ctf_field_type_structure_create();
-       if (!structure) {
-               goto error;
-       }
-
+       BT_ASSERT(structure);
        ui8 = bt_ctf_field_type_integer_create(8);
-       if (!ui8) {
-               diag("Failed to create uint8_t type");
-               goto error;
-       }
+       BT_ASSERT(ui8);
        ret = bt_ctf_field_type_structure_add_field(structure, ui8,
                        "payload_8");
-       if (ret) {
-               diag("Failed to add uint8_t to structure");
-               goto error;
-       }
+       BT_ASSERT(ret == 0);
        ui16 = bt_ctf_field_type_integer_create(16);
-       if (!ui16) {
-               diag("Failed to create uint16_t type");
-               goto error;
-       }
+       BT_ASSERT(ui16);
        ret = bt_ctf_field_type_structure_add_field(structure, ui16,
                        "payload_16");
-       if (ret) {
-               diag("Failed to add uint16_t to structure");
-               goto error;
-       }
+       BT_ASSERT(ret == 0);
        ui32 = bt_ctf_field_type_integer_create(32);
-       if (!ui32) {
-               diag("Failed to create uint32_t type");
-               goto error;
-       }
+       BT_ASSERT(ui32);
        ret = bt_ctf_field_type_structure_add_field(structure, ui32,
                        "payload_32");
-       if (ret) {
-               diag("Failed to add uint32_t to structure");
-               goto error;
-       }
-end:
+       BT_ASSERT(ret == 0);
        BT_PUT(ui8);
        BT_PUT(ui16);
        BT_PUT(ui32);
        return structure;
-error:
-       BT_PUT(structure);
-       goto end;
 }
 
 /**
@@ -190,36 +146,24 @@ error:
  *     - uint16_t payload_16;
  *     - uint32_t payload_32;
  */
-static struct bt_event_class *create_simple_event(const char *name)
+static struct bt_event_class *create_simple_event(struct bt_stream_class *sc,
+               const char *name)
 {
        int ret;
        struct bt_event_class *event = NULL;
        struct bt_field_type *payload = NULL;
 
        BT_ASSERT(name);
-       event = bt_event_class_create(name);
-       if (!event) {
-               diag("Failed to create simple event");
-               goto error;
-       }
-
+       event = bt_event_class_create(sc);
+       BT_ASSERT(event);
+       ret = bt_event_class_set_name(event, name);
+       BT_ASSERT(ret == 0);
        payload = create_integer_struct();
-       if (!payload) {
-               diag("Failed to initialize integer structure");
-               goto error;
-       }
-
+       BT_ASSERT(payload);
        ret = bt_event_class_set_payload_field_type(event, payload);
-       if (ret) {
-               diag("Failed to set simple event payload");
-               goto error;
-       }
-end:
+       BT_ASSERT(ret == 0);
        BT_PUT(payload);
        return event;
-error:
-       BT_PUT(event);
-       goto end;;
 }
 
 /**
@@ -232,50 +176,30 @@ error:
  *           - uint16_t payload_16;
  *           - uint32_t payload_32;
  */
-static struct bt_event_class *create_complex_event(const char *name)
+static struct bt_event_class *create_complex_event(struct bt_stream_class *sc,
+               const char *name)
 {
        int ret;
        struct bt_event_class *event = NULL;
        struct bt_field_type *inner = NULL, *outer = NULL;
 
        BT_ASSERT(name);
-       event = bt_event_class_create(name);
-       if (!event) {
-               diag("Failed to create complex event");
-               goto error;
-       }
-
+       event = bt_event_class_create(sc);
+       BT_ASSERT(event);
+       ret = bt_event_class_set_name(event, name);
+       BT_ASSERT(ret == 0);
        outer = create_integer_struct();
-       if (!outer) {
-               diag("Failed to initialize integer structure");
-               goto error;
-       }
-
+       BT_ASSERT(outer);
        inner = create_integer_struct();
-       if (!inner) {
-               diag("Failed to initialize integer structure");
-               goto error;
-       }
-
-       ret = bt_field_type_structure_add_field(outer, inner,
-                       "payload_struct");
-       if (ret) {
-               diag("Failed to add inner structure to outer structure");
-               goto error;
-       }
-
+       BT_ASSERT(inner);
+       ret = bt_field_type_structure_append_member(outer,
+               "payload_struct", inner);
+       BT_ASSERT(ret == 0);
        ret = bt_event_class_set_payload_field_type(event, outer);
-       if (ret) {
-               diag("Failed to set complex event payload");
-               goto error;
-       }
-end:
+       BT_ASSERT(ret == 0);
        BT_PUT(inner);
        BT_PUT(outer);
        return event;
-error:
-       BT_PUT(event);
-       goto end;;
 }
 
 static void set_stream_class_field_types(
@@ -288,123 +212,82 @@ static void set_stream_class_field_types(
 
        packet_context_type = bt_field_type_structure_create();
        BT_ASSERT(packet_context_type);
-       ft = bt_field_type_integer_create(32);
+       ft = bt_field_type_unsigned_integer_create();
        BT_ASSERT(ft);
-       ret = bt_field_type_structure_add_field(packet_context_type,
-               ft, "packet_size");
+       ret = bt_field_type_integer_set_field_value_range(ft, 32);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_structure_append_member(packet_context_type,
+               "packet_size", ft);
        BT_ASSERT(ret == 0);
        bt_put(ft);
-       ft = bt_field_type_integer_create(32);
+       ft = bt_field_type_unsigned_integer_create();
        BT_ASSERT(ft);
-       ret = bt_field_type_structure_add_field(packet_context_type,
-               ft, "content_size");
+       ret = bt_field_type_integer_set_field_value_range(ft, 32);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_structure_append_member(packet_context_type,
+               "content_size", ft);
        BT_ASSERT(ret == 0);
        bt_put(ft);
-
        event_header_type = bt_field_type_structure_create();
        BT_ASSERT(event_header_type);
-       ft = bt_field_type_integer_create(32);
+       ft = bt_field_type_unsigned_integer_create();
        BT_ASSERT(ft);
-       ret = bt_field_type_structure_add_field(event_header_type,
-               ft, "id");
+       ret = bt_field_type_integer_set_field_value_range(ft, 32);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_structure_append_member(event_header_type,
+               "id", ft);
        BT_ASSERT(ret == 0);
        bt_put(ft);
-
        ret = bt_stream_class_set_packet_context_field_type(stream_class,
                packet_context_type);
        BT_ASSERT(ret == 0);
        ret = bt_stream_class_set_event_header_field_type(stream_class,
                event_header_type);
        BT_ASSERT(ret == 0);
-
        bt_put(packet_context_type);
        bt_put(event_header_type);
 }
 
-static struct bt_stream_class *create_sc1(void)
+static void create_sc1(struct bt_trace *trace)
 {
        int ret;
        struct bt_event_class *ec1 = NULL, *ec2 = NULL;
        struct bt_stream_class *sc1 = NULL, *ret_stream = NULL;
 
-       sc1 = bt_stream_class_create("sc1");
-       if (!sc1) {
-               diag("Failed to create Stream Class");
-               goto error;
-       }
-
+       sc1 = bt_stream_class_create(trace);
+       BT_ASSERT(sc1);
+       ret = bt_stream_class_set_name(sc1, "sc1");
+       BT_ASSERT(ret == 0);
        set_stream_class_field_types(sc1);
-       ec1 = create_complex_event("ec1");
-       if (!ec1) {
-               diag("Failed to create complex event EC1");
-               goto error;
-       }
-       ret = bt_stream_class_add_event_class(sc1, ec1);
-       if (ret) {
-               diag("Failed to add EC1 to SC1");
-               goto error;
-       }
-
-       ec2 = create_simple_event("ec2");
-       if (!ec2) {
-               diag("Failed to create simple event EC2");
-               goto error;
-       }
-       ret = bt_stream_class_add_event_class(sc1, ec2);
-       if (ret) {
-               diag("Failed to add EC1 to SC1");
-               goto error;
-       }
-
-       ret_stream = bt_event_class_get_stream_class(ec1);
-       ok(ret_stream == sc1, "Get parent stream SC1 from EC1");
-       BT_PUT(ret_stream);
-
-       ret_stream = bt_event_class_get_stream_class(ec2);
-       ok(ret_stream == sc1, "Get parent stream SC1 from EC2");
-end:
-       BT_PUT(ret_stream);
+       ec1 = create_complex_event(sc1, "ec1");
+       BT_ASSERT(ec1);
+       ec2 = create_simple_event(sc1, "ec2");
+       BT_ASSERT(ec2);
+       ret_stream = bt_event_class_borrow_stream_class(ec1);
+       ok(ret_stream == sc1, "Borrow parent stream SC1 from EC1");
+       ret_stream = bt_event_class_borrow_stream_class(ec2);
+       ok(ret_stream == sc1, "Borrow parent stream SC1 from EC2");
        BT_PUT(ec1);
        BT_PUT(ec2);
-       return sc1;
-error:
        BT_PUT(sc1);
-       goto end;
 }
 
-static struct bt_stream_class *create_sc2(void)
+static void create_sc2(struct bt_trace *trace)
 {
        int ret;
        struct bt_event_class *ec3 = NULL;
        struct bt_stream_class *sc2 = NULL, *ret_stream = NULL;
 
-       sc2 = bt_stream_class_create("sc2");
-       if (!sc2) {
-               diag("Failed to create Stream Class");
-               goto error;
-       }
-
+       sc2 = bt_stream_class_create(trace);
+       BT_ASSERT(sc2);
+       ret = bt_stream_class_set_name(sc2, "sc2");
+       BT_ASSERT(ret == 0);
        set_stream_class_field_types(sc2);
-       ec3 = create_simple_event("ec3");
-       if (!ec3) {
-               diag("Failed to create simple event EC3");
-               goto error;
-       }
-       ret = bt_stream_class_add_event_class(sc2, ec3);
-       if (ret) {
-               diag("Failed to add EC3 to SC2");
-               goto error;
-       }
-
-       ret_stream = bt_event_class_get_stream_class(ec3);
-       ok(ret_stream == sc2, "Get parent stream SC2 from EC3");
-end:
-       BT_PUT(ret_stream);
+       ec3 = create_simple_event(sc2, "ec3");
+       ret_stream = bt_event_class_borrow_stream_class(ec3);
+       ok(ret_stream == sc2, "Borrow parent stream SC2 from EC3");
        BT_PUT(ec3);
-       return sc2;
-error:
        BT_PUT(sc2);
-       goto end;
 }
 
 static void set_trace_packet_header(struct bt_trace *trace)
@@ -415,13 +298,14 @@ static void set_trace_packet_header(struct bt_trace *trace)
 
        packet_header_type = bt_field_type_structure_create();
        BT_ASSERT(packet_header_type);
-       ft = bt_field_type_integer_create(32);
+       ft = bt_field_type_unsigned_integer_create();
        BT_ASSERT(ft);
-       ret = bt_field_type_structure_add_field(packet_header_type,
-               ft, "stream_id");
+       ret = bt_field_type_integer_set_field_value_range(ft, 32);
+       BT_ASSERT(ret == 0);
+       ret = bt_field_type_structure_append_member(packet_header_type,
+               "stream_id", ft);
        BT_ASSERT(ret == 0);
        bt_put(ft);
-
        ret = bt_trace_set_packet_header_field_type(trace,
                packet_header_type);
        BT_ASSERT(ret == 0);
@@ -431,45 +315,14 @@ static void set_trace_packet_header(struct bt_trace *trace)
 
 static struct bt_trace *create_tc1(void)
 {
-       int ret;
        struct bt_trace *tc1 = NULL;
-       struct bt_stream_class *sc1 = NULL, *sc2 = NULL;
 
        tc1 = bt_trace_create();
-       if (!tc1) {
-               diag("bt_trace_create returned NULL");
-               goto error;
-       }
-
+       BT_ASSERT(tc1);
        set_trace_packet_header(tc1);
-       sc1 = create_sc1();
-       ok(sc1, "Create SC1");
-       if (!sc1) {
-               goto error;
-       }
-       ret = bt_trace_add_stream_class(tc1, sc1);
-       ok(!ret, "Add SC1 to TC1");
-       if (ret) {
-               goto error;
-       }
-
-       sc2 = create_sc2();
-       ok(sc2, "Create SC2");
-       if (!sc2) {
-               goto error;
-       }
-       ret = bt_trace_add_stream_class(tc1, sc2);
-       ok(!ret, "Add SC2 to TC1");
-       if (ret) {
-               goto error;
-       }
-end:
-       BT_PUT(sc1);
-       BT_PUT(sc2);
+       create_sc1(tc1);
+       create_sc2(tc1);
        return tc1;
-error:
-       BT_PUT(tc1);
-       goto end;
 }
 
 static void init_weak_refs(struct bt_trace *tc,
@@ -481,16 +334,11 @@ static void init_weak_refs(struct bt_trace *tc,
                struct bt_event_class **ec3)
 {
        *tc1 = tc;
-       *sc1 = bt_trace_get_stream_class_by_index(tc, 0);
-       *sc2 = bt_trace_get_stream_class_by_index(tc, 1);
-       *ec1 = bt_stream_class_get_event_class_by_index(*sc1, 0);
-       *ec2 = bt_stream_class_get_event_class_by_index(*sc1, 1);
-       *ec3 = bt_stream_class_get_event_class_by_index(*sc2, 0);
-       bt_put(*sc1);
-       bt_put(*sc2);
-       bt_put(*ec1);
-       bt_put(*ec2);
-       bt_put(*ec3);
+       *sc1 = bt_trace_borrow_stream_class_by_index(tc, 0);
+       *sc2 = bt_trace_borrow_stream_class_by_index(tc, 1);
+       *ec1 = bt_stream_class_borrow_event_class_by_index(*sc1, 0);
+       *ec2 = bt_stream_class_borrow_event_class_by_index(*sc1, 1);
+       *ec3 = bt_stream_class_borrow_event_class_by_index(*sc2, 0);
 }
 
 static void test_example_scenario(void)
@@ -511,13 +359,9 @@ static void test_example_scenario(void)
        /* The only reference which exists at this point is on TC1. */
        tc1 = create_tc1();
        ok(tc1, "Initialize trace");
-       if (!tc1) {
-               return;
-       }
-
+       BT_ASSERT(tc1);
        init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1,
                        &weak_ec2, &weak_ec3);
-
        ok(bt_object_get_ref_count((void *) weak_sc1) == 0,
                        "Initial SC1 reference count is 0");
        ok(bt_object_get_ref_count((void *) weak_sc2) == 0,
@@ -535,7 +379,7 @@ static void test_example_scenario(void)
                        "TC1 reference count is 1");
 
        /* User A acquires a reference to SC2 from TC1. */
-       user_a.sc = bt_trace_get_stream_class_by_index(user_a.tc, 1);
+       user_a.sc = bt_get(bt_trace_borrow_stream_class_by_index(user_a.tc, 1));
        ok(user_a.sc, "User A acquires SC2 from TC1");
        ok(bt_object_get_ref_count((void *) weak_tc1) == 2,
                        "TC1 reference count is 2");
@@ -543,7 +387,8 @@ static void test_example_scenario(void)
                        "SC2 reference count is 1");
 
        /* User A acquires a reference to EC3 from SC2. */
-       user_a.ec = bt_stream_class_get_event_class_by_index(user_a.sc, 0);
+       user_a.ec = bt_get(
+               bt_stream_class_borrow_event_class_by_index(user_a.sc, 0));
        ok(user_a.ec, "User A acquires EC3 from SC2");
        ok(bt_object_get_ref_count((void *) weak_tc1) == 2,
                        "TC1 reference count is 2");
@@ -590,7 +435,8 @@ static void test_example_scenario(void)
 
        /* User C acquires a reference to EC1. */
        diag("User C acquires a reference to EC1");
-       user_c.ec = bt_stream_class_get_event_class_by_index(user_b.sc, 0);
+       user_c.ec = bt_get(
+               bt_stream_class_borrow_event_class_by_index(user_b.sc, 0));
        ok(bt_object_get_ref_count((void *) weak_ec1) == 1,
                        "EC1 reference count is 1");
        ok(bt_object_get_ref_count((void *) weak_sc1) == 2,
index 7ea42392dd7aa32536f7530bc355ed275d1f2e36..e68d66717021dddd723e9664662accc5778f5f3c 100644 (file)
@@ -11,11 +11,7 @@ check_SCRIPTS =
 noinst_PROGRAMS =
 
 if !ENABLE_BUILT_IN_PLUGINS
-test_utils_muxer_SOURCES = test-utils-muxer.c
-test_utils_muxer_LDADD = $(COMMON_TEST_LDADD)
-
-noinst_PROGRAMS += test-utils-muxer
-check_SCRIPTS += test-utils-muxer-complete
+# plugin tests here
 endif # !ENABLE_BUILT_IN_PLUGINS
 
 if ENABLE_DEBUG_INFO
diff --git a/tests/plugins/test-utils-muxer.c b/tests/plugins/test-utils-muxer.c
deleted file mode 100644 (file)
index d7c582b..0000000
+++ /dev/null
@@ -1,1669 +0,0 @@
-/*
- * Copyright 2017 - Philippe Proulx <pproulx@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <inttypes.h>
-#include <string.h>
-#include <babeltrace/assert-internal.h>
-#include <babeltrace/babeltrace.h>
-#include <glib.h>
-
-#include "tap/tap.h"
-
-#define NR_TESTS       12
-
-enum test {
-       TEST_NO_TS,
-       TEST_NO_UPSTREAM_CONNECTION,
-       TEST_SIMPLE_4_PORTS,
-       TEST_4_PORTS_WITH_RETRIES,
-       TEST_SINGLE_END_THEN_MULTIPLE_FULL,
-       TEST_SINGLE_AGAIN_END_THEN_MULTIPLE_FULL,
-};
-
-enum test_event_type {
-       TEST_EV_TYPE_NOTIF_UNEXPECTED,
-       TEST_EV_TYPE_NOTIF_EVENT,
-       TEST_EV_TYPE_NOTIF_INACTIVITY,
-       TEST_EV_TYPE_NOTIF_PACKET_BEGIN,
-       TEST_EV_TYPE_NOTIF_PACKET_END,
-       TEST_EV_TYPE_NOTIF_STREAM_BEGIN,
-       TEST_EV_TYPE_NOTIF_STREAM_END,
-       TEST_EV_TYPE_AGAIN,
-       TEST_EV_TYPE_END,
-       TEST_EV_TYPE_SENTINEL,
-};
-
-struct test_event {
-       enum test_event_type type;
-       int64_t ts_ns;
-};
-
-struct source_muxer_sink {
-       struct bt_component *source;
-       struct bt_component *muxer;
-       struct bt_component *sink;
-};
-
-struct graph_listener_data {
-       struct bt_graph *graph;
-       struct bt_component *source;
-       struct bt_component *muxer;
-       struct bt_component *sink;
-};
-
-static bool debug = false;
-static enum test current_test;
-static GArray *test_events;
-static struct bt_graph *graph;
-static struct bt_private_connection_private_notification_iterator *cur_notif_iter;
-static struct bt_clock_class *src_clock_class;
-static struct bt_stream_class *src_stream_class;
-static struct bt_event_class *src_event_class;
-static struct bt_packet *src_packet0;
-static struct bt_packet *src_packet1;
-static struct bt_packet *src_packet2;
-static struct bt_packet *src_packet3;
-
-enum {
-       SEQ_END = -1,
-       SEQ_AGAIN = -2,
-       SEQ_PACKET_BEGIN = -3,
-       SEQ_PACKET_END = -4,
-       SEQ_STREAM_BEGIN = -5,
-       SEQ_STREAM_END = -6,
-};
-
-struct src_iter_user_data {
-       size_t iter_index;
-       int64_t *seq;
-       size_t at;
-       struct bt_packet *packet;
-};
-
-struct sink_user_data {
-       struct bt_notification_iterator *notif_iter;
-};
-
-static int64_t seq1[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 24, 53, 97, 105, 119, 210,
-       222, 240, 292, 317, 353, 407, 433, 473, 487, 504, 572, 615, 708,
-       766, 850, 852, 931, 951, 956, 996, SEQ_PACKET_END,
-       SEQ_STREAM_END, SEQ_END,
-};
-
-static int64_t seq2[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 51, 59, 68, 77, 91, 121,
-       139, 170, 179, 266, 352, 454, 478, 631, 644, 668, 714, 744, 750,
-       778, 790, 836, SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
-};
-
-static int64_t seq3[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 8, 71, 209, 254, 298, 320,
-       350, 393, 419, 624, 651, 678, 717, 731, 733, 788, 819, 820, 857,
-       892, 903, 944, 998, SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
-};
-
-static int64_t seq4[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 41, 56, 120, 138, 154, 228,
-       471, 479, 481, 525, 591, 605, 612, 618, 632, 670, 696, 825, 863,
-       867, 871, 884, 953, 985, 999, SEQ_PACKET_END, SEQ_STREAM_END,
-       SEQ_END,
-};
-
-static int64_t seq1_with_again[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 24, 53, 97, 105, 119, 210,
-       SEQ_AGAIN, SEQ_AGAIN, 222, 240, 292, 317, 353, 407, 433, 473,
-       487, 504, 572, 615, 708, 766, 850, 852, 931, 951, 956, 996,
-       SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
-};
-
-static int64_t seq2_with_again[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 51, 59, 68, 77, 91, 121,
-       139, 170, 179, 266, 352, 454, 478, 631, 644, 668, 714, 744, 750,
-       778, 790, 836, SEQ_AGAIN, SEQ_AGAIN, SEQ_PACKET_END,
-       SEQ_STREAM_END, SEQ_END,
-};
-
-static int64_t seq3_with_again[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 8, 71, 209, 254, 298, 320,
-       350, 393, 419, 624, 651, SEQ_AGAIN, SEQ_AGAIN, 678, 717, 731,
-       733, 788, 819, 820, 857, 892, 903, 944, 998, SEQ_PACKET_END,
-       SEQ_STREAM_END, SEQ_END,
-};
-
-static int64_t seq4_with_again[] = {
-       SEQ_AGAIN, SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 41, 56, 120, 138,
-       154, 228, 471, 479, 481, 525, 591, 605, 612, 618, 632, 670, 696,
-       825, 863, 867, 871, 884, 953, 985, 999, SEQ_PACKET_END,
-       SEQ_STREAM_END, SEQ_END,
-};
-
-static int64_t seq5[] = {
-       SEQ_STREAM_BEGIN, SEQ_PACKET_BEGIN, 1, 4, 189, 1001,
-       SEQ_PACKET_END, SEQ_STREAM_END, SEQ_END,
-};
-
-static
-void clear_test_events(void)
-{
-       g_array_set_size(test_events, 0);
-}
-
-static
-void print_test_event(FILE *fp, const struct test_event *event)
-{
-       fprintf(fp, "{ type = ");
-
-       switch (event->type) {
-       case TEST_EV_TYPE_NOTIF_UNEXPECTED:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_UNEXPECTED");
-               break;
-       case TEST_EV_TYPE_NOTIF_EVENT:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_EVENT");
-               break;
-       case TEST_EV_TYPE_NOTIF_INACTIVITY:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_INACTIVITY");
-               break;
-       case TEST_EV_TYPE_NOTIF_PACKET_BEGIN:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_PACKET_BEGIN");
-               break;
-       case TEST_EV_TYPE_NOTIF_PACKET_END:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_PACKET_END");
-               break;
-       case TEST_EV_TYPE_NOTIF_STREAM_BEGIN:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_STREAM_BEGIN");
-               break;
-       case TEST_EV_TYPE_NOTIF_STREAM_END:
-               fprintf(fp, "TEST_EV_TYPE_NOTIF_STREAM_END");
-               break;
-       case TEST_EV_TYPE_AGAIN:
-               fprintf(fp, "TEST_EV_TYPE_AGAIN");
-               break;
-       case TEST_EV_TYPE_END:
-               fprintf(fp, "TEST_EV_TYPE_END");
-               break;
-       case TEST_EV_TYPE_SENTINEL:
-               fprintf(fp, "TEST_EV_TYPE_SENTINEL");
-               break;
-       default:
-               fprintf(fp, "(UNKNOWN)");
-               break;
-       }
-
-       switch (event->type) {
-       case TEST_EV_TYPE_NOTIF_EVENT:
-       case TEST_EV_TYPE_NOTIF_INACTIVITY:
-               fprintf(fp, ", ts-ns = %" PRId64, event->ts_ns);
-       default:
-               break;
-       }
-
-       fprintf(fp, " }");
-}
-
-static
-void append_test_event(struct test_event *event)
-{
-       g_array_append_val(test_events, *event);
-}
-
-static
-bool compare_single_test_events(const struct test_event *ev_a,
-               const struct test_event *ev_b)
-{
-       if (debug) {
-               fprintf(stderr, ":: Comparing test events: ");
-               print_test_event(stderr, ev_a);
-               fprintf(stderr, " vs. ");
-               print_test_event(stderr, ev_b);
-               fprintf(stderr, "\n");
-       }
-
-       if (ev_a->type != ev_b->type) {
-               return false;
-       }
-
-       switch (ev_a->type) {
-               case TEST_EV_TYPE_NOTIF_EVENT:
-               case TEST_EV_TYPE_NOTIF_INACTIVITY:
-                       if (ev_a->ts_ns != ev_b->ts_ns) {
-                               return false;
-                       }
-                       break;
-               default:
-                       break;
-       }
-
-       return true;
-}
-
-static
-bool compare_test_events(const struct test_event *expected_events)
-{
-       const struct test_event *expected_event = expected_events;
-       size_t i = 0;
-
-       BT_ASSERT(expected_events);
-
-       while (true) {
-               const struct test_event *event;
-
-               if (expected_event->type == TEST_EV_TYPE_SENTINEL) {
-                       break;
-               }
-
-               if (i >= test_events->len) {
-                       return false;
-               }
-
-               event = &g_array_index(test_events, struct test_event, i);
-
-               if (!compare_single_test_events(event, expected_event)) {
-                       return false;
-               }
-
-               i++;
-               expected_event++;
-       }
-
-       if (i != test_events->len) {
-               if (debug) {
-                       fprintf(stderr, ":: Length mismatch\n");
-               }
-
-               return false;
-       }
-
-       return true;
-}
-
-static
-void init_static_data(void)
-{
-       int ret;
-       struct bt_trace *trace;
-       struct bt_stream *stream;
-       struct bt_field_type *empty_struct_ft;
-       struct bt_field_type *eh_ft;
-       struct bt_field_type *eh_ts_ft;
-
-       /* Test events */
-       test_events = g_array_new(FALSE, TRUE, sizeof(struct test_event));
-       BT_ASSERT(test_events);
-
-       /* Metadata */
-       empty_struct_ft = bt_field_type_structure_create();
-       BT_ASSERT(empty_struct_ft);
-       src_clock_class = bt_clock_class_create("my-clock", 1000000000);
-       BT_ASSERT(src_clock_class);
-       trace = bt_trace_create();
-       BT_ASSERT(trace);
-       ret = bt_trace_set_native_byte_order(trace,
-               BT_BYTE_ORDER_LITTLE_ENDIAN);
-       BT_ASSERT(ret == 0);
-       ret = bt_trace_set_packet_header_field_type(trace, empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_clock_class_set_is_absolute(src_clock_class, 1);
-       BT_ASSERT(ret == 0);
-       ret = bt_trace_add_clock_class(trace, src_clock_class);
-       BT_ASSERT(ret == 0);
-       src_stream_class = bt_stream_class_create("my-stream-class");
-       BT_ASSERT(src_stream_class);
-       ret = bt_stream_class_set_packet_context_field_type(src_stream_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       eh_ft = bt_field_type_structure_create();
-       BT_ASSERT(eh_ft);
-       eh_ts_ft = bt_field_type_integer_create(64);
-       BT_ASSERT(eh_ts_ft);
-       ret = bt_field_type_structure_add_field(eh_ft, eh_ts_ft, "ts");
-       BT_ASSERT(ret == 0);
-       ret = bt_field_type_integer_set_mapped_clock_class(eh_ts_ft,
-               src_clock_class);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_set_event_header_field_type(src_stream_class,
-               eh_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_set_event_context_field_type(src_stream_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       src_event_class = bt_event_class_create("my-event-class");
-       ret = bt_event_class_set_context_field_type(src_event_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_event_class_set_context_field_type(src_event_class,
-               empty_struct_ft);
-       BT_ASSERT(ret == 0);
-       ret = bt_stream_class_add_event_class(src_stream_class,
-               src_event_class);
-       BT_ASSERT(ret == 0);
-       ret = bt_trace_add_stream_class(trace, src_stream_class);
-       BT_ASSERT(ret == 0);
-       stream = bt_stream_create(src_stream_class, "stream0", 0);
-       BT_ASSERT(stream);
-       src_packet0 = bt_packet_create(stream,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
-       BT_ASSERT(src_packet0);
-       bt_put(stream);
-       stream = bt_stream_create(src_stream_class, "stream1", 1);
-       BT_ASSERT(stream);
-       src_packet1 = bt_packet_create(stream,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
-       BT_ASSERT(src_packet0);
-       bt_put(stream);
-       stream = bt_stream_create(src_stream_class, "stream2", 2);
-       BT_ASSERT(stream);
-       src_packet2 = bt_packet_create(stream,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
-       BT_ASSERT(src_packet0);
-       bt_put(stream);
-       stream = bt_stream_create(src_stream_class, "stream3", 3);
-       BT_ASSERT(stream);
-       src_packet3 = bt_packet_create(stream,
-               BT_PACKET_PREVIOUS_PACKET_AVAILABILITY_NONE, NULL);
-       BT_ASSERT(src_packet0);
-       bt_put(stream);
-
-       bt_put(trace);
-       bt_put(empty_struct_ft);
-       bt_put(eh_ft);
-       bt_put(eh_ts_ft);
-}
-
-static
-void fini_static_data(void)
-{
-       /* Test events */
-       g_array_free(test_events, TRUE);
-
-       /* Metadata */
-       bt_put(src_clock_class);
-       bt_put(src_stream_class);
-       bt_put(src_event_class);
-       bt_put(src_packet0);
-       bt_put(src_packet1);
-       bt_put(src_packet2);
-       bt_put(src_packet3);
-}
-
-static
-void src_iter_finalize(
-               struct bt_private_connection_private_notification_iterator *private_notification_iterator)
-{
-       struct src_iter_user_data *user_data =
-               bt_private_connection_private_notification_iterator_get_user_data(
-                       private_notification_iterator);
-
-       if (user_data) {
-               g_free(user_data);
-       }
-}
-
-static
-enum bt_notification_iterator_status src_iter_init(
-               struct bt_private_connection_private_notification_iterator *priv_notif_iter,
-               struct bt_private_port *private_port)
-{
-       struct src_iter_user_data *user_data =
-               g_new0(struct src_iter_user_data, 1);
-       struct bt_port *port = bt_port_borrow_from_private(private_port);
-       const char *port_name;
-       int ret;
-
-       BT_ASSERT(user_data);
-       BT_ASSERT(port);
-       ret = bt_private_connection_private_notification_iterator_set_user_data(priv_notif_iter,
-               user_data);
-       BT_ASSERT(ret == 0);
-       port_name = bt_port_get_name(port);
-       BT_ASSERT(port_name);
-       user_data->iter_index = port_name[3] - '0';
-
-       switch (user_data->iter_index) {
-       case 0:
-               user_data->packet = src_packet0;
-               break;
-       case 1:
-               user_data->packet = src_packet1;
-               break;
-       case 2:
-               user_data->packet = src_packet2;
-               break;
-       case 3:
-               user_data->packet = src_packet3;
-               break;
-       default:
-               abort();
-       }
-
-       switch (current_test) {
-       case TEST_NO_TS:
-               if (user_data->iter_index == 1) {
-                       user_data->seq = seq5;
-               }
-               break;
-       case TEST_SIMPLE_4_PORTS:
-               if (user_data->iter_index == 0) {
-                       user_data->seq = seq1;
-               } else if (user_data->iter_index == 1) {
-                       user_data->seq = seq2;
-               } else if (user_data->iter_index == 2) {
-                       user_data->seq = seq3;
-               } else {
-                       user_data->seq = seq4;
-               }
-               break;
-       case TEST_4_PORTS_WITH_RETRIES:
-               if (user_data->iter_index == 0) {
-                       user_data->seq = seq1_with_again;
-               } else if (user_data->iter_index == 1) {
-                       user_data->seq = seq2_with_again;
-               } else if (user_data->iter_index == 2) {
-                       user_data->seq = seq3_with_again;
-               } else {
-                       user_data->seq = seq4_with_again;
-               }
-               break;
-       case TEST_SINGLE_END_THEN_MULTIPLE_FULL:
-       case TEST_SINGLE_AGAIN_END_THEN_MULTIPLE_FULL:
-               if (user_data->iter_index == 0) {
-                       /* Ignore: this iterator only returns END */
-               } else if (user_data->iter_index == 1) {
-                       user_data->seq = seq2;
-               } else {
-                       user_data->seq = seq3;
-               }
-               break;
-       default:
-               abort();
-       }
-
-       return BT_NOTIFICATION_ITERATOR_STATUS_OK;
-}
-
-static
-struct bt_notification *src_create_event_notif(struct bt_packet *packet,
-               int64_t ts_ns)
-{
-       int ret;
-       struct bt_event *event;
-       struct bt_notification *notif;
-       struct bt_field *field;
-
-       notif = bt_notification_event_create(cur_notif_iter,
-               src_event_class, packet);
-       BT_ASSERT(notif);
-       event = bt_notification_event_borrow_event(notif);
-       BT_ASSERT(event);
-       field = bt_event_borrow_header(event);
-       BT_ASSERT(field);
-       field = bt_field_structure_borrow_field_by_name(field, "ts");
-       BT_ASSERT(field);
-       ret = bt_field_integer_unsigned_set_value(field, (uint64_t) ts_ns);
-       BT_ASSERT(ret == 0);
-
-       if (ts_ns != UINT64_C(-1)) {
-               ret = bt_event_set_clock_value(event, src_clock_class, (uint64_t) ts_ns,
-                       BT_TRUE);
-               BT_ASSERT(ret == 0);
-       }
-
-       return notif;
-}
-
-static
-enum bt_notification_iterator_status src_iter_next_seq(
-               struct src_iter_user_data *user_data,
-               bt_notification_array notifs)
-{
-       enum bt_notification_iterator_status status =
-               BT_NOTIFICATION_ITERATOR_STATUS_OK;
-       int64_t cur_ts_ns;
-       struct bt_stream *stream;
-
-       BT_ASSERT(user_data->seq);
-       cur_ts_ns = user_data->seq[user_data->at];
-
-       switch (cur_ts_ns) {
-       case SEQ_END:
-               status = BT_NOTIFICATION_ITERATOR_STATUS_END;
-               break;
-       case SEQ_AGAIN:
-               status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
-               break;
-       case SEQ_PACKET_BEGIN:
-               notifs[0] = bt_notification_packet_begin_create(cur_notif_iter,
-                               user_data->packet);
-               BT_ASSERT(notifs[0]);
-               break;
-       case SEQ_PACKET_END:
-               notifs[0] = bt_notification_packet_end_create(cur_notif_iter,
-                               user_data->packet);
-               BT_ASSERT(notifs[0]);
-               break;
-       case SEQ_STREAM_BEGIN:
-               stream = bt_packet_get_stream(user_data->packet);
-               notifs[0] = bt_notification_stream_begin_create(cur_notif_iter,
-                       stream);
-               BT_ASSERT(notifs[0]);
-               bt_put(stream);
-               break;
-       case SEQ_STREAM_END:
-               stream = bt_packet_get_stream(user_data->packet);
-               notifs[0] = bt_notification_stream_end_create(cur_notif_iter,
-                       stream);
-               BT_ASSERT(notifs[0]);
-               bt_put(stream);
-               break;
-       default:
-       {
-               notifs[0] = src_create_event_notif(user_data->packet,
-                       cur_ts_ns);
-               BT_ASSERT(notifs[0]);
-               break;
-       }
-       }
-
-       if (status != BT_NOTIFICATION_ITERATOR_STATUS_END) {
-               user_data->at++;
-       }
-
-       return status;
-}
-
-static
-enum bt_notification_iterator_status src_iter_next(
-               struct bt_private_connection_private_notification_iterator *priv_iterator,
-               bt_notification_array notifs, uint64_t capacity,
-               uint64_t *count)
-{
-       enum bt_notification_iterator_status status =
-               BT_NOTIFICATION_ITERATOR_STATUS_OK;
-       struct src_iter_user_data *user_data =
-               bt_private_connection_private_notification_iterator_get_user_data(priv_iterator);
-       struct bt_private_component *private_component =
-               bt_private_connection_private_notification_iterator_get_private_component(priv_iterator);
-       struct bt_stream *stream;
-       int ret;
-
-       BT_ASSERT(user_data);
-       BT_ASSERT(private_component);
-       cur_notif_iter = priv_iterator;
-
-       /*
-        * We can always set it to 1: it's not going to be considered
-        * anyway if the status is not
-        * BT_NOTIFICATION_ITERATOR_STATUS_OK.
-        */
-       *count = 1;
-
-       switch (current_test) {
-       case TEST_NO_TS:
-               if (user_data->iter_index == 0) {
-                       if (user_data->at == 0) {
-                               stream = bt_packet_get_stream(user_data->packet);
-                               notifs[0] =
-                                       bt_notification_stream_begin_create(
-                                               cur_notif_iter, stream);
-                               bt_put(stream);
-                               BT_ASSERT(notifs[0]);
-                       } else if (user_data->at == 1) {
-                               notifs[0] =
-                                       bt_notification_packet_begin_create(
-                                               cur_notif_iter,
-                                               user_data->packet);
-                               BT_ASSERT(notifs[0]);
-                       } else if (user_data->at < 7) {
-                               notifs[0] =
-                                       src_create_event_notif(
-                                               user_data->packet, UINT64_C(-1));
-                               BT_ASSERT(notifs[0]);
-                       } else if (user_data->at == 7) {
-                               notifs[0] =
-                                       bt_notification_packet_end_create(
-                                               cur_notif_iter,
-                                               user_data->packet);
-                               BT_ASSERT(notifs[0]);
-                       } else if (user_data->at == 8) {
-                               stream = bt_packet_get_stream(user_data->packet);
-                               notifs[0] =
-                                       bt_notification_stream_end_create(
-                                               cur_notif_iter, stream);
-                               bt_put(stream);
-                               BT_ASSERT(notifs[0]);
-                       } else {
-                               status =
-                                       BT_NOTIFICATION_ITERATOR_STATUS_END;
-                       }
-
-                       user_data->at++;
-               } else {
-                       status = src_iter_next_seq(user_data, notifs);
-               }
-               break;
-       case TEST_SIMPLE_4_PORTS:
-       case TEST_4_PORTS_WITH_RETRIES:
-               status = src_iter_next_seq(user_data, notifs);
-               break;
-       case TEST_SINGLE_END_THEN_MULTIPLE_FULL:
-               if (user_data->iter_index == 0) {
-                       ret = bt_private_component_source_add_output_private_port(
-                               private_component, "out1", NULL, NULL);
-                       BT_ASSERT(ret == 0);
-                       ret = bt_private_component_source_add_output_private_port(
-                               private_component, "out2", NULL, NULL);
-                       BT_ASSERT(ret == 0);
-                       status = BT_NOTIFICATION_ITERATOR_STATUS_END;
-               } else {
-                       status = src_iter_next_seq(user_data, notifs);
-               }
-               break;
-       case TEST_SINGLE_AGAIN_END_THEN_MULTIPLE_FULL:
-               if (user_data->iter_index == 0) {
-                       if (user_data->at == 0) {
-                               status = BT_NOTIFICATION_ITERATOR_STATUS_AGAIN;
-                               user_data->at++;
-                       } else {
-                               ret = bt_private_component_source_add_output_private_port(
-                                       private_component, "out1", NULL, NULL);
-                               BT_ASSERT(ret == 0);
-                               ret = bt_private_component_source_add_output_private_port(
-                                       private_component, "out2", NULL, NULL);
-                               BT_ASSERT(ret == 0);
-                               status = BT_NOTIFICATION_ITERATOR_STATUS_END;
-                       }
-               } else {
-                       status = src_iter_next_seq(user_data, notifs);
-               }
-               break;
-       default:
-               abort();
-       }
-
-       bt_put(private_component);
-       return status;
-}
-
-static
-enum bt_component_status src_init(
-               struct bt_private_component *private_component,
-               struct bt_value *params, void *init_method_data)
-{
-       int ret;
-       size_t nb_ports;
-
-       switch (current_test) {
-       case TEST_NO_TS:
-               nb_ports = 2;
-               break;
-       case TEST_SINGLE_END_THEN_MULTIPLE_FULL:
-       case TEST_SINGLE_AGAIN_END_THEN_MULTIPLE_FULL:
-               nb_ports = 1;
-               break;
-       default:
-               nb_ports = 4;
-               break;
-       }
-
-       if (nb_ports >= 1) {
-               ret = bt_private_component_source_add_output_private_port(
-                       private_component, "out0", NULL, NULL);
-               BT_ASSERT(ret == 0);
-       }
-
-       if (nb_ports >= 2) {
-               ret = bt_private_component_source_add_output_private_port(
-                       private_component, "out1", NULL, NULL);
-               BT_ASSERT(ret == 0);
-       }
-
-       if (nb_ports >= 3) {
-               ret = bt_private_component_source_add_output_private_port(
-                       private_component, "out2", NULL, NULL);
-               BT_ASSERT(ret == 0);
-       }
-
-       if (nb_ports >= 4) {
-               ret = bt_private_component_source_add_output_private_port(
-                       private_component, "out3", NULL, NULL);
-               BT_ASSERT(ret == 0);
-       }
-
-       return BT_COMPONENT_STATUS_OK;
-}
-
-static
-void src_finalize(struct bt_private_component *private_component)
-{
-}
-
-static
-void append_test_event_from_notification(struct bt_notification *notification)
-{
-       int ret;
-       struct test_event test_event;
-       struct bt_clock_value *cv;
-
-       switch (bt_notification_get_type(notification)) {
-       case BT_NOTIFICATION_TYPE_EVENT:
-       {
-               struct bt_event *event;
-
-               test_event.type = TEST_EV_TYPE_NOTIF_EVENT;
-               event = bt_notification_event_borrow_event(notification);
-               BT_ASSERT(event);
-               cv = bt_event_borrow_default_clock_value(event);
-
-               if (cv) {
-                       ret = bt_clock_value_get_value_ns_from_epoch(
-                               cv, &test_event.ts_ns);
-                       BT_ASSERT(ret == 0);
-               } else {
-                       test_event.ts_ns = -1;
-               }
-
-               break;
-       }
-       case BT_NOTIFICATION_TYPE_INACTIVITY:
-       {
-               test_event.type = TEST_EV_TYPE_NOTIF_INACTIVITY;
-               cv = bt_notification_inactivity_borrow_default_clock_value(
-                       notification);
-
-               if (cv) {
-                       ret = bt_clock_value_get_value_ns_from_epoch(
-                                       cv, &test_event.ts_ns);
-                       BT_ASSERT(ret == 0);
-               } else {
-                       test_event.ts_ns = -1;
-               }
-
-               break;
-       }
-       case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
-               test_event.type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN;
-               break;
-       case BT_NOTIFICATION_TYPE_PACKET_END:
-               test_event.type = TEST_EV_TYPE_NOTIF_PACKET_END;
-               break;
-       case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
-               test_event.type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN;
-               break;
-       case BT_NOTIFICATION_TYPE_STREAM_END:
-               test_event.type = TEST_EV_TYPE_NOTIF_STREAM_END;
-               break;
-       default:
-               test_event.type = TEST_EV_TYPE_NOTIF_UNEXPECTED;
-               break;
-       }
-
-       append_test_event(&test_event);
-}
-
-static
-enum bt_component_status sink_consume(
-               struct bt_private_component *priv_component)
-{
-       enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
-       bt_notification_array notifications = NULL;
-       uint64_t count;
-       struct sink_user_data *user_data =
-               bt_private_component_get_user_data(priv_component);
-       enum bt_notification_iterator_status it_ret;
-       struct test_event test_event;
-       bool do_append_test_event = true;
-       uint64_t i;
-
-       BT_ASSERT(user_data && user_data->notif_iter);
-       it_ret = bt_private_connection_notification_iterator_next(
-               user_data->notif_iter, &notifications, &count);
-       if (it_ret < 0) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               do_append_test_event = false;
-               goto end;
-       }
-
-       switch (it_ret) {
-       case BT_NOTIFICATION_ITERATOR_STATUS_END:
-               test_event.type = TEST_EV_TYPE_END;
-               ret = BT_COMPONENT_STATUS_END;
-               BT_PUT(user_data->notif_iter);
-               goto end;
-       case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
-               test_event.type = TEST_EV_TYPE_AGAIN;
-               ret = BT_COMPONENT_STATUS_AGAIN;
-               goto end;
-       default:
-               break;
-       }
-
-       BT_ASSERT(notifications);
-
-       for (i = 0; i < count; i++) {
-               append_test_event_from_notification(notifications[i]);
-               bt_put(notifications[i]);
-       }
-
-       do_append_test_event = false;
-
-end:
-       if (do_append_test_event) {
-               append_test_event(&test_event);
-       }
-
-       return ret;
-}
-
-static
-enum bt_component_status sink_port_connected(
-               struct bt_private_component *private_component,
-               struct bt_private_port *self_private_port,
-               struct bt_port *other_port)
-{
-       struct bt_private_connection *priv_conn =
-               bt_private_port_get_private_connection(self_private_port);
-       struct sink_user_data *user_data = bt_private_component_get_user_data(
-               private_component);
-       enum bt_connection_status conn_status;
-
-       BT_ASSERT(user_data);
-       BT_ASSERT(priv_conn);
-       conn_status = bt_private_connection_create_notification_iterator(
-               priv_conn, &user_data->notif_iter);
-       BT_ASSERT(conn_status == 0);
-       bt_put(priv_conn);
-       return BT_COMPONENT_STATUS_OK;
-}
-
-static
-enum bt_component_status sink_init(
-               struct bt_private_component *private_component,
-               struct bt_value *params, void *init_method_data)
-{
-       struct sink_user_data *user_data = g_new0(struct sink_user_data, 1);
-       int ret;
-
-       BT_ASSERT(user_data);
-       ret = bt_private_component_set_user_data(private_component,
-               user_data);
-       BT_ASSERT(ret == 0);
-       ret = bt_private_component_sink_add_input_private_port(
-               private_component, "in", NULL, NULL);
-       BT_ASSERT(ret == 0);
-       return BT_COMPONENT_STATUS_OK;
-}
-
-static
-void sink_finalize(struct bt_private_component *private_component)
-{
-       struct sink_user_data *user_data = bt_private_component_get_user_data(
-               private_component);
-
-       if (user_data) {
-               bt_put(user_data->notif_iter);
-               g_free(user_data);
-       }
-}
-
-static
-void create_source_muxer_sink(struct bt_graph *graph,
-               struct bt_component **source,
-               struct bt_component **muxer,
-               struct bt_component **sink)
-{
-       struct bt_component_class *src_comp_class;
-       struct bt_component_class *muxer_comp_class;
-       struct bt_component_class *sink_comp_class;
-       int ret;
-
-       /* Create source component */
-       src_comp_class = bt_component_class_source_create("src", src_iter_next);
-       BT_ASSERT(src_comp_class);
-       ret = bt_component_class_set_init_method(src_comp_class, src_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_set_finalize_method(src_comp_class,
-               src_finalize);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_notification_iterator_init_method(
-               src_comp_class, src_iter_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_notification_iterator_finalize_method(
-               src_comp_class, src_iter_finalize);
-       BT_ASSERT(ret == 0);
-       ret = bt_graph_add_component(graph, src_comp_class, "source", NULL, source);
-       BT_ASSERT(ret == 0);
-
-       /* Create muxer component */
-       muxer_comp_class = bt_plugin_find_component_class("utils", "muxer",
-               BT_COMPONENT_CLASS_TYPE_FILTER);
-       BT_ASSERT(muxer_comp_class);
-       ret = bt_graph_add_component(graph, muxer_comp_class, "muxer", NULL, muxer);
-       BT_ASSERT(ret == 0);
-
-       /* Create sink component */
-       sink_comp_class = bt_component_class_sink_create("sink", sink_consume);
-       BT_ASSERT(sink_comp_class);
-       ret = bt_component_class_set_init_method(sink_comp_class, sink_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_set_finalize_method(sink_comp_class,
-               sink_finalize);
-       ret = bt_component_class_set_port_connected_method(sink_comp_class,
-               sink_port_connected);
-       BT_ASSERT(ret == 0);
-       ret = bt_graph_add_component(graph, sink_comp_class, "sink", NULL, sink);
-       BT_ASSERT(ret == 0);
-
-       bt_put(src_comp_class);
-       bt_put(muxer_comp_class);
-       bt_put(sink_comp_class);
-}
-
-static
-void do_std_test(enum test test, const char *name,
-               const struct test_event *expected_test_events,
-               bool with_upstream)
-{
-       struct bt_component *src_comp;
-       struct bt_component *muxer_comp;
-       struct bt_component *sink_comp;
-       struct bt_port *upstream_port;
-       struct bt_port *downstream_port;
-       int64_t i;
-       int64_t count;
-       enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
-
-       clear_test_events();
-       current_test = test;
-       diag("test: %s", name);
-       BT_ASSERT(!graph);
-       graph = bt_graph_create();
-       BT_ASSERT(graph);
-       create_source_muxer_sink(graph, &src_comp, &muxer_comp, &sink_comp);
-
-       /* Connect source output ports to muxer input ports */
-       if (with_upstream) {
-               count = bt_component_source_get_output_port_count(src_comp);
-               BT_ASSERT(count >= 0);
-
-               for (i = 0; i < count; i++) {
-                       upstream_port = bt_component_source_get_output_port_by_index(
-                               src_comp, i);
-                       BT_ASSERT(upstream_port);
-                       downstream_port = bt_component_filter_get_input_port_by_index(
-                               muxer_comp, i);
-                       BT_ASSERT(downstream_port);
-                       graph_status = bt_graph_connect_ports(graph,
-                               upstream_port, downstream_port, NULL);
-                       BT_ASSERT(graph_status == 0);
-                       bt_put(upstream_port);
-                       bt_put(downstream_port);
-               }
-       }
-
-       /* Connect muxer output port to sink input port */
-       upstream_port = bt_component_filter_get_output_port_by_name(muxer_comp,
-               "out");
-       BT_ASSERT(upstream_port);
-       downstream_port = bt_component_sink_get_input_port_by_name(sink_comp, "in");
-       BT_ASSERT(downstream_port);
-       graph_status = bt_graph_connect_ports(graph, upstream_port,
-               downstream_port, NULL);
-       BT_ASSERT(graph_status == 0);
-       bt_put(upstream_port);
-       bt_put(downstream_port);
-
-       while (graph_status == BT_GRAPH_STATUS_OK ||
-                       graph_status == BT_GRAPH_STATUS_AGAIN) {
-               graph_status = bt_graph_run(graph);
-       }
-
-       ok(graph_status == BT_GRAPH_STATUS_END, "graph finishes without any error");
-       ok(compare_test_events(expected_test_events),
-               "the produced sequence of test events is the expected one");
-
-       bt_put(src_comp);
-       bt_put(muxer_comp);
-       bt_put(sink_comp);
-       BT_PUT(graph);
-}
-
-static
-void test_no_ts(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = -1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = -1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = -1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = -1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = -1, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 1, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 4, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 189, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 1001, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_NO_TS, "event notifications with no time",
-               expected_test_events, true);
-}
-
-static
-void test_no_upstream_connection(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_NO_UPSTREAM_CONNECTION, "no upstream connection",
-               expected_test_events, false);
-}
-
-static
-void test_simple_4_ports(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 8 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 24 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 41 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 51 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 53 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 56 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 59 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 68 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 71 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 77 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 91 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 97 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 105 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 119 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 120 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 121 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 138 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 139 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 154 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 170 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 179 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 209 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 210 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 222 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 228 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 240 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 254 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 266 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 292 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 298 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 317 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 320 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 350 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 352 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 353 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 393 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 407 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 419 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 433 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 454 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 471 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 473 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 478 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 479 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 481 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 487 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 504 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 525 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 572 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 591 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 605 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 612 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 615 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 618 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 624 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 631 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 632 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 644 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 651 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 668 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 670 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 678 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 696 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 708 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 714 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 717 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 731 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 733 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 744 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 750 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 766 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 778 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 788 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 790 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 819 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 820 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 825 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 836 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 850 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 852 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 857 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 863 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 867 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 871 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 884 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 892 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 903 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 931 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 944 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 951 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 953 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 956 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 985 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 996 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 998 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 999 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_SIMPLE_4_PORTS, "simple: 4 ports without retries",
-               expected_test_events, true);
-}
-
-static
-void test_4_ports_with_retries(void)
-{
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_AGAIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 8 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 24 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 41 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 51 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 53 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 56 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 59 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 68 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 71 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 77 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 91 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 97 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 105 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 119 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 120 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 121 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 138 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 139 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 154 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 170 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 179 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 209 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 210 },
-               { .type = TEST_EV_TYPE_AGAIN, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 222 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 228 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 240 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 254 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 266 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 292 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 298 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 317 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 320 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 350 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 352 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 353 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 393 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 407 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 419 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 433 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 454 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 471 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 473 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 478 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 479 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 481 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 487 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 504 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 525 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 572 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 591 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 605 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 612 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 615 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 618 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 624 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 631 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 632 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 644 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 651 },
-               { .type = TEST_EV_TYPE_AGAIN, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 668 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 670 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 678 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 696 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 708 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 714 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 717 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 731 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 733 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 744 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 750 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 766 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 778 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 788 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 790 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 819 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 820 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 825 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 836 },
-               { .type = TEST_EV_TYPE_AGAIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 850 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 852 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 857 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 863 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 867 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 871 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 884 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 892 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 903 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 931 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 944 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 951 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 953 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 956 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 985 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 996 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 998 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 999 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       do_std_test(TEST_4_PORTS_WITH_RETRIES, "4 ports with retries",
-               expected_test_events, true);
-}
-
-static
-void connect_port_to_first_avail_muxer_port(struct bt_graph *graph,
-               struct bt_port *source_port,
-               struct bt_component *muxer_comp)
-{
-       struct bt_port *avail_muxer_port = NULL;
-       int64_t i;
-       int64_t count;
-       enum bt_graph_status graph_status;
-
-       count = bt_component_filter_get_input_port_count(muxer_comp);
-       BT_ASSERT(count >= 0);
-
-       for (i = 0; i < count; i++) {
-               struct bt_port *muxer_port =
-                       bt_component_filter_get_input_port_by_index(
-                               muxer_comp, i);
-
-               BT_ASSERT(muxer_port);
-
-               if (!bt_port_is_connected(muxer_port)) {
-                       BT_MOVE(avail_muxer_port, muxer_port);
-                       break;
-               } else {
-                       bt_put(muxer_port);
-               }
-       }
-
-       graph_status = bt_graph_connect_ports(graph, source_port,
-               avail_muxer_port, NULL);
-       BT_ASSERT(graph_status == 0);
-       bt_put(avail_muxer_port);
-}
-
-static
-void graph_port_added_listener_connect_to_avail_muxer_port(struct bt_port *port,
-               void *data)
-{
-       struct graph_listener_data *graph_listener_data = data;
-       struct bt_component *comp;
-
-       comp = bt_port_get_component(port);
-       BT_ASSERT(comp);
-
-       if (comp != graph_listener_data->source) {
-               goto end;
-       }
-
-       connect_port_to_first_avail_muxer_port(graph_listener_data->graph,
-               port, graph_listener_data->muxer);
-
-end:
-       bt_put(comp);
-}
-
-static
-void test_single_end_then_multiple_full(void)
-{
-       struct bt_component *src_comp;
-       struct bt_component *muxer_comp;
-       struct bt_component *sink_comp;
-       struct bt_port *upstream_port;
-       struct bt_port *downstream_port;
-       int64_t i;
-       int64_t count;
-       int ret;
-       enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
-       struct graph_listener_data graph_listener_data;
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 8 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 51 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 59 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 68 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 71 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 77 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 91 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 121 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 139 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 170 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 179 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 209 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 254 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 266 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 298 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 320 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 350 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 352 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 393 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 419 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 454 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 478 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 624 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 631 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 644 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 651 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 668 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 678 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 714 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 717 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 731 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 733 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 744 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 750 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 778 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 788 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 790 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 819 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 820 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 836 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 857 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 892 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 903 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 944 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 998 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       clear_test_events();
-       current_test = TEST_SINGLE_END_THEN_MULTIPLE_FULL;
-       diag("test: single end then multiple full");
-       BT_ASSERT(!graph);
-       graph = bt_graph_create();
-       BT_ASSERT(graph);
-       create_source_muxer_sink(graph, &src_comp, &muxer_comp, &sink_comp);
-       graph_listener_data.graph = graph;
-       graph_listener_data.source = src_comp;
-       graph_listener_data.muxer = muxer_comp;
-       graph_listener_data.sink = sink_comp;
-       ret = bt_graph_add_port_added_listener(graph,
-               graph_port_added_listener_connect_to_avail_muxer_port, NULL,
-               &graph_listener_data);
-       BT_ASSERT(ret >= 0);
-
-       /* Connect source output ports to muxer input ports */
-       count = bt_component_source_get_output_port_count(src_comp);
-       BT_ASSERT(ret == 0);
-
-       for (i = 0; i < count; i++) {
-               upstream_port = bt_component_source_get_output_port_by_index(
-                       src_comp, i);
-               BT_ASSERT(upstream_port);
-               connect_port_to_first_avail_muxer_port(graph,
-                       upstream_port, muxer_comp);
-               bt_put(upstream_port);
-       }
-
-       /* Connect muxer output port to sink input port */
-       upstream_port = bt_component_filter_get_output_port_by_name(muxer_comp,
-               "out");
-       BT_ASSERT(upstream_port);
-       downstream_port = bt_component_sink_get_input_port_by_name(sink_comp, "in");
-       BT_ASSERT(downstream_port);
-       graph_status = bt_graph_connect_ports(graph, upstream_port,
-               downstream_port, NULL);
-       BT_ASSERT(graph_status == 0);
-       bt_put(upstream_port);
-       bt_put(downstream_port);
-
-       while (graph_status == BT_GRAPH_STATUS_OK ||
-                       graph_status == BT_GRAPH_STATUS_AGAIN) {
-               graph_status = bt_graph_run(graph);
-       }
-
-       ok(graph_status == BT_GRAPH_STATUS_END, "graph finishes without any error");
-       ok(compare_test_events(expected_test_events),
-               "the produced sequence of test events is the expected one");
-
-       bt_put(src_comp);
-       bt_put(muxer_comp);
-       bt_put(sink_comp);
-       BT_PUT(graph);
-}
-
-static
-void test_single_again_end_then_multiple_full(void)
-{
-       struct bt_component *src_comp;
-       struct bt_component *muxer_comp;
-       struct bt_component *sink_comp;
-       struct bt_port *upstream_port;
-       struct bt_port *downstream_port;
-       int64_t i;
-       int64_t count;
-       int ret;
-       enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
-       struct graph_listener_data graph_listener_data;
-       const struct test_event expected_test_events[] = {
-               { .type = TEST_EV_TYPE_AGAIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 8 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 51 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 59 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 68 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 71 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 77 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 91 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 121 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 139 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 170 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 179 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 209 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 254 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 266 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 298 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 320 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 350 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 352 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 393 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 419 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 454 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 478 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 624 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 631 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 644 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 651 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 668 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 678 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 714 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 717 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 731 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 733 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 744 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 750 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 778 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 788 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 790 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 819 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 820 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 836 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 857 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 892 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 903 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 944 },
-               { .type = TEST_EV_TYPE_NOTIF_EVENT, .ts_ns = 998 },
-               { .type = TEST_EV_TYPE_NOTIF_PACKET_END, },
-               { .type = TEST_EV_TYPE_NOTIF_STREAM_END, },
-               { .type = TEST_EV_TYPE_END, },
-               { .type = TEST_EV_TYPE_SENTINEL, },
-       };
-
-       clear_test_events();
-       current_test = TEST_SINGLE_AGAIN_END_THEN_MULTIPLE_FULL;
-       diag("test: single again then end then multiple full");
-       BT_ASSERT(!graph);
-       graph = bt_graph_create();
-       BT_ASSERT(graph);
-       create_source_muxer_sink(graph, &src_comp, &muxer_comp, &sink_comp);
-       graph_listener_data.graph = graph;
-       graph_listener_data.source = src_comp;
-       graph_listener_data.muxer = muxer_comp;
-       graph_listener_data.sink = sink_comp;
-       ret = bt_graph_add_port_added_listener(graph,
-               graph_port_added_listener_connect_to_avail_muxer_port, NULL,
-               &graph_listener_data);
-       BT_ASSERT(ret >= 0);
-
-       /* Connect source output ports to muxer input ports */
-       count = bt_component_source_get_output_port_count(src_comp);
-       BT_ASSERT(ret == 0);
-
-       for (i = 0; i < count; i++) {
-               upstream_port = bt_component_source_get_output_port_by_index(
-                       src_comp, i);
-               BT_ASSERT(upstream_port);
-               connect_port_to_first_avail_muxer_port(graph,
-                       upstream_port, muxer_comp);
-               bt_put(upstream_port);
-       }
-
-       /* Connect muxer output port to sink input port */
-       upstream_port = bt_component_filter_get_output_port_by_name(muxer_comp,
-               "out");
-       BT_ASSERT(upstream_port);
-       downstream_port = bt_component_sink_get_input_port_by_name(sink_comp, "in");
-       BT_ASSERT(downstream_port);
-       graph_status = bt_graph_connect_ports(graph, upstream_port,
-               downstream_port, NULL);
-       BT_ASSERT(graph_status == 0);
-       bt_put(upstream_port);
-       bt_put(downstream_port);
-
-       while (graph_status == BT_GRAPH_STATUS_OK ||
-                       graph_status == BT_GRAPH_STATUS_AGAIN) {
-               graph_status = bt_graph_run(graph);
-       }
-
-       ok(graph_status == BT_GRAPH_STATUS_END, "graph finishes without any error");
-       ok(compare_test_events(expected_test_events),
-               "the produced sequence of test events is the expected one");
-
-       bt_put(src_comp);
-       bt_put(muxer_comp);
-       bt_put(sink_comp);
-       BT_PUT(graph);
-}
-
-#define DEBUG_ENV_VAR  "TEST_UTILS_MUXER_DEBUG"
-
-int main(int argc, char **argv)
-{
-       if (getenv(DEBUG_ENV_VAR) && strcmp(getenv(DEBUG_ENV_VAR), "1") == 0) {
-               debug = true;
-       }
-
-       plan_tests(NR_TESTS);
-       init_static_data();
-       test_no_ts();
-       test_no_upstream_connection();
-       test_simple_4_ports();
-       test_4_ports_with_retries();
-       test_single_end_then_multiple_full();
-       test_single_again_end_then_multiple_full();
-       fini_static_data();
-       return exit_status();
-}
This page took 0.625272 seconds and 4 git commands to generate.