ctf-writer: externalize libbabeltrace2-ctf-writer
authorMichael Jeanson <mjeanson@efficios.com>
Fri, 7 Jun 2019 16:25:10 +0000 (12:25 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 11 Jun 2019 21:14:32 +0000 (17:14 -0400)
Completely split the ctf writer part from the main babeltrace2 library.

 * Remove the obsolete libbabeltrace2-ctf library
 * Add a new libbabeltrace2-ctf-writer library
 * Remove the ctf writer includes from the main include file
 * Fork an internal copy of assert-pre.h that doesn't use the library
   structures.
 * Add a logging context specific to ctf writer

Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Change-Id: Iff9ab62ee9eeb8abd290fb1d758a73050e21c99b
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1410
Tested-by: jenkins
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
65 files changed:
.gitignore
Makefile.am
babeltrace2-ctf-writer.pc.in [new file with mode: 0644]
babeltrace2-ctf.pc.in [deleted file]
configure.ac
ctf-writer/Makefile.am [new file with mode: 0644]
ctf-writer/attributes.c [new file with mode: 0644]
ctf-writer/clock-class.c [new file with mode: 0644]
ctf-writer/clock.c [new file with mode: 0644]
ctf-writer/event-class.c [new file with mode: 0644]
ctf-writer/event.c [new file with mode: 0644]
ctf-writer/field-path.c [new file with mode: 0644]
ctf-writer/field-types.c [new file with mode: 0644]
ctf-writer/field-wrapper.c [new file with mode: 0644]
ctf-writer/fields.c [new file with mode: 0644]
ctf-writer/functor.c [new file with mode: 0644]
ctf-writer/logging.c [new file with mode: 0644]
ctf-writer/logging.h [new file with mode: 0644]
ctf-writer/object-pool.c [new file with mode: 0644]
ctf-writer/object.c [new file with mode: 0644]
ctf-writer/resolve.c [new file with mode: 0644]
ctf-writer/stream-class.c [new file with mode: 0644]
ctf-writer/stream.c [new file with mode: 0644]
ctf-writer/trace.c [new file with mode: 0644]
ctf-writer/utils.c [new file with mode: 0644]
ctf-writer/validation.c [new file with mode: 0644]
ctf-writer/values.c [new file with mode: 0644]
ctf-writer/visitor.c [new file with mode: 0644]
ctf-writer/writer.c [new file with mode: 0644]
extras/gen-babeltrace-h.py
include/Makefile.am
include/babeltrace2/babeltrace.h
include/babeltrace2/ctf-writer/assert-pre-internal.h [new file with mode: 0644]
include/babeltrace2/ctf-writer/event-class-internal.h
include/babeltrace2/ctf-writer/event-internal.h
include/babeltrace2/ctf-writer/field-types-internal.h
include/babeltrace2/ctf-writer/fields-internal.h
include/babeltrace2/ctf-writer/stream-class-internal.h
include/babeltrace2/ctf-writer/stream-internal.h
include/babeltrace2/ctf-writer/trace-internal.h
lib/Makefile.am
lib/ctf-writer/Makefile.am [deleted file]
lib/ctf-writer/attributes.c [deleted file]
lib/ctf-writer/clock-class.c [deleted file]
lib/ctf-writer/clock.c [deleted file]
lib/ctf-writer/event-class.c [deleted file]
lib/ctf-writer/event.c [deleted file]
lib/ctf-writer/field-path.c [deleted file]
lib/ctf-writer/field-types.c [deleted file]
lib/ctf-writer/field-wrapper.c [deleted file]
lib/ctf-writer/fields.c [deleted file]
lib/ctf-writer/functor.c [deleted file]
lib/ctf-writer/object-pool.c [deleted file]
lib/ctf-writer/object.c [deleted file]
lib/ctf-writer/resolve.c [deleted file]
lib/ctf-writer/stream-class.c [deleted file]
lib/ctf-writer/stream.c [deleted file]
lib/ctf-writer/trace.c [deleted file]
lib/ctf-writer/utils.c [deleted file]
lib/ctf-writer/validation.c [deleted file]
lib/ctf-writer/values.c [deleted file]
lib/ctf-writer/visitor.c [deleted file]
lib/ctf-writer/writer.c [deleted file]
tests/lib/Makefile.am
tests/lib/test_trace_ir_ref.c

index 13fdf9581ce42dea760662fc5aeb71827896318f..9c71bb9d64ee4ba9ccf3845846516a90effb2b8e 100644 (file)
@@ -88,7 +88,7 @@ core
 stamp-h1
 __pycache__
 /babeltrace2.pc
-/babeltrace2-ctf.pc
+/babeltrace2-ctf-writer.pc
 TAGS
 cscope*
 doc/api/Doxyfile
index 76ba8249d5bd33e28086f4d390b72de1c63c6def..938dc75bbcdf23b7bdf868dfcfc9d0e5d0c2aaf5 100644 (file)
@@ -8,6 +8,7 @@ SUBDIRS = include               \
        logging                 \
        lib                     \
        python-plugin-provider  \
+       ctf-writer              \
        plugins                 \
        cli                     \
        bindings                \
@@ -24,7 +25,7 @@ dist_doc_DATA = ChangeLog LICENSE mit-license.txt gpl-2.0.txt \
 dist_noinst_DATA = CodingStyle
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = babeltrace2.pc babeltrace2-ctf.pc
+pkgconfig_DATA = babeltrace2.pc babeltrace2-ctf-writer.pc
 
 # This is a convenience target, it's not part of the build process.
 CONTRIBUTING.html: CONTRIBUTING.adoc
diff --git a/babeltrace2-ctf-writer.pc.in b/babeltrace2-ctf-writer.pc.in
new file mode 100644 (file)
index 0000000..504d859
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Babeltrace CTF parser
+Description: libbabeltrace2-ctf provides the specific bits necessary to write a Common Trace Format (CTF) trace.
+Version: @PACKAGE_VERSION@
+Requires:
+Requires.private: uuid popt
+Libs: -L${libdir} -lbabeltrace2-ctf-writer
+Cflags: -I${includedir}
+
diff --git a/babeltrace2-ctf.pc.in b/babeltrace2-ctf.pc.in
deleted file mode 100644 (file)
index b20d98b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Babeltrace CTF parser
-Description: libbabeltrace2-ctf provides the specific bits necessary to read a Common Trace Format (CTF) trace.
-Version: @PACKAGE_VERSION@
-Requires: babeltrace
-Requires.private:
-Libs: -L${libdir} -lbabeltrace2-ctf
-Cflags: -I${includedir}
-
index 3fc2eb94dea64d229a556289ac1c72d6d71dc930..b4f1e915a68821b5b1c4e7388bdd946e9d37f958 100644 (file)
@@ -732,6 +732,7 @@ AC_CONFIG_FILES([
        bindings/python/bt2/bt2/__init__.py
        common/Makefile
        ctfser/Makefile
+       ctf-writer/Makefile
        compat/Makefile
        cli/Makefile
        doc/Makefile
@@ -749,7 +750,6 @@ AC_CONFIG_FILES([
        lib/graph/Makefile
        lib/graph/message/Makefile
        lib/trace-ir/Makefile
-       lib/ctf-writer/Makefile
        include/Makefile
        logging/Makefile
        bindings/Makefile
@@ -782,7 +782,7 @@ AC_CONFIG_FILES([
        plugins/lttng-utils/Makefile
        plugins/lttng-utils/debug-info/Makefile
        babeltrace2.pc
-       babeltrace2-ctf.pc
+       babeltrace2-ctf-writer.pc
 ])
 
 AC_CONFIG_FILES([tests/cli/test_intersection], [chmod +x tests/cli/test_intersection])
diff --git a/ctf-writer/Makefile.am b/ctf-writer/Makefile.am
new file mode 100644 (file)
index 0000000..7c5d046
--- /dev/null
@@ -0,0 +1,36 @@
+lib_LTLIBRARIES = libbabeltrace2-ctf-writer.la
+
+libbabeltrace2_ctf_writer_la_SOURCES = \
+       attributes.c \
+       clock.c \
+       clock-class.c \
+       event.c \
+       event-class.c \
+       field-path.c \
+       fields.c \
+       field-types.c \
+       field-wrapper.c \
+       functor.c \
+       logging.c \
+       logging.h \
+       object.c \
+       object-pool.c \
+       resolve.c \
+       stream.c \
+       stream-class.c \
+       trace.c \
+       utils.c \
+       validation.c \
+       values.c \
+       visitor.c \
+       writer.c
+
+libbabeltrace2_ctf_writer_la_LDFLAGS = $(LT_NO_UNDEFINED) \
+                       -version-info $(BABELTRACE_LIBRARY_VERSION)
+
+libbabeltrace2_ctf_writer_la_LIBADD = \
+       $(top_builddir)/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/common/libbabeltrace2-common.la \
+       $(top_builddir)/ctfser/libbabeltrace2-ctfser.la \
+       $(top_builddir)/compat/libcompat.la \
+       $(UUID_LIBS)
diff --git a/ctf-writer/attributes.c b/ctf-writer/attributes.c
new file mode 100644 (file)
index 0000000..fbb81a0
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * attributes.c
+ *
+ * Babeltrace CTF writer - Attributes
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 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 "CTF-WRITER-ATTRS"
+#include "logging.h"
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/babeltrace-internal.h>
+#include <babeltrace2/compat/string-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <inttypes.h>
+
+#define BT_CTF_ATTR_NAME_INDEX         0
+#define BT_CTF_ATTR_VALUE_INDEX                1
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_create(void)
+{
+       struct bt_ctf_private_value *attr_obj;
+
+       /*
+        * Attributes: array value object of array value objects, each one
+        * containing two entries: a string value object (attributes
+        * field name), and a value object (attributes field value).
+        *
+        * Example (JSON representation):
+        *
+        *     [
+        *         ["hostname", "eeppdesk"],
+        *         ["sysname", "Linux"],
+        *         ["tracer_major", 2],
+        *         ["tracer_minor", 5]
+        *     ]
+        */
+       BT_LOGD_STR("Creating attributes object.");
+       attr_obj = bt_ctf_private_value_array_create();
+       if (!attr_obj) {
+               BT_LOGE_STR("Failed to create array value.");
+       } else {
+               BT_LOGD("Created attributes object: addr=%p",
+                       attr_obj);
+       }
+
+       return attr_obj;
+}
+
+BT_HIDDEN
+void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj)
+{
+       BT_LOGD("Destroying attributes object: addr=%p", attr_obj);
+       bt_ctf_object_put_ref(attr_obj);
+}
+
+BT_HIDDEN
+int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj)
+{
+       return bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
+}
+
+BT_HIDDEN
+const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj,
+               uint64_t index)
+{
+       const char *ret = NULL;
+       struct bt_ctf_private_value *attr_field_obj = NULL;
+       struct bt_ctf_private_value *attr_field_name_obj = NULL;
+
+       if (!attr_obj) {
+               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
+               goto end;
+       }
+
+       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "index=%" PRIu64 ", count=%" PRId64,
+                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
+               attr_obj, index);
+       if (!attr_field_obj) {
+               BT_LOGE("Cannot get attributes object's array value's element by index: "
+                       "value-addr=%p, index=%" PRIu64, attr_obj, index);
+               goto end;
+       }
+
+       attr_field_name_obj =
+               bt_ctf_private_value_array_borrow_element_by_index(
+                       attr_field_obj, BT_CTF_ATTR_NAME_INDEX);
+       if (!attr_field_name_obj) {
+               BT_LOGE("Cannot get attribute array value's element by index: "
+                       "value-addr=%p, index=%" PRIu64, attr_field_obj,
+                       (uint64_t) BT_CTF_ATTR_NAME_INDEX);
+               goto end;
+       }
+
+       ret = bt_ctf_value_string_get(
+               bt_ctf_private_value_as_value(attr_field_name_obj));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj,
+               uint64_t index)
+{
+       struct bt_ctf_private_value *value_obj = NULL;
+       struct bt_ctf_private_value *attr_field_obj = NULL;
+
+       if (!attr_obj) {
+               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
+               goto end;
+       }
+
+       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "index=%" PRIu64 ", count=%" PRId64,
+                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
+               attr_obj, index);
+       if (!attr_field_obj) {
+               BT_LOGE("Cannot get attributes object's array value's element by index: "
+                       "value-addr=%p, index=%" PRIu64, attr_obj, index);
+               goto end;
+       }
+
+       value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
+               BT_CTF_ATTR_VALUE_INDEX);
+       if (!value_obj) {
+               BT_LOGE("Cannot get attribute array value's element by index: "
+                       "value-addr=%p, index=%" PRIu64, attr_field_obj,
+                       (uint64_t) BT_CTF_ATTR_VALUE_INDEX);
+       }
+
+end:
+       return value_obj;
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_by_name(
+               struct bt_ctf_private_value *attr_obj, const char *name)
+{
+       uint64_t i;
+       int64_t attr_size;
+       struct bt_ctf_private_value *value_obj = NULL;
+       struct bt_ctf_private_value *attr_field_name_obj = NULL;
+
+       attr_size = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
+       if (attr_size < 0) {
+               BT_LOGE("Cannot get array value's size: value-addr=%p",
+                       attr_obj);
+               goto error;
+       }
+
+       for (i = 0; i < attr_size; ++i) {
+               const char *field_name;
+
+               value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_obj, i);
+               if (!value_obj) {
+                       BT_LOGE("Cannot get attributes object's array value's element by index: "
+                               "value-addr=%p, index=%" PRIu64, attr_obj, i);
+                       goto error;
+               }
+
+               attr_field_name_obj = bt_ctf_private_value_array_borrow_element_by_index(value_obj,
+                       BT_CTF_ATTR_NAME_INDEX);
+               if (!attr_field_name_obj) {
+                       BT_LOGE("Cannot get attribute array value's element by index: "
+                               "value-addr=%p, index=%" PRIu64,
+                               value_obj, (int64_t) BT_CTF_ATTR_NAME_INDEX);
+                       goto error;
+               }
+
+               field_name = bt_ctf_value_string_get(
+                       bt_ctf_private_value_as_value(attr_field_name_obj));
+
+               if (!strcmp(field_name, name)) {
+                       break;
+               }
+
+               value_obj = NULL;
+       }
+
+       return value_obj;
+
+error:
+       value_obj = NULL;
+       return value_obj;
+}
+
+BT_HIDDEN
+int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj,
+               const char *name, struct bt_ctf_private_value *value_obj)
+{
+       int ret = 0;
+       struct bt_ctf_private_value *attr_field_obj = NULL;
+
+       if (!attr_obj || !name || !value_obj) {
+               BT_LOGW("Invalid parameter: attributes object, name, or value object is NULL: "
+                       "attr-value-addr=%p, name-addr=%p, value-addr=%p",
+                       attr_obj, name, value_obj);
+               ret = -1;
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name);
+       if (attr_field_obj) {
+               ret = bt_ctf_private_value_array_set_element_by_index(
+                       attr_field_obj, BT_CTF_ATTR_VALUE_INDEX,
+                       bt_ctf_private_value_as_value(value_obj));
+               attr_field_obj = NULL;
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_private_value_array_create();
+       if (!attr_field_obj) {
+               BT_LOGE_STR("Failed to create empty array value.");
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_private_value_array_append_string_element(attr_field_obj, name);
+       ret |= bt_ctf_private_value_array_append_element(attr_field_obj,
+               bt_ctf_private_value_as_value(value_obj));
+       if (ret) {
+               BT_LOGE("Cannot append elements to array value: addr=%p",
+                       attr_field_obj);
+               goto end;
+       }
+
+       ret = bt_ctf_private_value_array_append_element(attr_obj,
+               bt_ctf_private_value_as_value(attr_field_obj));
+       if (ret) {
+               BT_LOGE("Cannot append element to array value: "
+                       "array-value-addr=%p, element-value-addr=%p",
+                       attr_obj, attr_field_obj);
+       }
+
+end:
+       bt_ctf_object_put_ref(attr_field_obj);
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name(
+               struct bt_ctf_private_value *attr_obj, const char *name)
+{
+       struct bt_ctf_private_value *value_obj = NULL;
+       struct bt_ctf_private_value *attr_field_obj = NULL;
+
+       if (!attr_obj || !name) {
+               BT_LOGW("Invalid parameter: attributes object or name is NULL: "
+                       "value-addr=%p, name-addr=%p", attr_obj, name);
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name);
+       if (!attr_field_obj) {
+               BT_LOGD("Cannot find attributes object's field by name: "
+                       "value-addr=%p, name=\"%s\"", attr_obj, name);
+               goto end;
+       }
+
+       value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
+               BT_CTF_ATTR_VALUE_INDEX);
+       if (!value_obj) {
+               BT_LOGE("Cannot get attribute array value's element by index: "
+                       "value-addr=%p, index=%" PRIu64, attr_field_obj,
+                       (uint64_t) BT_CTF_ATTR_VALUE_INDEX);
+       }
+
+end:
+       return value_obj;
+}
+
+BT_HIDDEN
+int bt_ctf_attributes_freeze(struct bt_ctf_private_value *attr_obj)
+{
+       uint64_t i;
+       int64_t count;
+       int ret = 0;
+
+       if (!attr_obj) {
+               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGD("Freezing attributes object: value-addr=%p", attr_obj);
+       count = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
+       BT_ASSERT(count >= 0);
+
+       /*
+        * We do not freeze the array value object itself here, since
+        * internal stuff could need to modify/add attributes. Each
+        * attribute is frozen one by one.
+        */
+       for (i = 0; i < count; ++i) {
+               struct bt_ctf_private_value *obj = NULL;
+
+               obj = bt_ctf_attributes_borrow_field_value(attr_obj, i);
+               if (!obj) {
+                       BT_LOGE("Cannot get attributes object's field value by index: "
+                               "value-addr=%p, index=%" PRIu64,
+                               attr_obj, i);
+                       ret = -1;
+                       goto end;
+               }
+
+               bt_ctf_value_freeze(bt_ctf_private_value_as_value(obj));
+       }
+
+end:
+       return ret;
+}
diff --git a/ctf-writer/clock-class.c b/ctf-writer/clock-class.c
new file mode 100644 (file)
index 0000000..1c507e3
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * clock-class.c
+ *
+ * Babeltrace CTF writer - Clock class
+ *
+ * Copyright 2013, 2014 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.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-CLOCK-CLASS"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/compat/uuid-internal.h>
+#include <babeltrace2/ctf-writer/clock-class-internal.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/compat/string-internal.h>
+#include <inttypes.h>
+#include <babeltrace2/ctf-writer/object-internal.h>
+#include <babeltrace2/assert-internal.h>
+
+static
+void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class)
+{
+       return clock_class && clock_class->name;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class,
+               const char *name)
+{
+       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_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_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->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;
+}
+
+static
+bool validate_freq(struct bt_ctf_clock_class *clock_class,
+               const char *name, uint64_t freq)
+{
+       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_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name,
+               uint64_t freq)
+{
+       int ret;
+       struct bt_ctf_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;
+       }
+
+       clock_class = g_new0(struct bt_ctf_clock_class, 1);
+       if (!clock_class) {
+               BT_LOGE_STR("Failed to allocate one clock class.");
+               goto error;
+       }
+
+       clock_class->precision = 1;
+       clock_class->frequency = freq;
+       bt_ctf_object_init_shared(&clock_class->base, bt_ctf_clock_class_destroy);
+
+       if (name) {
+               ret = bt_ctf_clock_class_set_name(clock_class, name);
+               if (ret) {
+                       /* bt_ctf_clock_class_set_name() logs errors */
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Created clock class object: addr=%p, name=\"%s\"",
+               clock_class, name);
+       return clock_class;
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock_class);
+       return clock_class;
+}
+
+BT_HIDDEN
+const char *bt_ctf_clock_class_get_name(struct bt_ctf_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;
+}
+
+BT_HIDDEN
+const char *bt_ctf_clock_class_get_description(
+               struct bt_ctf_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->description) {
+               ret = clock_class->description->str;
+       }
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class,
+               const char *desc)
+{
+       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_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class), desc);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_clock_class_get_frequency(
+               struct bt_ctf_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_HIDDEN
+int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class,
+               uint64_t freq)
+{
+       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_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (!validate_freq(clock_class, bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class), freq);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_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_HIDDEN
+int bt_ctf_clock_class_set_precision(struct bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       clock_class->precision = precision;
+       BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64,
+               clock_class, bt_ctf_clock_class_get_name(clock_class),
+               precision);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class,
+               int64_t *offset_s)
+{
+       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_ctf_clock_class_get_name(clock_class),
+                       offset_s);
+               ret = -1;
+               goto end;
+       }
+
+       *offset_s = clock_class->offset_s;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_offset_s(struct bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class),
+               offset_s);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_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_ctf_clock_class_get_name(clock_class),
+                       offset);
+               ret = -1;
+               goto end;
+       }
+
+       *offset = clock_class->offset;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class,
+               int64_t offset)
+{
+       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_ctf_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_ctf_clock_class_get_name(clock_class), offset);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_clock_class_is_absolute(struct bt_ctf_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_HIDDEN
+int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class),
+               is_absolute);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+const unsigned char *bt_ctf_clock_class_get_uuid(
+               struct bt_ctf_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_ctf_clock_class_get_name(clock_class));
+               ret = NULL;
+               goto end;
+       }
+
+       ret = clock_class->uuid;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class,
+               const unsigned char *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_ctf_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_ctf_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_ctf_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_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class)
+{
+       if (!clock_class || clock_class->frozen) {
+               return;
+       }
+
+       BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"",
+               clock_class, bt_ctf_clock_class_get_name(clock_class));
+       clock_class->frozen = 1;
+}
+
+static
+void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_clock_class *clock_class;
+
+       clock_class = container_of(obj, struct bt_ctf_clock_class, base);
+       BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"",
+               obj, bt_ctf_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);
+       }
+
+       g_free(clock_class);
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a,
+               struct bt_ctf_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;
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
diff --git a/ctf-writer/clock.c b/ctf-writer/clock.c
new file mode 100644 (file)
index 0000000..0238c25
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * clock.c
+ *
+ * Babeltrace CTF writer - Clock
+ *
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017 Philippe Proulx <pproulx@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.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-CLOCK"
+#include "logging.h"
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compat/uuid-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/clock-class-internal.h>
+#include <babeltrace2/ctf-writer/clock-internal.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/writer-internal.h>
+#include <babeltrace2/ctf-writer/object-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <inttypes.h>
+
+static
+void bt_ctf_clock_destroy(struct bt_ctf_object *obj);
+
+struct bt_ctf_clock *bt_ctf_clock_create(const char *name)
+{
+       int ret;
+       struct bt_ctf_clock *clock = NULL;
+       unsigned char cc_uuid[BABELTRACE_UUID_LEN];
+
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       clock = g_new0(struct bt_ctf_clock, 1);
+       if (!clock) {
+               goto error;
+       }
+
+       bt_ctf_object_init_shared(&clock->base, bt_ctf_clock_destroy);
+       clock->value = 0;
+
+       /* Pre-2.0.0 backward compatibility: default frequency is 1 GHz */
+       clock->clock_class = (void *) bt_ctf_clock_class_create(name, 1000000000);
+       if (!clock->clock_class) {
+               goto error;
+       }
+
+       /* Automatically set clock class's UUID. */
+       ret = bt_uuid_generate(cc_uuid);
+       if (ret) {
+               goto error;
+       }
+
+       ret = bt_ctf_clock_class_set_uuid(clock->clock_class, cc_uuid);
+       BT_ASSERT(ret == 0);
+       return clock;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock);
+       return clock;
+}
+
+const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_name(clock->clock_class);
+}
+
+const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_description(clock->clock_class);
+}
+
+int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_description(clock->clock_class,
+               desc);
+}
+
+uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_frequency(clock->clock_class);
+}
+
+int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_frequency(clock->clock_class,
+               freq);
+}
+
+uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_precision(clock->clock_class);
+}
+
+int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_precision(clock->clock_class,
+               precision);
+}
+
+int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, int64_t *offset_s)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_offset_s(clock->clock_class,
+               offset_s);
+}
+
+int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, int64_t offset_s)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_offset_s(clock->clock_class,
+               offset_s);
+}
+
+int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, int64_t *offset)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_offset_cycles(clock->clock_class,
+               offset);
+}
+
+int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, int64_t offset)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_offset_cycles(clock->clock_class,
+               offset);
+}
+
+int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_is_absolute(clock->clock_class);
+}
+
+int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_is_absolute(clock->clock_class,
+               is_absolute);
+}
+
+const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_uuid(clock->clock_class);
+}
+
+int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, const unsigned char *uuid)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_uuid(clock->clock_class, uuid);
+}
+
+int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, int64_t time)
+{
+       int64_t value;
+       struct bt_ctf_clock_class *cc;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       cc = clock->clock_class;
+
+       /* Common case where cycles are actually nanoseconds */
+       if (cc->frequency == 1000000000) {
+               value = time;
+       } else {
+               value = (uint64_t) (((double) time *
+                       (double) cc->frequency) / 1e9);
+       }
+
+       BT_CTF_ASSERT_PRE(clock->value <= value,
+               "CTF writer clock value must be updated monotonically: "
+               "prev-value=%" PRId64 ", new-value=%" PRId64,
+               clock->value, value);
+       clock->value = value;
+       return 0;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       *value = clock->value;
+       return 0;
+}
+
+static
+void bt_ctf_clock_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_clock *clock;
+
+       clock = container_of(obj, struct bt_ctf_clock, base);
+       bt_ctf_object_put_ref(clock->clock_class);
+       g_free(clock);
+}
+
+BT_HIDDEN
+void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class,
+               struct metadata_context *context)
+{
+       unsigned char *uuid;
+
+       BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, "
+               "name=\"%s\", metadata-context-addr=%p", clock_class,
+               bt_ctf_clock_class_get_name(clock_class),
+               context);
+
+       if (!clock_class || !context) {
+               BT_LOGW("Invalid parameter: clock class or metadata context is NULL: "
+                       "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p",
+                       clock_class,
+                       bt_ctf_clock_class_get_name(clock_class),
+                       context);
+               return;
+       }
+
+       uuid = clock_class->uuid;
+       g_string_append(context->string, "clock {\n");
+       g_string_append_printf(context->string, "\tname = %s;\n",
+               clock_class->name->str);
+
+       if (clock_class->uuid_set) {
+               g_string_append_printf(context->string,
+                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
+                       uuid[0], uuid[1], uuid[2], uuid[3],
+                       uuid[4], uuid[5], uuid[6], uuid[7],
+                       uuid[8], uuid[9], uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+       }
+
+       if (clock_class->description) {
+               g_string_append_printf(context->string, "\tdescription = \"%s\";\n",
+                       clock_class->description->str);
+       }
+
+       g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n",
+               clock_class->frequency);
+       g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n",
+               clock_class->precision);
+       g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n",
+               clock_class->offset_s);
+       g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n",
+               clock_class->offset);
+       g_string_append_printf(context->string, "\tabsolute = %s;\n",
+               clock_class->absolute ? "true" : "false");
+       g_string_append(context->string, "};\n\n");
+}
diff --git a/ctf-writer/event-class.c b/ctf-writer/event-class.c
new file mode 100644 (file)
index 0000000..3d8c1f5
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * 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 "CTF-WRITER-EVENT-CLASS"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/attributes-internal.h>
+#include <babeltrace2/ctf-writer/event-class-internal.h>
+#include <babeltrace2/ctf-writer/event-internal.h>
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/ctf-writer/stream-class-internal.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/trace-internal.h>
+#include <babeltrace2/ctf-writer/utils-internal.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/validation-internal.h>
+#include <babeltrace2/ctf-writer/writer-internal.h>
+#include <babeltrace2/endian-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+BT_HIDDEN
+void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_event_class_common *event_class;
+
+       event_class = container_of(obj, struct bt_ctf_event_class_common, base);
+       BT_LOGD("Finalizing common event class: addr=%p, name=\"%s\", id=%" PRId64,
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+
+       if (event_class->name) {
+               g_string_free(event_class->name, TRUE);
+       }
+
+       if (event_class->emf_uri) {
+               g_string_free(event_class->emf_uri, TRUE);
+       }
+
+       BT_LOGD_STR("Putting context field type.");
+       bt_ctf_object_put_ref(event_class->context_field_type);
+       BT_LOGD_STR("Putting payload field type.");
+       bt_ctf_object_put_ref(event_class->payload_field_type);
+}
+
+BT_HIDDEN
+int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class,
+               const char *name, bt_ctf_object_release_func release_func,
+               bt_ctf_field_type_structure_create_func ft_struct_create_func)
+{
+       int ret = 0;
+
+       BT_LOGD("Initializing common event class object: name=\"%s\"",
+               name);
+       bt_ctf_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_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED;
+       BT_LOGD("Initialized common event class object: addr=%p, name=\"%s\"",
+               event_class, bt_ctf_event_class_common_get_name(event_class));
+       return ret;
+
+error:
+       ret = -1;
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *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_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+       event_class->frozen = 1;
+       BT_LOGD_STR("Freezing event class's context field type.");
+       bt_ctf_field_type_common_freeze(event_class->context_field_type);
+       BT_LOGD_STR("Freezing event class's payload field type.");
+       bt_ctf_field_type_common_freeze(event_class->payload_field_type);
+}
+
+BT_HIDDEN
+int bt_ctf_event_class_common_validate_single_clock_class(
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_clock_class **expected_clock_class)
+{
+       int ret = 0;
+
+       BT_ASSERT(event_class);
+       BT_ASSERT(expected_clock_class);
+       ret = bt_ctf_field_type_common_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_ctf_event_class_common_get_name(event_class),
+                       event_class->id,
+                       event_class->context_field_type);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_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_ctf_event_class_common_get_name(event_class),
+                       event_class->id,
+                       event_class->payload_field_type);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+void bt_ctf_event_class_destroy(struct bt_ctf_object *obj)
+{
+       bt_ctf_event_class_common_finalize(obj);
+       g_free(obj);
+}
+
+struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name)
+{
+       struct bt_ctf_event_class *ctf_event_class = NULL;
+       int ret;
+
+       if (!name) {
+               BT_LOGW_STR("Invalid parameter: name is NULL.");
+               goto error;
+       }
+
+       BT_LOGD("Creating event class object: name=\"%s\"",
+               name);
+       ctf_event_class = g_new0(struct bt_ctf_event_class, 1);
+       if (!ctf_event_class) {
+               BT_LOGE_STR("Failed to allocate one event class.");
+               goto error;
+       }
+
+       ret = bt_ctf_event_class_common_initialize(BT_CTF_TO_COMMON(ctf_event_class),
+               name, bt_ctf_event_class_destroy,
+               (bt_ctf_field_type_structure_create_func)
+                       bt_ctf_field_type_structure_create);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       bt_ctf_object_put_ref(ctf_event_class);
+
+end:
+       return ctf_event_class;
+}
+
+const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_name(BT_CTF_TO_COMMON(event_class));
+}
+
+int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_id(BT_CTF_TO_COMMON(event_class));
+}
+
+int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class,
+               uint64_t id)
+{
+       return bt_ctf_event_class_common_set_id(BT_CTF_TO_COMMON(event_class), id);
+}
+
+enum bt_ctf_event_class_log_level bt_ctf_event_class_get_log_level(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_log_level(BT_CTF_TO_COMMON(event_class));
+}
+
+int bt_ctf_event_class_set_log_level(struct bt_ctf_event_class *event_class,
+               enum bt_ctf_event_class_log_level log_level)
+{
+       return bt_ctf_event_class_common_set_log_level(BT_CTF_TO_COMMON(event_class),
+               log_level);
+}
+
+const char *bt_ctf_event_class_get_emf_uri(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_emf_uri(BT_CTF_TO_COMMON(event_class));
+}
+
+int bt_ctf_event_class_set_emf_uri(struct bt_ctf_event_class *event_class,
+               const char *emf_uri)
+{
+       return bt_ctf_event_class_common_set_emf_uri(BT_CTF_TO_COMMON(event_class),
+               emf_uri);
+}
+
+struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class(
+               struct bt_ctf_event_class *event_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_stream_class(
+               BT_CTF_TO_COMMON(event_class)));
+}
+
+struct bt_ctf_field_type *bt_ctf_event_class_get_payload_field_type(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_payload_field_type(
+               BT_CTF_TO_COMMON(event_class)));
+}
+
+int bt_ctf_event_class_set_payload_field_type(
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *field_type)
+{
+       return bt_ctf_event_class_common_set_payload_field_type(
+               BT_CTF_TO_COMMON(event_class), (void *) field_type);
+}
+
+struct bt_ctf_field_type *bt_ctf_event_class_get_context_field_type(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_context_field_type(
+               BT_CTF_TO_COMMON(event_class)));
+}
+
+int bt_ctf_event_class_set_context_field_type(
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *field_type)
+{
+       return bt_ctf_event_class_common_set_context_field_type(
+               BT_CTF_TO_COMMON(event_class), (void *) field_type);
+}
+
+int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *type,
+               const char *name)
+{
+       int ret = 0;
+
+       if (!event_class || !type) {
+               BT_LOGW("Invalid parameter: event class or field type is NULL: "
+                       "event-class-addr=%p, field-type-addr=%p",
+                       event_class, type);
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_identifier_is_valid(name)) {
+               BT_LOGW("Invalid parameter: event class's payload field type's field name is not a valid CTF identifier: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", field-name=\"%s\"",
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class),
+                       name);
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class->common.frozen) {
+               BT_LOGW("Invalid parameter: event class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (!event_class->common.payload_field_type) {
+               BT_LOGW("Event class has no payload field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class));
+               ret = -1;
+               goto end;
+       }
+
+       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
+               event_class->common.payload_field_type) ==
+               BT_CTF_FIELD_TYPE_ID_STRUCT);
+       ret = bt_ctf_field_type_structure_add_field(
+               (void *) event_class->common.payload_field_type,
+               (void *) type, name);
+       BT_LOGV("Added field to event class's payload field type: "
+               "event-class-addr=%p, event-class-name=\"%s\", "
+               "event-class-id=%" PRId64 ", field-name=\"%s\", ft-addr=%p",
+               event_class, bt_ctf_event_class_get_name(event_class),
+               bt_ctf_event_class_get_id(event_class), name, type);
+end:
+       return ret;
+}
+
+int64_t bt_ctf_event_class_get_payload_type_field_count(
+               struct bt_ctf_event_class *event_class)
+{
+       int64_t ret;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = (int64_t) -1;
+               goto end;
+       }
+
+       if (!event_class->common.payload_field_type) {
+               BT_LOGV("Event class has no payload field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class));
+               ret = (int64_t) -1;
+               goto end;
+       }
+
+       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
+               event_class->common.payload_field_type) ==
+                       BT_CTF_FIELD_TYPE_ID_STRUCT);
+       ret = bt_ctf_field_type_common_structure_get_field_count(
+               event_class->common.payload_field_type);
+end:
+       return ret;
+}
+
+int bt_ctf_event_class_get_payload_type_field_by_index(
+               struct bt_ctf_event_class *event_class,
+               const char **field_name, struct bt_ctf_field_type **field_type,
+               uint64_t index)
+{
+       int ret;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!event_class->common.payload_field_type) {
+               BT_LOGV("Event class has no payload field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", index=%" PRIu64,
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class), index);
+               ret = -1;
+               goto end;
+       }
+
+       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
+               event_class->common.payload_field_type) ==
+                       BT_CTF_FIELD_TYPE_ID_STRUCT);
+       ret = bt_ctf_field_type_structure_get_field_by_index(
+               (void *) event_class->common.payload_field_type,
+               field_name, (void *) field_type, index);
+
+end:
+       return ret;
+}
+
+struct bt_ctf_field_type *
+bt_ctf_event_class_get_payload_type_field_type_by_name(
+               struct bt_ctf_event_class *event_class, const char *name)
+{
+       GQuark name_quark;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (!event_class || !name) {
+               BT_LOGW("Invalid parameter: event class or name is NULL: "
+                       "event-class-addr=%p, name-addr=%p",
+                       event_class, name);
+               goto end;
+       }
+
+       if (!event_class->common.payload_field_type) {
+               BT_LOGV("Event class has no payload field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class));
+               goto end;
+       }
+
+       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
+               event_class->common.payload_field_type) ==
+                       BT_CTF_FIELD_TYPE_ID_STRUCT);
+       name_quark = g_quark_try_string(name);
+       if (!name_quark) {
+               BT_LOGE("Cannot get GQuark: string=\"%s\"", name);
+               goto end;
+       }
+
+       /*
+        * No need to increment field_type's reference count since getting it
+        * from the structure already does.
+        */
+       field_type = (void *)
+               bt_ctf_field_type_structure_get_field_type_by_name(
+                       (void *) event_class->common.payload_field_type, name);
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       struct bt_ctf_value *attr_value = NULL;
+
+       BT_ASSERT(event_class);
+       BT_ASSERT(context);
+       BT_LOGD("Serializing event class's metadata: "
+               "event-class-addr=%p, event-class-name=\"%s\", "
+               "event-class-id=%" PRId64 ", metadata-context-addr=%p",
+               event_class, bt_ctf_event_class_get_name(event_class),
+               bt_ctf_event_class_get_id(event_class), context);
+       context->current_indentation_level = 1;
+       g_string_assign(context->field_name, "");
+       g_string_append(context->string, "event {\n");
+
+       /* Serialize attributes */
+       g_string_append_printf(context->string, "\tname = \"%s\";\n",
+               event_class->common.name->str);
+       BT_ASSERT(event_class->common.id >= 0);
+       g_string_append_printf(context->string, "\tid = %" PRId64 ";\n",
+               event_class->common.id);
+       g_string_append_printf(context->string, "\tstream_id = %" PRId64 ";\n",
+               bt_ctf_stream_class_common_get_id(
+                       bt_ctf_event_class_common_borrow_stream_class(
+                               BT_CTF_TO_COMMON(event_class))));
+
+       if (event_class->common.log_level !=
+                       BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) {
+               g_string_append_printf(context->string, "\tloglevel = %d;\n",
+                       (int) event_class->common.log_level);
+       }
+
+       if (event_class->common.emf_uri->len > 0) {
+               g_string_append_printf(context->string, "\tmodel.emf.uri = \"%s\";\n",
+                       event_class->common.emf_uri->str);
+       }
+
+       /* Serialize context field type */
+       if (event_class->common.context_field_type) {
+               g_string_append(context->string, "\tcontext := ");
+               BT_LOGD_STR("Serializing event class's context field type metadata.");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) event_class->common.context_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event class's context field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";\n");
+       }
+
+       /* Serialize payload field type */
+       if (event_class->common.payload_field_type) {
+               g_string_append(context->string, "\tfields := ");
+               BT_LOGD_STR("Serializing event class's payload field type metadata.");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) event_class->common.payload_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event class's payload field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";\n");
+       }
+
+       g_string_append(context->string, "};\n\n");
+
+end:
+       context->current_indentation_level = 0;
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(attr_value);
+       return ret;
+}
+
+struct bt_ctf_field_type *bt_ctf_event_class_get_field_by_name(
+               struct bt_ctf_event_class *event_class, const char *name)
+{
+       GQuark name_quark;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (!event_class || !name) {
+               BT_LOGW("Invalid parameter: event class or name is NULL: "
+                       "event-class-addr=%p, name-addr=%p",
+                       event_class, name);
+               goto end;
+       }
+
+       if (!event_class->common.payload_field_type) {
+               BT_LOGV("Event class has no payload field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class,
+                       bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class));
+               goto end;
+       }
+
+       BT_ASSERT(event_class->common.payload_field_type->id ==
+               BT_CTF_FIELD_TYPE_ID_STRUCT);
+       name_quark = g_quark_try_string(name);
+       if (!name_quark) {
+               BT_LOGE("Cannot get GQuark: string=\"%s\"", name);
+               goto end;
+       }
+
+       /*
+        * No need to increment field_type's reference count since getting it
+        * from the structure already does.
+        */
+       field_type = bt_ctf_object_get_ref(
+               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+                       event_class->common.payload_field_type, name));
+
+end:
+       return field_type;
+}
diff --git a/ctf-writer/event.c b/ctf-writer/event.c
new file mode 100644 (file)
index 0000000..b074cdb
--- /dev/null
@@ -0,0 +1,900 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * 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 "CTF-WRITER-EVENT"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/attributes-internal.h>
+#include <babeltrace2/ctf-writer/clock-class-internal.h>
+#include <babeltrace2/ctf-writer/clock-internal.h>
+#include <babeltrace2/ctf-writer/event-class-internal.h>
+#include <babeltrace2/ctf-writer/event-internal.h>
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/ctf-writer/stream-class-internal.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/stream-internal.h>
+#include <babeltrace2/ctf-writer/trace-internal.h>
+#include <babeltrace2/ctf-writer/trace.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/validation-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <inttypes.h>
+
+static
+int bt_ctf_event_common_validate_types_for_create(
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_validation_output *validation_output,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
+{
+       int ret;
+       enum bt_ctf_validation_flag validation_flags =
+               BT_CTF_VALIDATION_FLAG_STREAM |
+               BT_CTF_VALIDATION_FLAG_EVENT;
+       struct bt_ctf_trace_common *trace = NULL;
+       struct bt_ctf_stream_class_common *stream_class = NULL;
+       struct bt_ctf_field_type_common *packet_header_type = NULL;
+       struct bt_ctf_field_type_common *packet_context_type = NULL;
+       struct bt_ctf_field_type_common *event_header_type = NULL;
+       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
+       struct bt_ctf_field_type_common *event_context_type = NULL;
+       struct bt_ctf_field_type_common *event_payload_type = NULL;
+       int trace_valid = 0;
+       struct bt_ctf_private_value *environment = NULL;
+
+       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
+       BT_ASSERT(stream_class);
+       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
+       if (trace) {
+               BT_LOGD_STR("Event class is part of a trace.");
+               packet_header_type =
+                       bt_ctf_trace_common_borrow_packet_header_field_type(trace);
+               trace_valid = trace->valid;
+               BT_ASSERT(trace_valid);
+               environment = trace->environment;
+       }
+
+       packet_context_type =
+               bt_ctf_stream_class_common_borrow_packet_context_field_type(
+                       stream_class);
+       event_header_type =
+               bt_ctf_stream_class_common_borrow_event_header_field_type(
+                       stream_class);
+       stream_event_ctx_type =
+               bt_ctf_stream_class_common_borrow_event_context_field_type(
+                       stream_class);
+       event_context_type =
+               bt_ctf_event_class_common_borrow_context_field_type(event_class);
+       event_payload_type =
+               bt_ctf_event_class_common_borrow_payload_field_type(event_class);
+       ret = bt_ctf_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_ctf_validation_output_put_types(validation_output);
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_event_common_create_fields(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_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_ctf_field_wrapper **header_field,
+               struct bt_ctf_field_common **stream_event_context_field,
+               struct bt_ctf_field_common **context_field,
+               struct bt_ctf_field_common **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_ctf_event_common_validate(struct bt_ctf_event_common *event)
+{
+       int ret = 0;
+       struct bt_ctf_stream_class_common *stream_class;
+
+       BT_ASSERT(event);
+       if (event->header_field) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       event->header_field->field);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid event's header field: "
+                               "event-addr=%p, field-addr=%p",
+                               event, event->header_field->field);
+                       goto end;
+               }
+       }
+
+       stream_class = bt_ctf_event_class_common_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_ctf_field_common_validate_recursive(
+                       event->stream_event_context_field);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid event's stream event context field: "
+                               "event-addr=%p, field-addr=%p",
+                               event, event->stream_event_context_field);
+                       goto end;
+               }
+       }
+
+       if (event->class->context_field_type) {
+               ret = bt_ctf_field_common_validate_recursive(event->context_field);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: "
+                               "event-addr=%p, field-addr=%p",
+                               event, event->context_field);
+                       goto end;
+               }
+       }
+
+       ret = bt_ctf_field_common_validate_recursive(event->payload_field);
+       if (ret) {
+               BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: "
+                       "event-addr=%p, field-addr=%p",
+                       event, event->payload_field);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event,
+               bool is_frozen)
+{
+       BT_ASSERT(event);
+       BT_LOGD("Freezing event: addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               event, bt_ctf_event_class_common_get_name(event->class),
+               bt_ctf_event_class_common_get_id(event->class));
+
+       if (event->header_field) {
+               BT_LOGD_STR("Freezing event's header field.");
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       event->header_field->field, is_frozen);
+       }
+
+       if (event->stream_event_context_field) {
+               BT_LOGD_STR("Freezing event's stream event context field.");
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       event->stream_event_context_field, is_frozen);
+       }
+
+       if (event->context_field) {
+               BT_LOGD_STR("Freezing event's context field.");
+               bt_ctf_field_common_set_is_frozen_recursive(event->context_field,
+                       is_frozen);
+       }
+
+       if (event->payload_field) {
+               BT_LOGD_STR("Freezing event's payload field.");
+               bt_ctf_field_common_set_is_frozen_recursive(event->payload_field,
+                       is_frozen);
+       }
+
+       event->frozen = is_frozen;
+}
+
+BT_HIDDEN
+int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event,
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_clock_class *init_expected_clock_class,
+               bool is_shared_with_parent, bt_ctf_object_release_func release_func,
+               bt_ctf_validation_flag_copy_field_type_func field_type_copy_func,
+               bool must_be_in_trace,
+               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
+                       struct bt_ctf_field_type_common *packet_context_field_type,
+                       struct bt_ctf_field_type_common *event_header_field_type),
+               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_ctf_trace_common *trace = NULL;
+       struct bt_ctf_stream_class_common *stream_class = NULL;
+       struct bt_ctf_field_wrapper *event_header = NULL;
+       struct bt_ctf_field_common *stream_event_context = NULL;
+       struct bt_ctf_field_common *event_context = NULL;
+       struct bt_ctf_field_common *event_payload = NULL;
+       struct bt_ctf_validation_output validation_output = { 0 };
+       struct bt_ctf_clock_class *expected_clock_class =
+               init_expected_clock_class ? bt_ctf_object_get_ref(init_expected_clock_class) :
+               NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_LOGD("Initializing common event object: event-class-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+
+       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
+       BT_CTF_ASSERT_PRE(stream_class,
+               "Event class is not part of a stream class: event-class-addr=%p",
+               event_class);
+
+       /* The event class was frozen when added to its stream class */
+       BT_ASSERT(event_class->frozen);
+       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
+
+       if (must_be_in_trace) {
+               BT_CTF_ASSERT_PRE(trace,
+                       "Event class's stream class is not part of a trace: "
+                       "ec-addr=%p, sc-addr=%p", 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.
+        */
+       if (is_shared_with_parent) {
+               bt_ctf_object_init_shared_with_parent(&event->base, release_func);
+       } else {
+               bt_ctf_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_ctf_stream_class_common_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_ctf_stream_class_common_get_id(stream_class),
+                               bt_ctf_stream_class_common_get_name(stream_class),
+                               expected_clock_class,
+                               expected_clock_class ?
+                                       bt_ctf_clock_class_get_name(expected_clock_class) :
+                                       NULL);
+                       goto error;
+               }
+       }
+
+       /* Validate the trace, the stream class, and the event class */
+       ret = bt_ctf_event_common_validate_types_for_create(
+               event_class, &validation_output, field_type_copy_func);
+       if (ret) {
+               /* bt_ctf_event_common_validate_types_for_create() logs errors */
+               goto error;
+       }
+
+       if (map_clock_classes_func) {
+               /*
+                * Safe to automatically map selected fields to the
+                * stream's clock's class here because the stream class
+                * is about to be frozen.
+                */
+               if (map_clock_classes_func(stream_class,
+                               validation_output.packet_context_type,
+                               validation_output.event_header_type)) {
+                       BT_LOGW_STR("Cannot automatically map selected stream class's "
+                               "field types to stream class's clock's class.");
+                       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.
+        */
+       event->class = bt_ctf_object_get_ref(event_class);
+
+       ret = bt_ctf_event_common_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_ctf_event_common_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_ctf_validation_replace_types(trace, stream_class, event_class,
+               &validation_output,
+               BT_CTF_VALIDATION_FLAG_STREAM | BT_CTF_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_ctf_validation_replace_types().
+        */
+       bt_ctf_validation_output_put_types(&validation_output);
+
+       /*
+        * Freeze the stream class since the event header must not be changed
+        * anymore.
+        */
+       bt_ctf_stream_class_common_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_CTF_OBJECT_MOVE_REF(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_ctf_event_class_common_get_name(event->class),
+               bt_ctf_event_class_common_get_id(event->class));
+       goto end;
+
+error:
+       bt_ctf_validation_output_put_types(&validation_output);
+       bt_ctf_object_put_ref(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;
+}
+
+int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type)
+{
+       int ret = bt_ctf_stream_class_map_clock_class(
+               BT_CTF_FROM_COMMON(stream_class),
+               BT_CTF_FROM_COMMON(packet_context_type),
+               BT_CTF_FROM_COMMON(event_header_type));
+
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
+       }
+
+       return ret;
+}
+
+static
+void destroy_event_header_field(struct bt_ctf_field_wrapper *field_wrapper)
+{
+       BT_ASSERT(field_wrapper);
+       bt_ctf_object_put_ref(field_wrapper->field);
+       bt_ctf_field_wrapper_destroy(field_wrapper);
+}
+
+static
+struct bt_ctf_field_wrapper *create_event_header_field(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_wrapper *field_wrapper = NULL;
+       struct bt_ctf_field *field = bt_ctf_field_create((void *) ft);
+
+       if (!field) {
+               goto error;
+       }
+
+       field_wrapper = bt_ctf_field_wrapper_new(NULL);
+       if (!field_wrapper) {
+               goto error;
+       }
+
+       field_wrapper->field = (void *) field;
+       field = NULL;
+       goto end;
+
+error:
+       bt_ctf_object_put_ref(field);
+
+       if (field_wrapper) {
+               destroy_event_header_field(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
+
+static
+void release_event_header_field(struct bt_ctf_field_wrapper *field_wrapper,
+               struct bt_ctf_event_common *event_common)
+{
+       BT_ASSERT(field_wrapper);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_wrapper->field);
+       bt_ctf_field_wrapper_destroy(field_wrapper);
+}
+
+static
+void bt_ctf_event_destroy(struct bt_ctf_object *obj)
+{
+       bt_ctf_event_common_finalize(obj, (void *) bt_ctf_object_put_ref,
+               (void *) release_event_header_field);
+       g_free(obj);
+}
+
+struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
+{
+       int ret;
+       struct bt_ctf_event *event = NULL;
+       struct bt_ctf_clock_class *expected_clock_class = NULL;
+
+       event = g_new0(struct bt_ctf_event, 1);
+       if (!event) {
+               BT_LOGE_STR("Failed to allocate one CTF writer event.");
+               goto error;
+       }
+
+       if (event_class) {
+               struct bt_ctf_stream_class *stream_class =
+                       BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class(
+                               BT_CTF_TO_COMMON(event_class)));
+
+               if (stream_class && stream_class->clock) {
+                       expected_clock_class = stream_class->clock->clock_class;
+               }
+       }
+
+       ret = bt_ctf_event_common_initialize(BT_CTF_TO_COMMON(event),
+               BT_CTF_TO_COMMON(event_class), expected_clock_class,
+               true, bt_ctf_event_destroy,
+               (bt_ctf_validation_flag_copy_field_type_func)
+                       bt_ctf_field_type_copy,
+               false, map_clock_classes_func,
+               (create_field_func) bt_ctf_field_create,
+               (release_field_func) bt_ctf_object_put_ref,
+               (create_header_field_func) create_event_header_field,
+               (release_header_field_func) destroy_event_header_field);
+       if (ret) {
+               /* bt_ctf_event_common_initialize() logs errors */
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event);
+
+end:
+       return event;
+}
+
+struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)));
+}
+
+BT_HIDDEN
+struct bt_ctf_stream *bt_ctf_event_borrow_stream(struct bt_ctf_event *event)
+{
+       BT_ASSERT(event);
+       return (struct bt_ctf_stream *)
+               bt_ctf_object_borrow_parent(&BT_CTF_TO_COMMON(event)->base);
+}
+
+struct bt_ctf_stream *bt_ctf_event_get_stream(struct bt_ctf_event *event)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       return bt_ctf_object_get_ref(bt_ctf_event_borrow_stream(event));
+}
+
+int bt_ctf_event_set_payload(struct bt_ctf_event *event, const char *name,
+               struct bt_ctf_field *field)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Payload field");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+       return bt_ctf_field_structure_set_field_by_name(
+               (void *) event->common.payload_field, name, field);
+}
+
+struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event,
+               const char *name)
+{
+       struct bt_ctf_field *field = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+
+       if (name) {
+               field = bt_ctf_field_structure_get_field_by_name(
+                       BT_CTF_FROM_COMMON(event->common.payload_field), name);
+       } else {
+               field = BT_CTF_FROM_COMMON(event->common.payload_field);
+               bt_ctf_object_get_ref(field);
+       }
+
+       return field;
+}
+
+struct bt_ctf_field *bt_ctf_event_get_payload_field(
+               struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_payload(BT_CTF_TO_COMMON(event)));
+}
+
+struct bt_ctf_field *bt_ctf_event_get_header(struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_header(BT_CTF_TO_COMMON(event)));
+}
+
+struct bt_ctf_field *bt_ctf_event_get_context(struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_context(BT_CTF_TO_COMMON(event)));
+}
+
+struct bt_ctf_field *bt_ctf_event_get_stream_event_context(
+               struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_stream_event_context(
+               BT_CTF_TO_COMMON(event)));
+}
+
+BT_HIDDEN
+int bt_ctf_event_serialize(struct bt_ctf_event *event,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret = 0;
+
+       BT_ASSERT(event);
+       BT_ASSERT(ctfser);
+
+       BT_LOGV_STR("Serializing event's context field.");
+       if (event->common.context_field) {
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) event->common.context_field, ctfser,
+                       native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event's context field: "
+                               "event-addr=%p, event-class-name=\"%s\", "
+                               "event-class-id=%" PRId64,
+                               event,
+                               bt_ctf_event_class_common_get_name(event->common.class),
+                               bt_ctf_event_class_common_get_id(event->common.class));
+                       goto end;
+               }
+       }
+
+       BT_LOGV_STR("Serializing event's payload field.");
+       if (event->common.payload_field) {
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) event->common.payload_field, ctfser,
+                       native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event's payload field: "
+                               "event-addr=%p, event-class-name=\"%s\", "
+                               "event-class-id=%" PRId64,
+                               event,
+                               bt_ctf_event_class_common_get_name(event->common.class),
+                               bt_ctf_event_class_common_get_id(event->common.class));
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void _bt_ctf_event_freeze(struct bt_ctf_event *event)
+{
+       _bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
+}
+
+int bt_ctf_event_set_header(struct bt_ctf_event *event,
+               struct bt_ctf_field *header)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       /*
+        * Ensure the provided header's type matches the one registered to the
+        * stream class.
+        */
+       if (header) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) header)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type) == 0,
+                       "Header field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event, ((struct bt_ctf_field_common *) header)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type,
+                       "Setting no event header field, "
+                       "but event header field type is not NULL: "
+                       "event-addr=%p, header-ft-addr=%p",
+                       event,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.header_field->field);
+       event->common.header_field->field = bt_ctf_object_get_ref(header);
+       BT_LOGV("Set event's header field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "header-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class), header);
+       return 0;
+}
+
+int bt_ctf_event_common_set_payload(struct bt_ctf_event *event,
+               struct bt_ctf_field *payload)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       if (payload) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) payload)->type,
+                       event->common.class->payload_field_type) == 0,
+                       "Payload field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event,
+                       ((struct bt_ctf_field_common *) payload)->type,
+                       event->common.class->payload_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!event->common.class->payload_field_type,
+                       "Setting no event payload field, "
+                       "but event payload field type is not NULL: "
+                       "event-addr=%p, payload-ft-addr=%p",
+                       event, event->common.class->payload_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.payload_field);
+       event->common.payload_field = bt_ctf_object_get_ref(payload);
+       BT_LOGV("Set event's payload field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "payload-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class), payload);
+       return 0;
+}
+
+int bt_ctf_event_set_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *context)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       if (context) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) context)->type,
+                       event->common.class->context_field_type) == 0,
+                       "Context field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event, ((struct bt_ctf_field_common *) context)->type,
+                       event->common.class->context_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!event->common.class->context_field_type,
+                       "Setting no event context field, "
+                       "but event context field type is not NULL: "
+                       "event-addr=%p, context-ft-addr=%p",
+                       event, event->common.class->context_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.context_field);
+       event->common.context_field = bt_ctf_object_get_ref(context);
+       BT_LOGV("Set event's context field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "context-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class), context);
+       return 0;
+}
+
+int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *stream_event_context)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       if (stream_event_context) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) stream_event_context)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type) == 0,
+                       "Stream event context field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event,
+                       ((struct bt_ctf_field_common *) stream_event_context)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type,
+                       "Setting no stream event context field, "
+                       "but stream event context field type is not NULL: "
+                       "event-addr=%p, context-ft-addr=%p",
+                       event,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.stream_event_context_field);
+       event->common.stream_event_context_field = bt_ctf_object_get_ref(stream_event_context);
+       BT_LOGV("Set event's stream event context field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "stream-event-context-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class),
+               stream_event_context);
+       return 0;
+}
diff --git a/ctf-writer/field-path.c b/ctf-writer/field-path.c
new file mode 100644 (file)
index 0000000..284e850
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * field-path.c
+ *
+ * Babeltrace CTF writer - Field path
+ *
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * 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.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-FIELD-PATH"
+#include "logging.h"
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/ctf-writer/field-path-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+
+static
+void field_path_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_path *field_path = (struct bt_ctf_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);
+       }
+       g_free(field_path);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_path_create(void)
+{
+       struct bt_ctf_field_path *field_path = NULL;
+
+       BT_LOGD_STR("Creating empty field path object.");
+
+       field_path = g_new0(struct bt_ctf_field_path, 1);
+       if (!field_path) {
+               BT_LOGE_STR("Failed to allocate one field path.");
+               goto error;
+       }
+
+       bt_ctf_object_init_shared(&field_path->base, field_path_destroy);
+       field_path->root = BT_CTF_SCOPE_UNKNOWN;
+       field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int));
+       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;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
+       return NULL;
+}
+
+BT_HIDDEN
+void bt_ctf_field_path_clear(struct bt_ctf_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_ctf_field_path *bt_ctf_field_path_copy(
+               struct bt_ctf_field_path *path)
+{
+       struct bt_ctf_field_path *new_path;
+
+       BT_ASSERT(path);
+       BT_LOGD("Copying field path: addr=%p, index-count=%u",
+               path, path->indexes->len);
+       new_path = bt_ctf_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;
+}
+
+enum bt_ctf_scope bt_ctf_field_path_get_root_scope(
+               const struct bt_ctf_field_path *field_path)
+{
+       enum bt_ctf_scope scope = BT_CTF_SCOPE_UNKNOWN;
+
+       if (!field_path) {
+               BT_LOGW_STR("Invalid parameter: field path is NULL.");
+               goto end;
+       }
+
+       scope = field_path->root;
+
+end:
+       return scope;
+}
+
+int64_t bt_ctf_field_path_get_index_count(
+               const struct bt_ctf_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;
+}
+
+int bt_ctf_field_path_get_index(const struct bt_ctf_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;
+}
diff --git a/ctf-writer/field-types.c b/ctf-writer/field-types.c
new file mode 100644 (file)
index 0000000..2d18c45
--- /dev/null
@@ -0,0 +1,5564 @@
+/*
+ * Copyright 2013, 2014 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.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-FIELD-TYPES"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/clock-class-internal.h>
+#include <babeltrace2/ctf-writer/clock-internal.h>
+#include <babeltrace2/ctf-writer/field-path-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/ctf-writer/utils-internal.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/endian-internal.h>
+#include <babeltrace2/ctf-writer/object-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <float.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+static
+void destroy_enumeration_mapping(struct bt_ctf_enumeration_mapping *mapping)
+{
+       g_free(mapping);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft,
+               bool init_bo, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       BT_ASSERT(ft && (ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN) &&
+               (ft->id < BT_CTF_FIELD_TYPE_ID_NR));
+
+       bt_ctf_object_init_shared(&ft->base, release_func);
+       ft->methods = methods;
+
+       if (init_bo) {
+               int ret;
+               const enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_NATIVE;
+
+               BT_LOGD("Setting initial field type's byte order: bo=%s",
+                       bt_ctf_byte_order_string(bo));
+               ret = bt_ctf_field_type_common_set_byte_order(ft, bo);
+               BT_ASSERT(ret == 0);
+       }
+
+       ft->alignment = 1;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_initialize(
+               struct bt_ctf_field_type_common *ft,
+               unsigned int size, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(size > 0);
+       BT_LOGD("Initializing common integer field type object: size=%u",
+               size);
+       ft->id = BT_CTF_FIELD_TYPE_ID_INTEGER;
+       int_ft->size = size;
+       int_ft->base = BT_CTF_INTEGER_BASE_DECIMAL;
+       int_ft->encoding = BT_CTF_STRING_ENCODING_NONE;
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       BT_LOGD("Initialized common integer field type object: addr=%p, size=%u",
+               ft, size);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD_STR("Initializing common floating point number field type object.");
+       ft->id = BT_CTF_FIELD_TYPE_ID_FLOAT;
+       flt_ft->exp_dig = sizeof(float) * CHAR_BIT - FLT_MANT_DIG;
+       flt_ft->mant_dig = FLT_MANT_DIG;
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       BT_LOGD("Initialized common floating point number field type object: addr=%p, "
+               "exp-size=%u, mant-size=%u", ft, flt_ft->exp_dig,
+               flt_ft->mant_dig);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *container_ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(container_ft);
+       BT_LOGD("Initializing common enumeration field type object: int-ft-addr=%p",
+               container_ft);
+       ft->id = BT_CTF_FIELD_TYPE_ID_ENUM;
+       enum_ft->container_ft = bt_ctf_object_get_ref(container_ft);
+       enum_ft->entries = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) destroy_enumeration_mapping);
+       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
+       BT_LOGD("Initialized common enumeration field type object: addr=%p, "
+               "int-ft-addr=%p, int-ft-size=%u", ft, container_ft,
+               bt_ctf_field_type_common_integer_get_size(container_ft));
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_string_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD_STR("Initializing common string field type object.");
+       ft->id = BT_CTF_FIELD_TYPE_ID_STRING;
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       string_ft->encoding = BT_CTF_STRING_ENCODING_UTF8;
+       ft->alignment = CHAR_BIT;
+       BT_LOGD("Initialized common string field type object: addr=%p", ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD_STR("Initializing common structure field type object.");
+       ft->id = BT_CTF_FIELD_TYPE_ID_STRUCT;
+       struct_ft->fields = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_ctf_field_type_common_structure_field));
+       struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL);
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       BT_LOGD("Initialized common structure field type object: addr=%p", ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft,
+               unsigned int length, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(element_ft);
+       BT_LOGD("Initializing common array field type object: element-ft-addr=%p, "
+               "length=%u", element_ft, length);
+       ft->id = BT_CTF_FIELD_TYPE_ID_ARRAY;
+       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
+       array_ft->length = length;
+       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
+       BT_LOGD("Initialized common array field type object: addr=%p, "
+               "element-ft-addr=%p, length=%u", ft, element_ft, length);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft,
+               const char *length_field_name,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(element_ft);
+       BT_ASSERT(length_field_name);
+       BT_ASSERT(bt_ctf_identifier_is_valid(length_field_name));
+       BT_LOGD("Initializing common sequence field type object: element-ft-addr=%p, "
+               "length-field-name=\"%s\"", element_ft, length_field_name);
+       ft->id = BT_CTF_FIELD_TYPE_ID_SEQUENCE;
+       seq_ft->element_ft = bt_ctf_object_get_ref(element_ft);
+       seq_ft->length_field_name = g_string_new(length_field_name);
+       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
+       BT_LOGD("Initialized common sequence field type object: addr=%p, "
+               "element-ft-addr=%p, length-field-name=\"%s\"",
+               ft, element_ft, length_field_name);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *tag_ft,
+               const char *tag_name,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(!tag_name || bt_ctf_identifier_is_valid(tag_name));
+       BT_LOGD("Initializing common variant field type object: "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               tag_ft, tag_name);
+       ft->id = BT_CTF_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_ctf_field_type_common_variant_choice));
+
+       if (tag_ft) {
+               var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft);
+       }
+
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       /* A variant's alignment is undefined */
+       ft->alignment = 0;
+       BT_LOGD("Initialized common variant field type object: addr=%p, "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               ft, tag_ft, tag_name);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_integer *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying integer field type object: addr=%p", ft);
+       BT_LOGD_STR("Putting mapped clock class.");
+       bt_ctf_object_put_ref(ft->mapped_clock_class);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_floating_point *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying floating point number field type object: addr=%p", ft);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_enumeration *ft = (void *) obj;
+
+       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_ctf_object_put_ref(ft->container_ft);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_string *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying string field type object: addr=%p", ft);
+       g_free(ft);
+}
+
+static
+void bt_ctf_field_type_common_structure_field_finalize(
+               struct bt_ctf_field_type_common_structure_field *field)
+{
+       if (!field) {
+               return;
+       }
+
+       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_ctf_object_put_ref(field->type);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_structure *ft = (void *) obj;
+       uint64_t i;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying structure field type object: addr=%p", ft);
+
+       if (ft->fields) {
+               for (i = 0; i < ft->fields->len; i++) {
+                       bt_ctf_field_type_common_structure_field_finalize(
+                               BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                                       ft, i));
+               }
+
+               g_array_free(ft->fields, TRUE);
+       }
+
+       if (ft->field_name_to_index) {
+               g_hash_table_destroy(ft->field_name_to_index);
+       }
+
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_array *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying array field type object: addr=%p", ft);
+       BT_LOGD_STR("Putting element field type.");
+       bt_ctf_object_put_ref(ft->element_ft);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_sequence *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying sequence field type object: addr=%p", ft);
+       BT_LOGD_STR("Putting element field type.");
+       bt_ctf_object_put_ref(ft->element_ft);
+       g_string_free(ft->length_field_name, TRUE);
+       BT_LOGD_STR("Putting length field path.");
+       bt_ctf_object_put_ref(ft->length_field_path);
+       g_free(ft);
+}
+
+static
+void bt_ctf_field_type_common_variant_choice_finalize(
+               struct bt_ctf_field_type_common_variant_choice *choice)
+{
+       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_ctf_object_put_ref(choice->type);
+
+       if (choice->ranges) {
+               g_array_free(choice->ranges, TRUE);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_variant *ft = (void *) obj;
+       uint64_t i;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying variant field type object: addr=%p", ft);
+
+       if (ft->choices) {
+               for (i = 0; i < ft->choices->len; i++) {
+                       bt_ctf_field_type_common_variant_choice_finalize(
+                               BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                                       ft, i));
+               }
+
+               g_array_free(ft->choices, TRUE);
+       }
+
+       if (ft->choice_name_to_index) {
+               g_hash_table_destroy(ft->choice_name_to_index);
+       }
+
+       if (ft->tag_name) {
+               g_string_free(ft->tag_name, TRUE);
+       }
+
+       BT_LOGD_STR("Putting tag field type.");
+       bt_ctf_object_put_ref(ft->tag_ft);
+       BT_LOGD_STR("Putting tag field path.");
+       bt_ctf_object_put_ref(ft->tag_field_path);
+       g_free(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
+void check_ranges_overlap(gpointer element, gpointer query)
+{
+       struct bt_ctf_enumeration_mapping *mapping = element;
+       struct range_overlap_query *overlap_query = query;
+
+       if (mapping->range_start._signed <= overlap_query->range_end._signed
+                       && overlap_query->range_start._signed <=
+                       mapping->range_end._signed) {
+               overlap_query->overlaps = 1;
+               overlap_query->mapping_name = mapping->string;
+       }
+
+       overlap_query->overlaps |=
+               mapping->string == overlap_query->mapping_name;
+
+       if (overlap_query->overlaps) {
+               BT_LOGV("Overlapping enumeration field type mappings: "
+                       "mapping-name=\"%s\", "
+                       "mapping-a-range-start=%" PRId64 ", "
+                       "mapping-a-range-end=%" PRId64 ", "
+                       "mapping-b-range-start=%" PRId64 ", "
+                       "mapping-b-range-end=%" PRId64,
+                       g_quark_to_string(mapping->string),
+                       mapping->range_start._signed,
+                       mapping->range_end._signed,
+                       overlap_query->range_start._signed,
+                       overlap_query->range_end._signed);
+       }
+}
+
+static
+void check_ranges_overlap_unsigned(gpointer element, gpointer query)
+{
+       struct bt_ctf_enumeration_mapping *mapping = element;
+       struct range_overlap_query *overlap_query = query;
+
+       if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned
+                       && overlap_query->range_start._unsigned <=
+                       mapping->range_end._unsigned) {
+               overlap_query->overlaps = 1;
+               overlap_query->mapping_name = mapping->string;
+       }
+
+       overlap_query->overlaps |=
+               mapping->string == overlap_query->mapping_name;
+
+       if (overlap_query->overlaps) {
+               BT_LOGW("Overlapping enumeration field type mappings: "
+                       "mapping-name=\"%s\", "
+                       "mapping-a-range-start=%" PRIu64 ", "
+                       "mapping-a-range-end=%" PRIu64 ", "
+                       "mapping-b-range-start=%" PRIu64 ", "
+                       "mapping-b-range-end=%" PRIu64,
+                       g_quark_to_string(mapping->string),
+                       mapping->range_start._unsigned,
+                       mapping->range_end._unsigned,
+                       overlap_query->range_start._unsigned,
+                       overlap_query->range_end._unsigned);
+       }
+}
+
+static
+gint compare_enumeration_mappings_signed(struct bt_ctf_enumeration_mapping **a,
+               struct bt_ctf_enumeration_mapping **b)
+{
+       return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1;
+}
+
+static
+gint compare_enumeration_mappings_unsigned(struct bt_ctf_enumeration_mapping **a,
+               struct bt_ctf_enumeration_mapping **b)
+{
+       return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1;
+}
+
+static
+int add_structure_variant_member(GArray *members,
+               GHashTable *field_name_to_index,
+               struct bt_ctf_field_type_common *field_type, const char *field_name,
+               bool is_variant)
+{
+       int ret = 0;
+       GQuark name_quark = g_quark_from_string(field_name);
+       struct bt_ctf_field_type_common **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);
+               ret = -1;
+               goto end;
+       }
+
+       g_array_set_size(members, members->len + 1);
+
+       if (is_variant) {
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       &g_array_index(members,
+                               struct bt_ctf_field_type_common_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_ctf_field_type_common_variant_choice_range));
+               BT_ASSERT(choice->ranges);
+       } else {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       &g_array_index(members,
+                               struct bt_ctf_field_type_common_structure_field,
+                               members->len - 1);
+
+               member_ft = &field->type;
+               member_name = &field->name;
+       }
+
+       *member_name = name_quark;
+       *member_ft = bt_ctf_object_get_ref(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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_ctf_clock_class_get_name(int_ft->mapped_clock_class));
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+void bt_ctf_field_type_enum_iter_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
+               container_of(obj,
+                       struct bt_ctf_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_ctf_object_put_ref(iter->enumeration_ft);
+       g_free(iter);
+}
+
+static
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_find_mappings_type(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_field_type_enumeration_mapping_iterator_type iterator_type)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM,
+               "Field type");
+       iter = g_new0(struct bt_ctf_field_type_enumeration_mapping_iterator, 1);
+       if (!iter) {
+               BT_LOGE_STR("Failed to allocate one enumeration field type mapping.");
+               goto end;
+       }
+
+       bt_ctf_object_init_shared(&iter->base, bt_ctf_field_type_enum_iter_destroy);
+       iter->enumeration_ft = bt_ctf_object_get_ref(ft);
+       iter->index = -1;
+       iter->type = iterator_type;
+
+end:
+       return iter;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_find_mappings_by_name(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
+
+       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
+                       ft, CTF_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_ctf_object_put_ref(iter);
+       return NULL;
+}
+
+static
+struct bt_ctf_enumeration_mapping *bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_enumeration_mapping *mapping = NULL;
+
+       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_HIDDEN
+int bt_ctf_field_type_enumeration_mapping_iterator_next(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = iter->enumeration_ft;
+       int i, ret = 0, len;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
+       len = enum_ft->entries->len;
+       for (i = iter->index + 1; i < len; i++) {
+               struct bt_ctf_enumeration_mapping *mapping =
+                       bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+                               BT_CTF_TO_COMMON(enum_ft), i);
+
+               switch (iter->type) {
+               case CTF_ITERATOR_BY_NAME:
+                       if (mapping->string == iter->u.name_quark) {
+                               iter->index = i;
+                               goto end;
+                       }
+                       break;
+               case CTF_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 CTF_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;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value(
+               struct bt_ctf_field_type_common *ft, int64_t value)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
+
+       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
+                       ft, CTF_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_ctf_field_type_common_integer_is_signed(
+                       BT_CTF_TO_COMMON(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_ctf_object_put_ref(iter);
+       return NULL;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value(
+               struct bt_ctf_field_type_common *ft, uint64_t value)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
+
+       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
+                       ft, CTF_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_ctf_field_type_common_integer_is_signed(
+                       BT_CTF_TO_COMMON(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_ctf_object_put_ref(iter);
+       return NULL;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
+               const char **mapping_name, int64_t *range_begin,
+               int64_t *range_end)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
+       BT_CTF_ASSERT_PRE(iter->index != -1,
+               "Invalid enumeration field type mapping iterator access: "
+               "addr=%p, position=-1", iter);
+       return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
+                       (void *) iter->enumeration_ft, iter->index,
+                       mapping_name, range_begin, range_end);
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
+               const char **mapping_name, uint64_t *range_begin,
+               uint64_t *range_end)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
+       BT_CTF_ASSERT_PRE(iter->index != -1,
+               "Invalid enumeration field type mapping iterator access: "
+               "addr=%p, position=-1", iter);
+       return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
+                       (void *) iter->enumeration_ft, iter->index,
+                       mapping_name, range_begin, range_end);
+}
+
+/*
+ * Note: This algorithm is O(n^2) vs number of enumeration mappings.
+ * Only used when freezing an enumeration.
+ */
+static
+void bt_ctf_field_type_common_enumeration_set_range_overlap(
+               struct bt_ctf_field_type_common_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_ctf_field_type_common_integer_is_signed(
+               BT_CTF_TO_COMMON(ft->container_ft));
+
+       for (i = 0; i < len; i++) {
+               for (j = i + 1; j < len; j++) {
+                       struct bt_ctf_enumeration_mapping *mapping[2];
+
+                       mapping[0] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+                               BT_CTF_TO_COMMON(ft), i);
+                       mapping[1] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+                               BT_CTF_TO_COMMON(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;
+                               }
+                       }
+               }
+       }
+
+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.");
+       }
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       ret = bt_ctf_field_type_common_integer_validate(
+                       BT_CTF_TO_COMMON(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;
+       }
+
+       /* 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;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       /* 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);
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_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);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       ret = bt_ctf_field_type_common_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);
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common *child_ft = NULL;
+       int64_t field_count =
+               bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_by_index(ft,
+                       &field_name, &child_ft, i);
+               BT_ASSERT(ret == 0);
+               ret = bt_ctf_field_type_common_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;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_type_common_enumeration_has_overlapping_ranges(
+               struct bt_ctf_field_type_common_enumeration *enum_ft)
+{
+       if (!enum_ft->common.frozen) {
+               bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
+       }
+
+       return enum_ft->has_overlapping_ranges;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       int64_t field_count;
+       struct bt_ctf_field_type_common *child_ft = NULL;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_ctf_field_type_common_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;
+       }
+
+       /*
+        * 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_ctf_field_type_common_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;
+               goto end;
+       }
+
+       for (i = 0; i < field_count; ++i) {
+               const char *field_name;
+
+               ret = bt_ctf_field_type_common_variant_borrow_field_by_index(ft,
+                       &field_name, &child_ft, i);
+               BT_ASSERT(ret == 0);
+               ret = bt_ctf_field_type_common_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;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * 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_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+
+       BT_ASSERT(ft);
+
+       if (ft->valid) {
+               /* Already marked as valid */
+               goto end;
+       }
+
+       if (ft->methods->validate) {
+               ret = ft->methods->validate(ft);
+       }
+
+       if (ret == 0 && ft->frozen) {
+               /* Field type is valid */
+               BT_LOGV("Marking field type as valid: addr=%p", ft);
+               ft->valid = 1;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return (int) int_ft->size;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->is_signed;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft,
+               bt_bool is_signed)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       int_ft->is_signed = !!is_signed;
+       BT_LOGV("Set integer field type's signedness: addr=%p, is-signed=%d",
+               ft, is_signed);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft,
+               unsigned int size)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       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;
+       }
+
+       int_ft->size = size;
+       BT_LOGV("Set integer field type's size: addr=%p, size=%u",
+               ft, size);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->base;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_integer_base base)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       switch (base) {
+       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
+       case BT_CTF_INTEGER_BASE_BINARY:
+       case BT_CTF_INTEGER_BASE_OCTAL:
+       case BT_CTF_INTEGER_BASE_DECIMAL:
+       case BT_CTF_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;
+       }
+
+       BT_LOGV("Set integer field type's base: addr=%p, base=%s",
+               ft, bt_ctf_integer_base_string(base));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->encoding;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
+                       encoding != BT_CTF_STRING_ENCODING_ASCII &&
+                       encoding != BT_CTF_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_ctf_string_encoding_string(encoding));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->mapped_clock_class;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class *clock_class)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+       int ret = 0;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               goto end;
+       }
+
+       if (!bt_ctf_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_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(int_ft->mapped_clock_class);
+       int_ft->mapped_clock_class = bt_ctf_object_get_ref(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_ctf_clock_class_get_name(clock_class));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_mapped_clock_class(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_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_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
+               ft, clock_class);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index,
+               const char **mapping_name, int64_t *range_begin,
+               int64_t *range_end)
+{
+       int ret = 0;
+       struct bt_ctf_enumeration_mapping *mapping;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(ft,
+               index);
+       if (!mapping) {
+               /* bt_ctf_field_type_common_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index,
+               const char **mapping_name, uint64_t *range_begin,
+               uint64_t *range_end)
+{
+       int ret = 0;
+       struct bt_ctf_enumeration_mapping *mapping;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+               ft, index);
+       if (!mapping) {
+               /* bt_ctf_field_type_common_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;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       return BT_CTF_TO_COMMON(enum_ft->container_ft);
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_signed_add_mapping(
+               struct bt_ctf_field_type_common *ft, const char *string,
+               int64_t range_start, int64_t range_end)
+{
+       int ret = 0;
+       GQuark mapping_name;
+       struct bt_ctf_enumeration_mapping *mapping;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_ENUM) {
+               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_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 bt_ctf_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 bt_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
+               struct bt_ctf_field_type_common *ft, const char *string,
+               uint64_t range_start, uint64_t range_end)
+{
+       int ret = 0;
+       GQuark mapping_name;
+       struct bt_ctf_enumeration_mapping *mapping;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_ENUM) {
+               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_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 bt_ctf_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 bt_ctf_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;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_enumeration_get_mapping_count(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       return (int64_t) enum_ft->entries->len;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_get_exponent_digits(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
+               "Field type");
+       return (int) flt_ft->exp_dig;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_set_exponent_digits(
+               struct bt_ctf_field_type_common *ft,
+               unsigned int exponent_digits)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(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_CTF_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_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_get_mantissa_digits(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
+               "Field type");
+       return (int) flt_ft->mant_dig;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_set_mantissa_digits(
+               struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(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_CTF_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_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_replace_field(
+               struct bt_ctf_field_type_common *ft,
+               const char *field_name,
+               struct bt_ctf_field_type_common *field_type)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       GQuark name_quark;
+       uint64_t i;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(field_name);
+       BT_ASSERT(field_type);
+       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_STRUCT);
+       name_quark = g_quark_from_string(field_name);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
+
+               if (field->name == name_quark) {
+                       bt_ctf_object_put_ref(field->type);
+                       field->type = bt_ctf_object_get_ref(field_type);
+               }
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *field_type,
+               const char *field_name)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid parameter: field type is not a structure field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_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;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_structure_get_field_count(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
+               "Field type");
+       return (int64_t) struct_ft->fields->len;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_borrow_field_by_index(
+               struct bt_ctf_field_type_common *ft,
+               const char **field_name,
+               struct bt_ctf_field_type_common **field_type, uint64_t index)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common_structure_field *field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
+               "Field type");
+       BT_CTF_ASSERT_PRE(index < struct_ft->fields->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u, ft-addr=%p",
+               index, struct_ft->fields->len, ft);
+       field = BT_CTF_FIELD_TYPE_COMMON_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;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_structure_field *field;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, index);
+       field_type = field->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_tag_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common *tag_ft = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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 = BT_CTF_TO_COMMON(var_ft->tag_ft);
+
+end:
+       return tag_ft;
+}
+
+BT_HIDDEN
+const char *bt_ctf_field_type_common_variant_get_tag_name(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       const char *tag_name = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_set_tag_name(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_VARIANT) {
+               BT_LOGW("Invalid parameter: field type is not a variant field type: "
+                       "addr=%p, ft-id=%s", ft, bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *field_type,
+               const char *field_name)
+{
+       size_t i;
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_VARIANT) {
+               BT_LOGW("Invalid parameter: field type is not a variant field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_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 bt_ctf_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;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_by_name(
+               struct bt_ctf_field_type_common *ft,
+               const char *field_name)
+{
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_variant_choice *choice;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(field_name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
+       field_type = choice->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_variant_get_field_count(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Variant field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       return (int64_t) var_ft->choices->len;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_borrow_field_by_index(
+               struct bt_ctf_field_type_common *ft,
+               const char **field_name,
+               struct bt_ctf_field_type_common **field_type, uint64_t index)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common_variant_choice *choice;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       BT_CTF_ASSERT_PRE(index < var_ft->choices->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u, ft-addr=%p",
+               index, var_ft->choices->len, ft);
+       choice = BT_CTF_FIELD_TYPE_COMMON_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_ctf_field_type_common_variant_find_choice_index(
+               struct bt_ctf_field_type_common *ft, uint64_t uval,
+               bool is_signed)
+{
+       int64_t ret;
+       uint64_t i;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(ft);
+       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_VARIANT);
+
+       if (bt_ctf_field_type_common_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_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft, i);
+
+               for (range_i = 0; range_i < choice->ranges->len; range_i++) {
+                       struct bt_ctf_field_type_common_variant_choice_range *range =
+                               &g_array_index(
+                                       choice->ranges,
+                                       struct bt_ctf_field_type_common_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;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_array_borrow_element_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
+               "Field type");
+       BT_ASSERT(array_ft && array_ft->element_ft);
+       return array_ft->element_ft;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_set_element_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: array field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!element_ft) {
+               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_ARRAY) {
+               BT_LOGW("Invalid parameter: field type is not an array field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (array_ft->element_ft) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(array_ft->element_ft);
+       }
+
+       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
+       BT_LOGV("Set array field type's element field type: array-ft-addr=%p, "
+               "element-ft-addr=%p", ft, element_ft);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
+               "Field type");
+       return (int64_t) array_ft->length;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_sequence_borrow_element_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field type");
+       return seq_ft->element_ft;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_set_element_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: sequence field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!element_ft) {
+               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
+               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (seq_ft->element_ft) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(seq_ft->element_ft);
+       }
+
+       seq_ft->element_ft = element_ft;
+       bt_ctf_object_get_ref(seq_ft->element_ft);
+       BT_LOGV("Set sequence field type's element field type: sequence-ft-addr=%p, "
+               "element-ft-addr=%p", ft, element_ft);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+const char *bt_ctf_field_type_common_sequence_get_length_field_name(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field type");
+       return seq_ft->length_field_name ?
+               seq_ft->length_field_name->str : NULL;
+}
+
+BT_HIDDEN
+enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRING,
+               "Field type");
+       return string_ft->encoding;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_STRING) {
+               BT_LOGW("Invalid parameter: field type is not a string field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
+                       encoding != BT_CTF_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_ctf_string_encoding_string(encoding));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *ft)
+{
+       int ret;
+       enum bt_ctf_field_type_id type_id;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+
+       if (ft->frozen) {
+               ret = (int) ft->alignment;
+               goto end;
+       }
+
+       type_id = bt_ctf_field_type_common_get_type_id(ft);
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct bt_ctf_field_type_common *element_ft =
+                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
+
+               BT_ASSERT(element_ft);
+               ret = bt_ctf_field_type_common_get_alignment(element_ft);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       {
+               struct bt_ctf_field_type_common *element_ft =
+                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
+
+               BT_ASSERT(element_ft);
+               ret = bt_ctf_field_type_common_get_alignment(element_ft);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               int64_t i, element_count;
+
+               element_count = bt_ctf_field_type_common_structure_get_field_count(
+                       ft);
+               BT_ASSERT(element_count >= 0);
+
+               for (i = 0; i < element_count; i++) {
+                       struct bt_ctf_field_type_common *field = NULL;
+                       int field_alignment;
+
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               ft, NULL, &field, i);
+                       BT_ASSERT(ret == 0);
+                       BT_ASSERT(field);
+                       field_alignment = bt_ctf_field_type_common_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_CTF_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft,
+               unsigned int alignment)
+{
+       int ret = 0;
+       enum bt_ctf_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_ctf_field_type_common_get_type_id(ft);
+       if (type_id == BT_CTF_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_CTF_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_CTF_FIELD_TYPE_ID_VARIANT ||
+                       type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE ||
+                       type_id == BT_CTF_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_ctf_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;
+}
+
+BT_HIDDEN
+enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order(
+               struct bt_ctf_field_type_common *ft)
+{
+       enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_INTEGER:
+       {
+               struct bt_ctf_field_type_common_integer *integer =
+                       BT_CTF_FROM_COMMON(ft);
+
+               ret = integer->user_byte_order;
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ENUM:
+       {
+               struct bt_ctf_field_type_common_enumeration *enum_ft =
+                       BT_CTF_FROM_COMMON(ft);
+
+               ret = bt_ctf_field_type_common_get_byte_order(
+                       BT_CTF_TO_COMMON(enum_ft->container_ft));
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_FLOAT:
+       {
+               struct bt_ctf_field_type_common_floating_point *floating_point =
+                       BT_CTF_FROM_COMMON(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_ctf_field_type_id_string(ft->id));
+               goto end;
+       }
+
+       BT_ASSERT(ret == BT_CTF_BYTE_ORDER_NATIVE ||
+               ret == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
+               ret == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
+               ret == BT_CTF_BYTE_ORDER_NETWORK);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_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_CTF_BYTE_ORDER_NATIVE &&
+                       byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
+               BT_LOGW("Invalid parameter: invalid byte order: "
+                       "addr=%p, bo=%s", ft,
+                       bt_ctf_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_ctf_byte_order_string(byte_order));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id(
+               struct bt_ctf_field_type_common *ft)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       return ft->id;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft)
+{
+       if (!ft || ft->frozen) {
+               return;
+       }
+
+       BT_ASSERT(ft->methods->freeze);
+       ft->methods->freeze(ft);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_signed(
+               struct bt_ctf_field_type_common_variant *var_ft,
+               int64_t tag_value)
+{
+       struct bt_ctf_field_type_common *field_type = NULL;
+       GQuark field_name_quark;
+       gpointer index;
+       struct bt_ctf_field_type_common_variant_choice *choice;
+       struct range_overlap_query query = {
+               .range_start._signed = tag_value,
+               .range_end._signed = tag_value,
+               .mapping_name = 0,
+               .overlaps = 0,
+       };
+
+       g_ptr_array_foreach(var_ft->tag_ft->entries, check_ranges_overlap,
+               &query);
+       if (!query.overlaps) {
+               goto end;
+       }
+
+       field_name_quark = query.mapping_name;
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
+                       GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
+               goto end;
+       }
+
+       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
+               (size_t) index);
+       field_type = choice->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_unsigned(
+               struct bt_ctf_field_type_common_variant *var_ft,
+               uint64_t tag_value)
+{
+       struct bt_ctf_field_type_common *field_type = NULL;
+       GQuark field_name_quark;
+       gpointer index;
+       struct bt_ctf_field_type_common_variant_choice *choice;
+       struct range_overlap_query query = {
+               .range_start._unsigned = tag_value,
+               .range_end._unsigned = tag_value,
+               .mapping_name = 0,
+               .overlaps = 0,
+       };
+
+       g_ptr_array_foreach(var_ft->tag_ft->entries,
+               check_ranges_overlap_unsigned, &query);
+       if (!query.overlaps) {
+               goto end;
+       }
+
+       field_name_quark = query.mapping_name;
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
+               GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
+               goto end;
+       }
+
+       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
+               (size_t) index);
+       field_type = choice->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common *ft_copy = NULL;
+
+       BT_CTF_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_get_field_name_index(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       int ret;
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_get_field_name_index(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       int ret;
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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_ctf_field_type_common_sequence_set_length_field_path(
+               struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
+               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_get_ref(path);
+       BT_CTF_OBJECT_MOVE_REF(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_ctf_field_type_common_variant_set_tag_field_path(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_path *path)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
+               BT_LOGW("Invalid parameter: field type is not a variant field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_get_ref(path);
+       BT_CTF_OBJECT_MOVE_REF(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_ctf_field_type_common_variant_set_tag_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *tag_ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_CTF_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_ctf_field_type_id_string(tag_ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(var_ft->tag_ft);
+       var_ft->tag_ft = bt_ctf_object_get_ref(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;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft)
+{
+       ft->frozen = 1;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD("Freezing enumeration field type object: addr=%p", ft);
+       bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+       BT_LOGD("Freezing enumeration field type object's container field type: int-ft-addr=%p",
+               enum_ft->container_ft);
+       bt_ctf_field_type_common_freeze(BT_CTF_TO_COMMON(enum_ft->container_ft));
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       uint64_t i;
+
+       /* Cache the alignment */
+       BT_LOGD("Freezing structure field type object: addr=%p", ft);
+       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_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_ctf_field_type_common_freeze(field->type);
+       }
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_update_choices(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
+               const char *choice_name = g_quark_to_string(choice->name);
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
+                       bt_ctf_field_type_common_enumeration_find_mappings_by_name(
+                               BT_CTF_TO_COMMON(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_ctf_field_type_enumeration_mapping_iterator_next(iter) == 0) {
+                       struct bt_ctf_field_type_common_variant_choice_range range;
+
+                       if (is_signed) {
+                               ret = bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
+                                       iter, NULL,
+                                       &range.lower.i, &range.upper.i);
+                       } else {
+                               ret = bt_ctf_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_ctf_object_put_ref(iter);
+       }
+
+       var_ft->choices_up_to_date = true;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       uint64_t i;
+
+       BT_LOGD("Freezing variant field type object: addr=%p", ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_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_ctf_field_type_common_freeze(choice->type);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       /* Cache the alignment */
+       BT_LOGD("Freezing array field type object: addr=%p", ft);
+       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+       BT_LOGD("Freezing array field type object's element field type: element-ft-addr=%p",
+               array_ft->element_ft);
+       bt_ctf_field_type_common_freeze(array_ft->element_ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       /* Cache the alignment */
+       BT_LOGD("Freezing sequence field type object: addr=%p", ft);
+       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+       BT_LOGD("Freezing sequence field type object's element field type: element-ft-addr=%p",
+               seq_ft->element_ft);
+       bt_ctf_field_type_common_freeze(seq_ft->element_ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_set_byte_order(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       int_ft->user_byte_order = byte_order;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       bt_ctf_field_type_common_set_byte_order(BT_CTF_TO_COMMON(enum_ft->container_ft),
+               byte_order);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_set_byte_order(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       flt_ft->user_byte_order = byte_order;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       int i;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft, i);
+               struct bt_ctf_field_type_common *field_type = field->type;
+
+               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       int i;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft, i);
+               struct bt_ctf_field_type_common *field_type = choice->type;
+
+               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       bt_ctf_field_type_common_set_byte_order(array_ft->element_ft, byte_order);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       bt_ctf_field_type_common_set_byte_order(seq_ft->element_ft, byte_order);
+}
+
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_integer *int_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_integer *int_ft_b = BT_CTF_FROM_COMMON(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_ctf_byte_order_string(int_ft_a->user_byte_order),
+                       bt_ctf_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_ctf_integer_base_string(int_ft_a->base),
+                       bt_ctf_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_ctf_string_encoding_string(int_ft_a->encoding),
+                       bt_ctf_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_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_compare(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_floating_point *flt_ft_a =
+               BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_floating_point *flt_ft_b =
+               BT_CTF_FROM_COMMON(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_ctf_byte_order_string(flt_ft_a->user_byte_order),
+                       bt_ctf_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 bt_ctf_enumeration_mapping *mapping_a,
+               struct bt_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       int i;
+       struct bt_ctf_field_type_common_enumeration *enum_ft_a =
+               BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_enumeration *enum_ft_b =
+               BT_CTF_FROM_COMMON(ft_b);
+
+       /* Container field type */
+       ret = bt_ctf_field_type_common_compare(
+               BT_CTF_TO_COMMON(enum_ft_a->container_ft),
+               BT_CTF_TO_COMMON(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 bt_ctf_enumeration_mapping *mapping_a =
+                       g_ptr_array_index(enum_ft_a->entries, i);
+               struct bt_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_string *string_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_string *string_ft_b = BT_CTF_FROM_COMMON(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_ctf_string_encoding_string(string_ft_a->encoding),
+                       bt_ctf_string_encoding_string(string_ft_b->encoding));
+               goto end;
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static
+int compare_structure_variant_members(
+               struct bt_ctf_field_type_common *member_a_ft,
+               struct bt_ctf_field_type_common *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_ctf_field_type_common_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       int i;
+       struct bt_ctf_field_type_common_structure *struct_ft_a =
+               BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_structure *struct_ft_b =
+               BT_CTF_FROM_COMMON(ft_b);
+
+       /* Alignment */
+       if (bt_ctf_field_type_common_get_alignment(ft_a) !=
+                       bt_ctf_field_type_common_get_alignment(ft_b)) {
+               BT_LOGV("Structure field types differ: different alignments: "
+                       "ft-a-align=%u, ft-b-align=%u",
+                       bt_ctf_field_type_common_get_alignment(ft_a),
+                       bt_ctf_field_type_common_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_ctf_field_type_common_structure_field *field_a =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft_a, i);
+               struct bt_ctf_field_type_common_structure_field *field_b =
+                       BT_CTF_FIELD_TYPE_COMMON_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       int i;
+       struct bt_ctf_field_type_common_variant *var_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_variant *var_ft_b = BT_CTF_FROM_COMMON(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_ctf_field_type_common_compare(BT_CTF_TO_COMMON(var_ft_a->tag_ft),
+               BT_CTF_TO_COMMON(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_ctf_field_type_common_variant_choice *choice_a =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft_a, i);
+               struct bt_ctf_field_type_common_variant_choice *choice_b =
+                       BT_CTF_FIELD_TYPE_COMMON_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_array *array_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_array *array_ft_b = BT_CTF_FROM_COMMON(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_ctf_field_type_common_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;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = -1;
+       struct bt_ctf_field_type_common_sequence *seq_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_sequence *seq_ft_b = BT_CTF_FROM_COMMON(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_ctf_field_type_common_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_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft_a, "Field type A");
+       BT_CTF_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_ctf_field_type_id_string(ft_a->id),
+                       bt_ctf_field_type_id_string(ft_b->id));
+               goto end;
+       }
+
+       if (ft_a->id == BT_CTF_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);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft)
+{
+       int64_t field_count = -1;
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+               field_count =
+                       bt_ctf_field_type_common_structure_get_field_count(ft);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               field_count =
+                       bt_ctf_field_type_common_variant_get_field_count(ft);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       case BT_CTF_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;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index(
+               struct bt_ctf_field_type_common *ft, int index)
+{
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                       ft, NULL, &field_type, index);
+               if (ret) {
+                       field_type = NULL;
+                       goto end;
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
+                       ft, NULL, &field_type, index);
+               if (ret) {
+                       field_type = NULL;
+                       goto end;
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+               field_type =
+                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               field_type =
+                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
+               break;
+       default:
+               break;
+       }
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft,
+               const char *name)
+{
+       int field_index = -1;
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+               field_index = bt_ctf_field_type_common_structure_get_field_name_index(
+                       ft, name);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               field_index = bt_ctf_field_type_common_variant_get_field_name_index(
+                       ft, name);
+               break;
+       default:
+               break;
+       }
+
+       return field_index;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       return var_ft->tag_field_path;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field type");
+       return seq_ft->length_field_path;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_validate_single_clock_class(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class **expected_clock_class)
+{
+       int ret = 0;
+
+       if (!ft) {
+               goto end;
+       }
+
+       BT_ASSERT(expected_clock_class);
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_INTEGER:
+       {
+               struct bt_ctf_clock_class *mapped_clock_class =
+                       bt_ctf_field_type_common_integer_borrow_mapped_clock_class(ft);
+
+               if (!mapped_clock_class) {
+                       goto end;
+               }
+
+               if (!*expected_clock_class) {
+                       /* Move reference to output parameter */
+                       *expected_clock_class = bt_ctf_object_get_ref(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_ctf_clock_class_get_name(mapped_clock_class),
+                                       *expected_clock_class,
+                                       bt_ctf_clock_class_get_name(*expected_clock_class));
+                               bt_ctf_object_put_ref(mapped_clock_class);
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ENUM:
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct bt_ctf_field_type_common *sub_ft = NULL;
+
+               switch (ft->id) {
+               case BT_CTF_FIELD_TYPE_ID_ENUM:
+                       sub_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+                               ft);
+                       break;
+               case BT_CTF_FIELD_TYPE_ID_ARRAY:
+                       sub_ft = bt_ctf_field_type_common_array_borrow_element_field_type(
+                               ft);
+                       break;
+               case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+                       sub_ft = bt_ctf_field_type_common_sequence_borrow_element_field_type(
+                               ft);
+                       break;
+               default:
+                       BT_LOGF("Unexpected field type ID: id=%d", ft->id);
+                       abort();
+               }
+
+               BT_ASSERT(sub_ft);
+               ret = bt_ctf_field_type_common_validate_single_clock_class(sub_ft,
+                       expected_clock_class);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               uint64_t i;
+               int64_t count = bt_ctf_field_type_common_structure_get_field_count(
+                       ft);
+
+               for (i = 0; i < count; i++) {
+                       const char *name;
+                       struct bt_ctf_field_type_common *member_type;
+
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               ft, &name, &member_type, i);
+                       BT_ASSERT(ret == 0);
+                       ret = bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               uint64_t i;
+               int64_t count = bt_ctf_field_type_common_variant_get_field_count(
+                       ft);
+
+               for (i = 0; i < count; i++) {
+                       const char *name;
+                       struct bt_ctf_field_type_common *member_type;
+
+                       ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
+                               ft, &name, &member_type, i);
+                       BT_ASSERT(ret == 0);
+                       ret = bt_ctf_field_type_common_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;
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
+               struct bt_ctf_field_type *type);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_string_copy(
+               struct bt_ctf_field_type *type);
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_integer_methods = {
+       .freeze = bt_ctf_field_type_common_generic_freeze,
+       .validate = bt_ctf_field_type_common_integer_validate,
+       .set_byte_order = bt_ctf_field_type_common_integer_set_byte_order,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_integer_copy,
+       .compare = bt_ctf_field_type_common_integer_compare,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_floating_point_methods = {
+       .freeze = bt_ctf_field_type_common_generic_freeze,
+       .validate = NULL,
+       .set_byte_order = bt_ctf_field_type_common_floating_point_set_byte_order,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_floating_point_copy,
+       .compare = bt_ctf_field_type_common_floating_point_compare,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_enumeration_methods = {
+       .freeze = bt_ctf_field_type_common_enumeration_freeze_recursive,
+       .validate = bt_ctf_field_type_common_enumeration_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_enumeration_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_enumeration_copy_recursive,
+       .compare = bt_ctf_field_type_common_enumeration_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_string_methods = {
+       .freeze = bt_ctf_field_type_common_generic_freeze,
+       .validate = NULL,
+       .set_byte_order = NULL,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_string_copy,
+       .compare = bt_ctf_field_type_common_string_compare,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_array_methods = {
+       .freeze = bt_ctf_field_type_common_array_freeze_recursive,
+       .validate = bt_ctf_field_type_common_array_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_array_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_array_copy_recursive,
+       .compare = bt_ctf_field_type_common_array_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_sequence_methods = {
+       .freeze = bt_ctf_field_type_common_sequence_freeze_recursive,
+       .validate = bt_ctf_field_type_common_sequence_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_sequence_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_sequence_copy_recursive,
+       .compare = bt_ctf_field_type_common_sequence_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_structure_methods = {
+       .freeze = bt_ctf_field_type_common_structure_freeze_recursive,
+       .validate = bt_ctf_field_type_common_structure_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_structure_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_structure_copy_recursive,
+       .compare = bt_ctf_field_type_common_structure_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_variant_methods = {
+       .freeze = bt_ctf_field_type_common_variant_freeze_recursive,
+       .validate = bt_ctf_field_type_common_variant_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_variant_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_variant_copy_recursive,
+       .compare = bt_ctf_field_type_common_variant_compare_recursive,
+};
+
+typedef int (*bt_ctf_field_type_serialize_func)(struct bt_ctf_field_type_common *,
+               struct metadata_context *);
+
+BT_HIDDEN
+int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type,
+               struct metadata_context *context)
+{
+       int ret;
+       struct bt_ctf_field_type_common *type_common = (void *) type;
+       bt_ctf_field_type_serialize_func serialize_func;
+
+       BT_ASSERT(type);
+       BT_ASSERT(context);
+
+       /* Make sure field type is valid before serializing it */
+       ret = bt_ctf_field_type_common_validate((void *) type);
+       if (ret) {
+               BT_LOGW("Cannot serialize field type's metadata: field type is invalid: "
+                       "addr=%p", type);
+               goto end;
+       }
+
+       serialize_func = type_common->spec.writer.serialize_func;
+       ret = serialize_func((void *) type, context);
+
+end:
+       return ret;
+}
+
+static
+const char *get_encoding_string(enum bt_ctf_string_encoding encoding)
+{
+       const char *encoding_string;
+
+       switch (encoding) {
+       case BT_CTF_STRING_ENCODING_NONE:
+               encoding_string = "none";
+               break;
+       case BT_CTF_STRING_ENCODING_ASCII:
+               encoding_string = "ASCII";
+               break;
+       case BT_CTF_STRING_ENCODING_UTF8:
+               encoding_string = "UTF8";
+               break;
+       default:
+               encoding_string = "unknown";
+               break;
+       }
+
+       return encoding_string;
+}
+
+static
+const char *get_integer_base_string(enum bt_ctf_integer_base base)
+{
+       const char *base_string;
+
+       switch (base) {
+       case BT_CTF_INTEGER_BASE_DECIMAL:
+       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
+               base_string = "decimal";
+               break;
+       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
+               base_string = "hexadecimal";
+               break;
+       case BT_CTF_INTEGER_BASE_OCTAL:
+               base_string = "octal";
+               break;
+       case BT_CTF_INTEGER_BASE_BINARY:
+               base_string = "binary";
+               break;
+       default:
+               base_string = "unknown";
+               break;
+       }
+
+       return base_string;
+}
+
+static
+void append_field_name(struct metadata_context *context,
+               const char *name)
+{
+       g_string_append_c(context->string, ' ');
+
+       if (!bt_ctf_identifier_is_valid(name) || *name == '_') {
+               g_string_append_c(context->string, '_');
+       }
+
+       g_string_append(context->string, name);
+}
+
+static
+int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       struct bt_ctf_field_type_common_integer *integer = BT_CTF_FROM_COMMON(type);
+       int ret = 0;
+
+       BT_LOGD("Serializing CTF writer integer field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       g_string_append_printf(context->string,
+               "integer { size = %u; align = %u; signed = %s; encoding = %s; base = %s; byte_order = %s",
+               integer->size, type->alignment,
+               (integer->is_signed ? "true" : "false"),
+               get_encoding_string(integer->encoding),
+               get_integer_base_string(integer->base),
+               bt_ctf_get_byte_order_string(integer->user_byte_order));
+       if (integer->mapped_clock_class) {
+               const char *clock_name = bt_ctf_clock_class_get_name(
+                       integer->mapped_clock_class);
+
+               BT_ASSERT(clock_name);
+               g_string_append_printf(context->string,
+                       "; map = clock.%s.value", clock_name);
+       }
+
+       g_string_append(context->string, "; }");
+       return ret;
+}
+
+static
+int bt_ctf_field_type_enumeration_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       size_t entry;
+       int ret;
+       struct bt_ctf_field_type_common_enumeration *enumeration =
+               BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_type_common *container_type;
+       int container_signed;
+
+       BT_LOGD("Serializing CTF writer enumeration field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       container_type =
+               bt_ctf_field_type_common_enumeration_borrow_container_field_type(type);
+       BT_ASSERT(container_type);
+       container_signed = bt_ctf_field_type_common_integer_is_signed(
+               container_type);
+       BT_ASSERT(container_signed >= 0);
+       g_string_append(context->string, "enum : ");
+       BT_LOGD_STR("Serializing CTF writer enumeration field type's container field type's metadata.");
+       ret = bt_ctf_field_type_serialize_recursive(
+               (void *) enumeration->container_ft, context);
+       if (ret) {
+               BT_LOGW("Cannot serialize CTF writer enumeration field type's container field type's metadata: "
+                       "container-ft-addr=%p", enumeration->container_ft);
+               goto end;
+       }
+
+       g_string_append(context->string, " { ");
+       for (entry = 0; entry < enumeration->entries->len; entry++) {
+               struct bt_ctf_enumeration_mapping *mapping =
+                       enumeration->entries->pdata[entry];
+               const char *label = g_quark_to_string(mapping->string);
+
+               g_string_append(context->string, "\"");
+
+               if (!bt_ctf_identifier_is_valid(label) || label[0] == '_') {
+                       g_string_append(context->string, "_");
+               }
+
+               g_string_append_printf(context->string, "%s\" = ", label);
+
+               if (container_signed) {
+                       if (mapping->range_start._signed ==
+                               mapping->range_end._signed) {
+                               g_string_append_printf(context->string,
+                                       "%" PRId64,
+                                       mapping->range_start._signed);
+                       } else {
+                               g_string_append_printf(context->string,
+                                       "%" PRId64 " ... %" PRId64,
+                                       mapping->range_start._signed,
+                                       mapping->range_end._signed);
+                       }
+               } else {
+                       if (mapping->range_start._unsigned ==
+                               mapping->range_end._unsigned) {
+                               g_string_append_printf(context->string,
+                                       "%" PRIu64,
+                                       mapping->range_start._unsigned);
+                       } else {
+                               g_string_append_printf(context->string,
+                                       "%" PRIu64 " ... %" PRIu64,
+                                       mapping->range_start._unsigned,
+                                       mapping->range_end._unsigned);
+                       }
+               }
+
+               g_string_append(context->string,
+                       ((entry != (enumeration->entries->len - 1)) ?
+                       ", " : " }"));
+       }
+
+       if (context->field_name->len) {
+               append_field_name(context,
+                       context->field_name->str);
+               g_string_assign(context->field_name, "");
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       struct bt_ctf_field_type_common_floating_point *floating_point =
+               BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer floating point number field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       g_string_append_printf(context->string,
+               "floating_point { exp_dig = %u; mant_dig = %u; byte_order = %s; align = %u; }",
+               floating_point->exp_dig,
+               floating_point->mant_dig,
+               bt_ctf_get_byte_order_string(floating_point->user_byte_order),
+               type->alignment);
+       return 0;
+}
+
+static
+int bt_ctf_field_type_structure_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       size_t i;
+       unsigned int indent;
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *structure = BT_CTF_FROM_COMMON(type);
+       GString *structure_field_name = context->field_name;
+
+       BT_LOGD("Serializing CTF writer structure field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       context->field_name = g_string_new("");
+
+       context->current_indentation_level++;
+       g_string_append(context->string, "struct {\n");
+
+       for (i = 0; i < structure->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               structure, i);
+
+               BT_LOGD("Serializing CTF writer structure field type's field metadata: "
+                       "index=%zu, "
+                       "field-ft-addr=%p, field-name=\"%s\"",
+                       i, field, g_quark_to_string(field->name));
+
+               for (indent = 0; indent < context->current_indentation_level;
+                       indent++) {
+                       g_string_append_c(context->string, '\t');
+               }
+
+               g_string_assign(context->field_name,
+                       g_quark_to_string(field->name));
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) field->type, context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize CTF writer structure field type's field's metadata: "
+                               "index=%zu, "
+                               "field-ft-addr=%p, field-name=\"%s\"",
+                               i, field->type,
+                               g_quark_to_string(field->name));
+                       goto end;
+               }
+
+               if (context->field_name->len) {
+                       append_field_name(context,
+                               context->field_name->str);
+               }
+               g_string_append(context->string, ";\n");
+       }
+
+       context->current_indentation_level--;
+       for (indent = 0; indent < context->current_indentation_level;
+               indent++) {
+               g_string_append_c(context->string, '\t');
+       }
+
+       g_string_append_printf(context->string, "} align(%u)",
+                type->alignment);
+
+end:
+       g_string_free(context->field_name, TRUE);
+       context->field_name = structure_field_name;
+       return ret;
+}
+
+static
+int bt_ctf_field_type_variant_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       size_t i;
+       unsigned int indent;
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *variant = BT_CTF_FROM_COMMON(type);
+       GString *variant_field_name = context->field_name;
+
+       BT_LOGD("Serializing CTF writer variant field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       context->field_name = g_string_new("");
+       if (variant->tag_name->len > 0) {
+               g_string_append(context->string, "variant <");
+               append_field_name(context, variant->tag_name->str);
+               g_string_append(context->string, "> {\n");
+       } else {
+               g_string_append(context->string, "variant {\n");
+       }
+
+       context->current_indentation_level++;
+       for (i = 0; i < variant->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *field =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               variant, i);
+
+               BT_LOGD("Serializing CTF writer variant field type's field metadata: "
+                       "index=%zu, "
+                       "field-ft-addr=%p, field-name=\"%s\"",
+                       i, field, g_quark_to_string(field->name));
+
+               g_string_assign(context->field_name,
+                       g_quark_to_string(field->name));
+               for (indent = 0; indent < context->current_indentation_level;
+                       indent++) {
+                       g_string_append_c(context->string, '\t');
+               }
+
+               g_string_assign(context->field_name,
+                       g_quark_to_string(field->name));
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) field->type, context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize CTF writer variant field type's field's metadata: "
+                               "index=%zu, "
+                               "field-ft-addr=%p, field-name=\"%s\"",
+                               i, field->type,
+                               g_quark_to_string(field->name));
+                       goto end;
+               }
+
+               if (context->field_name->len) {
+                       append_field_name(context,
+                               context->field_name->str);
+                       g_string_append_c(context->string, ';');
+               }
+
+               g_string_append_c(context->string, '\n');
+       }
+
+       context->current_indentation_level--;
+       for (indent = 0; indent < context->current_indentation_level;
+               indent++) {
+               g_string_append_c(context->string, '\t');
+       }
+
+       g_string_append(context->string, "}");
+
+end:
+       g_string_free(context->field_name, TRUE);
+       context->field_name = variant_field_name;
+       return ret;
+}
+
+static
+int bt_ctf_field_type_array_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_array *array = BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer array field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       BT_LOGD_STR("Serializing CTF writer array field type's element field type's metadata.");
+       ret = bt_ctf_field_type_serialize_recursive(
+               (void *) array->element_ft, context);
+       if (ret) {
+               BT_LOGW("Cannot serialize CTF writer array field type's element field type's metadata: "
+                       "element-ft-addr=%p", array->element_ft);
+               goto end;
+       }
+
+       if (context->field_name->len) {
+               append_field_name(context,
+                       context->field_name->str);
+
+               g_string_append_printf(context->string, "[%u]", array->length);
+               g_string_assign(context->field_name, "");
+       } else {
+               g_string_append_printf(context->string, "[%u]", array->length);
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_type_sequence_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *sequence = BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer sequence field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       BT_LOGD_STR("Serializing CTF writer sequence field type's element field type's metadata.");
+       ret = bt_ctf_field_type_serialize_recursive(
+               (void *) sequence->element_ft, context);
+       if (ret) {
+               BT_LOGW("Cannot serialize CTF writer sequence field type's element field type's metadata: "
+                       "element-ft-addr=%p", sequence->element_ft);
+               goto end;
+       }
+
+       if (context->field_name->len) {
+               append_field_name(context, context->field_name->str);
+               g_string_assign(context->field_name, "");
+       }
+       g_string_append(context->string, "[");
+       append_field_name(context, sequence->length_field_name->str);
+       g_string_append(context->string, "]");
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       struct bt_ctf_field_type_common_string *string = BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer string field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       g_string_append_printf(context->string,
+               "string { encoding = %s; }",
+               get_encoding_string(string->encoding));
+       return 0;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size)
+{
+       struct bt_ctf_field_type_common_integer *integer = NULL;
+
+       BT_LOGD("Creating CTF writer integer field type object: size=%u", size);
+
+       if (size == 0 || size > 64) {
+               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
+                       "size=%u", size);
+               goto error;
+       }
+
+       integer = g_new0(struct bt_ctf_field_type_common_integer, 1);
+       if (!integer) {
+               BT_LOGE_STR("Failed to allocate one integer field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_integer_initialize(BT_CTF_TO_COMMON(integer),
+               size, bt_ctf_field_type_common_integer_destroy,
+               &bt_ctf_field_type_integer_methods);
+       integer->common.spec.writer.serialize_func =
+               bt_ctf_field_type_integer_serialize;
+       BT_LOGD("Created CTF writer integer field type object: addr=%p, size=%u",
+               integer, size);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(integer);
+
+end:
+       return (void *) integer;
+}
+
+int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_integer_get_size((void *) ft);
+}
+
+bt_bool bt_ctf_field_type_integer_is_signed(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_integer_is_signed((void *) ft);
+}
+
+int bt_ctf_field_type_integer_set_is_signed(struct bt_ctf_field_type *ft,
+               bt_bool is_signed)
+{
+       return bt_ctf_field_type_common_integer_set_is_signed((void *) ft,
+               is_signed);
+}
+
+int bt_ctf_field_type_integer_set_size(struct bt_ctf_field_type *ft,
+               unsigned int size)
+{
+       return bt_ctf_field_type_common_integer_set_size((void *) ft, size);
+}
+
+enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_integer_get_base((void *) ft);
+}
+
+int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *ft,
+               enum bt_ctf_integer_base base)
+{
+       return bt_ctf_field_type_common_integer_set_base((void *) ft,
+               (int) base);
+}
+
+enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_integer_get_encoding((void *) ft);
+}
+
+int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       return bt_ctf_field_type_common_integer_set_encoding((void *) ft,
+               (int) encoding);
+}
+
+struct bt_ctf_clock_class *bt_ctf_field_type_integer_get_mapped_clock_class(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
+               (void *) ft));
+}
+
+int bt_ctf_field_type_integer_set_mapped_clock_class(
+               struct bt_ctf_field_type *ft,
+               struct bt_ctf_clock_class *clock_class)
+{
+       return bt_ctf_field_type_common_integer_set_mapped_clock_class((void *) ft,
+               clock_class);
+}
+
+int bt_ctf_field_type_enumeration_signed_get_mapping_by_index(
+               struct bt_ctf_field_type *ft, uint64_t index,
+               const char **mapping_name, int64_t *range_begin,
+               int64_t *range_end)
+{
+       return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
+               (void *) ft, index, mapping_name, range_begin, range_end);
+}
+
+int bt_ctf_field_type_enumeration_unsigned_get_mapping_by_index(
+               struct bt_ctf_field_type *ft, uint64_t index,
+               const char **mapping_name, uint64_t *range_begin,
+               uint64_t *range_end)
+{
+       return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
+               (void *) ft, index, mapping_name, range_begin, range_end);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create(
+               struct bt_ctf_field_type *container_ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enumeration = NULL;
+       struct bt_ctf_field_type_common *int_ft = (void *) container_ft;
+
+       BT_LOGD("Creating CTF writer 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_CTF_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_ctf_field_type_id_string(int_ft->id));
+               goto error;
+       }
+
+       enumeration = g_new0(struct bt_ctf_field_type_common_enumeration, 1);
+       if (!enumeration) {
+               BT_LOGE_STR("Failed to allocate one enumeration field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_enumeration_initialize(BT_CTF_TO_COMMON(enumeration),
+               int_ft, bt_ctf_field_type_common_enumeration_destroy_recursive,
+               &bt_ctf_field_type_enumeration_methods);
+       enumeration->common.spec.writer.serialize_func =
+               bt_ctf_field_type_enumeration_serialize_recursive;
+       BT_LOGD("Created CTF writer enumeration field type object: addr=%p, "
+               "int-ft-addr=%p, int-ft-size=%u",
+               enumeration, container_ft,
+               bt_ctf_field_type_integer_get_size(container_ft));
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
+
+end:
+       return (void *) enumeration;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+                       (void *) ft));
+}
+
+int bt_ctf_field_type_enumeration_signed_add_mapping(
+               struct bt_ctf_field_type *ft, const char *string,
+               int64_t range_start, int64_t range_end)
+{
+       return bt_ctf_field_type_common_enumeration_signed_add_mapping(
+               (void *) ft, string, range_start, range_end);
+}
+
+int bt_ctf_field_type_enumeration_unsigned_add_mapping(
+               struct bt_ctf_field_type *ft, const char *string,
+               uint64_t range_start, uint64_t range_end)
+{
+       return bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
+               (void *) ft, string, range_start, range_end);
+}
+
+int64_t bt_ctf_field_type_enumeration_get_mapping_count(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_enumeration_get_mapping_count((void *) ft);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void)
+{
+       struct bt_ctf_field_type_common_floating_point *floating_point =
+               g_new0(struct bt_ctf_field_type_common_floating_point, 1);
+
+       BT_LOGD_STR("Creating CTF writer floating point number field type object.");
+
+       if (!floating_point) {
+               BT_LOGE_STR("Failed to allocate one floating point number field type.");
+               goto end;
+       }
+
+       bt_ctf_field_type_common_floating_point_initialize(
+               BT_CTF_TO_COMMON(floating_point),
+               bt_ctf_field_type_common_floating_point_destroy,
+               &bt_ctf_field_type_floating_point_methods);
+       floating_point->common.spec.writer.serialize_func =
+               bt_ctf_field_type_floating_point_serialize;
+       BT_LOGD("Created CTF writer 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_ctf_field_type_floating_point_get_exponent_digits(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_floating_point_get_exponent_digits(
+               (void *) ft);
+}
+
+int bt_ctf_field_type_floating_point_set_exponent_digits(
+               struct bt_ctf_field_type *ft, unsigned int exponent_digits)
+{
+       return bt_ctf_field_type_common_floating_point_set_exponent_digits(
+               (void *) ft, exponent_digits);
+}
+
+int bt_ctf_field_type_floating_point_get_mantissa_digits(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_floating_point_get_mantissa_digits(
+               (void *) ft);
+}
+
+int bt_ctf_field_type_floating_point_set_mantissa_digits(
+               struct bt_ctf_field_type *ft, unsigned int mantissa_digits)
+{
+       return bt_ctf_field_type_common_floating_point_set_mantissa_digits(
+               (void *) ft, mantissa_digits);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void)
+{
+       struct bt_ctf_field_type_common_structure *structure =
+               g_new0(struct bt_ctf_field_type_common_structure, 1);
+
+       BT_LOGD_STR("Creating CTF writer structure field type object.");
+
+       if (!structure) {
+               BT_LOGE_STR("Failed to allocate one structure field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_structure_initialize(BT_CTF_TO_COMMON(structure),
+               bt_ctf_field_type_common_structure_destroy_recursive,
+               &bt_ctf_field_type_structure_methods);
+       structure->common.spec.writer.serialize_func =
+               bt_ctf_field_type_structure_serialize_recursive;
+       BT_LOGD("Created CTF writer structure field type object: addr=%p",
+               structure);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
+
+end:
+       return (void *) structure;
+}
+
+int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *ft,
+               struct bt_ctf_field_type *field_type,
+               const char *field_name)
+{
+       return bt_ctf_field_type_common_structure_add_field((void *) ft,
+               (void *) field_type, field_name);
+}
+
+int64_t bt_ctf_field_type_structure_get_field_count(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_structure_get_field_count((void *) ft);
+}
+
+int bt_ctf_field_type_structure_get_field_by_index(
+               struct bt_ctf_field_type *ft,
+               const char **field_name,
+               struct bt_ctf_field_type **field_type, uint64_t index)
+{
+       int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+               (void *) ft, field_name, (void *) field_type, index);
+
+       if (ret == 0 && field_type) {
+               bt_ctf_object_get_ref(*field_type);
+       }
+
+       return ret;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name(
+               struct bt_ctf_field_type *ft, const char *name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               (void *) ft, name));
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_create(
+       struct bt_ctf_field_type *tag_ft, const char *tag_name)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = NULL;
+
+       BT_LOGD("Creating CTF writer variant field type object: "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               tag_ft, tag_name);
+
+       if (tag_name && !bt_ctf_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_ctf_field_type_common_variant, 1);
+       if (!var_ft) {
+               BT_LOGE_STR("Failed to allocate one variant field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_variant_initialize(BT_CTF_TO_COMMON(var_ft),
+               (void *) tag_ft, tag_name,
+               bt_ctf_field_type_common_variant_destroy_recursive,
+               &bt_ctf_field_type_variant_methods);
+       var_ft->common.spec.writer.serialize_func =
+               bt_ctf_field_type_variant_serialize_recursive;
+       BT_LOGD("Created CTF writer variant field type object: addr=%p, "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               var_ft, tag_ft, tag_name);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(var_ft);
+
+end:
+       return (void *) var_ft;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_tag_field_type(
+               (void *) ft));
+}
+
+const char *bt_ctf_field_type_variant_get_tag_name(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_variant_get_tag_name((void *) ft);
+}
+
+int bt_ctf_field_type_variant_set_tag_name(
+               struct bt_ctf_field_type *ft, const char *name)
+{
+       return bt_ctf_field_type_common_variant_set_tag_name((void *) ft, name);
+}
+
+int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *ft,
+               struct bt_ctf_field_type *field_type,
+               const char *field_name)
+{
+       return bt_ctf_field_type_common_variant_add_field((void *) ft,
+               (void *) field_type, field_name);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name(
+               struct bt_ctf_field_type *ft,
+               const char *field_name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_field_type_by_name(
+               (void *) ft, field_name));
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag(
+               struct bt_ctf_field_type *ft,
+               struct bt_ctf_field *tag_field)
+{
+       int ret;
+       int64_t choice_index;
+       struct bt_ctf_field *container;
+       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
+       struct bt_ctf_field_type *ret_ft = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_ctf_field_common *) tag_field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((struct bt_ctf_field_common *) tag_field,
+               "Tag field");
+
+       container = bt_ctf_field_enumeration_borrow_container(tag_field);
+       BT_ASSERT(container);
+
+       if (var_ft->tag_ft->container_ft->is_signed) {
+               int64_t val;
+
+               ret = bt_ctf_field_integer_signed_get_value(container,
+                       &val);
+               BT_ASSERT(ret == 0);
+               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
+                       (void *) ft, (uint64_t) val, true);
+       } else {
+               uint64_t val;
+
+               ret = bt_ctf_field_integer_unsigned_get_value(container,
+                       &val);
+               BT_ASSERT(ret == 0);
+               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
+                       (void *) ft, val, false);
+       }
+
+       if (choice_index < 0) {
+               BT_LOGW("Cannot find variant field type's field: "
+                       "var-ft-addr=%p, tag-field-addr=%p", ft, tag_field);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_variant_get_field_by_index(ft, NULL,
+               &ret_ft, choice_index);
+       BT_ASSERT(ret == 0);
+
+end:
+       return ret_ft;
+}
+
+int64_t bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_variant_get_field_count((void *) ft);
+}
+
+int bt_ctf_field_type_variant_get_field_by_index(struct bt_ctf_field_type *ft,
+               const char **field_name, struct bt_ctf_field_type **field_type,
+               uint64_t index)
+{
+       int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
+               (void *) ft, field_name, (void *) field_type, index);
+
+       if (ret == 0 && field_type) {
+               bt_ctf_object_get_ref(*field_type);
+       }
+
+       return ret;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_array_create(
+               struct bt_ctf_field_type *element_ft, unsigned int length)
+{
+       struct bt_ctf_field_type_common_array *array = NULL;
+
+       BT_LOGD("Creating CTF writer 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_ctf_field_type_common_array, 1);
+       if (!array) {
+               BT_LOGE_STR("Failed to allocate one array field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_array_initialize(BT_CTF_TO_COMMON(array),
+               (void *) element_ft, length,
+               bt_ctf_field_type_common_array_destroy_recursive,
+               &bt_ctf_field_type_array_methods);
+       array->common.spec.writer.serialize_func =
+               bt_ctf_field_type_array_serialize_recursive;
+       BT_LOGD("Created CTF writer array field type object: addr=%p, "
+               "element-ft-addr=%p, length=%u",
+               array, element_ft, length);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
+
+end:
+       return (void *) array;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_array_borrow_element_field_type(
+               (void *) ft));
+}
+
+int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_array_get_length((void *) ft);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
+               struct bt_ctf_field_type *element_ft,
+               const char *length_field_name)
+{
+       struct bt_ctf_field_type_common_sequence *sequence = NULL;
+
+       BT_LOGD("Creating CTF writer 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_ctf_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_ctf_field_type_common_sequence, 1);
+       if (!sequence) {
+               BT_LOGE_STR("Failed to allocate one sequence field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
+               (void *) element_ft, length_field_name,
+               bt_ctf_field_type_common_sequence_destroy_recursive,
+               &bt_ctf_field_type_sequence_methods);
+       sequence->common.spec.writer.serialize_func =
+               bt_ctf_field_type_sequence_serialize_recursive;
+       BT_LOGD("Created CTF writer sequence field type object: addr=%p, "
+               "element-ft-addr=%p, length-field-name=\"%s\"",
+               sequence, element_ft, length_field_name);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(sequence);
+
+end:
+       return (void *) sequence;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_sequence_borrow_element_field_type(
+               (void *) ft));
+}
+
+const char *bt_ctf_field_type_sequence_get_length_field_name(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_sequence_get_length_field_name((void *) ft);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_string_create(void)
+{
+       struct bt_ctf_field_type_common_string *string =
+               g_new0(struct bt_ctf_field_type_common_string, 1);
+
+       BT_LOGD_STR("Creating CTF writer string field type object.");
+
+       if (!string) {
+               BT_LOGE_STR("Failed to allocate one string field type.");
+               return NULL;
+       }
+
+       bt_ctf_field_type_common_string_initialize(BT_CTF_TO_COMMON(string),
+               bt_ctf_field_type_common_string_destroy,
+               &bt_ctf_field_type_string_methods);
+       string->common.spec.writer.serialize_func =
+               bt_ctf_field_type_string_serialize;
+       BT_LOGD("Created CTF writer string field type object: addr=%p", string);
+       return (void *) string;
+}
+
+enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_string_get_encoding((void *) ft);
+}
+
+int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       return bt_ctf_field_type_common_string_set_encoding((void *) ft,
+               (int) encoding);
+}
+
+int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_get_alignment((void *) ft);
+}
+
+int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *ft,
+               unsigned int alignment)
+{
+       return bt_ctf_field_type_common_set_alignment((void *) ft, alignment);
+}
+
+enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_get_byte_order((void *) ft);
+}
+
+int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       return bt_ctf_field_type_common_set_byte_order((void *) ft,
+               (int) byte_order);
+}
+
+enum bt_ctf_field_type_id bt_ctf_field_type_get_type_id(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_get_type_id((void *) ft);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft)
+{
+       return (void *) bt_ctf_field_type_common_copy((void *) ft);
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = (void *) ft;
+       struct bt_ctf_field_type_common_integer *copy_ft;
+
+       BT_LOGD("Copying CTF writer integer field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_integer_create(int_ft->size);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer integer field type.");
+               goto end;
+       }
+
+       copy_ft->mapped_clock_class = bt_ctf_object_get_ref(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 CTF writer integer field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       size_t i;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) ft;
+       struct bt_ctf_field_type_common_enumeration *copy_ft = NULL;
+       struct bt_ctf_field_type_common_enumeration *container_copy_ft;
+
+       BT_LOGD("Copying CTF writer enumeration field type's: addr=%p", ft);
+
+       /* Copy the source enumeration's container */
+       BT_LOGD_STR("Copying CTF writer enumeration field type's container field type.");
+       container_copy_ft = BT_CTF_FROM_COMMON(bt_ctf_field_type_common_copy(
+               BT_CTF_TO_COMMON(enum_ft->container_ft)));
+       if (!container_copy_ft) {
+               BT_LOGE_STR("Cannot copy CTF writer enumeration field type's container field type.");
+               goto end;
+       }
+
+       copy_ft = (void *) bt_ctf_field_type_enumeration_create(
+               (void *) container_copy_ft);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer enumeration field type.");
+               goto end;
+       }
+
+       /* Copy all enumaration entries */
+       for (i = 0; i < enum_ft->entries->len; i++) {
+               struct bt_ctf_enumeration_mapping *mapping = g_ptr_array_index(
+                       enum_ft->entries, i);
+               struct bt_ctf_enumeration_mapping *copy_mapping = g_new0(
+                       struct bt_ctf_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 CTF writer enumeration field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(container_copy_ft);
+       return (void *) copy_ft;
+
+error:
+       bt_ctf_object_put_ref(container_copy_ft);
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common_floating_point *copy_ft;
+
+       BT_LOGD("Copying CTF writer floating point number field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_floating_point_create();
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer 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 CTF writer floating point number field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       int64_t i;
+       GHashTableIter iter;
+       gpointer key, value;
+       struct bt_ctf_field_type_common_structure *struct_ft = (void *) ft;
+       struct bt_ctf_field_type_common_structure *copy_ft;
+
+       BT_LOGD("Copying CTF writer structure field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_structure_create();
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer 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_ctf_field_type_common_structure_field *entry, *copy_entry;
+               struct bt_ctf_field_type_common *field_ft_copy;
+
+               entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       struct_ft, i);
+               copy_entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       copy_ft, i);
+               BT_LOGD("Copying CTF writer 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_ctf_field_type_copy(
+                       (void *) entry->type);
+               if (!field_ft_copy) {
+                       BT_LOGE("Cannot copy CTF writer 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 CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+
+error:
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return NULL;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       int64_t i;
+       GHashTableIter iter;
+       gpointer key, value;
+       struct bt_ctf_field_type_common *tag_ft_copy = NULL;
+       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
+       struct bt_ctf_field_type_common_variant *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer variant field type's: addr=%p", ft);
+       if (var_ft->tag_ft) {
+               BT_LOGD_STR("Copying CTF writer variant field type's tag field type.");
+               tag_ft_copy = bt_ctf_field_type_common_copy(
+                       BT_CTF_TO_COMMON(var_ft->tag_ft));
+               if (!tag_ft_copy) {
+                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field type.");
+                       goto end;
+               }
+       }
+
+       copy_ft = (void *) bt_ctf_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 CTF writer 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_ctf_field_type_common_variant_choice *entry, *copy_entry;
+               struct bt_ctf_field_type_common *field_ft_copy;
+               uint64_t range_i;
+
+               entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i);
+               copy_entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                       copy_ft, i);
+               BT_LOGD("Copying CTF writer 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_ctf_field_type_copy(
+                       (void *) entry->type);
+               if (!field_ft_copy) {
+                       BT_LOGE("Cannot copy CTF writer 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_ctf_field_type_common_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 CTF writer variant field type's tag field path.");
+               copy_ft->tag_field_path = bt_ctf_field_path_copy(
+                       var_ft->tag_field_path);
+               if (!copy_ft->tag_field_path) {
+                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field path.");
+                       goto error;
+               }
+       }
+
+       copy_ft->choices_up_to_date = var_ft->choices_up_to_date;
+       BT_LOGD("Copied CTF writer variant field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(tag_ft_copy);
+       return (void *) copy_ft;
+
+error:
+       bt_ctf_object_put_ref(tag_ft_copy);
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return NULL;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common *container_ft_copy = NULL;
+       struct bt_ctf_field_type_common_array *array_ft = (void *) ft;
+       struct bt_ctf_field_type_common_array *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer array field type's: addr=%p", ft);
+       BT_LOGD_STR("Copying CTF writer array field type's element field type.");
+       container_ft_copy = bt_ctf_field_type_common_copy(array_ft->element_ft);
+       if (!container_ft_copy) {
+               BT_LOGE_STR("Cannot copy CTF writer array field type's element field type.");
+               goto end;
+       }
+
+       copy_ft = (void *) bt_ctf_field_type_array_create(
+               (void *) container_ft_copy, array_ft->length);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer array field type.");
+               goto end;
+       }
+
+       BT_LOGD("Copied CTF writer array field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(container_ft_copy);
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common *container_ft_copy = NULL;
+       struct bt_ctf_field_type_common_sequence *seq_ft = (void *) ft;
+       struct bt_ctf_field_type_common_sequence *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer sequence field type's: addr=%p", ft);
+       BT_LOGD_STR("Copying CTF writer sequence field type's element field type.");
+       container_ft_copy = bt_ctf_field_type_common_copy(seq_ft->element_ft);
+       if (!container_ft_copy) {
+               BT_LOGE_STR("Cannot copy CTF writer sequence field type's element field type.");
+               goto end;
+       }
+
+       copy_ft = (void *) bt_ctf_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 CTF writer sequence field type.");
+               goto end;
+       }
+
+       if (seq_ft->length_field_path) {
+               BT_LOGD_STR("Copying CTF writer sequence field type's length field path.");
+               copy_ft->length_field_path = bt_ctf_field_path_copy(
+                       seq_ft->length_field_path);
+               if (!copy_ft->length_field_path) {
+                       BT_LOGE_STR("Cannot copy CTF writer sequence field type's length field path.");
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Copied CTF writer sequence field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(container_ft_copy);
+       return (void *) copy_ft;
+error:
+       bt_ctf_object_put_ref(container_ft_copy);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return NULL;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_string_copy(struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common_string *string_ft = (void *) ft;
+       struct bt_ctf_field_type_common_string *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer string field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_string_create();
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer string field type.");
+               goto end;
+       }
+
+       copy_ft->encoding = string_ft->encoding;
+       BT_LOGD("Copied CTF writer string field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+}
diff --git a/ctf-writer/field-wrapper.c b/ctf-writer/field-wrapper.c
new file mode 100644 (file)
index 0000000..a5a3b46
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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 "CTF-WRITER-FIELD-WRAPPER"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/object-pool-internal.h>
+#include <babeltrace2/ctf-writer/object-internal.h>
+#include <glib.h>
+
+BT_HIDDEN
+struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data)
+{
+       struct bt_ctf_field_wrapper *field_wrapper =
+               g_new0(struct bt_ctf_field_wrapper, 1);
+
+       BT_LOGD_STR("Creating empty field wrapper object.");
+
+       if (!field_wrapper) {
+               BT_LOGE("Failed to allocate one field wrapper.");
+               goto end;
+       }
+
+       bt_ctf_object_init_unique(&field_wrapper->base);
+       BT_LOGD("Created empty field wrapper object: addr=%p",
+               field_wrapper);
+
+end:
+       return field_wrapper;
+}
+
+BT_HIDDEN
+void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field_wrapper)
+{
+       BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper);
+       BT_ASSERT(!field_wrapper->field);
+       BT_LOGD_STR("Putting stream class.");
+       g_free(field_wrapper);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create(
+               struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_wrapper *field_wrapper = NULL;
+
+       BT_ASSERT(pool);
+       BT_ASSERT(ft);
+       field_wrapper = bt_ctf_object_pool_create_object(pool);
+       if (!field_wrapper) {
+               BT_LOGE("Cannot allocate one field wrapper");
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_ctf_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
diff --git a/ctf-writer/fields.c b/ctf-writer/fields.c
new file mode 100644 (file)
index 0000000..327f62e
--- /dev/null
@@ -0,0 +1,1860 @@
+/*
+ * Copyright 2013, 2014 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.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-FIELDS"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/align-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compat/fcntl-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/endian-internal.h>
+#include <babeltrace2/ctf-writer/object-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctfser-internal.h>
+#include <float.h>
+#include <inttypes.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_IS_INT_OR_ENUM(_field, _name)              \
+       BT_CTF_ASSERT_PRE((_field)->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || \
+               (_field)->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,        \
+               _name " is not an integer or an enumeration field: "    \
+               "field-addr=%p", (_field))
+
+BT_HIDDEN
+struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common *copy = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT(field_type_common_has_known_id(field->type));
+       BT_ASSERT(field->methods->copy);
+       copy = field->methods->copy(field);
+       if (!copy) {
+               BT_LOGW("Cannot create field: ft-addr=%p", field->type);
+               goto end;
+       }
+
+       bt_ctf_field_common_set(copy, field->payload_set);
+
+end:
+       return copy;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *structure_type =
+               BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+       size_t i;
+
+       BT_LOGD("Initializing common structure field object: ft-addr=%p", type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       structure->fields = g_ptr_array_new_with_free_func(field_release_func);
+       g_ptr_array_set_size(structure->fields, structure_type->fields->len);
+
+       /* Create all fields contained in the structure field. */
+       for (i = 0; i < structure_type->fields->len; i++) {
+               struct bt_ctf_field_common *field;
+               struct bt_ctf_field_type_common_structure_field *struct_field =
+                       BT_CTF_FIELD_TYPE_COMMON_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;
+               }
+
+               g_ptr_array_index(structure->fields, i) = field;
+       }
+
+       BT_LOGD("Initialized common structure field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *variant_type =
+               BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+       size_t i;
+
+       BT_LOGD("Initializing common variant field object: ft-addr=%p", type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       ret = bt_ctf_field_type_common_variant_update_choices(type);
+       if (ret) {
+               BT_LOGE("Cannot update common 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_ctf_field_common *field;
+               struct bt_ctf_field_type_common_variant_choice *var_choice =
+                       BT_CTF_FIELD_TYPE_COMMON_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 common variant field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods)
+{
+       int ret = 0;
+       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Initializing common string field object: ft-addr=%p", type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, 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 common string field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_destroy_func)
+{
+       struct bt_ctf_field_type_common_array *array_type = BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+       unsigned int array_length;
+       int ret = 0;
+       uint64_t i;
+
+       BT_LOGD("Initializing common array field object: ft-addr=%p", type);
+       BT_ASSERT(type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       array_length = array_type->length;
+       array->elements = g_ptr_array_sized_new(array_length);
+       if (!array->elements) {
+               ret = -1;
+               goto end;
+       }
+
+       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 common array field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               GDestroyNotify field_destroy_func)
+{
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+       int ret = 0;
+
+       BT_LOGD("Initializing common sequence field object: ft-addr=%p", type);
+       BT_ASSERT(type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       sequence->elements = g_ptr_array_new();
+       if (!sequence->elements) {
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_set_free_func(sequence->elements, field_destroy_func);
+       BT_LOGD("Initialized common sequence field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field)
+{
+       return (field && field->payload_set) ? 0 : -1;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < structure->fields->len; i++) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) structure->fields->pdata[i]);
+
+               if (ret) {
+                       int this_ret;
+                       const char *name;
+
+                       this_ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               field->type, &name, NULL, i);
+                       BT_ASSERT(this_ret == 0);
+                       BT_CTF_ASSERT_PRE_MSG("Invalid structure field's field: "
+                               "struct-field-addr=%p, field-name=\"%s\", "
+                               "index=%" PRId64 ", field-addr=%p",
+                               field, name, i, structure->fields->pdata[i]);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int ret = 0;
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       if (!variant->current_field) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_common_validate_recursive(variant->current_field);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array->elements->len; i++) {
+               ret = bt_ctf_field_common_validate_recursive((void *) array->elements->pdata[i]);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid array field's element field: "
+                               "array-field-addr=%p, %" PRId64 ", "
+                               "elem-field-addr=%p",
+                               field, i, array->elements->pdata[i]);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) sequence->elements->pdata[i]);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid sequence field's element field: "
+                               "seq-field-addr=%p, %" PRId64 ", "
+                               "elem-field-addr=%p",
+                               field, i, sequence->elements->pdata[i]);
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field)
+{
+       BT_ASSERT(field);
+       field->payload_set = false;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < structure->fields->len; i++) {
+               struct bt_ctf_field_common *member = structure->fields->pdata[i];
+
+               if (!member) {
+                       /*
+                        * Structure members are lazily initialized;
+                        * skip if this member has not been allocated
+                        * yet.
+                        */
+                       continue;
+               }
+
+               bt_ctf_field_common_reset_recursive(member);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       variant->current_field = NULL;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field)
+{
+       size_t i;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array->elements->len; i++) {
+               struct bt_ctf_field_common *member = array->elements->pdata[i];
+
+               if (!member) {
+                       /*
+                        * Array elements are lazily initialized; skip
+                        * if this member has not been allocated yet.
+                        */
+                       continue;
+               }
+
+               bt_ctf_field_common_reset_recursive(member);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+       uint64_t i;
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               if (sequence->elements->pdata[i]) {
+                       bt_ctf_field_common_reset_recursive(
+                               sequence->elements->pdata[i]);
+               }
+       }
+
+       sequence->length = 0;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field,
+               bool is_frozen)
+{
+       field->frozen = is_frozen;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_structure_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       uint64_t i;
+       struct bt_ctf_field_common_structure *structure_field =
+               BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing structure field object: addr=%p", field);
+
+       for (i = 0; i < structure_field->fields->len; i++) {
+               struct bt_ctf_field_common *struct_field =
+                       g_ptr_array_index(structure_field->fields, i);
+
+               BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64,
+                       struct_field, i);
+               bt_ctf_field_common_set_is_frozen_recursive(struct_field,
+                       is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_variant_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       uint64_t i;
+       struct bt_ctf_field_common_variant *variant_field = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing variant field object: addr=%p", field);
+
+       for (i = 0; i < variant_field->fields->len; i++) {
+               struct bt_ctf_field_common *var_field =
+                       g_ptr_array_index(variant_field->fields, i);
+
+               BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64,
+                       var_field, i);
+               bt_ctf_field_common_set_is_frozen_recursive(var_field, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_array_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       int64_t i;
+       struct bt_ctf_field_common_array *array_field = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing array field object: addr=%p", field);
+
+       for (i = 0; i < array_field->elements->len; i++) {
+               struct bt_ctf_field_common *elem_field =
+                       g_ptr_array_index(array_field->elements, i);
+
+               BT_LOGD("Freezing array field object's element field: "
+                       "element-field-addr=%p, index=%" PRId64,
+                       elem_field, i);
+               bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_sequence_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       int64_t i;
+       struct bt_ctf_field_common_sequence *sequence_field =
+               BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing sequence field object: addr=%p", field);
+
+       for (i = 0; i < sequence_field->length; i++) {
+               struct bt_ctf_field_common *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_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field,
+               bool is_frozen)
+{
+       if (!field) {
+               goto end;
+       }
+
+       BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d",
+               field, is_frozen);
+       BT_ASSERT(field_type_common_has_known_id(field->type));
+       BT_ASSERT(field->methods->set_is_frozen);
+       field->methods->set_is_frozen(field, is_frozen);
+
+end:
+       return;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field)
+{
+       return field && field->payload_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_structure_is_set_recursive(
+               struct bt_ctf_field_common *field)
+{
+       bt_bool is_set = BT_FALSE;
+       size_t i;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < structure->fields->len; i++) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       structure->fields->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+       bt_bool is_set = BT_FALSE;
+
+       BT_ASSERT(field);
+
+       if (variant->current_field) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       variant->current_field);
+       }
+
+       return is_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       size_t i;
+       bt_bool is_set = BT_FALSE;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array->elements->len; i++) {
+               is_set = bt_ctf_field_common_is_set_recursive(array->elements->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       size_t i;
+       bt_bool is_set = BT_FALSE;
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       if (!sequence->elements) {
+               goto end;
+       }
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       sequence->elements->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
+
+static struct bt_ctf_field_common_methods bt_ctf_field_integer_methods = {
+       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
+       .validate = bt_ctf_field_common_generic_validate,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_generic_is_set,
+       .reset = bt_ctf_field_common_generic_reset,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_floating_point_methods = {
+       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
+       .validate = bt_ctf_field_common_generic_validate,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_generic_is_set,
+       .reset = bt_ctf_field_common_generic_reset,
+};
+
+static
+void bt_ctf_field_enumeration_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen);
+
+static
+int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field);
+
+static
+bt_bool bt_ctf_field_enumeration_is_set_recursive(
+               struct bt_ctf_field_common *field);
+
+static
+void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field);
+
+static struct bt_ctf_field_common_methods bt_ctf_field_enumeration_methods = {
+       .set_is_frozen = bt_ctf_field_enumeration_set_is_frozen_recursive,
+       .validate = bt_ctf_field_enumeration_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_enumeration_is_set_recursive,
+       .reset = bt_ctf_field_enumeration_reset_recursive,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_string_methods = {
+       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
+       .validate = bt_ctf_field_common_generic_validate,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_generic_is_set,
+       .reset = bt_ctf_field_common_generic_reset,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_structure_methods = {
+       .set_is_frozen = bt_ctf_field_common_structure_set_is_frozen_recursive,
+       .validate = bt_ctf_field_common_structure_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_structure_is_set_recursive,
+       .reset = bt_ctf_field_common_structure_reset_recursive,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_sequence_methods = {
+       .set_is_frozen = bt_ctf_field_common_sequence_set_is_frozen_recursive,
+       .validate = bt_ctf_field_common_sequence_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_sequence_is_set_recursive,
+       .reset = bt_ctf_field_common_sequence_reset_recursive,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_array_methods = {
+       .set_is_frozen = bt_ctf_field_common_array_set_is_frozen_recursive,
+       .validate = bt_ctf_field_common_array_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_array_is_set_recursive,
+       .reset = bt_ctf_field_common_array_reset_recursive,
+};
+
+static
+void bt_ctf_field_variant_set_is_frozen_recursive(struct bt_ctf_field_common *field,
+               bool is_frozen);
+
+static
+int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field);
+
+static
+bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field);
+
+static
+void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field);
+
+static struct bt_ctf_field_common_methods bt_ctf_field_variant_methods = {
+       .set_is_frozen = bt_ctf_field_variant_set_is_frozen_recursive,
+       .validate = bt_ctf_field_variant_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_variant_is_set_recursive,
+       .reset = bt_ctf_field_variant_reset_recursive,
+};
+
+static
+struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_enumeration_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_floating_point_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_structure_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *(* const field_create_funcs[])(struct bt_ctf_field_type *) = {
+       [BT_CTF_FIELD_TYPE_ID_INTEGER] =        bt_ctf_field_integer_create,
+       [BT_CTF_FIELD_TYPE_ID_ENUM] =           bt_ctf_field_enumeration_create,
+       [BT_CTF_FIELD_TYPE_ID_FLOAT] =          bt_ctf_field_floating_point_create,
+       [BT_CTF_FIELD_TYPE_ID_STRUCT] =         bt_ctf_field_structure_create,
+       [BT_CTF_FIELD_TYPE_ID_VARIANT] =        bt_ctf_field_variant_create,
+       [BT_CTF_FIELD_TYPE_ID_ARRAY] =          bt_ctf_field_array_create,
+       [BT_CTF_FIELD_TYPE_ID_SEQUENCE] =       bt_ctf_field_sequence_create,
+       [BT_CTF_FIELD_TYPE_ID_STRING] =         bt_ctf_field_string_create,
+};
+
+typedef int (*bt_ctf_field_serialize_recursive_func)(
+               struct bt_ctf_field_common *, struct bt_ctfser *,
+               enum bt_ctf_byte_order);
+
+static
+void bt_ctf_field_integer_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer integer field object: addr=%p", field);
+       bt_ctf_field_common_integer_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer floating point field object: addr=%p",
+               field);
+       bt_ctf_field_common_floating_point_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_enumeration_destroy_recursive(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Destroying CTF writer enumeration field object: addr=%p",
+               field);
+       BT_LOGD_STR("Putting container field.");
+       bt_ctf_object_put_ref(enumeration->container);
+       bt_ctf_field_common_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_structure_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer structure field object: addr=%p", field);
+       bt_ctf_field_common_structure_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_variant_destroy_recursive(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Destroying CTF writer variant field object: addr=%p", field);
+       BT_LOGD_STR("Putting tag field.");
+       bt_ctf_object_put_ref(variant->tag);
+       bt_ctf_field_common_variant_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_array_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer array field object: addr=%p", field);
+       bt_ctf_field_common_array_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_sequence_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer sequence field object: addr=%p", field);
+       bt_ctf_field_common_sequence_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_string_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer string field object: addr=%p", field);
+       bt_ctf_field_common_string_finalize((void *) field);
+       g_free(field);
+}
+
+BT_HIDDEN
+int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       struct bt_ctf_field_common *field_common = (void *) field;
+       bt_ctf_field_serialize_recursive_func serialize_func;
+
+       BT_ASSERT(ctfser);
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT(field_common->spec.writer.serialize_func);
+       serialize_func = field_common->spec.writer.serialize_func;
+       return serialize_func(field_common, ctfser,
+               native_byte_order);
+}
+
+static
+int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret;
+       struct bt_ctf_field_type_common_integer *int_type =
+               BT_CTF_FROM_COMMON(field->type);
+       struct bt_ctf_field_common_integer *int_field =
+               BT_CTF_FROM_COMMON(field);
+       enum bt_ctf_byte_order byte_order;
+
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field");
+       BT_LOGV("Serializing CTF writer integer field: addr=%p, native-bo=%s",
+               field,
+               bt_ctf_byte_order_string(native_byte_order));
+       byte_order = int_type->user_byte_order;
+       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+               byte_order = native_byte_order;
+       }
+
+       if (int_type->is_signed) {
+               ret = bt_ctfser_write_signed_int(ctfser,
+                       int_field->payload.signd, int_type->common.alignment,
+                       int_type->size,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       } else {
+               ret = bt_ctfser_write_unsigned_int(ctfser,
+                       int_field->payload.unsignd, int_type->common.alignment,
+                       int_type->size,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       }
+
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot serialize integer field: ret=%d", ret);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_enumeration_serialize_recursive(
+               struct bt_ctf_field_common *field, struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       BT_LOGV("Serializing enumeration field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+       BT_LOGV_STR("Serializing enumeration field's payload field.");
+       return bt_ctf_field_serialize_recursive(
+               (void *) enumeration->container, ctfser, native_byte_order);
+}
+
+static
+int bt_ctf_field_floating_point_serialize(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret = -1;
+       struct bt_ctf_field_type_common_floating_point *flt_type =
+               BT_CTF_FROM_COMMON(field->type);
+       struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field);
+       enum bt_ctf_byte_order byte_order;
+
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
+       BT_LOGV("Serializing floating point number field: "
+               "addr=%p, native-bo=%s", field,
+               bt_ctf_byte_order_string(native_byte_order));
+
+       byte_order = flt_type->user_byte_order;
+       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+               byte_order = native_byte_order;
+       }
+
+       if (flt_type->mant_dig == FLT_MANT_DIG) {
+               ret = bt_ctfser_write_float32(ctfser, flt_field->payload,
+                       flt_type->common.alignment,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       } else if (flt_type->mant_dig == DBL_MANT_DIG) {
+               ret = bt_ctfser_write_float64(ctfser, flt_field->payload,
+                       flt_type->common.alignment,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       } else {
+               abort();
+       }
+
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot serialize floating point number field: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_structure_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int64_t i;
+       int ret;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing structure field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+       ret = bt_ctfser_align_offset_in_current_packet(ctfser,
+               field->type->alignment);
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot align offset before serializing structure field: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       for (i = 0; i < structure->fields->len; i++) {
+               struct bt_ctf_field_common *member = g_ptr_array_index(
+                       structure->fields, i);
+               const char *field_name = NULL;
+
+               BT_LOGV("Serializing structure field's field: ser-offset=%" PRIu64 ", "
+                       "field-addr=%p, index=%" PRIu64,
+                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+                       member, i);
+
+               if (unlikely(!member)) {
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               field->type, &field_name, NULL, i);
+                       BT_ASSERT(ret == 0);
+                       BT_LOGW("Cannot serialize structure field's field: field is not set: "
+                               "struct-field-addr=%p, "
+                               "field-name=\"%s\", index=%" PRId64,
+                               field, field_name, i);
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = bt_ctf_field_serialize_recursive((void *) member, ctfser,
+                       native_byte_order);
+               if (unlikely(ret)) {
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               field->type, &field_name, NULL, i);
+                       BT_ASSERT(ret == 0);
+                       BT_LOGW("Cannot serialize structure field's field: "
+                               "struct-field-addr=%p, field-addr=%p, "
+                               "field-name=\"%s\", index=%" PRId64,
+                               field->type, member, field_name, i);
+                       break;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_variant_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing variant field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+       BT_LOGV_STR("Serializing variant field's payload field.");
+       return bt_ctf_field_serialize_recursive(
+               (void *) variant->current_field, ctfser, native_byte_order);
+}
+
+static
+int bt_ctf_field_array_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing array field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+
+       for (i = 0; i < array->elements->len; i++) {
+               struct bt_ctf_field_common *elem_field =
+                       g_ptr_array_index(array->elements, i);
+
+               BT_LOGV("Serializing array field's element field: "
+                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
+                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+                       elem_field, i);
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) elem_field, ctfser, native_byte_order);
+               if (unlikely(ret)) {
+                       BT_LOGW("Cannot serialize array field's element field: "
+                               "array-field-addr=%p, field-addr=%p, "
+                               "index=%" PRId64, field, elem_field, i);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_sequence_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing sequence field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               struct bt_ctf_field_common *elem_field =
+                       g_ptr_array_index(sequence->elements, i);
+
+               BT_LOGV("Serializing sequence field's element field: "
+                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
+                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+                       elem_field, i);
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) elem_field, ctfser, native_byte_order);
+               if (unlikely(ret)) {
+                       BT_LOGW("Cannot serialize sequence field's element field: "
+                               "sequence-field-addr=%p, field-addr=%p, "
+                               "index=%" PRId64, field, elem_field, i);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_string_serialize(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret;
+       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
+       BT_LOGV("Serializing string field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string((int) native_byte_order));
+       ret = bt_ctfser_write_string(ctfser, (const char *) string->buf->data);
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot serialize string field: ret=%d", ret);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field *field = NULL;
+       enum bt_ctf_field_type_id type_id;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(type, "Field type");
+       BT_ASSERT(field_type_common_has_known_id((void *) type));
+       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_validate((void *) type) == 0,
+               "Field type is invalid: ft-addr=%p", type);
+       type_id = bt_ctf_field_type_get_type_id(type);
+       field = field_create_funcs[type_id](type);
+       if (!field) {
+               goto end;
+       }
+
+       bt_ctf_field_type_common_freeze((void *) type);
+
+end:
+       return field;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_borrow_type((void *) field));
+}
+
+enum bt_ctf_field_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_common *field_common = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
+       return (int) field_common->type->id;
+}
+
+int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field,
+               struct bt_ctf_field *length_field)
+{
+       int ret;
+       struct bt_ctf_field_common *common_length_field = (void *) length_field;
+       uint64_t length;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(length_field, "Length field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) length_field, "Length field");
+       BT_CTF_ASSERT_PRE(common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER ||
+                       common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,
+               "Length field must be an integer or enumeration field: field-addr=%p",
+               length_field);
+
+       if (common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
+               struct bt_ctf_field_enumeration *enumeration = (void *)
+                       length_field;
+
+               length_field = (void *) enumeration->container;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_get_value(length_field, &length);
+       BT_ASSERT(ret == 0);
+       return bt_ctf_field_common_sequence_set_length((void *) field,
+               length, (bt_ctf_field_common_create_func) bt_ctf_field_create);
+}
+
+struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
+               struct bt_ctf_field *field, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_index(
+               (void *) field, index));
+}
+
+struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name(
+               struct bt_ctf_field *field, const char *name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_name(
+               (void *) field, name));
+}
+
+struct bt_ctf_field *bt_ctf_field_array_get_field(
+               struct bt_ctf_field *field, uint64_t index)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_field_common_array_borrow_field((void *) field, index));
+}
+
+struct bt_ctf_field *bt_ctf_field_sequence_get_field(
+               struct bt_ctf_field *field, uint64_t index)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_field_common_sequence_borrow_field((void *) field, index));
+}
+
+struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field,
+               struct bt_ctf_field *tag_field)
+{
+       struct bt_ctf_field_variant *variant_field = (void *) field;
+       struct bt_ctf_field_enumeration *enum_field = (void *) tag_field;
+       struct bt_ctf_field_type_common_variant *variant_ft;
+       struct bt_ctf_field_type_common_enumeration *tag_ft;
+       struct bt_ctf_field *current_field = NULL;
+       bt_bool is_signed;
+       uint64_t tag_uval;
+       int ret;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Variant field");
+       BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) tag_field, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_ctf_field_common *) tag_field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_ctf_field_common *) field,
+               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_CTF_ASSERT_PRE(
+               bt_ctf_field_common_validate_recursive((void *) tag_field) == 0,
+               "Tag field is invalid: field-addr=%p", tag_field);
+       variant_ft = BT_CTF_FROM_COMMON(variant_field->common.common.type);
+       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+               BT_CTF_TO_COMMON(variant_ft->tag_ft), enum_field->common.type) == 0,
+               "Unexpected tag field's type: expected-ft-addr=%p, "
+               "tag-ft-addr=%p", variant_ft->tag_ft,
+               enum_field->common.type);
+       tag_ft = BT_CTF_FROM_COMMON(enum_field->common.type);
+       is_signed = tag_ft->container_ft->is_signed;
+
+       if (is_signed) {
+               int64_t tag_ival;
+
+               ret = bt_ctf_field_integer_signed_get_value(
+                       (void *) enum_field->container, &tag_ival);
+               tag_uval = (uint64_t) tag_ival;
+       } else {
+               ret = bt_ctf_field_integer_unsigned_get_value(
+                       (void *) enum_field->container, &tag_uval);
+       }
+
+       BT_ASSERT(ret == 0);
+       ret = bt_ctf_field_common_variant_set_tag((void *) field, tag_uval,
+               is_signed);
+       if (ret) {
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(variant_field->tag);
+       variant_field->tag = bt_ctf_object_get_ref(tag_field);
+       current_field = bt_ctf_field_variant_get_current_field(field);
+       BT_ASSERT(current_field);
+
+end:
+       return current_field;
+}
+
+struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
+               struct bt_ctf_field *variant_field)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_variant_borrow_current_field(
+               (void *) variant_field));
+}
+
+BT_HIDDEN
+struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
+               struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Enumeration field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID((struct bt_ctf_field_common *) field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Field");
+       BT_ASSERT(enumeration->container);
+       return (void *) enumeration->container;
+}
+
+struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
+               struct bt_ctf_field *field)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_enumeration_borrow_container(field));
+}
+
+int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field,
+               int64_t *value)
+{
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_integer_is_signed(
+               integer->common.type),
+               "Field's type is unsigned: field-addr=%p", field);
+       *value = integer->payload.signd;
+       return 0;
+}
+
+int bt_ctf_field_integer_signed_set_value(struct bt_ctf_field *field,
+               int64_t value)
+{
+       int ret = 0;
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+       struct bt_ctf_field_type_common_integer *integer_type;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
+       BT_CTF_ASSERT_PRE(
+               bt_ctf_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is unsigned: field-addr=%p", field);
+       BT_CTF_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value),
+               "Value is out of bounds: value=%" PRId64 ", field-addr=%p",
+               value, field);
+       integer->payload.signd = value;
+       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
+       return ret;
+}
+
+int bt_ctf_field_integer_unsigned_get_value(struct bt_ctf_field *field,
+               uint64_t *value)
+{
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       BT_CTF_ASSERT_PRE(
+               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is signed: field-addr=%p", field);
+       *value = integer->payload.unsignd;
+       return 0;
+}
+
+int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field,
+               uint64_t value)
+{
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+       struct bt_ctf_field_type_common_integer *integer_type;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
+       BT_CTF_ASSERT_PRE(
+               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is signed: field-addr=%p", field);
+       BT_CTF_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value),
+               "Value is out of bounds: value=%" PRIu64 ", field-addr=%p",
+               value, field);
+       integer->payload.unsignd = value;
+       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
+       return 0;
+}
+
+int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field,
+               double *value)
+{
+       return bt_ctf_field_common_floating_point_get_value((void *) field, value);
+}
+
+int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field,
+               double value)
+{
+       return bt_ctf_field_common_floating_point_set_value((void *) field, value);
+}
+
+const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field)
+{
+       return bt_ctf_field_common_string_get_value((void *) field);
+}
+
+int bt_ctf_field_string_set_value(struct bt_ctf_field *field, const char *value)
+{
+       return bt_ctf_field_common_string_set_value((void *) field, value);
+}
+
+int bt_ctf_field_string_append(struct bt_ctf_field *field, const char *value)
+{
+       return bt_ctf_field_common_string_append((void *) field, value);
+}
+
+int bt_ctf_field_string_append_len(struct bt_ctf_field *field,
+               const char *value, unsigned int length)
+{
+       return bt_ctf_field_common_string_append_len((void *) field, value, length);
+}
+
+struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field)
+{
+       return (void *) bt_ctf_field_common_copy((void *) field);
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_integer *integer =
+               g_new0(struct bt_ctf_field_common_integer, 1);
+
+       BT_LOGD("Creating CTF writer integer field object: ft-addr=%p", type);
+
+       if (integer) {
+               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(integer), (void *) type,
+                       true,
+                       (bt_ctf_object_release_func) bt_ctf_field_integer_destroy,
+                       &bt_ctf_field_integer_methods);
+               integer->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_integer_serialize;
+               BT_LOGD("Created CTF writer 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_ctf_field *bt_ctf_field_enumeration_create(
+               struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) type;
+       struct bt_ctf_field_enumeration *enumeration = g_new0(
+               struct bt_ctf_field_enumeration, 1);
+
+       BT_LOGD("Creating CTF writer enumeration field object: ft-addr=%p", type);
+
+       if (!enumeration) {
+               BT_LOGE_STR("Failed to allocate one enumeration field.");
+               goto end;
+       }
+
+       bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(enumeration),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_enumeration_destroy_recursive,
+               &bt_ctf_field_enumeration_methods);
+       enumeration->container = (void *) bt_ctf_field_create(
+               BT_CTF_FROM_COMMON(enum_ft->container_ft));
+       if (!enumeration->container) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
+               goto end;
+       }
+
+       enumeration->common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func)
+                       bt_ctf_field_enumeration_serialize_recursive;
+       BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p",
+               enumeration, type);
+
+end:
+       return (void *) enumeration;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_floating_point_create(
+               struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_floating_point *floating_point;
+
+       BT_LOGD("Creating CTF writer floating point number field object: ft-addr=%p", type);
+       floating_point = g_new0(struct bt_ctf_field_common_floating_point, 1);
+
+       if (floating_point) {
+               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(floating_point),
+                       (void *) type,
+                       true, (bt_ctf_object_release_func)
+                               bt_ctf_field_floating_point_destroy,
+                       &bt_ctf_field_floating_point_methods);
+               floating_point->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_floating_point_serialize;
+               BT_LOGD("Created CTF writer 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
+struct bt_ctf_field *bt_ctf_field_structure_create(
+               struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_structure *structure = g_new0(
+               struct bt_ctf_field_common_structure, 1);
+       int iret;
+
+       BT_LOGD("Creating CTF writer structure field object: ft-addr=%p", type);
+
+       if (!structure) {
+               BT_LOGE_STR("Failed to allocate one structure field.");
+               goto end;
+       }
+
+       iret = bt_ctf_field_common_structure_initialize(BT_CTF_TO_COMMON(structure),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_structure_destroy_recursive,
+               &bt_ctf_field_structure_methods,
+               (bt_ctf_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       structure->common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_structure_serialize_recursive;
+       if (iret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
+               goto end;
+       }
+
+       BT_LOGD("Created CTF writer structure field object: addr=%p, ft-addr=%p",
+               structure, type);
+
+end:
+       return (void *) structure;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = (void *) type;
+       struct bt_ctf_field_variant *variant = g_new0(
+               struct bt_ctf_field_variant, 1);
+
+       BT_LOGD("Creating CTF writer variant field object: ft-addr=%p", type);
+
+       if (!variant) {
+               BT_LOGE_STR("Failed to allocate one variant field.");
+               goto end;
+       }
+
+       bt_ctf_field_common_variant_initialize(BT_CTF_TO_COMMON(BT_CTF_TO_COMMON(variant)),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_variant_destroy_recursive,
+               &bt_ctf_field_variant_methods,
+               (bt_ctf_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       variant->tag = (void *) bt_ctf_field_create(
+               BT_CTF_FROM_COMMON(var_ft->tag_ft));
+       variant->common.common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive;
+       BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p",
+               variant, type);
+
+end:
+       return (void *) variant;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_array *array =
+               g_new0(struct bt_ctf_field_common_array, 1);
+       int ret;
+
+       BT_LOGD("Creating CTF writer 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_ctf_field_common_array_initialize(BT_CTF_TO_COMMON(array),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_array_destroy_recursive,
+               &bt_ctf_field_array_methods,
+               (bt_ctf_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       array->common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_array_serialize_recursive;
+       if (ret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
+               goto end;
+       }
+
+       BT_LOGD("Created CTF writer array field object: addr=%p, ft-addr=%p",
+               array, type);
+
+end:
+       return (void *) array;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_sequence *sequence = g_new0(
+               struct bt_ctf_field_common_sequence, 1);
+
+       BT_LOGD("Creating CTF writer sequence field object: ft-addr=%p", type);
+
+       if (sequence) {
+               bt_ctf_field_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
+                       (void *) type,
+                       true, (bt_ctf_object_release_func)
+                               bt_ctf_field_sequence_destroy_recursive,
+                       &bt_ctf_field_sequence_methods,
+                       (GDestroyNotify) bt_ctf_object_put_ref);
+               sequence->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_sequence_serialize_recursive;
+               BT_LOGD("Created CTF writer sequence field object: addr=%p, ft-addr=%p",
+                       sequence, type);
+       } else {
+               BT_LOGE_STR("Failed to allocate one sequence field.");
+       }
+
+       return (void *) sequence;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_string *string = g_new0(
+               struct bt_ctf_field_common_string, 1);
+
+       BT_LOGD("Creating CTF writer string field object: ft-addr=%p", type);
+
+       if (string) {
+               bt_ctf_field_common_string_initialize(BT_CTF_TO_COMMON(string),
+                       (void *) type,
+                       true, (bt_ctf_object_release_func)
+                               bt_ctf_field_string_destroy,
+                       &bt_ctf_field_string_methods);
+               string->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_string_serialize;
+               BT_LOGD("Created CTF writer string field object: addr=%p, ft-addr=%p",
+                       string, type);
+       } else {
+               BT_LOGE_STR("Failed to allocate one string field.");
+       }
+
+       return (void *) string;
+}
+
+static
+void bt_ctf_field_enumeration_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       (void *) enumeration->container, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen((void *) field, is_frozen);
+}
+
+static
+int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int ret = -1;
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) enumeration->container);
+       }
+
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_enumeration_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       bt_bool is_set = BT_FALSE;
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       (void *) enumeration->container);
+       }
+
+       return is_set;
+}
+
+static
+void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               bt_ctf_field_common_reset_recursive(
+                       (void *) enumeration->container);
+       }
+
+       bt_ctf_field_common_generic_reset((void *) field);
+}
+
+static
+void bt_ctf_field_variant_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       (void *) variant->tag, is_frozen);
+       }
+
+       bt_ctf_field_common_variant_set_is_frozen_recursive((void *) field,
+               is_frozen);
+}
+
+static
+int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int ret;
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) variant->tag);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = bt_ctf_field_common_variant_validate_recursive((void *) field);
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       bt_bool is_set;
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       (void *) variant->tag);
+               if (is_set) {
+                       goto end;
+               }
+       }
+
+       is_set = bt_ctf_field_common_variant_is_set_recursive((void *) field);
+
+end:
+       return is_set;
+}
+
+static
+void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               bt_ctf_field_common_reset_recursive(
+                       (void *) variant->tag);
+       }
+
+       bt_ctf_field_common_variant_reset_recursive((void *) field);
+}
+
+BT_CTF_ASSERT_PRE_FUNC
+static inline bool field_to_set_has_expected_type(
+               struct bt_ctf_field_common *struct_field,
+               const char *name, struct bt_ctf_field_common *value)
+{
+       bool ret = true;
+       struct bt_ctf_field_type_common *expected_field_type = NULL;
+
+       expected_field_type =
+               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+                       struct_field->type, name);
+
+       if (bt_ctf_field_type_common_compare(expected_field_type, value->type)) {
+               BT_CTF_ASSERT_PRE_MSG("Value field's type is different from the expected field type: "
+                       "value-ft-addr=%p, expected-ft-addr=%p", value->type,
+                       expected_field_type);
+               ret = false;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
+               const char *name, struct bt_ctf_field *value)
+{
+       int ret = 0;
+       GQuark field_quark;
+       struct bt_ctf_field_common *common_field = (void *) field;
+       struct bt_ctf_field_common_structure *structure =
+               BT_CTF_FROM_COMMON(common_field);
+       struct bt_ctf_field_common *common_value = (void *) value;
+       size_t index;
+       GHashTable *field_name_to_index;
+       struct bt_ctf_field_type_common_structure *structure_ft;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Parent field");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(common_field,
+               BT_CTF_FIELD_TYPE_ID_STRUCT, "Parent field");
+       BT_CTF_ASSERT_PRE(field_to_set_has_expected_type(common_field,
+               name, common_value),
+               "Value field's type is different from the expected field type.");
+       field_quark = g_quark_from_string(name);
+       structure_ft = BT_CTF_FROM_COMMON(common_field->type);
+       field_name_to_index = structure_ft->field_name_to_index;
+       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, "
+                       "field-ft-addr=%p, name=\"%s\"",
+                       field, common_field->type, common_value->type, name);
+               ret = -1;
+               goto end;
+       }
+       bt_ctf_object_get_ref(value);
+       BT_CTF_OBJECT_MOVE_REF(structure->fields->pdata[index], value);
+
+end:
+       return ret;
+}
diff --git a/ctf-writer/functor.c b/ctf-writer/functor.c
new file mode 100644 (file)
index 0000000..e8ad20f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * functor.c
+ *
+ * Babeltrace CTF Writer
+ *
+ * Copyright 2013, 2014 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 <glib.h>
+#include <babeltrace2/ctf-writer/functor-internal.h>
+#include <babeltrace2/ctf-writer/utils-internal.h>
+
+BT_HIDDEN
+void value_exists(gpointer element, gpointer search_query)
+{
+       if (element == ((struct bt_ctf_search_query *)search_query)->value) {
+               ((struct bt_ctf_search_query *)search_query)->found = 1;
+       }
+}
diff --git a/ctf-writer/logging.c b/ctf-writer/logging.c
new file mode 100644 (file)
index 0000000..641d5d9
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 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_OUTPUT_LEVEL bt_lib_ctf_writer_log_level
+#include "logging.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_lib_ctf_writer_log_level,
+       "BABELTRACE_CTF_WRITER_LOG_LEVEL");
diff --git a/ctf-writer/logging.h b/ctf-writer/logging.h
new file mode 100644 (file)
index 0000000..a6cf543
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef BABELTRACE_CTF_WRITER_LOGGING_H
+#define BABELTRACE_CTF_WRITER_LOGGING_H
+
+/*
+ * Copyright (c) 2017 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_OUTPUT_LEVEL bt_lib_ctf_writer_log_level
+#include <babeltrace2/logging-internal.h>
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_lib_ctf_writer_log_level);
+
+#endif /* BABELTRACE_CTF_WRITER_LOGGING_H */
diff --git a/ctf-writer/object-pool.c b/ctf-writer/object-pool.c
new file mode 100644 (file)
index 0000000..2d932ac
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * 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.
+ */
+
+#define BT_LOG_TAG "OBJECT-POOL"
+#include "logging.h"
+
+#include <stdint.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/ctf-writer/object-pool-internal.h>
+
+int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool,
+               bt_ctf_object_pool_new_object_func new_object_func,
+               bt_ctf_object_pool_destroy_object_func destroy_object_func,
+               void *data)
+{
+       int ret = 0;
+
+       BT_ASSERT(new_object_func);
+       BT_ASSERT(destroy_object_func);
+       BT_LOGD("Initializing object pool: addr=%p, data-addr=%p",
+               pool, data);
+       pool->objects = g_ptr_array_new();
+       if (!pool->objects) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       pool->funcs.new_object = new_object_func;
+       pool->funcs.destroy_object = destroy_object_func;
+       pool->data = data;
+       pool->size = 0;
+       BT_LOGD("Initialized object pool.");
+       goto end;
+
+error:
+       if (pool) {
+               bt_ctf_object_pool_finalize(pool);
+       }
+
+       ret = -1;
+
+end:
+       return ret;
+}
+
+void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool)
+{
+       uint64_t i;
+
+       BT_ASSERT(pool);
+       BT_LOGD("Finalizing object pool.");
+
+       if (pool->objects) {
+               for (i = 0; i < pool->size; i++) {
+                       void *obj = pool->objects->pdata[i];
+
+                       if (obj) {
+                               pool->funcs.destroy_object(obj, pool->data);
+                       }
+               }
+
+               g_ptr_array_free(pool->objects, TRUE);
+               pool->objects = NULL;
+       }
+}
diff --git a/ctf-writer/object.c b/ctf-writer/object.c
new file mode 100644 (file)
index 0000000..b618512
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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 <babeltrace2/ctf-writer/object-internal.h>
+
+void *bt_ctf_object_get_ref(void *obj)
+{
+       if (unlikely(!obj)) {
+               goto end;
+       }
+
+       bt_ctf_object_get_no_null_check(obj);
+
+end:
+       return obj;
+}
+
+void bt_ctf_object_put_ref(void *obj)
+{
+       if (unlikely(!obj)) {
+               return;
+       }
+
+       bt_ctf_object_put_no_null_check(obj);
+}
diff --git a/ctf-writer/resolve.c b/ctf-writer/resolve.c
new file mode 100644 (file)
index 0000000..b0a5e15
--- /dev/null
@@ -0,0 +1,1339 @@
+/*
+ * resolve.c
+ *
+ * Babeltrace - CTF writer: 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 "CTF-WRITER-RESOLVE"
+#include "logging.h"
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/babeltrace-internal.h>
+#include <babeltrace2/ctf-writer/field-path-internal.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/resolve-internal.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/utils-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.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_ctf_field_type_common *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_ctf_private_value *environment;
+       struct bt_ctf_field_type_common *scopes[6];
+
+       /* Root scope being visited */
+       enum bt_ctf_scope root_scope;
+       type_stack *type_stack;
+       struct bt_ctf_field_type_common *cur_field_type;
+};
+
+/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
+static const char * const absolute_path_prefixes[] = {
+       [BT_CTF_SCOPE_ENV]                              = "env.",
+       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]              = "trace.packet.header.",
+       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = "stream.packet.context.",
+       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]              = "stream.event.header.",
+       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]             = "stream.event.context.",
+       [BT_CTF_SCOPE_EVENT_CONTEXT]            = "event.context.",
+       [BT_CTF_SCOPE_EVENT_FIELDS]                     = "event.fields.",
+};
+
+/* Number of path tokens used for the absolute prefixes */
+static const int absolute_path_prefix_ptoken_counts[] = {
+       [BT_CTF_SCOPE_ENV]                      = 1,
+       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]      = 3,
+       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = 3,
+       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]      = 3,
+       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]     = 3,
+       [BT_CTF_SCOPE_EVENT_CONTEXT]            = 2,
+       [BT_CTF_SCOPE_EVENT_FIELDS]             = 2,
+};
+
+/*
+ * Destroys a type stack frame.
+ */
+static
+void type_stack_destroy_notify(gpointer data)
+{
+       struct type_stack_frame *frame = data;
+
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common *get_type_from_ctx(struct resolve_context *ctx,
+               enum bt_ctf_scope scope)
+{
+       BT_ASSERT(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER &&
+               scope <= BT_CTF_SCOPE_EVENT_FIELDS);
+
+       return ctx->scopes[scope - BT_CTF_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_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
+{
+       enum bt_ctf_scope scope;
+       enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN;
+       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
+               sizeof(*absolute_path_prefixes);
+
+       for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_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_ctf_scope_string(scope));
+                       continue;
+               }
+
+               /* Found it! */
+               ret = scope;
+               BT_LOGV("Found root scope from absolute path: "
+                       "path=\"%s\", scope=%s", pathstr,
+                       bt_ctf_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_ctf_field_path *field_path,
+               struct bt_ctf_field_type_common *type, int src_index)
+{
+       int ret = 0;
+       GList *cur_ptoken = ptokens;
+       bt_bool first_level_done = BT_FALSE;
+
+       /* Get our own reference */
+       bt_ctf_object_get_ref(type);
+
+       /* Locate target */
+       while (cur_ptoken) {
+               int child_index;
+               struct bt_ctf_field_type_common *child_type;
+               const char *field_name = ptoken_get_string(cur_ptoken);
+               enum bt_ctf_field_type_id type_id =
+                       bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_ARRAY ||
+                               type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
+                       child_index = -1;
+               } else {
+                       child_index = bt_ctf_field_type_common_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_ctf_field_type_common_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_ctf_object_get_ref(child_type);
+               BT_CTF_OBJECT_MOVE_REF(type, child_type);
+       }
+
+end:
+       bt_ctf_object_put_ref(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_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       GList *cur_ptoken;
+       struct bt_ctf_field_type_common *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_ctf_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_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       int parent_pos_in_stack;
+       struct bt_ctf_field_path *tail_field_path = bt_ctf_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_ctf_field_type_common *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_ctf_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_ctf_field_type_common *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_CTF_SCOPE_TRACE_PACKET_HEADER) {
+                       struct bt_ctf_field_type_common *root_type;
+                       bt_ctf_field_path_clear(field_path);
+
+                       BT_LOGV("Looking into potential root scope: scope=%s",
+                               bt_ctf_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_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_path *pathstr_to_field_path(const char *pathstr,
+               struct resolve_context *ctx)
+{
+       int ret;
+       enum bt_ctf_scope root_scope;
+       GList *ptokens = NULL;
+       struct bt_ctf_field_path *field_path = NULL;
+
+       /* Create field path */
+       field_path = bt_ctf_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_CTF_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_ctf_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_ctf_scope_string(ctx->root_scope),
+                               bt_ctf_scope_string(field_path->root));
+                       goto end;
+               }
+       } else if (root_scope == BT_CTF_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_ctf_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_ctf_scope_string(root_scope));
+                       goto end;
+               }
+       }
+
+       if (ret == 0) {
+               GString *field_path_pretty =
+                       bt_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:
+       if (ret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_type_common *field_path_to_field_type(
+               struct bt_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int i;
+       struct bt_ctf_field_type_common *type;
+
+       /* Start with root type */
+       type = get_type_from_ctx(ctx, field_path->root);
+       bt_ctf_object_get_ref(type);
+       if (!type) {
+               /* Error: root type is not available */
+               BT_LOGW("Root field type is not available: root-scope=%s",
+                       bt_ctf_scope_string(field_path->root));
+               goto error;
+       }
+
+       /* Locate target */
+       for (i = 0; i < field_path->indexes->len; i++) {
+               struct bt_ctf_field_type_common *child_type;
+               int child_index =
+                       g_array_index(field_path->indexes, int, i);
+
+               /* Get child field type */
+               child_type = bt_ctf_field_type_common_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_ctf_object_get_ref(child_type);
+               BT_CTF_OBJECT_MOVE_REF(type, child_type);
+       }
+
+       return type;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx)
+{
+       int i;
+       struct bt_ctf_field_path *field_path;
+
+       /* Create field path */
+       field_path = bt_ctf_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_CTF_OBJECT_PUT_REF_AND_RESET(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.
+ */
+static
+int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1,
+               struct bt_ctf_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_ctf_field_path_string(field_path1);
+               GString *field_path2_pretty =
+                       bt_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->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_ctf_field_path *target_field_path,
+               struct bt_ctf_field_type_common *target_type,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       struct bt_ctf_field_path *ctx_field_path;
+       int target_field_path_len = target_field_path->indexes->len;
+       int lca_index;
+       enum bt_ctf_field_type_id ctx_cur_field_type_id;
+       enum bt_ctf_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_ctf_scope_string(target_field_path->root),
+                       bt_ctf_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_ctf_field_type_common_get_type_id(
+               ctx->cur_field_type);
+       target_type_id = bt_ctf_field_type_common_get_type_id(target_type);
+
+       switch (ctx_cur_field_type_id) {
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               if (target_type_id != BT_CTF_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_ctf_field_type_id_string(target_type_id));
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               if (target_type_id != BT_CTF_FIELD_TYPE_ID_INTEGER ||
+                               bt_ctf_field_type_common_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_ctf_field_type_id_string(target_type_id));
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       default:
+               abort();
+       }
+
+end:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_type_common *type,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       const char *pathstr;
+       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
+       struct bt_ctf_field_path *target_field_path = NULL;
+       struct bt_ctf_field_type_common *target_type = NULL;
+       GString *target_field_path_pretty = NULL;
+       const char *target_field_path_pretty_str;
+
+
+       /* Get path string */
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               pathstr =
+                       bt_ctf_field_type_common_sequence_get_length_field_name(type);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               pathstr =
+                       bt_ctf_field_type_common_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_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_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_CTF_FIELD_TYPE_ID_SEQUENCE:
+               ret = bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_VARIANT:
+               ret = bt_ctf_field_type_common_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_ctf_field_type_common_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_CTF_OBJECT_PUT_REF_AND_RESET(target_field_path);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(target_type);
+       return ret;
+}
+
+/*
+ * Resolves a field type `type`.
+ *
+ * `type` is owned by the caller.
+ */
+static
+int resolve_type(struct bt_ctf_field_type_common *type, struct resolve_context *ctx)
+{
+       int ret = 0;
+       enum bt_ctf_field_type_id type_id;
+
+       if (!type) {
+               /* Type is not available; still valid */
+               goto end;
+       }
+
+       type_id = bt_ctf_field_type_common_get_type_id(type);
+       ctx->cur_field_type = type;
+
+       /* Resolve sequence/variant field type */
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       case BT_CTF_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_CTF_FIELD_TYPE_ID_STRUCT:
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       case BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common *child_type =
+                               bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_ARRAY||
+                                       type_id == BT_CTF_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_ctf_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_CTF_SCOPE_UNKNOWN;
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_resolve_types(
+               struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *event_payload_type,
+               enum bt_ctf_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_CTF_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_CTF_RESOLVE_FLAG_PACKET_HEADER) {
+               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_PACKET_CONTEXT) {
+               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_EVENT_HEADER) {
+               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) {
+               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_EVENT_CONTEXT) {
+               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) {
+               ret = resolve_root_type(BT_CTF_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;
+}
diff --git a/ctf-writer/stream-class.c b/ctf-writer/stream-class.c
new file mode 100644 (file)
index 0000000..4b61a7e
--- /dev/null
@@ -0,0 +1,1145 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * 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 "CTF-WRITER-STREAM-CLASS"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/align-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/clock-class-internal.h>
+#include <babeltrace2/ctf-writer/event-class-internal.h>
+#include <babeltrace2/ctf-writer/event-internal.h>
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/ctf-writer/stream-class-internal.h>
+#include <babeltrace2/ctf-writer/trace.h>
+#include <babeltrace2/ctf-writer/utils-internal.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/validation-internal.h>
+#include <babeltrace2/ctf-writer/visitor-internal.h>
+#include <babeltrace2/ctf-writer/writer-internal.h>
+#include <babeltrace2/endian-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class,
+               const char *name, bt_ctf_object_release_func release_func)
+{
+       BT_LOGD("Initializing common stream class object: name=\"%s\"", name);
+
+       bt_ctf_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_ctf_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 common stream class object: addr=%p, name=\"%s\"",
+               stream_class, name);
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class)
+{
+       BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+       bt_ctf_object_put_ref(stream_class->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);
+       }
+
+       BT_LOGD_STR("Putting event header field type.");
+       bt_ctf_object_put_ref(stream_class->event_header_field_type);
+       BT_LOGD_STR("Putting packet context field type.");
+       bt_ctf_object_put_ref(stream_class->packet_context_field_type);
+       BT_LOGD_STR("Putting event context field type.");
+       bt_ctf_object_put_ref(stream_class->event_context_field_type);
+}
+
+static
+void event_class_exists(gpointer element, gpointer query)
+{
+       struct bt_ctf_event_class_common *event_class_a = element;
+       struct bt_ctf_search_query *search_query = query;
+       struct bt_ctf_event_class_common *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_ctf_event_class_common_get_id(event_class_a);
+       id_b = bt_ctf_event_class_common_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_ctf_event_class_common_get_name(event_class_a));
+               search_query->found = 1;
+               goto end;
+       }
+
+end:
+       return;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_add_event_class(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_event_class_common *event_class,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
+{
+       int ret = 0;
+       int64_t *event_id = NULL;
+       struct bt_ctf_trace_common *trace = NULL;
+       struct bt_ctf_stream_class_common *old_stream_class = NULL;
+       struct bt_ctf_validation_output validation_output = { 0 };
+       struct bt_ctf_field_type_common *packet_header_type = NULL;
+       struct bt_ctf_field_type_common *packet_context_type = NULL;
+       struct bt_ctf_field_type_common *event_header_type = NULL;
+       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
+       struct bt_ctf_field_type_common *event_context_type = NULL;
+       struct bt_ctf_field_type_common *event_payload_type = NULL;
+       const enum bt_ctf_validation_flag validation_flags =
+               BT_CTF_VALIDATION_FLAG_EVENT;
+       struct bt_ctf_clock_class *expected_clock_class = NULL;
+
+       BT_ASSERT(copy_field_type_func);
+
+       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_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class),
+               event_class,
+               bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+       trace = bt_ctf_stream_class_common_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_ctf_trace_add_stream_class() or
+                * bt_ctf_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_ctf_object_get_ref(stream_class->clock_class);
+
+               /*
+                * At this point, `expected_clock_class` can be NULL,
+                * and bt_ctf_event_class_validate_single_clock_class()
+                * below can set it.
+                */
+               ret = bt_ctf_event_class_common_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_ctf_stream_class_common_get_id(stream_class),
+                               bt_ctf_stream_class_common_get_name(stream_class),
+                               expected_clock_class,
+                               expected_clock_class ?
+                                       bt_ctf_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;
+       }
+
+       /* Check for duplicate event classes */
+       struct bt_ctf_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;
+       }
+
+       old_stream_class = bt_ctf_event_class_common_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_ctf_stream_class_common_get_name(old_stream_class),
+                       bt_ctf_stream_class_common_get_id(old_stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       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_ctf_trace_common_borrow_packet_header_field_type(trace);
+               packet_context_type =
+                       bt_ctf_stream_class_common_borrow_packet_context_field_type(
+                               stream_class);
+               event_header_type =
+                       bt_ctf_stream_class_common_borrow_event_header_field_type(
+                               stream_class);
+               stream_event_ctx_type =
+                       bt_ctf_stream_class_common_borrow_event_context_field_type(
+                               stream_class);
+               event_context_type =
+                       bt_ctf_event_class_common_borrow_context_field_type(
+                               event_class);
+               event_payload_type =
+                       bt_ctf_event_class_common_borrow_payload_field_type(
+                               event_class);
+               ret = bt_ctf_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,
+                       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 class: ret=%d", ret);
+                       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_ctf_event_class_common_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_ctf_event_class_common_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_ctf_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_ctf_validation_replace_types(NULL, NULL, event_class,
+                       &validation_output, validation_flags);
+               event_class->valid = 1;
+
+               /*
+                * Put what was not moved in
+                * bt_ctf_validation_replace_types().
+                */
+               bt_ctf_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_ctf_event_class_common_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_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
+       }
+
+       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_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class),
+               event_class,
+               bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+
+end:
+       bt_ctf_validation_output_put_types(&validation_output);
+       bt_ctf_object_put_ref(expected_clock_class);
+       g_free(event_id);
+       return ret;
+}
+
+static
+int64_t get_event_class_count(void *element)
+{
+       return bt_ctf_stream_class_get_event_class_count(
+                       (struct bt_ctf_stream_class *) element);
+}
+
+static
+void *get_event_class(void *element, int i)
+{
+       return bt_ctf_stream_class_get_event_class_by_index(
+                       (struct bt_ctf_stream_class *) element, i);
+}
+
+static
+int visit_event_class(void *object, bt_ctf_visitor visitor,void *data)
+{
+       struct bt_ctf_visitor_object obj = {
+               .object = object,
+               .type = BT_CTF_VISITOR_OBJECT_TYPE_EVENT_CLASS
+       };
+
+       return visitor(&obj, data);
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class,
+               bt_ctf_visitor visitor, void *data)
+{
+       int ret;
+       struct bt_ctf_visitor_object obj = {
+               .object = stream_class,
+               .type = BT_CTF_VISITOR_OBJECT_TYPE_STREAM_CLASS
+       };
+
+       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;
+       }
+
+       ret = bt_ctf_visitor_helper(&obj, get_event_class_count,
+                       get_event_class,
+                       visit_event_class, visitor, data);
+       BT_LOGV("bt_ctf_visitor_helper() returned: ret=%d", ret);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
+               bt_ctf_visitor visitor, void *data)
+{
+       return bt_ctf_stream_class_common_visit(BT_CTF_FROM_COMMON(stream_class),
+               visitor, data);
+}
+
+BT_HIDDEN
+void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class)
+{
+       if (!stream_class || stream_class->frozen) {
+               return;
+       }
+
+       BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+       stream_class->frozen = 1;
+       bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
+       bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
+       bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
+       bt_ctf_clock_class_freeze(stream_class->clock_class);
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_validate_single_clock_class(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_clock_class **expected_clock_class)
+{
+       int ret;
+       uint64_t i;
+
+       BT_ASSERT(stream_class);
+       BT_ASSERT(expected_clock_class);
+       ret = bt_ctf_field_type_common_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_ctf_stream_class_common_get_name(stream_class),
+                       stream_class->id,
+                       stream_class->packet_context_field_type);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_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_ctf_stream_class_common_get_name(stream_class),
+                       stream_class->id,
+                       stream_class->event_header_field_type);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_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_ctf_stream_class_common_get_name(stream_class),
+                       stream_class->id,
+                       stream_class->event_context_field_type);
+               goto end;
+       }
+
+       for (i = 0; i < stream_class->event_classes->len; i++) {
+               struct bt_ctf_event_class_common *event_class =
+                       g_ptr_array_index(stream_class->event_classes, i);
+
+               BT_ASSERT(event_class);
+               ret = bt_ctf_event_class_common_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_ctf_stream_class_common_get_name(stream_class),
+                               stream_class->id);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int init_event_header(struct bt_ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *event_header_type =
+               bt_ctf_field_type_structure_create();
+       struct bt_ctf_field_type *_uint32_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
+       struct bt_ctf_field_type *_uint64_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
+
+       if (!event_header_type) {
+               BT_LOGE_STR("Cannot create empty structure field type.");
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(event_header_type,
+               _uint32_t, "id");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `id` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(event_header_type,
+               _uint64_t, "timestamp");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(stream_class->common.event_header_field_type);
+       stream_class->common.event_header_field_type =
+               (void *) event_header_type;
+       event_header_type = NULL;
+
+end:
+       if (ret) {
+               bt_ctf_object_put_ref(event_header_type);
+       }
+
+       bt_ctf_object_put_ref(_uint32_t);
+       bt_ctf_object_put_ref(_uint64_t);
+       return ret;
+}
+
+static
+int init_packet_context(struct bt_ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *packet_context_type =
+               bt_ctf_field_type_structure_create();
+       struct bt_ctf_field_type *_uint64_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
+       struct bt_ctf_field_type *ts_begin_end_uint64_t;
+
+       if (!packet_context_type) {
+               BT_LOGE_STR("Cannot create empty structure field type.");
+               ret = -1;
+               goto end;
+       }
+
+       ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
+       if (!ts_begin_end_uint64_t) {
+               BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * We create a stream packet context as proposed in the CTF
+        * specification.
+        */
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               ts_begin_end_uint64_t, "timestamp_begin");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               ts_begin_end_uint64_t, "timestamp_end");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               _uint64_t, "content_size");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               _uint64_t, "packet_size");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               _uint64_t, "events_discarded");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(stream_class->common.packet_context_field_type);
+       stream_class->common.packet_context_field_type =
+               (void *) packet_context_type;
+       packet_context_type = NULL;
+
+end:
+       if (ret) {
+               bt_ctf_object_put_ref(packet_context_type);
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(_uint64_t);
+       bt_ctf_object_put_ref(ts_begin_end_uint64_t);
+       return ret;
+}
+
+static
+void bt_ctf_stream_class_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_stream_class *stream_class;
+
+       stream_class = (void *) obj;
+       BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_get_name(stream_class),
+               bt_ctf_stream_class_get_id(stream_class));
+       bt_ctf_stream_class_common_finalize(BT_CTF_TO_COMMON(stream_class));
+       bt_ctf_object_put_ref(stream_class->clock);
+       g_free(stream_class);
+}
+
+struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name)
+{
+       struct bt_ctf_stream_class *stream_class;
+       int ret;
+
+       BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name);
+       stream_class = g_new0(struct bt_ctf_stream_class, 1);
+       if (!stream_class) {
+               BT_LOGE_STR("Failed to allocate one CTF writer stream class.");
+               goto error;
+       }
+
+       ret = bt_ctf_stream_class_common_initialize(BT_CTF_TO_COMMON(stream_class),
+               name, bt_ctf_stream_class_destroy);
+       if (ret) {
+               /* bt_ctf_stream_class_common_initialize() logs errors */
+               goto error;
+       }
+
+       ret = init_event_header(stream_class);
+       if (ret) {
+               BT_LOGE_STR("Cannot initialize stream class's event header field type.");
+               goto error;
+       }
+
+       ret = init_packet_context(stream_class);
+       if (ret) {
+               BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
+               goto error;
+       }
+
+       BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"",
+               stream_class, name);
+       return stream_class;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_class);
+       return stream_class;
+}
+
+static
+int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *parent_ft, const char *field_name)
+{
+       struct bt_ctf_clock_class *mapped_clock_class = NULL;
+       int ret = 0;
+       struct bt_ctf_field_type *ft =
+               bt_ctf_field_type_structure_get_field_type_by_name(parent_ft,
+                       field_name);
+
+       BT_ASSERT(stream_class->clock);
+
+       if (!ft) {
+               /* Field does not exist: not an error */
+               goto end;
+       }
+
+       BT_ASSERT(((struct bt_ctf_field_type_common *) ft)->id ==
+               BT_CTF_FIELD_TYPE_ID_INTEGER);
+       mapped_clock_class =
+               bt_ctf_field_type_integer_get_mapped_clock_class(ft);
+       if (!mapped_clock_class) {
+               struct bt_ctf_field_type *ft_copy;
+
+               if (!stream_class->clock) {
+                       BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
+                               "stream-class-addr=%p, stream-class-name=\"%s\", "
+                               "stream-class-id=%" PRId64 ", ft-addr=%p",
+                               stream_class,
+                               bt_ctf_stream_class_get_name(stream_class),
+                               bt_ctf_stream_class_get_id(stream_class), ft);
+                       ret = -1;
+                       goto end;
+               }
+
+               ft_copy = bt_ctf_field_type_copy(ft);
+               if (!ft_copy) {
+                       BT_LOGE("Failed to copy integer field type: ft-addr=%p",
+                               ft);
+               }
+
+               ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
+                       (void *) ft_copy, stream_class->clock->clock_class);
+               BT_ASSERT(ret == 0);
+
+               ret = bt_ctf_field_type_common_structure_replace_field(
+                       (void *) parent_ft, field_name, (void *) ft_copy);
+               bt_ctf_object_put_ref(ft_copy);
+               BT_LOGV("Automatically mapped field type to stream class's clock class: "
+                       "stream-class-addr=%p, stream-class-name=\"%s\", "
+                       "stream-class-id=%" PRId64 ", ft-addr=%p, "
+                       "ft-copy-addr=%p",
+                       stream_class,
+                       bt_ctf_stream_class_get_name(stream_class),
+                       bt_ctf_stream_class_get_id(stream_class), ft, ft_copy);
+       }
+
+end:
+       bt_ctf_object_put_ref(ft);
+       bt_ctf_object_put_ref(mapped_clock_class);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_map_clock_class(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type)
+{
+       int ret = 0;
+
+       BT_ASSERT(stream_class);
+
+       if (!stream_class->clock) {
+               /* No clock class to map to */
+               goto end;
+       }
+
+       if (packet_context_type) {
+               if (try_map_clock_class(stream_class, packet_context_type,
+                               "timestamp_begin")) {
+                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
+                       ret = -1;
+                       goto end;
+               }
+
+               if (try_map_clock_class(stream_class, packet_context_type,
+                               "timestamp_end")) {
+                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       if (event_header_type) {
+               if (try_map_clock_class(stream_class, event_header_type,
+                               "timestamp")) {
+                       BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
+               struct bt_ctf_stream_class *stream_class)
+{
+       struct bt_ctf_clock *clock = NULL;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               goto end;
+       }
+
+       if (!stream_class->clock) {
+               BT_LOGV("Stream class has no clock: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_get_name(stream_class),
+                       bt_ctf_stream_class_get_id(stream_class));
+               goto end;
+       }
+
+       clock = bt_ctf_object_get_ref(stream_class->clock);
+
+end:
+       return clock;
+}
+
+int bt_ctf_stream_class_set_clock(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_clock *clock)
+{
+       int ret = 0;
+
+       if (!stream_class || !clock) {
+               BT_LOGW("Invalid parameter: stream class or clock is NULL: "
+                       "stream-class-addr=%p, clock-addr=%p",
+                       stream_class, clock);
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->common.frozen) {
+               BT_LOGW("Invalid parameter: stream class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_get_name(stream_class),
+                       bt_ctf_stream_class_get_id(stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       /* Replace the current clock of this stream class. */
+       bt_ctf_object_put_ref(stream_class->clock);
+       stream_class->clock = bt_ctf_object_get_ref(clock);
+       BT_LOGV("Set stream class's clock: "
+               "addr=%p, name=\"%s\", id=%" PRId64 ", "
+               "clock-addr=%p, clock-name=\"%s\"",
+               stream_class,
+               bt_ctf_stream_class_get_name(stream_class),
+               bt_ctf_stream_class_get_id(stream_class),
+               stream_class->clock,
+               bt_ctf_clock_get_name(stream_class->clock));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       size_t i;
+       struct bt_ctf_trace *trace;
+       struct bt_ctf_field_type *packet_header_type = NULL;
+
+       BT_LOGD("Serializing stream class's metadata: "
+               "stream-class-addr=%p, stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
+               stream_class,
+               bt_ctf_stream_class_get_name(stream_class),
+               bt_ctf_stream_class_get_id(stream_class), context);
+       g_string_assign(context->field_name, "");
+       context->current_indentation_level = 1;
+       if (!stream_class->common.id_set) {
+               BT_LOGW_STR("Stream class's ID is not set.");
+               ret = -1;
+               goto end;
+       }
+
+       g_string_append(context->string, "stream {\n");
+
+       /*
+        * The reference to the trace is only borrowed since the
+        * serialization of the stream class might have been triggered
+        * by the trace's destruction. In such a case, the trace's
+        * reference count would, unexepectedly, go through the sequence
+        * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
+        * and serialization.
+        */
+       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
+               BT_CTF_TO_COMMON(stream_class)));
+       BT_ASSERT(trace);
+       packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace);
+       trace = NULL;
+       if (packet_header_type) {
+               struct bt_ctf_field_type *stream_id_type;
+
+               stream_id_type =
+                       bt_ctf_field_type_structure_get_field_type_by_name(
+                               packet_header_type, "stream_id");
+               if (stream_id_type) {
+                       /*
+                        * Only set the stream's id if the trace's packet header
+                        * contains a stream_id field. This field is only
+                        * needed if the trace contains only one stream
+                        * class.
+                        */
+                       g_string_append_printf(context->string,
+                               "\tid = %" PRId64 ";\n",
+                               stream_class->common.id);
+               }
+               bt_ctf_object_put_ref(stream_id_type);
+       }
+       if (stream_class->common.event_header_field_type) {
+               BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
+               g_string_append(context->string, "\tevent.header := ");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) stream_class->common.event_header_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";");
+       }
+
+
+       if (stream_class->common.packet_context_field_type) {
+               BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
+               g_string_append(context->string, "\n\n\tpacket.context := ");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) stream_class->common.packet_context_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";");
+       }
+
+       if (stream_class->common.event_context_field_type) {
+               BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
+               g_string_append(context->string, "\n\n\tevent.context := ");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) stream_class->common.event_context_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";");
+       }
+
+       g_string_append(context->string, "\n};\n\n");
+
+       for (i = 0; i < stream_class->common.event_classes->len; i++) {
+               struct bt_ctf_event_class *event_class =
+                       stream_class->common.event_classes->pdata[i];
+
+               ret = bt_ctf_event_class_serialize(event_class, context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event class's metadata: "
+                               "event-class-addr=%p, event-class-name=\"%s\", "
+                               "event-class-id=%" PRId64,
+                               event_class,
+                               bt_ctf_event_class_get_name(event_class),
+                               bt_ctf_event_class_get_id(event_class));
+                       goto end;
+               }
+       }
+
+end:
+       bt_ctf_object_put_ref(packet_header_type);
+       context->current_indentation_level = 0;
+       return ret;
+}
+
+struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(bt_ctf_stream_class_common_borrow_trace(
+               BT_CTF_TO_COMMON(stream_class)));
+}
+
+const char *bt_ctf_stream_class_get_name(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_stream_class_common_get_name(BT_CTF_TO_COMMON(stream_class));
+}
+
+int bt_ctf_stream_class_set_name(
+               struct bt_ctf_stream_class *stream_class, const char *name)
+{
+       return bt_ctf_stream_class_common_set_name(BT_CTF_TO_COMMON(stream_class),
+               name);
+}
+
+int64_t bt_ctf_stream_class_get_id(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_stream_class_common_get_id(BT_CTF_TO_COMMON(stream_class));
+}
+
+int bt_ctf_stream_class_set_id(
+               struct bt_ctf_stream_class *stream_class, uint64_t id)
+{
+       return bt_ctf_stream_class_common_set_id(BT_CTF_TO_COMMON(stream_class), id);
+}
+
+struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_packet_context_field_type(
+                       BT_CTF_TO_COMMON(stream_class)));
+}
+
+int bt_ctf_stream_class_set_packet_context_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *packet_context_type)
+{
+       return bt_ctf_stream_class_common_set_packet_context_field_type(
+               BT_CTF_TO_COMMON(stream_class), (void *) packet_context_type);
+}
+
+struct bt_ctf_field_type *
+bt_ctf_stream_class_get_event_header_type(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_header_field_type(
+                       BT_CTF_TO_COMMON(stream_class)));
+}
+
+int bt_ctf_stream_class_set_event_header_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *event_header_type)
+{
+       return bt_ctf_stream_class_common_set_event_header_field_type(
+               BT_CTF_TO_COMMON(stream_class), (void *) event_header_type);
+}
+
+struct bt_ctf_field_type *
+bt_ctf_stream_class_get_event_context_type(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_context_field_type(
+                       BT_CTF_TO_COMMON(stream_class)));
+}
+
+int bt_ctf_stream_class_set_event_context_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *event_context_type)
+{
+       return bt_ctf_stream_class_common_set_event_context_field_type(
+               BT_CTF_TO_COMMON(stream_class), (void *) event_context_type);
+}
+
+int64_t bt_ctf_stream_class_get_event_class_count(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_stream_class_common_get_event_class_count(
+               BT_CTF_TO_COMMON(stream_class));
+}
+
+struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
+               struct bt_ctf_stream_class *stream_class, uint64_t index)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_class_by_index(
+                       BT_CTF_TO_COMMON(stream_class), index));
+}
+
+struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
+               struct bt_ctf_stream_class *stream_class, uint64_t id)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_class_by_id(
+                       BT_CTF_TO_COMMON(stream_class), id));
+}
+
+int bt_ctf_stream_class_add_event_class(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_stream_class_common_add_event_class(
+               BT_CTF_TO_COMMON(stream_class), BT_CTF_TO_COMMON(event_class),
+               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy);
+}
diff --git a/ctf-writer/stream.c b/ctf-writer/stream.c
new file mode 100644 (file)
index 0000000..fc7557e
--- /dev/null
@@ -0,0 +1,1953 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * 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 "CTF-WRITER-STREAM"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/align-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/event-class-internal.h>
+#include <babeltrace2/ctf-writer/event-internal.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/ctf-writer/stream-class-internal.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/stream-internal.h>
+#include <babeltrace2/ctf-writer/stream.h>
+#include <babeltrace2/ctf-writer/trace-internal.h>
+#include <babeltrace2/ctf-writer/trace.h>
+#include <babeltrace2/ctf-writer/writer-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctfser-internal.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <unistd.h>
+
+BT_HIDDEN
+void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream)
+{
+       BT_LOGD("Finalizing common stream object: addr=%p, name=\"%s\"",
+               stream, bt_ctf_stream_common_get_name(stream));
+
+       if (stream->name) {
+               g_string_free(stream->name, TRUE);
+       }
+}
+
+BT_HIDDEN
+int bt_ctf_stream_common_initialize(
+               struct bt_ctf_stream_common *stream,
+               struct bt_ctf_stream_class_common *stream_class, const char *name,
+               uint64_t id, bt_ctf_object_release_func release_func)
+{
+       int ret = 0;
+       struct bt_ctf_trace_common *trace = NULL;
+
+       bt_ctf_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 common stream object: stream-class-addr=%p, "
+               "stream-class-name=\"%s\", stream-name=\"%s\", "
+               "stream-id=%" PRIu64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               name, id);
+       trace = bt_ctf_stream_class_common_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_ctf_stream_class_common_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;
+
+               for (i = 0; i < trace->streams->len; i++) {
+                       struct bt_ctf_stream_common *trace_stream =
+                               g_ptr_array_index(trace->streams, i);
+
+                       if (trace_stream->stream_class != (void *) stream_class) {
+                               continue;
+                       }
+
+                       if (trace_stream->id == id) {
+                               BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID.");
+                               goto error;
+                       }
+               }
+       }
+
+       /*
+        * Acquire reference to parent since stream will become publicly
+        * reachable; it needs its parent to remain valid.
+        */
+       bt_ctf_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;
+               }
+       }
+
+       BT_LOGD("Set common stream's trace parent: trace-addr=%p", trace);
+
+       /* Add this stream to the trace's streams */
+       BT_LOGD("Created common stream object: addr=%p", stream);
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+void bt_ctf_stream_destroy(struct bt_ctf_object *obj);
+
+static
+int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
+
+static
+int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (!field) {
+               BT_LOGW_STR("Invalid parameter: field is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       BT_ASSERT(field_type);
+
+       if (bt_ctf_field_type_get_type_id(field_type) !=
+                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               /* Not an integer and the value is unset, error. */
+               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
+                       "field-addr=%p, ft-addr=%p, ft-id=%s",
+                       field, field_type,
+                       bt_ctf_field_type_id_string((int)
+                               bt_ctf_field_type_get_type_id(field_type)));
+               ret = -1;
+               goto end;
+       }
+
+       if (bt_ctf_field_type_integer_is_signed(field_type)) {
+               ret = bt_ctf_field_integer_signed_set_value(field, (int64_t) value);
+               if (ret) {
+                       /* Value is out of range, error. */
+                       BT_LOGW("Cannot set signed integer field's value: "
+                               "addr=%p, value=%" PRId64,
+                               field, (int64_t) value);
+                       goto end;
+               }
+       } else {
+               ret = bt_ctf_field_integer_unsigned_set_value(field, value);
+               if (ret) {
+                       /* Value is out of range, error. */
+                       BT_LOGW("Cannot set unsigned integer field's value: "
+                               "addr=%p, value=%" PRIu64,
+                               field, value);
+                       goto end;
+               }
+       }
+end:
+       bt_ctf_object_put_ref(field_type);
+       return ret;
+}
+
+static
+int set_packet_header_magic(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_header, "magic");
+       const uint32_t magic_value = 0xc1fc1fc1;
+
+       BT_ASSERT(stream);
+
+       if (!magic_field) {
+               /* No magic field found. Not an error, skip. */
+               BT_LOGV("No field named `magic` in packet header: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_set_value(magic_field,
+               (uint64_t) magic_value);
+
+       if (ret) {
+               BT_LOGW("Cannot set packet header field's `magic` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       magic_field, (uint64_t) magic_value);
+       } else {
+               BT_LOGV("Set packet header field's `magic` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       magic_field, (uint64_t) magic_value);
+       }
+end:
+       bt_ctf_object_put_ref(magic_field);
+       return ret;
+}
+
+static
+int set_packet_header_uuid(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       int64_t i;
+       struct bt_ctf_trace *trace = NULL;
+       struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_header, "uuid");
+
+       BT_ASSERT(stream);
+
+       if (!uuid_field) {
+               /* No uuid field found. Not an error, skip. */
+               BT_LOGV("No field named `uuid` in packet header: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       trace = (struct bt_ctf_trace *)
+               bt_ctf_object_get_parent(&stream->common.base);
+
+       for (i = 0; i < 16; i++) {
+               struct bt_ctf_field *uuid_element =
+                       bt_ctf_field_array_get_field(uuid_field, i);
+
+               ret = bt_ctf_field_integer_unsigned_set_value(
+                       uuid_element, (uint64_t) trace->common.uuid[i]);
+               bt_ctf_object_put_ref(uuid_element);
+               if (ret) {
+                       BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
+                               "value=%" PRIu64 ", index=%" PRId64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               uuid_element, (uint64_t) trace->common.uuid[i], i);
+                       goto end;
+               }
+       }
+
+       BT_LOGV("Set packet header field's `uuid` field's value: "
+               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), uuid_field);
+
+end:
+       bt_ctf_object_put_ref(uuid_field);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
+       return ret;
+}
+static
+int set_packet_header_stream_id(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       uint32_t stream_id;
+       struct bt_ctf_field *stream_id_field =
+               bt_ctf_field_structure_get_field_by_name(
+                       stream->packet_header, "stream_id");
+
+       if (!stream_id_field) {
+               /* No stream_id field found. Not an error, skip. */
+               BT_LOGV("No field named `stream_id` in packet header: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       stream_id = stream->common.stream_class->id;
+       ret = bt_ctf_field_integer_unsigned_set_value(stream_id_field,
+               (uint64_t) stream_id);
+       if (ret) {
+               BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       stream_id_field, (uint64_t) stream_id);
+       } else {
+               BT_LOGV("Set packet header field's `stream_id` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       stream_id_field, (uint64_t) stream_id);
+       }
+
+end:
+       bt_ctf_object_put_ref(stream_id_field);
+       return ret;
+}
+
+static
+int auto_populate_packet_header(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+
+       if (!stream->packet_header) {
+               goto end;
+       }
+
+       ret = set_packet_header_magic(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's magic number field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_header_uuid(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's UUID field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_header_stream_id(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's stream class ID field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       BT_LOGV("Automatically populated stream's packet header's known fields: "
+               "stream-addr=%p, stream-name=\"%s\"",
+               stream, bt_ctf_stream_get_name(stream));
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_packet_size(struct bt_ctf_stream *stream,
+               uint64_t packet_size_bits)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "packet_size");
+
+       ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, packet_size_bits);
+       } else {
+               BT_LOGV("Set packet context field's `packet_size` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, packet_size_bits);
+       }
+
+       bt_ctf_object_put_ref(field);
+       return ret;
+}
+
+static
+int set_packet_context_content_size(struct bt_ctf_stream *stream,
+               uint64_t content_size_bits)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "content_size");
+
+       BT_ASSERT(stream);
+
+       if (!field) {
+               /* No content size field found. Not an error, skip. */
+               BT_LOGV("No field named `content_size` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, content_size_bits);
+       } else {
+               BT_LOGV("Set packet context field's `content_size` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, content_size_bits);
+       }
+
+end:
+       bt_ctf_object_put_ref(field);
+       return ret;
+}
+
+static
+int set_packet_context_events_discarded(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "events_discarded");
+
+       BT_ASSERT(stream);
+
+       if (!field) {
+               /* No discarded events count field found. Not an error, skip. */
+               BT_LOGV("No field named `events_discarded` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       /*
+        * If the field is set by the user, make sure that the value is
+        * greater than or equal to the stream's current count of
+        * discarded events. We do not allow wrapping here. If it's
+        * valid, update the stream's current count.
+        */
+       if (bt_ctf_field_is_set_recursive(field)) {
+               uint64_t user_val;
+
+               ret = bt_ctf_field_integer_unsigned_get_value(field,
+                       &user_val);
+               if (ret) {
+                       BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
+                               stream, bt_ctf_stream_get_name(stream), field);
+                       goto end;
+               }
+
+               if (user_val < stream->discarded_events) {
+                       BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: "
+                               "value is lesser than the stream's current discarded events count: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
+                               "value=%" PRIu64 ", "
+                               "stream-discarded-events-count=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream), field,
+                               user_val, stream->discarded_events);
+                       goto end;
+               }
+
+               stream->discarded_events = user_val;
+       } else {
+               ret = bt_ctf_field_integer_unsigned_set_value(field,
+                       stream->discarded_events);
+               if (ret) {
+                       BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               field, stream->discarded_events);
+               } else {
+                       BT_LOGV("Set packet context field's `events_discarded` field's value: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               field, stream->discarded_events);
+               }
+       }
+
+end:
+       bt_ctf_object_put_ref(field);
+       return ret;
+}
+
+static
+void update_clock_value(uint64_t *val, uint64_t new_val,
+               unsigned int new_val_size)
+{
+       const uint64_t pow2 = 1ULL << new_val_size;
+       const uint64_t mask = pow2 - 1;
+       uint64_t val_masked;
+
+#ifdef BT_LOG_ENABLED_VERBOSE
+       uint64_t old_val = *val;
+#endif
+
+       if (new_val_size == 64) {
+               *val = new_val;
+               goto end;
+       }
+
+       val_masked = *val & mask;
+
+       if (new_val < val_masked) {
+               /* Wrapped once */
+               new_val |= pow2;
+       }
+
+       *val &= ~mask;
+       *val |= new_val;
+
+end:
+       BT_LOGV("Updated clock value: old-val=%" PRIu64 ", new-val=%" PRIu64,
+               old_val, *val);
+       return;
+}
+
+static
+int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val)
+{
+       int ret = 0;
+       struct bt_ctf_field_common *field_common = (void *) field;
+
+       if (!field) {
+               goto end;
+       }
+
+       switch (bt_ctf_field_get_type_id(field)) {
+       case BT_CTF_FIELD_TYPE_ID_INTEGER:
+       {
+               struct bt_ctf_clock_class *cc =
+                       bt_ctf_field_type_integer_get_mapped_clock_class(
+                               (void *) field_common->type);
+               int val_size;
+               uint64_t uval;
+
+               if (!cc) {
+                       goto end;
+               }
+
+               bt_ctf_object_put_ref(cc);
+               val_size = bt_ctf_field_type_integer_get_size(
+                       (void *) field_common->type);
+               BT_ASSERT(val_size >= 1);
+
+               if (bt_ctf_field_type_integer_is_signed(
+                               (void *) field_common->type)) {
+                       int64_t ival;
+
+                       ret = bt_ctf_field_integer_signed_get_value(field, &ival);
+                       uval = (uint64_t) ival;
+               } else {
+                       ret = bt_ctf_field_integer_unsigned_get_value(field, &uval);
+               }
+
+               if (ret) {
+                       /* Not set */
+                       goto end;
+               }
+
+               update_clock_value(val, uval, val_size);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ENUM:
+       {
+               struct bt_ctf_field *int_field =
+                       bt_ctf_field_enumeration_get_container(field);
+
+               BT_ASSERT(int_field);
+               ret = visit_field_update_clock_value(int_field, val);
+               bt_ctf_object_put_ref(int_field);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       {
+               uint64_t i;
+               int64_t len = bt_ctf_field_type_array_get_length(
+                       (void *) field_common->type);
+
+               BT_ASSERT(len >= 0);
+
+               for (i = 0; i < len; i++) {
+                       struct bt_ctf_field *elem_field =
+                               bt_ctf_field_array_get_field(field, i);
+
+                       BT_ASSERT(elem_field);
+                       ret = visit_field_update_clock_value(elem_field, val);
+                       bt_ctf_object_put_ref(elem_field);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               uint64_t i;
+               int64_t len = bt_ctf_field_common_sequence_get_length(
+                       (void *) field);
+
+               if (len < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               for (i = 0; i < len; i++) {
+                       struct bt_ctf_field *elem_field =
+                               bt_ctf_field_sequence_get_field(field, i);
+
+                       BT_ASSERT(elem_field);
+                       ret = visit_field_update_clock_value(elem_field, val);
+                       bt_ctf_object_put_ref(elem_field);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               uint64_t i;
+               int64_t len = bt_ctf_field_type_structure_get_field_count(
+                       (void *) field_common->type);
+
+               BT_ASSERT(len >= 0);
+
+               for (i = 0; i < len; i++) {
+                       struct bt_ctf_field *member_field =
+                               bt_ctf_field_structure_get_field_by_index(field, i);
+
+                       BT_ASSERT(member_field);
+                       ret = visit_field_update_clock_value(member_field, val);
+                       bt_ctf_object_put_ref(member_field);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct bt_ctf_field *cur_field =
+                       bt_ctf_field_variant_get_current_field(field);
+
+               if (!cur_field) {
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = visit_field_update_clock_value(cur_field, val);
+               bt_ctf_object_put_ref(cur_field);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+int visit_event_update_clock_value(struct bt_ctf_event *event, uint64_t *val)
+{
+       int ret = 0;
+       struct bt_ctf_field *field;
+
+       field = bt_ctf_event_get_header(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's header.");
+               goto end;
+       }
+
+       field = bt_ctf_event_get_stream_event_context(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's stream event context.");
+               goto end;
+       }
+
+       field = bt_ctf_event_get_context(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's context.");
+               goto end;
+       }
+
+       field = bt_ctf_event_get_payload_field(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's payload.");
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_timestamps(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       uint64_t val;
+       uint64_t cur_clock_value;
+       uint64_t init_clock_value = 0;
+       struct bt_ctf_field *ts_begin_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "timestamp_begin");
+       struct bt_ctf_field *ts_end_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "timestamp_end");
+       struct bt_ctf_field_common *packet_context =
+               (void *) stream->packet_context;
+       uint64_t i;
+       int64_t len;
+
+       if (ts_begin_field && bt_ctf_field_is_set_recursive(ts_begin_field)) {
+               /* Use provided `timestamp_begin` value as starting value */
+               ret = bt_ctf_field_integer_unsigned_get_value(ts_begin_field, &val);
+               BT_ASSERT(ret == 0);
+               init_clock_value = val;
+       } else if (stream->last_ts_end != -1ULL) {
+               /* Use last packet's ending timestamp as starting value */
+               init_clock_value = stream->last_ts_end;
+       }
+
+       cur_clock_value = init_clock_value;
+
+       if (stream->last_ts_end != -1ULL &&
+                       cur_clock_value < stream->last_ts_end) {
+               BT_LOGW("Packet's initial timestamp is less than previous "
+                       "packet's final timestamp: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "cur-packet-ts-begin=%" PRIu64 ", "
+                       "prev-packet-ts-end=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       cur_clock_value, stream->last_ts_end);
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Visit all the packet context fields, followed by all the
+        * fields of all the events, in order, updating our current
+        * clock value as we visit.
+        *
+        * While visiting the packet context fields, do not consider
+        * `timestamp_begin` and `timestamp_end` because this function's
+        * purpose is to set them anyway. Also do not consider
+        * `packet_size`, `content_size`, `events_discarded`, and
+        * `packet_seq_num` if they are not set because those are
+        * autopopulating fields.
+        */
+       len = bt_ctf_field_type_structure_get_field_count(
+               (void *) packet_context->type);
+       BT_ASSERT(len >= 0);
+
+       for (i = 0; i < len; i++) {
+               const char *member_name;
+               struct bt_ctf_field *member_field;
+
+               ret = bt_ctf_field_type_structure_get_field_by_index(
+                       (void *) packet_context->type, &member_name, NULL, i);
+               BT_ASSERT(ret == 0);
+
+               if (strcmp(member_name, "timestamp_begin") == 0 ||
+                               strcmp(member_name, "timestamp_end") == 0) {
+                       continue;
+               }
+
+               member_field = bt_ctf_field_structure_get_field_by_index(
+                       stream->packet_context, i);
+               BT_ASSERT(member_field);
+
+               if (strcmp(member_name, "packet_size") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               if (strcmp(member_name, "content_size") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               if (strcmp(member_name, "events_discarded") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               if (strcmp(member_name, "packet_seq_num") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               ret = visit_field_update_clock_value(member_field,
+                       &cur_clock_value);
+               bt_ctf_object_put_ref(member_field);
+               if (ret) {
+                       BT_LOGW("Cannot automatically update clock value "
+                               "in stream's packet context: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "field-name=\"%s\"",
+                               stream, bt_ctf_stream_get_name(stream),
+                               member_name);
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < stream->events->len; i++) {
+               struct bt_ctf_event *event = g_ptr_array_index(stream->events, i);
+
+               BT_ASSERT(event);
+               ret = visit_event_update_clock_value(event, &cur_clock_value);
+               if (ret) {
+                       BT_LOGW("Cannot automatically update clock value "
+                               "in stream's packet context: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "index=%" PRIu64 ", event-addr=%p, "
+                               "event-class-id=%" PRId64 ", "
+                               "event-class-name=\"%s\"",
+                               stream, bt_ctf_stream_get_name(stream),
+                               i, event,
+                               bt_ctf_event_class_common_get_id(event->common.class),
+                               bt_ctf_event_class_common_get_name(event->common.class));
+                       goto end;
+               }
+       }
+
+       /*
+        * Everything is visited, thus the current clock value
+        * corresponds to the ending timestamp. Validate this value
+        * against the provided value of `timestamp_end`, if any,
+        * otherwise set it.
+        */
+       if (ts_end_field && bt_ctf_field_is_set_recursive(ts_end_field)) {
+               ret = bt_ctf_field_integer_unsigned_get_value(ts_end_field, &val);
+               BT_ASSERT(ret == 0);
+
+               if (val < cur_clock_value) {
+                       BT_LOGW("Packet's final timestamp is less than "
+                               "computed packet's final timestamp: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "cur-packet-ts-end=%" PRIu64 ", "
+                               "computed-packet-ts-end=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               val, cur_clock_value);
+                       ret = -1;
+                       goto end;
+               }
+
+               stream->last_ts_end = val;
+       }
+
+       if (ts_end_field && !bt_ctf_field_is_set_recursive(ts_end_field)) {
+               ret = set_integer_field_value(ts_end_field, cur_clock_value);
+               BT_ASSERT(ret == 0);
+               stream->last_ts_end = cur_clock_value;
+       }
+
+       if (!ts_end_field) {
+               stream->last_ts_end = cur_clock_value;
+       }
+
+       /* Set `timestamp_begin` field to initial clock value */
+       if (ts_begin_field && !bt_ctf_field_is_set_recursive(ts_begin_field)) {
+               ret = set_integer_field_value(ts_begin_field, init_clock_value);
+               BT_ASSERT(ret == 0);
+       }
+
+end:
+       bt_ctf_object_put_ref(ts_begin_field);
+       bt_ctf_object_put_ref(ts_end_field);
+       return ret;
+}
+
+static
+int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts,
+               uint64_t packet_size_bits, uint64_t content_size_bits)
+{
+       int ret = 0;
+
+       if (!stream->packet_context) {
+               goto end;
+       }
+
+       ret = set_packet_context_packet_size(stream, packet_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's packet size field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_context_content_size(stream, content_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's content size field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       if (set_ts) {
+               ret = set_packet_context_timestamps(stream);
+               if (ret) {
+                       BT_LOGW("Cannot set packet context's timestamp fields: "
+                               "stream-addr=%p, stream-name=\"%s\"",
+                               stream, bt_ctf_stream_get_name(stream));
+                       goto end;
+               }
+       }
+
+       ret = set_packet_context_events_discarded(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's discarded events count field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       BT_LOGV("Automatically populated stream's packet context's known fields: "
+               "stream-addr=%p, stream-name=\"%s\"",
+               stream, bt_ctf_stream_get_name(stream));
+
+end:
+       return ret;
+}
+
+static
+void release_event(struct bt_ctf_event *event)
+{
+       if (bt_ctf_object_get_ref_count(&event->common.base)) {
+               /*
+                * The event is being orphaned, but it must guarantee the
+                * existence of its event class for the duration of its
+                * lifetime.
+                */
+               bt_ctf_object_get_ref(event->common.class);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(event->common.base.parent);
+       } else {
+               bt_ctf_object_try_spec_release(&event->common.base);
+       }
+}
+
+static
+int create_stream_file(struct bt_ctf_writer *writer,
+               struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       GString *filename = g_string_new(NULL);
+       int64_t stream_class_id;
+       char *file_path = NULL;
+
+       BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
+               "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
+               writer, stream, bt_ctf_stream_get_name(stream),
+               stream->common.stream_class,
+               stream->common.stream_class->name->str);
+
+       if (stream->common.name && stream->common.name->len > 0) {
+               /* Use stream name's base name as prefix */
+               gchar *basename = g_path_get_basename(stream->common.name->str);
+
+               BT_ASSERT(basename);
+
+               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
+                       g_string_assign(filename, "stream");
+               } else {
+                       g_string_assign(filename, basename);
+               }
+
+               g_free(basename);
+               goto append_ids;
+       }
+
+       if (stream->common.stream_class->name &&
+                       stream->common.stream_class->name->len > 0) {
+               /* Use stream class name's base name as prefix */
+               gchar *basename =
+                       g_path_get_basename(
+                               stream->common.stream_class->name->str);
+
+               BT_ASSERT(basename);
+
+               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
+                       g_string_assign(filename, "stream");
+               } else {
+                       g_string_assign(filename, basename);
+               }
+
+               g_free(basename);
+               goto append_ids;
+       }
+
+       /* Default to using `stream-` as prefix */
+       g_string_assign(filename, "stream");
+
+append_ids:
+       stream_class_id = bt_ctf_stream_class_common_get_id(stream->common.stream_class);
+       BT_ASSERT(stream_class_id >= 0);
+       BT_ASSERT(stream->common.id >= 0);
+       g_string_append_printf(filename, "-%" PRId64 "-%" PRId64,
+               stream_class_id, stream->common.id);
+
+       file_path = g_build_filename(writer->path->str, filename->str, NULL);
+       if (file_path == NULL) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctfser_init(&stream->ctfser, file_path);
+       g_free(file_path);
+       if (ret) {
+               /* bt_ctfser_init() logs errors */
+               goto end;
+       }
+
+       BT_LOGD("Created stream file for writing: "
+               "stream-addr=%p, stream-name=\"%s\", "
+               "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream),
+               filename->str);
+
+end:
+       g_string_free(filename, TRUE);
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_stream *bt_ctf_stream_create_with_id(
+               struct bt_ctf_stream_class *stream_class,
+               const char *name, uint64_t id)
+{
+       int ret;
+       int fd;
+       struct bt_ctf_stream *stream = NULL;
+       struct bt_ctf_trace *trace = NULL;
+       struct bt_ctf_writer *writer = NULL;
+
+       BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, "
+               "stream-class-name=\"%s\", stream-name=\"%s\", "
+               "stream-id=%" PRIu64,
+               stream_class, bt_ctf_stream_class_get_name(stream_class),
+               name, id);
+       stream = g_new0(struct bt_ctf_stream, 1);
+       if (!stream) {
+               BT_LOGE_STR("Failed to allocate one stream.");
+               goto error;
+       }
+
+       if (id == -1ULL) {
+               id = stream_class->next_stream_id;
+       }
+
+       ret = bt_ctf_stream_common_initialize(BT_CTF_TO_COMMON(stream),
+               BT_CTF_TO_COMMON(stream_class), name, id, bt_ctf_stream_destroy);
+       if (ret) {
+               /* bt_ctf_stream_common_initialize() logs errors */
+               goto error;
+       }
+
+       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
+               BT_CTF_TO_COMMON(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_ctf_stream_class_get_name(stream_class),
+                       name);
+               goto error;
+       }
+
+       writer = (struct bt_ctf_writer *)
+               bt_ctf_object_get_parent(&trace->common.base);
+       stream->last_ts_end = -1ULL;
+       BT_LOGD("CTF writer stream object belongs writer's trace: "
+               "writer-addr=%p", writer);
+       BT_ASSERT(writer);
+
+       if (stream_class->common.packet_context_field_type) {
+               BT_LOGD("Creating stream's packet context field: "
+                       "ft-addr=%p",
+                       stream_class->common.packet_context_field_type);
+               stream->packet_context = bt_ctf_field_create(
+                       (void *) stream_class->common.packet_context_field_type);
+               if (!stream->packet_context) {
+                       BT_LOGW_STR("Cannot create stream's packet context field.");
+                       goto error;
+               }
+
+               /* Initialize events_discarded */
+               ret = try_set_structure_field_integer(
+                       stream->packet_context, "events_discarded", 0);
+               if (ret < 0) {
+                       BT_LOGW("Cannot set `events_discarded` field in packet context: "
+                               "ret=%d, packet-context-field-addr=%p",
+                               ret, stream->packet_context);
+                       goto error;
+               }
+       }
+
+       stream->events = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) release_event);
+       if (!stream->events) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       if (trace->common.packet_header_field_type) {
+               BT_LOGD("Creating stream's packet header field: "
+                       "ft-addr=%p", trace->common.packet_header_field_type);
+               stream->packet_header =
+                       bt_ctf_field_create(
+                               (void *) trace->common.packet_header_field_type);
+               if (!stream->packet_header) {
+                       BT_LOGW_STR("Cannot create stream's packet header field.");
+                       goto error;
+               }
+       }
+
+       /*
+        * Attempt to populate the default trace packet header fields
+        * (magic, uuid and stream_id). This will _not_ fail shall the
+        * fields not be found or be of an incompatible type; they will
+        * simply not be populated automatically. The user will have to
+        * make sure to set the trace packet header fields himself
+        * before flushing.
+        */
+       ret = auto_populate_packet_header(stream);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically populate the stream's packet header.");
+               goto error;
+       }
+
+       /* Create file associated with this stream */
+       fd = create_stream_file(writer, stream);
+       if (fd < 0) {
+               BT_LOGW_STR("Cannot create stream file.");
+               goto error;
+       }
+
+       /* Freeze the writer */
+       BT_LOGD_STR("Freezing stream's CTF writer.");
+       bt_ctf_writer_freeze(writer);
+
+       /* Add this stream to the trace's streams */
+       g_ptr_array_add(trace->common.streams, stream);
+       stream_class->next_stream_id++;
+       BT_LOGD("Created stream object: addr=%p", stream);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
+
+end:
+       bt_ctf_object_put_ref(writer);
+       return stream;
+}
+
+struct bt_ctf_stream *bt_ctf_stream_create(
+               struct bt_ctf_stream_class *stream_class,
+               const char *name, uint64_t id_param)
+{
+       return bt_ctf_stream_create_with_id(stream_class,
+               name, id_param);
+}
+
+int bt_ctf_stream_get_discarded_events_count(
+               struct bt_ctf_stream *stream, uint64_t *count)
+{
+       int ret = 0;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!count) {
+               BT_LOGW_STR("Invalid parameter: count is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       *count = (uint64_t) stream->discarded_events;
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream,
+       uint64_t count)
+{
+       int ret = 0;
+       struct bt_ctf_field *events_discarded_field = NULL;
+
+       if (!stream->packet_context) {
+               goto end;
+       }
+
+       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "events_discarded");
+       if (!events_discarded_field) {
+               goto end;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_set_value(
+               events_discarded_field, count);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's `events_discarded` field: "
+                       "field-addr=%p, value=%" PRIu64,
+                       events_discarded_field, count);
+               goto end;
+       }
+
+end:
+       bt_ctf_object_put_ref(events_discarded_field);
+       return ret;
+}
+
+void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
+               uint64_t event_count)
+{
+       int ret;
+       uint64_t new_count;
+       struct bt_ctf_field *events_discarded_field = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               goto end;
+       }
+
+       BT_LOGV("Appending discarded events to stream: "
+               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
+               stream, bt_ctf_stream_get_name(stream), event_count);
+
+       if (!stream->packet_context) {
+               BT_LOGW_STR("Invalid parameter: stream has no packet context field.");
+               goto end;
+       }
+
+       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "events_discarded");
+       if (!events_discarded_field) {
+               BT_LOGW_STR("No field named `events_discarded` in stream's packet context.");
+               goto end;
+       }
+
+       new_count = stream->discarded_events + event_count;
+       if (new_count < stream->discarded_events) {
+               BT_LOGW("New discarded events count is less than the stream's current discarded events count: "
+                       "cur-count=%" PRIu64 ", new-count=%" PRIu64,
+                       stream->discarded_events, new_count);
+               goto end;
+       }
+
+       ret = set_packet_context_events_discarded_field(stream, new_count);
+       if (ret) {
+               /* set_packet_context_events_discarded_field() logs errors */
+               goto end;
+       }
+
+       stream->discarded_events = new_count;
+       BT_LOGV("Appended discarded events to stream: "
+               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
+               stream, bt_ctf_stream_get_name(stream), event_count);
+
+end:
+       bt_ctf_object_put_ref(events_discarded_field);
+}
+
+static int auto_populate_event_header(struct bt_ctf_stream *stream,
+               struct bt_ctf_event *event)
+{
+       int ret = 0;
+       struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
+       struct bt_ctf_clock_class *mapped_clock_class = NULL;
+       struct bt_ctf_stream_class *stream_class =
+               BT_CTF_FROM_COMMON(bt_ctf_stream_common_borrow_class(
+                       BT_CTF_TO_COMMON(stream)));
+       int64_t event_class_id;
+
+       BT_ASSERT(event);
+
+       if (!event->common.header_field) {
+               goto end;
+       }
+
+       if (event->common.frozen) {
+               BT_LOGW_STR("Cannot populate event header field: event is frozen.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Automatically populating event's header field: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), event);
+
+       id_field = bt_ctf_field_structure_get_field_by_name(
+               (void *) event->common.header_field->field, "id");
+       event_class_id = bt_ctf_event_class_common_get_id(event->common.class);
+       BT_ASSERT(event_class_id >= 0);
+
+       if (id_field && bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               ret = set_integer_field_value(id_field, event_class_id);
+               if (ret) {
+                       BT_LOGW("Cannot set event header's `id` field's value: "
+                               "addr=%p, value=%" PRIu64, id_field,
+                               event_class_id);
+                       goto end;
+               }
+       }
+
+       /*
+        * The conditions to automatically set the timestamp are:
+        *
+        * 1. The event header field "timestamp" exists and is an
+        *    integer field.
+        * 2. This stream's class has a registered clock (set with
+        *    bt_ctf_stream_class_set_clock()).
+        * 3. The "timestamp" field is not set.
+        */
+       timestamp_field = bt_ctf_field_structure_get_field_by_name(
+                       (void *) event->common.header_field->field, "timestamp");
+       if (timestamp_field && stream_class->clock &&
+                       bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER &&
+                       !bt_ctf_field_is_set_recursive(timestamp_field)) {
+               mapped_clock_class =
+                       bt_ctf_field_type_integer_get_mapped_clock_class(
+                               (void *) ((struct bt_ctf_field_common *) timestamp_field)->type);
+               if (mapped_clock_class) {
+                       uint64_t timestamp;
+
+                       BT_ASSERT(mapped_clock_class ==
+                               stream_class->clock->clock_class);
+                       ret = bt_ctf_clock_get_value(
+                               stream_class->clock,
+                               &timestamp);
+                       BT_ASSERT(ret == 0);
+                       ret = set_integer_field_value(timestamp_field,
+                                       timestamp);
+                       if (ret) {
+                               BT_LOGW("Cannot set event header's `timestamp` field's value: "
+                                       "addr=%p, value=%" PRIu64,
+                                       timestamp_field, timestamp);
+                               goto end;
+                       }
+               }
+       }
+
+       BT_LOGV("Automatically populated event's header field: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), event);
+
+end:
+       bt_ctf_object_put_ref(id_field);
+       bt_ctf_object_put_ref(timestamp_field);
+       bt_ctf_object_put_ref(mapped_clock_class);
+       return ret;
+}
+
+int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
+               struct bt_ctf_event *event)
+{
+       int ret = 0;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!event) {
+               BT_LOGW_STR("Invalid parameter: event is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Appending event to stream: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               stream, bt_ctf_stream_get_name(stream), event,
+               bt_ctf_event_class_common_get_name(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
+               bt_ctf_event_class_common_get_id(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
+
+       /*
+        * The event is not supposed to have a parent stream at this
+        * point. The only other way an event can have a parent stream
+        * is if it was assigned when setting a packet to the event,
+        * in which case the packet's stream is not a writer stream,
+        * and thus the user is trying to append an event which belongs
+        * to another stream.
+        */
+       if (event->common.base.parent) {
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_set_parent(&event->common.base, &stream->common.base);
+       BT_LOGV_STR("Automatically populating the header of the event to append.");
+       ret = auto_populate_event_header(stream, event);
+       if (ret) {
+               /* auto_populate_event_header() reports errors */
+               goto error;
+       }
+
+       /* Make sure the various scopes of the event are set */
+       BT_LOGV_STR("Validating event to append.");
+       BT_CTF_ASSERT_PRE(bt_ctf_event_common_validate(BT_CTF_TO_COMMON(event)) == 0,
+               "Invalid event: event-addr=%p", event);
+
+       /* Save the new event and freeze it */
+       BT_LOGV_STR("Freezing the event to append.");
+       bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
+       g_ptr_array_add(stream->events, event);
+
+       /*
+        * Event had to hold a reference to its event class as long as it wasn't
+        * part of the same trace hierarchy. From now on, the event and its
+        * class share the same lifetime guarantees and the reference is no
+        * longer needed.
+        */
+       BT_LOGV_STR("Putting the event's class.");
+       bt_ctf_object_put_ref(event->common.class);
+       BT_LOGV("Appended event to stream: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               stream, bt_ctf_stream_get_name(stream), event,
+               bt_ctf_event_class_common_get_name(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
+               bt_ctf_event_class_common_get_id(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
+
+end:
+       return ret;
+
+error:
+       /*
+        * Orphan the event; we were not successful in associating it to
+        * a stream.
+        */
+       bt_ctf_object_set_parent(&event->common.base, NULL);
+       return ret;
+}
+
+struct bt_ctf_field *bt_ctf_stream_get_packet_context(struct bt_ctf_stream *stream)
+{
+       struct bt_ctf_field *packet_context = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               goto end;
+       }
+
+       packet_context = stream->packet_context;
+       if (packet_context) {
+               bt_ctf_object_get_ref(packet_context);
+       }
+end:
+       return packet_context;
+}
+
+int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *field)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       if (bt_ctf_field_type_common_compare((void *) field_type,
+                       stream->common.stream_class->packet_context_field_type)) {
+               BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "packet-context-field-addr=%p, "
+                       "packet-context-ft-addr=%p",
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, field_type);
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(field_type);
+       bt_ctf_object_put_ref(stream->packet_context);
+       stream->packet_context = bt_ctf_object_get_ref(field);
+       BT_LOGV("Set stream's packet context field: "
+               "stream-addr=%p, stream-name=\"%s\", "
+               "packet-context-field-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), field);
+end:
+       return ret;
+}
+
+struct bt_ctf_field *bt_ctf_stream_get_packet_header(struct bt_ctf_stream *stream)
+{
+       struct bt_ctf_field *packet_header = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               goto end;
+       }
+
+       packet_header = stream->packet_header;
+       if (packet_header) {
+               bt_ctf_object_get_ref(packet_header);
+       }
+end:
+       return packet_header;
+}
+
+int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *field)
+{
+       int ret = 0;
+       struct bt_ctf_trace *trace = NULL;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       trace = (struct bt_ctf_trace *)
+               bt_ctf_object_get_parent(&stream->common.base);
+
+       if (!field) {
+               if (trace->common.packet_header_field_type) {
+                       BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "packet-header-field-addr=%p, "
+                               "expected-ft-addr=%p",
+                               stream, bt_ctf_stream_get_name(stream),
+                               field, trace->common.packet_header_field_type);
+                       ret = -1;
+                       goto end;
+               }
+
+               goto skip_validation;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       BT_ASSERT(field_type);
+
+       if (bt_ctf_field_type_common_compare((void *) field_type,
+                       trace->common.packet_header_field_type)) {
+               BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "packet-header-field-addr=%p, "
+                       "packet-header-ft-addr=%p",
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, field_type);
+               ret = -1;
+               goto end;
+       }
+
+skip_validation:
+       bt_ctf_object_put_ref(stream->packet_header);
+       stream->packet_header = bt_ctf_object_get_ref(field);
+       BT_LOGV("Set stream's packet header field: "
+               "stream-addr=%p, stream-name=\"%s\", "
+               "packet-header-field-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), field);
+end:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
+       bt_ctf_object_put_ref(field_type);
+       return ret;
+}
+
+static
+void reset_structure_field(struct bt_ctf_field *structure, const char *name)
+{
+       struct bt_ctf_field *member;
+
+       member = bt_ctf_field_structure_get_field_by_name(structure, name);
+       if (member) {
+               bt_ctf_field_common_reset_recursive((void *) member);
+               bt_ctf_object_put_ref(member);
+       }
+}
+
+int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       size_t i;
+       uint64_t packet_context_offset_bits = 0;
+       struct bt_ctf_trace *trace;
+       enum bt_ctf_byte_order native_byte_order;
+       bool has_packet_size = false;
+       uint64_t packet_size_bits = 0;
+       uint64_t content_size_bits = 0;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end_no_stream;
+       }
+
+       if (stream->packet_context) {
+               struct bt_ctf_field *packet_size_field;
+
+               packet_size_field = bt_ctf_field_structure_get_field_by_name(
+                               stream->packet_context, "packet_size");
+               has_packet_size = (packet_size_field != NULL);
+               bt_ctf_object_put_ref(packet_size_field);
+       }
+
+       if (stream->flushed_packet_count == 1) {
+               if (!stream->packet_context) {
+                       BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
+                       ret = -1;
+                       goto end;
+               }
+
+               if (!has_packet_size) {
+                       BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       BT_LOGV("Flushing stream's current packet: stream-addr=%p, "
+               "stream-name=\"%s\", packet-index=%u", stream,
+               bt_ctf_stream_get_name(stream), stream->flushed_packet_count);
+       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
+               stream->common.stream_class));
+       BT_ASSERT(trace);
+       native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
+
+       ret = auto_populate_packet_header(stream);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically populate the stream's packet header field.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Initialize packet/content sizes to `0`; we will overwrite later */
+       ret = auto_populate_packet_context(stream, true, 0, 0);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctfser_open_packet(&stream->ctfser);
+       if (ret) {
+               /* bt_ctfser_open_packet() logs errors */
+               ret = -1;
+               goto end;
+       }
+
+       if (stream->packet_header) {
+               BT_LOGV_STR("Serializing packet header field (initial).");
+               ret = bt_ctf_field_serialize_recursive(stream->packet_header,
+                       &stream->ctfser, native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream's packet header field: "
+                               "field-addr=%p", stream->packet_header);
+                       goto end;
+               }
+       }
+
+       if (stream->packet_context) {
+               /* Save packet context's position to overwrite it later */
+               packet_context_offset_bits =
+                       bt_ctfser_get_offset_in_current_packet_bits(
+                               &stream->ctfser);
+
+               /* Write packet context */
+               BT_LOGV_STR("Serializing packet context field (initial).");
+               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
+                       &stream->ctfser, native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream's packet context field: "
+                               "field-addr=%p", stream->packet_context);
+                       goto end;
+               }
+       }
+
+       BT_LOGV("Serializing events: count=%u", stream->events->len);
+
+       for (i = 0; i < stream->events->len; i++) {
+               struct bt_ctf_event *event = g_ptr_array_index(
+                       stream->events, i);
+               struct bt_ctf_event_class *event_class =
+                       BT_CTF_FROM_COMMON(bt_ctf_event_common_borrow_class(
+                               BT_CTF_TO_COMMON(event)));
+
+               BT_LOGV("Serializing event: index=%zu, event-addr=%p, "
+                       "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+                       "ser-offset=%" PRIu64,
+                       i, event, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class),
+                       bt_ctfser_get_offset_in_current_packet_bits(
+                               &stream->ctfser));
+
+               /* Write event header */
+               if (event->common.header_field) {
+                       BT_LOGV_STR("Serializing event's header field.");
+                       ret = bt_ctf_field_serialize_recursive(
+                               (void *) event->common.header_field->field,
+                               &stream->ctfser, native_byte_order);
+                       if (ret) {
+                               BT_LOGW("Cannot serialize event's header field: "
+                                       "field-addr=%p",
+                                       event->common.header_field->field);
+                               goto end;
+                       }
+               }
+
+               /* Write stream event context */
+               if (event->common.stream_event_context_field) {
+                       BT_LOGV_STR("Serializing event's stream event context field.");
+                       ret = bt_ctf_field_serialize_recursive(
+                               (void *) event->common.stream_event_context_field,
+                               &stream->ctfser, native_byte_order);
+                       if (ret) {
+                               BT_LOGW("Cannot serialize event's stream event context field: "
+                                       "field-addr=%p",
+                                       event->common.stream_event_context_field);
+                               goto end;
+                       }
+               }
+
+               /* Write event content */
+               ret = bt_ctf_event_serialize(event, &stream->ctfser,
+                       native_byte_order);
+               if (ret) {
+                       /* bt_ctf_event_serialize() logs errors */
+                       goto end;
+               }
+       }
+
+       content_size_bits = bt_ctfser_get_offset_in_current_packet_bits(
+               &stream->ctfser);
+
+       if (!has_packet_size && content_size_bits % 8 != 0) {
+               BT_LOGW("Stream's packet context field type has no `packet_size` field, "
+                       "but current content size is not a multiple of 8 bits: "
+                       "content-size=%" PRIu64 ", "
+                       "packet-size=%" PRIu64,
+                       content_size_bits,
+                       packet_size_bits);
+               ret = -1;
+               goto end;
+       }
+
+       /* Set packet size; make it a multiple of 8 */
+       packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7);
+
+       if (stream->packet_context) {
+               /*
+                * The whole packet is serialized at this point. Make
+                * sure that, if `packet_size` is missing, the current
+                * content size is equal to the current packet size.
+                */
+               struct bt_ctf_field *field =
+                       bt_ctf_field_structure_get_field_by_name(
+                               stream->packet_context, "content_size");
+
+               bt_ctf_object_put_ref(field);
+               if (!field) {
+                       if (content_size_bits != packet_size_bits) {
+                               BT_LOGW("Stream's packet context's `content_size` field is missing, "
+                                       "but current packet's content size is not equal to its packet size: "
+                                       "content-size=%" PRIu64 ", "
+                                       "packet-size=%" PRIu64,
+                                       bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser),
+                                       packet_size_bits);
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               /*
+                * Overwrite the packet context now that the stream
+                * position's packet and content sizes have the correct
+                * values.
+                */
+               bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
+                       packet_context_offset_bits);
+               ret = auto_populate_packet_context(stream, false,
+                       packet_size_bits, content_size_bits);
+               if (ret) {
+                       BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
+                       ret = -1;
+                       goto end;
+               }
+
+               BT_LOGV("Rewriting (serializing) packet context field.");
+               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
+                       &stream->ctfser, native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream's packet context field: "
+                               "field-addr=%p", stream->packet_context);
+                       goto end;
+               }
+       }
+
+       g_ptr_array_set_size(stream->events, 0);
+       stream->flushed_packet_count++;
+       bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8);
+
+end:
+       /* Reset automatically-set fields. */
+       if (stream->packet_context) {
+               reset_structure_field(stream->packet_context, "timestamp_begin");
+               reset_structure_field(stream->packet_context, "timestamp_end");
+               reset_structure_field(stream->packet_context, "packet_size");
+               reset_structure_field(stream->packet_context, "content_size");
+               reset_structure_field(stream->packet_context, "events_discarded");
+       }
+
+       if (ret == 0) {
+               BT_LOGV("Flushed stream's current packet: "
+                       "content-size=%" PRIu64 ", packet-size=%" PRIu64,
+                       content_size_bits, packet_size_bits);
+       }
+
+end_no_stream:
+       return ret;
+}
+
+static
+void bt_ctf_stream_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_stream *stream = (void *) obj;
+
+       BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"",
+               stream, bt_ctf_stream_get_name(stream));
+
+       bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream));
+       bt_ctfser_fini(&stream->ctfser);
+
+       if (stream->events) {
+               BT_LOGD_STR("Putting events.");
+               g_ptr_array_free(stream->events, TRUE);
+       }
+
+       BT_LOGD_STR("Putting packet header field.");
+       bt_ctf_object_put_ref(stream->packet_header);
+       BT_LOGD_STR("Putting packet context field.");
+       bt_ctf_object_put_ref(stream->packet_context);
+       g_free(stream);
+}
+
+static
+int _set_structure_field_integer(struct bt_ctf_field *structure, char *name,
+               uint64_t value, bt_bool force)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type = NULL;
+       struct bt_ctf_field *integer;
+
+       BT_ASSERT(structure);
+       BT_ASSERT(name);
+
+       integer = bt_ctf_field_structure_get_field_by_name(structure, name);
+       if (!integer) {
+               /* Field not found, not an error. */
+               BT_LOGV("Field not found: struct-field-addr=%p, "
+                       "name=\"%s\", force=%d", structure, name, force);
+               goto end;
+       }
+
+       /* Make sure the payload has not already been set. */
+       if (!force && bt_ctf_field_is_set_recursive(integer)) {
+               /* Payload already set, not an error */
+               BT_LOGV("Field's payload is already set: struct-field-addr=%p, "
+                       "name=\"%s\", force=%d", structure, name, force);
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(integer);
+       BT_ASSERT(field_type);
+       if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               /*
+                * The user most likely meant for us to populate this field
+                * automatically. However, we can only do this if the field
+                * is an integer. Return an error.
+                */
+               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
+                       "field-addr=%p, ft-addr=%p, ft-id=%s",
+                       integer, field_type,
+                       bt_ctf_field_type_id_string((int)
+                               bt_ctf_field_type_get_type_id(field_type)));
+               ret = -1;
+               goto end;
+       }
+
+       if (bt_ctf_field_type_integer_is_signed(field_type)) {
+               ret = bt_ctf_field_integer_signed_set_value(integer,
+                       (int64_t) value);
+       } else {
+               ret = bt_ctf_field_integer_unsigned_set_value(integer, value);
+       }
+       ret = !ret ? 1 : ret;
+end:
+       bt_ctf_object_put_ref(integer);
+       bt_ctf_object_put_ref(field_type);
+       return ret;
+}
+
+/*
+ * Returns the following codes:
+ * 1 if the field was found and set,
+ * 0 if nothing was done (field not found, or was already set),
+ * <0 if an error was encoutered
+ */
+static
+int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name,
+               uint64_t value)
+{
+       return _set_structure_field_integer(structure, name, value, BT_FALSE);
+}
+
+struct bt_ctf_stream_class *bt_ctf_stream_get_class(
+               struct bt_ctf_stream *stream)
+{
+       return bt_ctf_object_get_ref(bt_ctf_stream_common_borrow_class(BT_CTF_TO_COMMON(stream)));
+}
+
+const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
+{
+       return bt_ctf_stream_common_get_name(BT_CTF_TO_COMMON(stream));
+}
+
+int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream)
+{
+       return bt_ctf_stream_common_get_id(BT_CTF_TO_COMMON(stream));
+}
diff --git a/ctf-writer/trace.c b/ctf-writer/trace.c
new file mode 100644 (file)
index 0000000..8737470
--- /dev/null
@@ -0,0 +1,1883 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * 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 "CTF-WRITER-TRACE"
+#include "logging.h"
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/attributes-internal.h>
+#include <babeltrace2/ctf-writer/clock-class-internal.h>
+#include <babeltrace2/ctf-writer/clock-internal.h>
+#include <babeltrace2/ctf-writer/event-class-internal.h>
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/event-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
+#include <babeltrace2/ctf-writer/functor-internal.h>
+#include <babeltrace2/ctf-writer/stream-class-internal.h>
+#include <babeltrace2/ctf-writer/stream-internal.h>
+#include <babeltrace2/ctf-writer/trace-internal.h>
+#include <babeltrace2/ctf-writer/utils-internal.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/validation-internal.h>
+#include <babeltrace2/ctf-writer/visitor-internal.h>
+#include <babeltrace2/ctf-writer/writer-internal.h>
+#include <babeltrace2/endian-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DEFAULT_IDENTIFIER_SIZE                128
+#define DEFAULT_METADATA_STRING_SIZE   4096
+
+BT_HIDDEN
+int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace,
+               bt_ctf_object_release_func release_func)
+{
+       int ret = 0;
+
+       BT_LOGD_STR("Initializing common trace object.");
+       trace->native_byte_order = BT_CTF_BYTE_ORDER_UNSPECIFIED;
+       bt_ctf_object_init_shared_with_parent(&trace->base, release_func);
+       trace->clock_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       if (!trace->clock_classes) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       trace->streams = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_ctf_object_try_spec_release);
+       if (!trace->streams) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       trace->stream_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_ctf_object_try_spec_release);
+       if (!trace->stream_classes) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       /* Create the environment array object */
+       trace->environment = bt_ctf_attributes_create();
+       if (!trace->environment) {
+               BT_LOGE_STR("Cannot create empty attributes object.");
+               goto error;
+       }
+
+       BT_LOGD("Initialized common trace object: addr=%p", trace);
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace)
+{
+       BT_LOGD("Finalizing common trace object: addr=%p, name=\"%s\"",
+               trace, bt_ctf_trace_common_get_name(trace));
+
+       if (trace->environment) {
+               BT_LOGD_STR("Destroying environment attributes.");
+               bt_ctf_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_ctf_object_put_ref(trace->packet_header_field_type);
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *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_ctf_trace_common_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_HIDDEN
+int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace,
+               const unsigned char *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_ctf_trace_common_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_ctf_trace_common_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_HIDDEN
+int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace,
+               const char *name, struct bt_ctf_private_value *value)
+{
+       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 (!value) {
+               BT_LOGW_STR("Invalid parameter: value is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_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_ctf_trace_common_get_name(trace), name);
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_value_is_integer(bt_ctf_private_value_as_value(value)) &&
+                       !bt_ctf_value_is_string(bt_ctf_private_value_as_value(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_ctf_trace_common_get_name(trace), name,
+                       bt_ctf_value_type_string(
+                               bt_ctf_value_get_type(
+                                       bt_ctf_private_value_as_value(value))));
+               ret = -1;
+               goto end;
+       }
+
+       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_ctf_private_value *attribute =
+                       bt_ctf_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_ctf_trace_common_get_name(trace), name);
+                       ret = -1;
+                       goto end;
+               }
+
+               bt_ctf_value_freeze(bt_ctf_private_value_as_value(value));
+       }
+
+       ret = bt_ctf_attributes_set_field_value(trace->environment, name,
+               value);
+       if (ret) {
+               BT_LOGE("Cannot set environment field's value: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "env-name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace), name);
+       } else {
+               BT_LOGV("Set environment field's value: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "env-name=\"%s\", value-addr=%p",
+                       trace, bt_ctf_trace_common_get_name(trace), name, value);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace,
+               const char *name, const char *value)
+{
+       int ret = 0;
+       struct bt_ctf_private_value *env_value_string_obj = NULL;
+
+       if (!value) {
+               BT_LOGW_STR("Invalid parameter: value is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       env_value_string_obj = bt_ctf_private_value_string_create_init(value);
+       if (!env_value_string_obj) {
+               BT_LOGE_STR("Cannot create string value object.");
+               ret = -1;
+               goto end;
+       }
+
+       /* bt_ctf_trace_common_set_environment_field() logs errors */
+       ret = bt_ctf_trace_common_set_environment_field(trace, name,
+               env_value_string_obj);
+
+end:
+       bt_ctf_object_put_ref(env_value_string_obj);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field_integer(
+               struct bt_ctf_trace_common *trace, const char *name, int64_t value)
+{
+       int ret = 0;
+       struct bt_ctf_private_value *env_value_integer_obj = NULL;
+
+       env_value_integer_obj = bt_ctf_private_value_integer_create_init(value);
+       if (!env_value_integer_obj) {
+               BT_LOGE_STR("Cannot create integer value object.");
+               ret = -1;
+               goto end;
+       }
+
+       /* bt_ctf_trace_common_set_environment_field() logs errors */
+       ret = bt_ctf_trace_common_set_environment_field(trace, name,
+               env_value_integer_obj);
+
+end:
+       bt_ctf_object_put_ref(env_value_integer_obj);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_clock_class *clock_class)
+{
+       int ret = 0;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_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_ctf_trace_common_get_name(trace),
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       /* Check for duplicate clock classes */
+       if (bt_ctf_trace_common_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_ctf_trace_common_get_name(trace),
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_get_ref(clock_class);
+       g_ptr_array_add(trace->clock_classes, clock_class);
+
+       if (trace->frozen) {
+               BT_LOGV_STR("Freezing added clock class because trace is frozen.");
+               bt_ctf_clock_class_freeze(clock_class);
+       }
+
+       BT_LOGV("Added clock class to trace: "
+               "trace-addr=%p, trace-name=\"%s\", "
+               "clock-class-addr=%p, clock-class-name=\"%s\"",
+               trace, bt_ctf_trace_common_get_name(trace),
+               clock_class, bt_ctf_clock_class_get_name(clock_class));
+
+end:
+       return ret;
+}
+
+static
+bool packet_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_field_type_common *packet_header_type)
+{
+       int ret;
+       bool is_valid = true;
+       struct bt_ctf_field_type_common *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;
+               }
+
+               /* No packet header field type: valid at this point */
+               goto end;
+       }
+
+       /* Packet header field type, if it exists, must be a structure */
+       if (packet_header_type->id != BT_CTF_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_ctf_field_type_id_string(packet_header_type->id));
+               goto invalid;
+       }
+
+       /*
+        * 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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_header_type, "magic");
+       if (field_type) {
+               const char *field_name;
+
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_field_type_common_integer_get_size(field_type));
+                       goto invalid;
+               }
+
+               ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                       packet_header_type, &field_name, NULL, 0);
+               BT_ASSERT(ret == 0);
+
+               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;
+               }
+       }
+
+       /*
+        * 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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_header_type, "uuid");
+       if (field_type) {
+               struct bt_ctf_field_type_common *elem_ft;
+
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_field_type_common_array_get_length(field_type));
+                       goto invalid;
+               }
+
+               elem_ft = bt_ctf_field_type_common_array_borrow_element_field_type(field_type);
+               BT_ASSERT(elem_ft);
+
+               if (elem_ft->id != BT_CTF_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_ctf_field_type_id_string(elem_ft->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_field_type_common_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_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_header_type, "packet_seq_num");
+       if (field_type) {
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *packet_context_type,
+               bool check_ts_begin_end_mapped)
+{
+       bool is_valid = true;
+       struct bt_ctf_field_type_common *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_CTF_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_ctf_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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "packet_size");
+       if (field_type) {
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "content_size");
+       if (field_type) {
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "events_discarded");
+       if (field_type) {
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "timestamp_begin");
+       if (field_type) {
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_clock_class *clock_class =
+                               bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "timestamp_end");
+       if (field_type) {
+               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_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_ctf_clock_class *clock_class =
+                               bt_ctf_field_type_common_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_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *event_header_type)
+{
+       bool is_valid = true;
+       struct bt_ctf_field_type_common *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_ctf_stream_class_common_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_CTF_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_ctf_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_ctf_field_type_common_structure_borrow_field_type_by_name(
+               event_header_type, "id");
+       if (field_type) {
+               struct bt_ctf_field_type_common *int_ft;
+
+               if (field_type->id == BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       int_ft = field_type;
+               } else if (field_type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
+                       int_ft = bt_ctf_field_type_common_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_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               BT_ASSERT(int_ft);
+               if (bt_ctf_field_type_common_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_ctf_trace_common *trace)
+{
+       int ret = 0;
+
+       if (trace->packet_header_field_type) {
+               struct bt_ctf_clock_class *clock_class = NULL;
+
+               ret = bt_ctf_field_type_common_validate_single_clock_class(
+                       trace->packet_header_field_type,
+                       &clock_class);
+               bt_ctf_object_put_ref(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_ctf_trace_common_get_name(trace),
+                               clock_class ?
+                                       bt_ctf_clock_class_get_name(clock_class) :
+                                       NULL);
+                       ret = -1;
+               }
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func,
+               struct bt_ctf_clock_class *init_expected_clock_class,
+               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
+                       struct bt_ctf_field_type_common *packet_context_field_type,
+                       struct bt_ctf_field_type_common *event_header_field_type),
+               bool check_ts_begin_end_mapped)
+{
+       int ret;
+       int64_t i;
+       int64_t stream_id;
+       struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
+       struct bt_ctf_validation_output *ec_validation_outputs = NULL;
+       const enum bt_ctf_validation_flag trace_sc_validation_flags =
+               BT_CTF_VALIDATION_FLAG_TRACE |
+               BT_CTF_VALIDATION_FLAG_STREAM;
+       const enum bt_ctf_validation_flag ec_validation_flags =
+               BT_CTF_VALIDATION_FLAG_EVENT;
+       struct bt_ctf_field_type_common *packet_header_type = NULL;
+       struct bt_ctf_field_type_common *packet_context_type = NULL;
+       struct bt_ctf_field_type_common *event_header_type = NULL;
+       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
+       int64_t event_class_count;
+       struct bt_ctf_trace_common *current_parent_trace = NULL;
+       struct bt_ctf_clock_class *expected_clock_class =
+               bt_ctf_object_get_ref(init_expected_clock_class);
+
+       BT_ASSERT(copy_field_type_func);
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               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_ctf_trace_common_get_name(trace),
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+
+       current_parent_trace = bt_ctf_stream_class_common_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_ctf_trace_common_get_name(current_parent_trace));
+               ret = -1;
+               goto end;
+       }
+
+       event_class_count =
+               bt_ctf_stream_class_common_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_ctf_stream_class_common_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_ctf_stream_class_common_validate_single_clock_class()
+                * succeeds below, the call to
+                * bt_ctf_stream_class_map_clock_class() at the end of this
+                * function is safe because it maps to the same, single
+                * clock class.
+                */
+               ret = bt_ctf_stream_class_common_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_ctf_stream_class_common_get_id(stream_class),
+                               bt_ctf_stream_class_common_get_name(stream_class),
+                               expected_clock_class,
+                               expected_clock_class ?
+                                       bt_ctf_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_ctf_trace_common_borrow_packet_header_field_type(trace);
+       packet_context_type =
+               bt_ctf_stream_class_common_borrow_packet_context_field_type(stream_class);
+       event_header_type =
+               bt_ctf_stream_class_common_borrow_event_header_field_type(stream_class);
+       stream_event_ctx_type =
+               bt_ctf_stream_class_common_borrow_event_context_field_type(stream_class);
+
+       BT_LOGD("Validating trace and stream class field types.");
+       ret = bt_ctf_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, 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 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_ctf_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_ctf_event_class_common *event_class =
+                       bt_ctf_stream_class_common_borrow_event_class_by_index(
+                               stream_class, i);
+               struct bt_ctf_field_type_common *event_context_type = NULL;
+               struct bt_ctf_field_type_common *event_payload_type = NULL;
+
+               event_context_type =
+                       bt_ctf_event_class_common_borrow_context_field_type(
+                               event_class);
+               event_payload_type =
+                       bt_ctf_event_class_common_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_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+               ret = bt_ctf_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, copy_field_type_func);
+
+               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_ctf_stream_class_common_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_ctf_stream_class_common_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_ctf_stream_class_common_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,
+                       check_ts_begin_end_mapped)) {
+               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;
+       }
+
+       /*
+        * Now is the time to automatically map specific field types of
+        * the stream class's packet context and event header field
+        * types to the stream class's clock's class if they are not
+        * mapped to a clock class yet. We do it here because we know
+        * that after this point, everything is frozen so it won't be
+        * possible for the user to modify the stream class's clock, or
+        * to map those field types to other clock classes.
+        */
+       if (map_clock_classes_func) {
+               if (map_clock_classes_func(stream_class,
+                               trace_sc_validation_output.packet_context_type,
+                               trace_sc_validation_output.event_header_type)) {
+                       /* map_clock_classes_func() logs errors */
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       bt_ctf_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_ctf_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_ctf_validation_replace_types().
+        */
+       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
+
+       for (i = 0; i < event_class_count; i++) {
+               struct bt_ctf_event_class_common *event_class =
+                       bt_ctf_stream_class_common_borrow_event_class_by_index(
+                               stream_class, i);
+
+               bt_ctf_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_ctf_validation_replace_types().
+                */
+               bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
+       }
+
+       /*
+        * Freeze the trace and the stream class.
+        */
+       bt_ctf_stream_class_common_freeze(stream_class);
+       bt_ctf_trace_common_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_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
+       }
+
+       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_ctf_trace_common_get_name(trace),
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+
+end:
+       if (ret) {
+               bt_ctf_object_set_parent(&stream_class->base, NULL);
+
+               if (ec_validation_outputs) {
+                       for (i = 0; i < event_class_count; i++) {
+                               bt_ctf_validation_output_put_types(
+                                       &ec_validation_outputs[i]);
+                       }
+               }
+       }
+
+       g_free(ec_validation_outputs);
+       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
+       bt_ctf_object_put_ref(expected_clock_class);
+       return ret;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_clock_class *clock_class)
+{
+       struct bt_ctf_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;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
+               enum bt_ctf_byte_order byte_order, bool allow_unspecified)
+{
+       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_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) {
+               BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
+               BT_LOGW("Invalid parameter: invalid byte order: "
+                       "addr=%p, name=\"%s\", bo=%s",
+                       trace, bt_ctf_trace_common_get_name(trace),
+                       bt_ctf_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_ctf_trace_common_get_name(trace),
+               bt_ctf_byte_order_string(byte_order));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_field_type_common *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_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       /* packet_header_type must be a structure. */
+       if (packet_header_type &&
+                       packet_header_type->id != BT_CTF_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_ctf_trace_common_get_name(trace),
+                       packet_header_type,
+                       bt_ctf_field_type_id_string(packet_header_type->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(trace->packet_header_field_type);
+       trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type);
+       BT_LOGV("Set trace's packet header field type: "
+               "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
+               trace, bt_ctf_trace_common_get_name(trace), packet_header_type);
+end:
+       return ret;
+}
+
+static
+int64_t get_stream_class_count(void *element)
+{
+       return bt_ctf_trace_get_stream_class_count(
+                       (struct bt_ctf_trace *) element);
+}
+
+static
+void *get_stream_class(void *element, int i)
+{
+       return bt_ctf_trace_get_stream_class_by_index(
+                       (struct bt_ctf_trace *) element, i);
+}
+
+static
+int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
+{
+       return bt_ctf_stream_class_visit(object, visitor, data);
+}
+
+int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
+               bt_ctf_visitor visitor, void *data)
+{
+       int ret;
+       struct bt_ctf_visitor_object obj = {
+               .object = trace,
+               .type = BT_CTF_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_ctf_trace_get_name(trace));
+       ret = bt_ctf_visitor_helper(&obj, get_stream_class_count,
+                       get_stream_class, visit_stream_class, visitor, data);
+end:
+       return ret;
+}
+
+static
+void bt_ctf_trace_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_trace *trace = (void *) obj;
+
+       BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"",
+               trace, bt_ctf_trace_get_name(trace));
+       bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace));
+       g_free(trace);
+}
+
+BT_HIDDEN
+struct bt_ctf_trace *bt_ctf_trace_create(void)
+{
+       struct bt_ctf_trace *trace = NULL;
+       int ret;
+
+       BT_LOGD_STR("Creating CTF writer trace object.");
+       trace = g_new0(struct bt_ctf_trace, 1);
+       if (!trace) {
+               BT_LOGE_STR("Failed to allocate one CTF writer trace.");
+               goto error;
+       }
+
+       ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace),
+               bt_ctf_trace_destroy);
+       if (ret) {
+               /* bt_ctf_trace_common_initialize() logs errors */
+               goto error;
+       }
+
+       BT_LOGD("Created CTF writer trace object: addr=%p", trace);
+       return trace;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
+       return trace;
+}
+
+const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace));
+}
+
+int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace,
+               const unsigned char *uuid)
+{
+       return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid);
+}
+
+int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
+               const char *name, const char *value)
+{
+       return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace),
+               name, value);
+}
+
+int bt_ctf_trace_set_environment_field_integer(
+               struct bt_ctf_trace *trace, const char *name, int64_t value)
+{
+       return bt_ctf_trace_common_set_environment_field_integer(
+               BT_CTF_TO_COMMON(trace), name, value);
+}
+
+int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace));
+}
+
+const char *
+bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
+               uint64_t index)
+{
+       return bt_ctf_trace_common_get_environment_field_name_by_index(
+               BT_CTF_TO_COMMON(trace), index);
+}
+
+struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name(
+               struct bt_ctf_trace *trace, const char *name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name(
+               BT_CTF_TO_COMMON(trace), name));
+}
+
+BT_HIDDEN
+int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
+               struct bt_ctf_clock_class *clock_class)
+{
+       return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace),
+               (void *) clock_class);
+}
+
+BT_HIDDEN
+int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace));
+}
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+static
+int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type)
+{
+       int ret = bt_ctf_stream_class_map_clock_class(
+               BT_CTF_FROM_COMMON(stream_class),
+               BT_CTF_FROM_COMMON(packet_context_type),
+               BT_CTF_FROM_COMMON(event_header_type));
+
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
+       }
+
+       return ret;
+}
+
+int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
+               struct bt_ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct bt_ctf_clock_class *expected_clock_class = NULL;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->clock) {
+               struct bt_ctf_clock_class *stream_clock_class =
+                       stream_class->clock->clock_class;
+
+               /*
+                * Make sure this clock was also added to the
+                * trace (potentially through its CTF writer
+                * owner).
+                */
+               size_t i;
+
+               for (i = 0; i < trace->common.clock_classes->len; i++) {
+                       if (trace->common.clock_classes->pdata[i] ==
+                                       stream_clock_class) {
+                               /* Found! */
+                               break;
+                       }
+               }
+
+               if (i == trace->common.clock_classes->len) {
+                       /* Not found */
+                       BT_LOGW("Stream class's clock's class is not part of the trace: "
+                               "clock-class-addr=%p, clock-class-name=\"%s\"",
+                               stream_clock_class,
+                               bt_ctf_clock_class_get_name(stream_clock_class));
+                       ret = -1;
+                       goto end;
+               }
+
+               if (stream_class->common.clock_class &&
+                               stream_class->common.clock_class !=
+                               stream_class->clock->clock_class) {
+                       /*
+                        * Stream class already has an expected clock
+                        * class, but it does not match its clock's
+                        * class.
+                        */
+                       BT_LOGW("Invalid parameter: stream class's clock's "
+                               "class does not match 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_ctf_stream_class_get_id(stream_class),
+                               bt_ctf_stream_class_get_name(stream_class),
+                               stream_class->common.clock_class,
+                               bt_ctf_clock_class_get_name(stream_class->common.clock_class));
+               } else if (!stream_class->common.clock_class) {
+                       /*
+                        * Set expected clock class to stream class's
+                        * clock's class.
+                        */
+                       expected_clock_class = stream_class->clock->clock_class;
+               }
+       }
+
+
+       ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace),
+               BT_CTF_TO_COMMON(stream_class),
+               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy,
+               expected_clock_class, map_clock_classes_func,
+               false);
+
+end:
+       return ret;
+}
+
+int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace));
+}
+
+struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace));
+}
+
+struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
+               struct bt_ctf_trace *trace, uint64_t id)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id(
+               BT_CTF_TO_COMMON(trace), id));
+}
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
+               struct bt_ctf_trace *trace, const char *name)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace),
+                       name));
+}
+
+static
+int append_trace_metadata(struct bt_ctf_trace *trace,
+               struct metadata_context *context)
+{
+       unsigned char *uuid = trace->common.uuid;
+       int ret = 0;
+
+       if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE ||
+                       trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) {
+               BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; "
+                       "set it with bt_ctf_trace_set_native_byte_order(): "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       g_string_append(context->string, "trace {\n");
+       g_string_append(context->string, "\tmajor = 1;\n");
+       g_string_append(context->string, "\tminor = 8;\n");
+       BT_ASSERT(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
+               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
+               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
+
+       if (trace->common.uuid_set) {
+               g_string_append_printf(context->string,
+                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
+                       uuid[0], uuid[1], uuid[2], uuid[3],
+                       uuid[4], uuid[5], uuid[6], uuid[7],
+                       uuid[8], uuid[9], uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+       }
+
+       g_string_append_printf(context->string, "\tbyte_order = %s;\n",
+               bt_ctf_get_byte_order_string(trace->common.native_byte_order));
+
+       if (trace->common.packet_header_field_type) {
+               g_string_append(context->string, "\tpacket.header := ");
+               context->current_indentation_level++;
+               g_string_assign(context->field_name, "");
+               BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) trace->common.packet_header_field_type,
+                       context);
+               if (ret) {
+                       goto end;
+               }
+               context->current_indentation_level--;
+       }
+
+       g_string_append(context->string, ";\n};\n\n");
+end:
+       return ret;
+}
+
+static
+void append_env_metadata(struct bt_ctf_trace *trace,
+               struct metadata_context *context)
+{
+       int64_t i;
+       int64_t env_size;
+
+       env_size = bt_ctf_attributes_get_count(trace->common.environment);
+       if (env_size <= 0) {
+               return;
+       }
+
+       g_string_append(context->string, "env {\n");
+
+       for (i = 0; i < env_size; i++) {
+               struct bt_ctf_private_value *env_field_value_obj = NULL;
+               const char *entry_name;
+
+               entry_name = bt_ctf_attributes_get_field_name(
+                       trace->common.environment, i);
+               env_field_value_obj = bt_ctf_attributes_borrow_field_value(
+                       trace->common.environment, i);
+
+               BT_ASSERT(entry_name);
+               BT_ASSERT(env_field_value_obj);
+
+               switch (bt_ctf_value_get_type(
+                       bt_ctf_private_value_as_value(env_field_value_obj))) {
+               case BT_CTF_VALUE_TYPE_INTEGER:
+               {
+                       int64_t int_value;
+
+                       int_value = bt_ctf_value_integer_get(
+                               bt_ctf_private_value_as_value(
+                                       env_field_value_obj));
+                       g_string_append_printf(context->string,
+                               "\t%s = %" PRId64 ";\n", entry_name,
+                               int_value);
+                       break;
+               }
+               case BT_CTF_VALUE_TYPE_STRING:
+               {
+                       const char *str_value;
+                       char *escaped_str = NULL;
+
+                       str_value = bt_ctf_value_string_get(
+                               bt_ctf_private_value_as_value(
+                                       env_field_value_obj));
+                       escaped_str = g_strescape(str_value, NULL);
+                       if (!escaped_str) {
+                               BT_LOGE("Cannot escape string: string=\"%s\"",
+                                       str_value);
+                               continue;
+                       }
+
+                       g_string_append_printf(context->string,
+                               "\t%s = \"%s\";\n", entry_name, escaped_str);
+                       free(escaped_str);
+                       break;
+               }
+               default:
+                       continue;
+               }
+       }
+
+       g_string_append(context->string, "};\n\n");
+}
+
+char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
+{
+       char *metadata = NULL;
+       struct metadata_context *context = NULL;
+       int err = 0;
+       size_t i;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               goto end;
+       }
+
+       context = g_new0(struct metadata_context, 1);
+       if (!context) {
+               BT_LOGE_STR("Failed to allocate one metadata context.");
+               goto end;
+       }
+
+       context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
+       context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
+       g_string_append(context->string, "/* CTF 1.8 */\n\n");
+       if (append_trace_metadata(trace, context)) {
+               /* append_trace_metadata() logs errors */
+               goto error;
+       }
+       append_env_metadata(trace, context);
+       g_ptr_array_foreach(trace->common.clock_classes,
+               (GFunc) bt_ctf_clock_class_serialize, context);
+
+       for (i = 0; i < trace->common.stream_classes->len; i++) {
+               /* bt_ctf_stream_class_serialize() logs details */
+               err = bt_ctf_stream_class_serialize(
+                       trace->common.stream_classes->pdata[i], context);
+               if (err) {
+                       /* bt_ctf_stream_class_serialize() logs errors */
+                       goto error;
+               }
+       }
+
+       metadata = context->string->str;
+
+error:
+       g_string_free(context->string, err ? TRUE : FALSE);
+       g_string_free(context->field_name, TRUE);
+       g_free(context);
+
+end:
+       return metadata;
+}
+
+enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
+               struct bt_ctf_trace *trace)
+{
+       return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace));
+}
+
+int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
+               enum bt_ctf_byte_order byte_order)
+{
+       return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace),
+               (int) byte_order, false);
+}
+
+struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type(
+               struct bt_ctf_trace *trace)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type(
+               BT_CTF_TO_COMMON(trace)));
+}
+
+int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace,
+               struct bt_ctf_field_type *packet_header_type)
+{
+       return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace),
+               (void *) packet_header_type);
+}
+
+const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace));
+}
diff --git a/ctf-writer/utils.c b/ctf-writer/utils.c
new file mode 100644 (file)
index 0000000..fdf0a93
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * utils.c
+ *
+ * Babeltrace CTF writer - 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.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-UTILS"
+#include "logging.h"
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/ctf-writer/clock-class-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <glib.h>
+#include <stdlib.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_ctf_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/ctf-writer/validation.c b/ctf-writer/validation.c
new file mode 100644 (file)
index 0000000..9c4276e
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * validation.c
+ *
+ * Babeltrace - CTF writer: 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 "CTF-WRITER-VALIDATION"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+#include <babeltrace2/babeltrace-internal.h>
+#include <babeltrace2/ctf-writer/event-class-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/resolve-internal.h>
+#include <babeltrace2/ctf-writer/stream-class-internal.h>
+#include <babeltrace2/ctf-writer/trace-internal.h>
+#include <babeltrace2/ctf-writer/validation-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/values-internal.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_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *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_ctf_resolve_types(environment, packet_header_type,
+               packet_context_type, event_header_type, stream_event_ctx_type,
+               event_context_type, event_payload_type,
+               BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT |
+               BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *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_ctf_resolve_types(environment, packet_header_type,
+               packet_context_type, event_header_type, stream_event_ctx_type,
+               NULL, NULL,
+               BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT |
+               BT_CTF_RESOLVE_FLAG_EVENT_HEADER |
+               BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *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_ctf_resolve_types(environment, packet_header_type,
+               NULL, NULL, NULL, NULL, NULL,
+               BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common *type)
+{
+       int ret = 0;
+       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
+
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               ret = 1;
+               goto end;
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               int i;
+               int field_count = bt_ctf_field_type_common_get_field_count(type);
+
+               if (field_count < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               for (i = 0; i < field_count; ++i) {
+                       struct bt_ctf_field_type_common *child_type =
+                               bt_ctf_field_type_common_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_ctf_validate_class_types(struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *event_payload_type,
+               int trace_valid, int stream_class_valid, int event_class_valid,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag validate_flags,
+               bt_ctf_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_CTF_VALIDATION_FLAG_TRACE;
+       }
+
+       if (stream_class_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
+       }
+
+       if (event_class_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
+       }
+
+       /* Own the type parameters */
+       bt_ctf_object_get_ref(packet_header_type);
+       bt_ctf_object_get_ref(packet_context_type);
+       bt_ctf_object_get_ref(event_header_type);
+       bt_ctf_object_get_ref(stream_event_ctx_type);
+       bt_ctf_object_get_ref(event_context_type);
+       bt_ctf_object_get_ref(event_payload_type);
+
+       /* Validate trace */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) {
+               struct bt_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common_freeze(packet_header_type_copy);
+               }
+
+skip_packet_header_type_copy:
+               /* Put original reference and move copy */
+               BT_CTF_OBJECT_MOVE_REF(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_CTF_VALIDATION_FLAG_TRACE;
+               }
+       }
+
+       /* Validate stream class */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) &&
+                       !stream_class_valid) {
+               struct bt_ctf_field_type_common *packet_context_type_copy = NULL;
+               struct bt_ctf_field_type_common *event_header_type_copy = NULL;
+               struct bt_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common_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_ctf_object_get_ref(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_ctf_field_type_common_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_ctf_object_get_ref(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_ctf_field_type_common_freeze(stream_event_ctx_type_copy);
+               }
+
+skip_stream_event_ctx_type_copy:
+               /* Put original references and move copies */
+               BT_CTF_OBJECT_MOVE_REF(packet_context_type, packet_context_type_copy);
+               BT_CTF_OBJECT_MOVE_REF(event_header_type, event_header_type_copy);
+               BT_CTF_OBJECT_MOVE_REF(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_CTF_VALIDATION_FLAG_STREAM;
+               }
+
+               goto sc_validation_done;
+
+sc_validation_error:
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type_copy);
+               ret = -1;
+               goto error;
+       }
+
+sc_validation_done:
+       /* Validate event class */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) &&
+                       !event_class_valid) {
+               struct bt_ctf_field_type_common *event_context_type_copy = NULL;
+               struct bt_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common_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_ctf_object_get_ref(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_ctf_field_type_common_freeze(event_payload_type_copy);
+               }
+
+skip_event_payload_type_copy:
+               /* Put original references and move copies */
+               BT_CTF_OBJECT_MOVE_REF(event_context_type, event_context_type_copy);
+               BT_CTF_OBJECT_MOVE_REF(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_CTF_VALIDATION_FLAG_EVENT;
+               }
+
+               goto ec_validation_done;
+
+ec_validation_error:
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(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_CTF_OBJECT_MOVE_REF(output->packet_header_type, packet_header_type);
+       BT_CTF_OBJECT_MOVE_REF(output->packet_context_type, packet_context_type);
+       BT_CTF_OBJECT_MOVE_REF(output->event_header_type, event_header_type);
+       BT_CTF_OBJECT_MOVE_REF(output->stream_event_ctx_type, stream_event_ctx_type);
+       BT_CTF_OBJECT_MOVE_REF(output->event_context_type, event_context_type);
+       BT_CTF_OBJECT_MOVE_REF(output->event_payload_type, event_payload_type);
+       return ret;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type);
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag replace_flags)
+{
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) {
+               bt_ctf_field_type_common_freeze(trace->packet_header_field_type);
+               BT_CTF_OBJECT_MOVE_REF(trace->packet_header_field_type,
+                       output->packet_header_type);
+       }
+
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) {
+               bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
+               bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
+               bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
+               BT_CTF_OBJECT_MOVE_REF(stream_class->packet_context_field_type,
+                       output->packet_context_type);
+               BT_CTF_OBJECT_MOVE_REF(stream_class->event_header_field_type,
+                       output->event_header_type);
+               BT_CTF_OBJECT_MOVE_REF(stream_class->event_context_field_type,
+                       output->stream_event_ctx_type);
+       }
+
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) {
+               bt_ctf_field_type_common_freeze(event_class->context_field_type);
+               bt_ctf_field_type_common_freeze(event_class->payload_field_type);
+               BT_CTF_OBJECT_MOVE_REF(event_class->context_field_type, output->event_context_type);
+               BT_CTF_OBJECT_MOVE_REF(event_class->payload_field_type, output->event_payload_type);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_validation_output_put_types(
+               struct bt_ctf_validation_output *output)
+{
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->stream_event_ctx_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_payload_type);
+}
diff --git a/ctf-writer/values.c b/ctf-writer/values.c
new file mode 100644 (file)
index 0000000..dd8ae94
--- /dev/null
@@ -0,0 +1,1344 @@
+/*
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 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 "CTF-WRITER-VALUES"
+#include "logging.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <inttypes.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/common-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <babeltrace2/compat/glib-internal.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/ctf-writer/object-internal.h>
+#include <babeltrace2/ctf-writer/values-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
+
+#define BT_CTF_VALUE_FROM_CONCRETE(_concrete) ((struct bt_ctf_value *) (_concrete))
+#define BT_CTF_VALUE_TO_BOOL(_base) ((struct bt_ctf_value_bool *) (_base))
+#define BT_CTF_VALUE_TO_INTEGER(_base) ((struct bt_ctf_value_integer *) (_base))
+#define BT_CTF_VALUE_TO_REAL(_base) ((struct bt_ctf_value_real *) (_base))
+#define BT_CTF_VALUE_TO_STRING(_base) ((struct bt_ctf_value_string *) (_base))
+#define BT_CTF_VALUE_TO_ARRAY(_base) ((struct bt_ctf_value_array *) (_base))
+#define BT_CTF_VALUE_TO_MAP(_base) ((struct bt_ctf_value_map *) (_base))
+
+#define BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(_value, _type)                 \
+       BT_CTF_ASSERT_PRE(((struct bt_ctf_value *) (_value))->type == (_type),  \
+               "Value has the wrong type ID: expected-type=%d", (_type))
+
+#define BT_CTF_ASSERT_PRE_VALUE_HOT(_value, _name)                             \
+       BT_CTF_ASSERT_PRE_HOT(((struct bt_ctf_value *) (_value)), (_name), "")
+
+#define BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count)                \
+       BT_CTF_ASSERT_PRE((_index) < (_count),                          \
+               "Index is out of bound: "                               \
+               "index=%" PRIu64 ", count=%u", (_index), (_count));
+
+struct bt_ctf_value {
+       struct bt_ctf_object base;
+       enum bt_ctf_value_type type;
+       bt_bool frozen;
+};
+
+static
+void bt_ctf_value_null_instance_release_func(struct bt_ctf_object *obj)
+{
+       BT_LOGW("Releasing the null value singleton: addr=%p", obj);
+}
+
+static
+struct bt_ctf_value bt_ctf_value_null_instance = {
+       .base = {
+               .is_shared = true,
+               .ref_count = 1,
+               .release_func = bt_ctf_value_null_instance_release_func,
+               .spec_release_func = NULL,
+               .parent_is_owner_listener_func = NULL,
+               .parent = NULL,
+       },
+       .type = BT_CTF_VALUE_TYPE_NULL,
+       .frozen = BT_TRUE,
+};
+
+struct bt_ctf_value *const bt_ctf_value_null = &bt_ctf_value_null_instance;
+struct bt_ctf_private_value *const bt_ctf_private_value_null =
+       (void *) &bt_ctf_value_null_instance;
+
+struct bt_ctf_value_bool {
+       struct bt_ctf_value base;
+       bt_bool value;
+};
+
+struct bt_ctf_value_integer {
+       struct bt_ctf_value base;
+       int64_t value;
+};
+
+struct bt_ctf_value_real {
+       struct bt_ctf_value base;
+       double value;
+};
+
+struct bt_ctf_value_string {
+       struct bt_ctf_value base;
+       GString *gstr;
+};
+
+struct bt_ctf_value_array {
+       struct bt_ctf_value base;
+       GPtrArray *garray;
+};
+
+struct bt_ctf_value_map {
+       struct bt_ctf_value base;
+       GHashTable *ght;
+};
+
+static
+void bt_ctf_value_destroy(struct bt_ctf_object *obj);
+
+static
+void bt_ctf_value_string_destroy(struct bt_ctf_value *object)
+{
+       g_string_free(BT_CTF_VALUE_TO_STRING(object)->gstr, TRUE);
+       BT_CTF_VALUE_TO_STRING(object)->gstr = NULL;
+}
+
+static
+void bt_ctf_value_array_destroy(struct bt_ctf_value *object)
+{
+       /*
+        * Pointer array's registered value destructor will take care
+        * of putting each contained object.
+        */
+       g_ptr_array_free(BT_CTF_VALUE_TO_ARRAY(object)->garray, TRUE);
+       BT_CTF_VALUE_TO_ARRAY(object)->garray = NULL;
+}
+
+static
+void bt_ctf_value_map_destroy(struct bt_ctf_value *object)
+{
+       /*
+        * Hash table's registered value destructor will take care of
+        * putting each contained object. Keys are GQuarks and cannot
+        * be destroyed anyway.
+        */
+       g_hash_table_destroy(BT_CTF_VALUE_TO_MAP(object)->ght);
+       BT_CTF_VALUE_TO_MAP(object)->ght = NULL;
+}
+
+static
+void (* const destroy_funcs[])(struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              NULL,
+       [BT_CTF_VALUE_TYPE_BOOL] =              NULL,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   NULL,
+       [BT_CTF_VALUE_TYPE_REAL] =              NULL,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_destroy,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_destroy,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_destroy,
+};
+
+static
+struct bt_ctf_private_value *bt_ctf_value_null_copy(const struct bt_ctf_value *null_obj)
+{
+       return (void *) bt_ctf_value_null;
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_bool_copy(const struct bt_ctf_value *bool_obj)
+{
+       return bt_ctf_private_value_bool_create_init(
+               BT_CTF_VALUE_TO_BOOL(bool_obj)->value);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_integer_copy(
+               const struct bt_ctf_value *integer_obj)
+{
+       return bt_ctf_private_value_integer_create_init(
+               BT_CTF_VALUE_TO_INTEGER(integer_obj)->value);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_real_copy(const struct bt_ctf_value *real_obj)
+{
+       return bt_ctf_private_value_real_create_init(
+               BT_CTF_VALUE_TO_REAL(real_obj)->value);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_string_copy(const struct bt_ctf_value *string_obj)
+{
+       return bt_ctf_private_value_string_create_init(
+               BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_array_copy(const struct bt_ctf_value *array_obj)
+{
+       int i;
+       int ret;
+       struct bt_ctf_private_value *copy_obj;
+       struct bt_ctf_value_array *typed_array_obj;
+
+       BT_LOGD("Copying array value: addr=%p", array_obj);
+       typed_array_obj = BT_CTF_VALUE_TO_ARRAY(array_obj);
+       copy_obj = bt_ctf_private_value_array_create();
+       if (!copy_obj) {
+               BT_LOGE_STR("Cannot create empty array value.");
+               goto end;
+       }
+
+       for (i = 0; i < typed_array_obj->garray->len; ++i) {
+               struct bt_ctf_private_value *element_obj_copy = NULL;
+               struct bt_ctf_value *element_obj =
+                       bt_ctf_value_array_borrow_element_by_index(
+                               array_obj, i);
+
+               BT_ASSERT(element_obj);
+               BT_LOGD("Copying array value's element: element-addr=%p, "
+                       "index=%d", element_obj, i);
+               ret = bt_ctf_value_copy(&element_obj_copy, element_obj);
+               if (ret) {
+                       BT_LOGE("Cannot copy array value's element: "
+                               "array-addr=%p, index=%d",
+                               array_obj, i);
+                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
+                       goto end;
+               }
+
+               BT_ASSERT(element_obj_copy);
+               ret = bt_ctf_private_value_array_append_element(copy_obj,
+                       (void *) element_obj_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
+               if (ret) {
+                       BT_LOGE("Cannot append to array value: addr=%p",
+                               array_obj);
+                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
+                       goto end;
+               }
+       }
+
+       BT_LOGD("Copied array value: original-addr=%p, copy-addr=%p",
+               array_obj, copy_obj);
+
+end:
+       return copy_obj;
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_map_copy(const struct bt_ctf_value *map_obj)
+{
+       int ret;
+       GHashTableIter iter;
+       gpointer key, element_obj;
+       struct bt_ctf_private_value *copy_obj;
+       struct bt_ctf_private_value *element_obj_copy = NULL;
+       struct bt_ctf_value_map *typed_map_obj;
+
+       BT_LOGD("Copying map value: addr=%p", map_obj);
+       typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
+       copy_obj = bt_ctf_private_value_map_create();
+       if (!copy_obj) {
+               goto end;
+       }
+
+       g_hash_table_iter_init(&iter, typed_map_obj->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
+               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
+
+               BT_ASSERT(key_str);
+               BT_LOGD("Copying map value's element: element-addr=%p, "
+                       "key=\"%s\"", element_obj, key_str);
+               ret = bt_ctf_value_copy(&element_obj_copy, element_obj);
+               if (ret) {
+                       BT_LOGE("Cannot copy map value's element: "
+                               "map-addr=%p, key=\"%s\"",
+                               map_obj, key_str);
+                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
+                       goto end;
+               }
+
+               BT_ASSERT(element_obj_copy);
+               ret = bt_ctf_private_value_map_insert_entry(copy_obj, key_str,
+                       (void *) element_obj_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
+               if (ret) {
+                       BT_LOGE("Cannot insert into map value: addr=%p, key=\"%s\"",
+                               map_obj, key_str);
+                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
+                       goto end;
+               }
+       }
+
+       BT_LOGD("Copied map value: addr=%p", map_obj);
+
+end:
+       return copy_obj;
+}
+
+static
+struct bt_ctf_private_value *(* const copy_funcs[])(const struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_copy,
+       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_copy,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_copy,
+       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_copy,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_copy,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_copy,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_copy,
+};
+
+static
+bt_bool bt_ctf_value_null_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       /*
+        * Always BT_TRUE since bt_ctf_value_compare() already checks if both
+        * object_a and object_b have the same type, and in the case of
+        * null value objects, they're always the same if it is so.
+        */
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_bool_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (BT_CTF_VALUE_TO_BOOL(object_a)->value !=
+                       BT_CTF_VALUE_TO_BOOL(object_b)->value) {
+               BT_LOGV("Boolean value objects are different: "
+                       "bool-a-val=%d, bool-b-val=%d",
+                       BT_CTF_VALUE_TO_BOOL(object_a)->value,
+                       BT_CTF_VALUE_TO_BOOL(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_integer_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (BT_CTF_VALUE_TO_INTEGER(object_a)->value !=
+                       BT_CTF_VALUE_TO_INTEGER(object_b)->value) {
+               BT_LOGV("Integer value objects are different: "
+                       "int-a-val=%" PRId64 ", int-b-val=%" PRId64,
+                       BT_CTF_VALUE_TO_INTEGER(object_a)->value,
+                       BT_CTF_VALUE_TO_INTEGER(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_real_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (BT_CTF_VALUE_TO_REAL(object_a)->value !=
+                       BT_CTF_VALUE_TO_REAL(object_b)->value) {
+               BT_LOGV("Real number value objects are different: "
+                       "real-a-val=%f, real-b-val=%f",
+                       BT_CTF_VALUE_TO_REAL(object_a)->value,
+                       BT_CTF_VALUE_TO_REAL(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_string_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (strcmp(BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
+                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str) != 0) {
+               BT_LOGV("String value objects are different: "
+                       "string-a-val=\"%s\", string-b-val=\"%s\"",
+                       BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
+                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_array_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       int i;
+       bt_bool ret = BT_TRUE;
+       const struct bt_ctf_value_array *array_obj_a =
+               BT_CTF_VALUE_TO_ARRAY(object_a);
+
+       if (bt_ctf_value_array_get_size(object_a) !=
+                       bt_ctf_value_array_get_size(object_b)) {
+               BT_LOGV("Array values are different: size mismatch "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
+                       object_a, object_b,
+                       bt_ctf_value_array_get_size(object_a),
+                       bt_ctf_value_array_get_size(object_b));
+               ret = BT_FALSE;
+               goto end;
+       }
+
+       for (i = 0; i < array_obj_a->garray->len; ++i) {
+               struct bt_ctf_value *element_obj_a;
+               struct bt_ctf_value *element_obj_b;
+
+               element_obj_a = bt_ctf_value_array_borrow_element_by_index(
+                       object_a, i);
+               element_obj_b = bt_ctf_value_array_borrow_element_by_index(
+                       object_b, i);
+
+               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
+                       BT_LOGV("Array values's elements are different: "
+                               "value-a-addr=%p, value-b-addr=%p, index=%d",
+                               element_obj_a, element_obj_b, i);
+                       ret = BT_FALSE;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_ctf_value_map_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       bt_bool ret = BT_TRUE;
+       GHashTableIter iter;
+       gpointer key, element_obj_a;
+       const struct bt_ctf_value_map *map_obj_a = BT_CTF_VALUE_TO_MAP(object_a);
+
+       if (bt_ctf_value_map_get_size(object_a) !=
+                       bt_ctf_value_map_get_size(object_b)) {
+               BT_LOGV("Map values are different: size mismatch "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
+                       object_a, object_b,
+                       bt_ctf_value_map_get_size(object_a),
+                       bt_ctf_value_map_get_size(object_b));
+               ret = BT_FALSE;
+               goto end;
+       }
+
+       g_hash_table_iter_init(&iter, map_obj_a->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
+               struct bt_ctf_value *element_obj_b;
+               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
+
+               element_obj_b = bt_ctf_value_map_borrow_entry_value(object_b,
+                       key_str);
+
+               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
+                       BT_LOGV("Map values's elements are different: "
+                               "value-a-addr=%p, value-b-addr=%p, key=\"%s\"",
+                               element_obj_a, element_obj_b, key_str);
+                       ret = BT_FALSE;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool (* const compare_funcs[])(const struct bt_ctf_value *,
+               const struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_compare,
+       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_compare,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_compare,
+       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_compare,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_compare,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_compare,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_compare,
+};
+
+static
+void bt_ctf_value_null_freeze(struct bt_ctf_value *object)
+{
+}
+
+static
+void bt_ctf_value_generic_freeze(struct bt_ctf_value *object)
+{
+       object->frozen = BT_TRUE;
+}
+
+static
+void bt_ctf_value_array_freeze(struct bt_ctf_value *object)
+{
+       int i;
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(object);
+
+       for (i = 0; i < typed_array_obj->garray->len; ++i) {
+               bt_ctf_value_freeze(g_ptr_array_index(typed_array_obj->garray, i));
+       }
+
+       bt_ctf_value_generic_freeze(object);
+}
+
+static
+void bt_ctf_value_map_freeze(struct bt_ctf_value *object)
+{
+       GHashTableIter iter;
+       gpointer key, element_obj;
+       const struct bt_ctf_value_map *map_obj = BT_CTF_VALUE_TO_MAP(object);
+
+       g_hash_table_iter_init(&iter, map_obj->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
+               bt_ctf_value_freeze(element_obj);
+       }
+
+       bt_ctf_value_generic_freeze(object);
+}
+
+static
+void (* const freeze_funcs[])(struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_freeze,
+       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_freeze,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_freeze,
+};
+
+static
+void bt_ctf_value_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_value *value;
+
+       value = container_of(obj, struct bt_ctf_value, base);
+       BT_LOGD("Destroying value: addr=%p", value);
+
+       if (bt_ctf_value_is_null(value)) {
+               BT_LOGD_STR("Not destroying the null value singleton.");
+               return;
+       }
+
+       if (destroy_funcs[value->type]) {
+               destroy_funcs[value->type](value);
+       }
+
+       g_free(value);
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object)
+{
+       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
+
+       BT_ASSERT(object);
+
+       if (object->frozen) {
+               goto end;
+       }
+
+       BT_LOGD("Freezing value: addr=%p", object);
+       freeze_funcs[object->type](object);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object");
+       return object->type;
+}
+
+static
+struct bt_ctf_value bt_ctf_value_create_base(enum bt_ctf_value_type type)
+{
+       struct bt_ctf_value value;
+
+       value.type = type;
+       value.frozen = BT_FALSE;
+       bt_ctf_object_init_shared(&value.base, bt_ctf_value_destroy);
+       return value;
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val)
+{
+       struct bt_ctf_value_bool *bool_obj;
+
+       BT_LOGD("Creating boolean value object: val=%d", val);
+       bool_obj = g_new0(struct bt_ctf_value_bool, 1);
+       if (!bool_obj) {
+               BT_LOGE_STR("Failed to allocate one boolean value object.");
+               goto end;
+       }
+
+       bool_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_BOOL);
+       bool_obj->value = val;
+       BT_LOGD("Created boolean value object: addr=%p", bool_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(bool_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void)
+{
+       return bt_ctf_private_value_bool_create_init(BT_FALSE);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(int64_t val)
+{
+       struct bt_ctf_value_integer *integer_obj;
+
+       BT_LOGD("Creating integer value object: val=%" PRId64, val);
+       integer_obj = g_new0(struct bt_ctf_value_integer, 1);
+       if (!integer_obj) {
+               BT_LOGE_STR("Failed to allocate one integer value object.");
+               goto end;
+       }
+
+       integer_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_INTEGER);
+       integer_obj->value = val;
+       BT_LOGD("Created integer value object: addr=%p",
+               integer_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(integer_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void)
+{
+       return bt_ctf_private_value_integer_create_init(0);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val)
+{
+       struct bt_ctf_value_real *real_obj;
+
+       BT_LOGD("Creating real number value object: val=%f", val);
+       real_obj = g_new0(struct bt_ctf_value_real, 1);
+       if (!real_obj) {
+               BT_LOGE_STR("Failed to allocate one real number value object.");
+               goto end;
+       }
+
+       real_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_REAL);
+       real_obj->value = val;
+       BT_LOGD("Created real number value object: addr=%p",
+               real_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(real_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_real_create(void)
+{
+       return bt_ctf_private_value_real_create_init(0.);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(const char *val)
+{
+       struct bt_ctf_value_string *string_obj = NULL;
+
+       if (!val) {
+               BT_LOGW_STR("Invalid parameter: value is NULL.");
+               goto end;
+       }
+
+       BT_LOGD("Creating string value object: val-len=%zu", strlen(val));
+       string_obj = g_new0(struct bt_ctf_value_string, 1);
+       if (!string_obj) {
+               BT_LOGE_STR("Failed to allocate one string object.");
+               goto end;
+       }
+
+       string_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_STRING);
+       string_obj->gstr = g_string_new(val);
+       if (!string_obj->gstr) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               g_free(string_obj);
+               string_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created string value object: addr=%p",
+               string_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(string_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_string_create(void)
+{
+       return bt_ctf_private_value_string_create_init("");
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_array_create(void)
+{
+       struct bt_ctf_value_array *array_obj;
+
+       BT_LOGD_STR("Creating empty array value object.");
+       array_obj = g_new0(struct bt_ctf_value_array, 1);
+       if (!array_obj) {
+               BT_LOGE_STR("Failed to allocate one array object.");
+               goto end;
+       }
+
+       array_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_ARRAY);
+       array_obj->garray = bt_g_ptr_array_new_full(0,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       if (!array_obj->garray) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               g_free(array_obj);
+               array_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created array value object: addr=%p",
+               array_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(array_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_map_create(void)
+{
+       struct bt_ctf_value_map *map_obj;
+
+       BT_LOGD_STR("Creating empty map value object.");
+       map_obj = g_new0(struct bt_ctf_value_map, 1);
+       if (!map_obj) {
+               BT_LOGE_STR("Failed to allocate one map object.");
+               goto end;
+       }
+
+       map_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_MAP);
+       map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+               NULL, (GDestroyNotify) bt_ctf_object_put_ref);
+       if (!map_obj->ght) {
+               BT_LOGE_STR("Failed to allocate a GHashTable.");
+               g_free(map_obj);
+               map_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created map value object: addr=%p",
+               map_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(map_obj);
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
+       return BT_CTF_VALUE_TO_BOOL(bool_obj)->value;
+}
+
+BT_HIDDEN
+void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj, bt_bool val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object");
+       BT_CTF_VALUE_TO_BOOL(bool_obj)->value = val;
+       BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d",
+               bool_obj, val);
+}
+
+BT_HIDDEN
+int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
+       return BT_CTF_VALUE_TO_INTEGER(integer_obj)->value;
+}
+
+BT_HIDDEN
+void bt_ctf_private_value_integer_set(struct bt_ctf_private_value *integer_obj,
+               int64_t val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object");
+       BT_CTF_VALUE_TO_INTEGER(integer_obj)->value = val;
+       BT_LOGV("Set integer value's raw value: value-addr=%p, value=%" PRId64,
+               integer_obj, val);
+}
+
+BT_HIDDEN
+double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
+       return BT_CTF_VALUE_TO_REAL(real_obj)->value;
+}
+
+BT_HIDDEN
+void bt_ctf_private_value_real_set(struct bt_ctf_private_value *real_obj, double val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(real_obj, "Value object");
+       BT_CTF_VALUE_TO_REAL(real_obj)->value = val;
+       BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f",
+               real_obj, val);
+}
+
+BT_HIDDEN
+const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
+       return BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_string_set(
+               struct bt_ctf_private_value *string_obj, const char *val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(string_obj, "Value object");
+       g_string_assign(BT_CTF_VALUE_TO_STRING(string_obj)->gstr, val);
+       BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p",
+               string_obj, val);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       return (uint64_t) BT_CTF_VALUE_TO_ARRAY(array_obj)->garray->len;
+}
+
+BT_HIDDEN
+struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index(
+               const struct bt_ctf_value *array_obj,
+               uint64_t index)
+{
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(array_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
+               typed_array_obj->garray->len);
+       return g_ptr_array_index(typed_array_obj->garray, index);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index(
+               const struct bt_ctf_private_value *array_obj,
+               uint64_t index)
+{
+       return (void *) bt_ctf_value_array_borrow_element_by_index(
+               (void *) array_obj, index);
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_element(
+               struct bt_ctf_private_value *array_obj,
+               struct bt_ctf_value *element_obj)
+{
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(array_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
+       g_ptr_array_add(typed_array_obj->garray, element_obj);
+       bt_ctf_object_get_ref(element_obj);
+       BT_LOGV("Appended element to array value: array-value-addr=%p, "
+               "element-value-addr=%p, new-size=%u",
+               array_obj, element_obj, typed_array_obj->garray->len);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element(
+               struct bt_ctf_private_value *array_obj, bt_bool val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *bool_obj = NULL;
+
+       bool_obj = bt_ctf_private_value_bool_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) bool_obj);
+       bt_ctf_object_put_ref(bool_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element(
+               struct bt_ctf_private_value *array_obj, int64_t val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *integer_obj = NULL;
+
+       integer_obj = bt_ctf_private_value_integer_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) integer_obj);
+       bt_ctf_object_put_ref(integer_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element(
+               struct bt_ctf_private_value *array_obj, double val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *real_obj = NULL;
+
+       real_obj = bt_ctf_private_value_real_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) real_obj);
+       bt_ctf_object_put_ref(real_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element(
+               struct bt_ctf_private_value *array_obj, const char *val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *string_obj = NULL;
+
+       string_obj = bt_ctf_private_value_string_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) string_obj);
+       bt_ctf_object_put_ref(string_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element(
+               struct bt_ctf_private_value *array_obj)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *empty_array_obj = NULL;
+
+       empty_array_obj = bt_ctf_private_value_array_create();
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) empty_array_obj);
+       bt_ctf_object_put_ref(empty_array_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element(
+               struct bt_ctf_private_value *array_obj)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *map_obj = NULL;
+
+       map_obj = bt_ctf_private_value_map_create();
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) map_obj);
+       bt_ctf_object_put_ref(map_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index(
+               struct bt_ctf_private_value *array_obj, uint64_t index,
+               struct bt_ctf_value *element_obj)
+{
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(array_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
+       BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
+               typed_array_obj->garray->len);
+       bt_ctf_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index));
+       g_ptr_array_index(typed_array_obj->garray, index) = element_obj;
+       bt_ctf_object_get_ref(element_obj);
+       BT_LOGV("Set array value's element: array-value-addr=%p, "
+               "index=%" PRIu64 ", element-value-addr=%p",
+               array_obj, index, element_obj);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       return (uint64_t) g_hash_table_size(BT_CTF_VALUE_TO_MAP(map_obj)->ght);
+}
+
+BT_HIDDEN
+struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(const struct bt_ctf_value *map_obj,
+               const char *key)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       return g_hash_table_lookup(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)));
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value(
+               const struct bt_ctf_private_value *map_obj, const char *key)
+{
+       return (void *) bt_ctf_value_map_borrow_entry_value((void *) map_obj, key);
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj, const char *key)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       return bt_g_hash_table_contains(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)));
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry(
+               struct bt_ctf_private_value *map_obj,
+               const char *key, struct bt_ctf_value *element_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Map value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object");
+       g_hash_table_insert(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)), element_obj);
+       bt_ctf_object_get_ref(element_obj);
+       BT_LOGV("Inserted value into map value: map-value-addr=%p, "
+               "key=\"%s\", element-value-addr=%p",
+               map_obj, key, element_obj);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, bt_bool val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *bool_obj = NULL;
+
+       bool_obj = bt_ctf_private_value_bool_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) bool_obj);
+       bt_ctf_object_put_ref(bool_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, int64_t val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *integer_obj = NULL;
+
+       integer_obj = bt_ctf_private_value_integer_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) integer_obj);
+       bt_ctf_object_put_ref(integer_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, double val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *real_obj = NULL;
+
+       real_obj = bt_ctf_private_value_real_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) real_obj);
+       bt_ctf_object_put_ref(real_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry(
+               struct bt_ctf_private_value *map_obj, const char *key,
+               const char *val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *string_obj = NULL;
+
+       string_obj = bt_ctf_private_value_string_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) string_obj);
+       bt_ctf_object_put_ref(string_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry(
+               struct bt_ctf_private_value *map_obj, const char *key)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *array_obj = NULL;
+
+       array_obj = bt_ctf_private_value_array_create();
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) array_obj);
+       bt_ctf_object_put_ref(array_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry(
+               struct bt_ctf_private_value *map_obj, const char *key)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *empty_map_obj = NULL;
+
+       empty_map_obj = bt_ctf_private_value_map_create();
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) empty_map_obj);
+       bt_ctf_object_put_ref(empty_map_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(const struct bt_ctf_value *map_obj,
+               bt_ctf_value_map_foreach_entry_cb cb, void *data)
+{
+       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
+       gpointer key, element_obj;
+       GHashTableIter iter;
+       struct bt_ctf_value_map *typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(cb, "Callback");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       g_hash_table_iter_init(&iter, typed_map_obj->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
+               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
+
+               if (!cb(key_str, element_obj, data)) {
+                       BT_LOGV("User canceled the loop: key=\"%s\", "
+                               "value-addr=%p, data=%p",
+                               key_str, element_obj, data);
+                       ret = BT_CTF_VALUE_STATUS_CANCELED;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry(
+               const struct bt_ctf_private_value *map_obj,
+               bt_ctf_private_value_map_foreach_entry_cb cb, void *data)
+{
+       return bt_ctf_value_map_foreach_entry((void *) map_obj,
+               (bt_ctf_value_map_foreach_entry_cb) cb, data);
+}
+
+struct extend_map_element_data {
+       struct bt_ctf_private_value *extended_obj;
+       enum bt_ctf_value_status status;
+};
+
+static
+bt_bool extend_map_element(const char *key,
+               struct bt_ctf_value *extension_obj_elem, void *data)
+{
+       bt_bool ret = BT_TRUE;
+       struct extend_map_element_data *extend_data = data;
+       struct bt_ctf_private_value *extension_obj_elem_copy = NULL;
+
+       /* Copy object which is to replace the current one */
+       extend_data->status = bt_ctf_value_copy(&extension_obj_elem_copy,
+               extension_obj_elem);
+       if (extend_data->status) {
+               BT_LOGE("Cannot copy map element: addr=%p",
+                       extension_obj_elem);
+               goto error;
+       }
+
+       BT_ASSERT(extension_obj_elem_copy);
+
+       /* Replace in extended object */
+       extend_data->status = bt_ctf_private_value_map_insert_entry(
+               extend_data->extended_obj, key,
+               (void *) extension_obj_elem_copy);
+       if (extend_data->status) {
+               BT_LOGE("Cannot replace value in extended value: key=\"%s\", "
+                       "extended-value-addr=%p, element-value-addr=%p",
+                       key, extend_data->extended_obj,
+                       extension_obj_elem_copy);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_ASSERT(extend_data->status != BT_CTF_VALUE_STATUS_OK);
+       ret = BT_FALSE;
+
+end:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_map_extend(
+               struct bt_ctf_private_value **extended_map_obj,
+               const struct bt_ctf_value *base_map_obj,
+               const struct bt_ctf_value *extension_obj)
+{
+       struct extend_map_element_data extend_data = {
+               .extended_obj = NULL,
+               .status = BT_CTF_VALUE_STATUS_OK,
+       };
+
+       BT_CTF_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(extended_map_obj,
+               "Extended value object (output)");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_CTF_VALUE_TYPE_MAP);
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_CTF_VALUE_TYPE_MAP);
+       BT_LOGD("Extending map value: base-value-addr=%p, extension-value-addr=%p",
+               base_map_obj, extension_obj);
+       *extended_map_obj = NULL;
+
+       /* Create copy of base map object to start with */
+       extend_data.status = bt_ctf_value_copy(extended_map_obj, base_map_obj);
+       if (extend_data.status) {
+               BT_LOGE("Cannot copy base value: base-value-addr=%p",
+                       base_map_obj);
+               goto error;
+       }
+
+       BT_ASSERT(extended_map_obj);
+
+       /*
+        * For each key in the extension map object, replace this key
+        * in the copied map object.
+        */
+       extend_data.extended_obj = *extended_map_obj;
+
+       if (bt_ctf_value_map_foreach_entry(extension_obj, extend_map_element,
+                       &extend_data)) {
+               BT_LOGE("Cannot iterate on the extension object's elements: "
+                       "extension-value-addr=%p", extension_obj);
+               goto error;
+       }
+
+       if (extend_data.status) {
+               BT_LOGE("Failed to successfully iterate on the extension object's elements: "
+                       "extension-value-addr=%p", extension_obj);
+               goto error;
+       }
+
+       BT_LOGD("Extended map value: extended-value-addr=%p",
+               *extended_map_obj);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(*extended_map_obj);
+       *extended_map_obj = NULL;
+
+end:
+       return extend_data.status;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy_obj,
+               const struct bt_ctf_value *object)
+{
+       enum bt_ctf_value_status status = BT_CTF_VALUE_STATUS_OK;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)");
+       BT_LOGD("Copying value object: addr=%p", object);
+       *copy_obj = copy_funcs[object->type](object);
+       if (*copy_obj) {
+               BT_LOGD("Copied value object: copy-value-addr=%p",
+                       copy_obj);
+       } else {
+               status = BT_CTF_VALUE_STATUS_NOMEM;
+               *copy_obj = NULL;
+               BT_LOGE_STR("Failed to copy value object.");
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a,
+       const struct bt_ctf_value *object_b)
+{
+       bt_bool ret = BT_FALSE;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(object_a, "Value object A");
+       BT_CTF_ASSERT_PRE_NON_NULL(object_b, "Value object B");
+
+       if (object_a->type != object_b->type) {
+               BT_LOGV("Values are different: type mismatch: "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-type=%d, value-b-type=%d",
+                       object_a, object_b, object_a->type, object_b->type);
+               goto end;
+       }
+
+       ret = compare_funcs[object_a->type](object_a, object_b);
+
+end:
+       return ret;
+}
diff --git a/ctf-writer/visitor.c b/ctf-writer/visitor.c
new file mode 100644 (file)
index 0000000..707cc7a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * visitor.c
+ *
+ * Babeltrace CTF writer - 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 <babeltrace2/ctf-writer/visitor-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+
+BT_HIDDEN
+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,
+               bt_ctf_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_CTF_OBJECT_PUT_REF_AND_RESET(child);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+enum bt_ctf_visitor_object_type bt_ctf_visitor_object_get_type(
+               struct bt_ctf_visitor_object *object)
+{
+       enum bt_ctf_visitor_object_type ret = BT_CTF_VISITOR_OBJECT_TYPE_UNKNOWN;
+
+       if (!object) {
+               goto end;
+       }
+
+       ret = object->type;
+end:
+       return ret;
+}
+
+void *bt_ctf_visitor_object_get_object(struct bt_ctf_visitor_object *object)
+{
+       void *ret = NULL;
+
+       if (!object) {
+               goto end;
+       }
+
+       ret = object->object;
+end:
+       return ret;
+}
diff --git a/ctf-writer/writer.c b/ctf-writer/writer.c
new file mode 100644 (file)
index 0000000..949bbea
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * writer.c
+ *
+ * Babeltrace CTF Writer
+ *
+ * Copyright 2013, 2014 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.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER"
+#include "logging.h"
+
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compat/uuid-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/ctf-writer/clock-internal.h>
+#include <babeltrace2/ctf-writer/field-types-internal.h>
+#include <babeltrace2/ctf-writer/fields-internal.h>
+#include <babeltrace2/ctf-writer/functor-internal.h>
+#include <babeltrace2/ctf-writer/stream-class-internal.h>
+#include <babeltrace2/ctf-writer/stream-internal.h>
+#include <babeltrace2/ctf-writer/trace-internal.h>
+#include <babeltrace2/ctf-writer/writer-internal.h>
+#include <babeltrace2/endian-internal.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+static
+void bt_ctf_writer_destroy(struct bt_ctf_object *obj);
+
+static
+int init_trace_packet_header(struct bt_ctf_trace *trace)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *_uint32_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
+       struct bt_ctf_field_type *_uint8_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
+       struct bt_ctf_field_type *trace_packet_header_type =
+               bt_ctf_field_type_structure_create();
+       struct bt_ctf_field_type *uuid_array_type =
+               bt_ctf_field_type_array_create(_uint8_t, 16);
+
+       if (!trace_packet_header_type || !uuid_array_type) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
+               _uint32_t, "magic");
+       if (ret) {
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
+               uuid_array_type, "uuid");
+       if (ret) {
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
+               _uint32_t, "stream_id");
+       if (ret) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_set_packet_header_field_type(trace,
+               trace_packet_header_type);
+       if (ret) {
+               goto end;
+       }
+end:
+       bt_ctf_object_put_ref(uuid_array_type);
+       bt_ctf_object_put_ref(_uint32_t);
+       bt_ctf_object_put_ref(_uint8_t);
+       bt_ctf_object_put_ref(trace_packet_header_type);
+       return ret;
+}
+
+struct bt_ctf_writer *bt_ctf_writer_create(const char *path)
+{
+       int ret;
+       struct bt_ctf_writer *writer = NULL;
+       unsigned char uuid[16];
+       char *metadata_path = NULL;
+
+       if (!path) {
+               goto error;
+       }
+
+       writer = g_new0(struct bt_ctf_writer, 1);
+       if (!writer) {
+               goto error;
+       }
+
+       metadata_path = g_build_filename(path, "metadata", NULL);
+
+       bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy);
+       writer->path = g_string_new(path);
+       if (!writer->path) {
+               goto error_destroy;
+       }
+
+       writer->trace = bt_ctf_trace_create();
+       if (!writer->trace) {
+               goto error_destroy;
+       }
+
+       ret = init_trace_packet_header(writer->trace);
+       if (ret) {
+               goto error_destroy;
+       }
+
+       /* Generate a UUID for this writer's trace */
+       ret = bt_uuid_generate(uuid);
+       if (ret) {
+               BT_LOGE_STR("Cannot generate UUID for CTF writer's trace.");
+               goto error_destroy;
+       }
+
+       ret = bt_ctf_trace_set_uuid(writer->trace, uuid);
+       if (ret) {
+               goto error_destroy;
+       }
+
+       bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base);
+       bt_ctf_object_put_ref(writer->trace);
+
+       /* Default to little-endian */
+       ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE);
+       BT_ASSERT(ret == 0);
+
+       /* Create trace directory if necessary and open a metadata file */
+       if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) {
+               perror("g_mkdir_with_parents");
+               goto error_destroy;
+       }
+
+       writer->metadata_fd = open(metadata_path,
+               O_WRONLY | O_CREAT | O_TRUNC,
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+       if (writer->metadata_fd < 0) {
+               perror("open");
+               goto error_destroy;
+       }
+
+       g_free(metadata_path);
+       return writer;
+
+error_destroy:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(writer);
+error:
+       g_free(metadata_path);
+       return writer;
+}
+
+void bt_ctf_writer_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_writer *writer;
+
+       writer = container_of(obj, struct bt_ctf_writer, base);
+       bt_ctf_writer_flush_metadata(writer);
+       if (writer->path) {
+               g_string_free(writer->path, TRUE);
+       }
+
+       if (writer->metadata_fd > 0) {
+               if (close(writer->metadata_fd)) {
+                       perror("close");
+               }
+       }
+
+       bt_ctf_object_try_spec_release(&writer->trace->common.base);
+       g_free(writer);
+}
+
+struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer)
+{
+       struct bt_ctf_trace *trace = NULL;
+
+       if (!writer) {
+               goto end;
+       }
+
+       trace = writer->trace;
+       bt_ctf_object_get_ref(trace);
+end:
+       return trace;
+}
+
+struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer,
+               struct bt_ctf_stream_class *stream_class)
+{
+       struct bt_ctf_stream *stream = NULL;
+       int stream_class_count;
+       bt_bool stream_class_found = BT_FALSE;
+       int i;
+
+       if (!writer || !stream_class) {
+               goto error;
+       }
+
+       /* Make sure the stream class is part of the writer's trace */
+       stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace);
+       if (stream_class_count < 0) {
+               goto error;
+       }
+
+       for (i = 0; i < stream_class_count; i++) {
+               struct bt_ctf_stream_class *existing_stream_class =
+                       bt_ctf_trace_get_stream_class_by_index(
+                               writer->trace, i);
+
+               if (existing_stream_class == stream_class) {
+                       stream_class_found = BT_TRUE;
+               }
+
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class);
+
+               if (stream_class_found) {
+                       break;
+               }
+       }
+
+       if (!stream_class_found) {
+               int ret = bt_ctf_trace_add_stream_class(writer->trace,
+                       stream_class);
+
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL);
+       if (!stream) {
+               goto error;
+       }
+
+       return stream;
+
+error:
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
+       return stream;
+}
+
+int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer,
+               const char *name,
+               const char *value)
+{
+       int ret = -1;
+
+       if (!writer || !name || !value) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_set_environment_field_string(writer->trace,
+               name, value);
+end:
+       return ret;
+}
+
+int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer,
+               const char *name, int64_t value)
+{
+       int ret = -1;
+
+       if (!writer || !name) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name,
+               value);
+end:
+       return ret;
+}
+
+int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer,
+               struct bt_ctf_clock *clock)
+{
+       int ret = -1;
+
+       if (!writer || !clock) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class);
+end:
+       return ret;
+}
+
+char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer)
+{
+       char *metadata_string = NULL;
+
+       if (!writer) {
+               goto end;
+       }
+
+       metadata_string = bt_ctf_trace_get_metadata_string(
+               writer->trace);
+end:
+       return metadata_string;
+}
+
+void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer)
+{
+       int ret;
+       char *metadata_string = NULL;
+
+       if (!writer) {
+               goto end;
+       }
+
+       metadata_string = bt_ctf_trace_get_metadata_string(
+               writer->trace);
+       if (!metadata_string) {
+               goto end;
+       }
+
+       if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) {
+               perror("lseek");
+               goto end;
+       }
+
+       if (ftruncate(writer->metadata_fd, 0)) {
+               perror("ftruncate");
+               goto end;
+       }
+
+       ret = write(writer->metadata_fd, metadata_string,
+               strlen(metadata_string));
+       if (ret < 0) {
+               perror("write");
+               goto end;
+       }
+end:
+       g_free(metadata_string);
+}
+
+int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer,
+               enum bt_ctf_byte_order byte_order)
+{
+       int ret = 0;
+
+       if (!writer || writer->frozen) {
+               ret = -1;
+               goto end;
+       }
+
+       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+               if (BYTE_ORDER == LITTLE_ENDIAN) {
+                       byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
+               } else {
+                       byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
+               }
+       }
+
+       ret = bt_ctf_trace_set_native_byte_order(writer->trace,
+               byte_order);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_writer_freeze(struct bt_ctf_writer *writer)
+{
+       writer->frozen = 1;
+}
+
+static
+const unsigned int field_type_aliases_alignments[] = {
+       [FIELD_TYPE_ALIAS_UINT5_T] = 1,
+       [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
+       [FIELD_TYPE_ALIAS_UINT27_T] = 1,
+       [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
+};
+
+static
+const unsigned int field_type_aliases_sizes[] = {
+       [FIELD_TYPE_ALIAS_UINT5_T] = 5,
+       [FIELD_TYPE_ALIAS_UINT8_T] = 8,
+       [FIELD_TYPE_ALIAS_UINT16_T] = 16,
+       [FIELD_TYPE_ALIAS_UINT27_T] = 27,
+       [FIELD_TYPE_ALIAS_UINT32_T] = 32,
+       [FIELD_TYPE_ALIAS_UINT64_T] = 64,
+};
+
+BT_HIDDEN
+struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
+{
+       int ret;
+       unsigned int alignment, size;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (alias >= NR_FIELD_TYPE_ALIAS) {
+               goto end;
+       }
+
+       alignment = field_type_aliases_alignments[alias];
+       size = field_type_aliases_sizes[alias];
+       field_type = bt_ctf_field_type_integer_create(size);
+       ret = bt_ctf_field_type_set_alignment(field_type, alignment);
+       if (ret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type);
+       }
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order)
+{
+       const char *string;
+
+       switch (byte_order) {
+       case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
+               string = "le";
+               break;
+       case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
+               string = "be";
+               break;
+       case BT_CTF_BYTE_ORDER_NATIVE:
+               string = "native";
+               break;
+       default:
+               abort();
+       }
+
+       return string;
+}
index f03110fc48f36fc63c6c1ef046f04ee374a8e51d..7c64a676e2220d5366ad63ab2d11cb6a34cdb89c 100644 (file)
@@ -45,6 +45,9 @@ def _c_includes_from_sections(sections):
     src = ''
 
     for section in sections:
+        if 'ctf' in section.title.lower():
+            continue
+
         src += '/* {} */\n'.format(section.title)
 
         for filename in sorted(section.filenames):
index e069b2cc2b98cccb95d27976c024d63569274cd8..a340b8052d835123f915ae1157071e4759806b0c 100644 (file)
@@ -235,6 +235,7 @@ noinst_HEADERS = \
        babeltrace2/plugin/python-plugin-provider-internal.h \
        babeltrace2/assert-internal.h \
        babeltrace2/value-internal.h \
+       babeltrace2/ctf-writer/assert-pre-internal.h \
        babeltrace2/ctf-writer/attributes-internal.h \
        babeltrace2/ctf-writer/clock-class-internal.h \
        babeltrace2/ctf-writer/clock-internal.h \
index 45509a8a1087c0251ea69fb0a7097520d8cbde28..20d50f596914ad9e704a99261636e1d03ba0a462 100644 (file)
 #include <babeltrace2/value.h>
 #include <babeltrace2/version.h>
 
-/* Legacy API (for CTF writer) */
-#include <babeltrace2/ctf/events.h>
-
-/* CTF writer API */
-#include <babeltrace2/ctf-writer/clock-class.h>
-#include <babeltrace2/ctf-writer/clock.h>
-#include <babeltrace2/ctf-writer/event-fields.h>
-#include <babeltrace2/ctf-writer/event-types.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/stream.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/visitor.h>
-#include <babeltrace2/ctf-writer/writer.h>
-
-/* Legacy API (for CTF writer) */
-#include <babeltrace2/ctf-ir/clock.h>
-#include <babeltrace2/ctf-ir/event-fields.h>
-#include <babeltrace2/ctf-ir/event-types.h>
-#include <babeltrace2/ctf-ir/event.h>
-#include <babeltrace2/ctf-ir/field-types.h>
-#include <babeltrace2/ctf-ir/fields.h>
-#include <babeltrace2/ctf-ir/stream-class.h>
-#include <babeltrace2/ctf-ir/stream.h>
-#include <babeltrace2/ctf-ir/trace.h>
-#include <babeltrace2/ctf-ir/utils.h>
-
 /* Trace IR API */
 #include <babeltrace2/trace-ir/clock-class-const.h>
 #include <babeltrace2/trace-ir/clock-class.h>
diff --git a/include/babeltrace2/ctf-writer/assert-pre-internal.h b/include/babeltrace2/ctf-writer/assert-pre-internal.h
new file mode 100644 (file)
index 0000000..3ac3af1
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * 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.
+ */
+
+/*
+ * The macros in this header use macros defined in
+ * <babeltrace2/lib-logging-internal.h>. We don't want this header to
+ * automatically include <babeltrace2/lib-logging-internal.h> because you
+ * need to manually define BT_LOG_TAG before including
+ * <babeltrace2/lib-logging-internal.h> and it is unexpected that you
+ * also need to define it before including this header.
+ *
+ * This is a reminder that in order to use
+ * <babeltrace2/assert-pre-internal.h>, you also need to use logging
+ * explicitly.
+ */
+
+#ifndef BABELTRACE_LOGGING_INTERNAL_H
+# error Include <babeltrace2/logging-internal.h> before this header.
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <babeltrace2/babeltrace-internal.h>
+
+#ifdef BT_DEV_MODE
+/*
+ * Asserts that the library precondition _cond is satisfied.
+ *
+ * If _cond is false, log a fatal statement using _fmt and the optional
+ * arguments using BT_LOGF(), and abort.
+ *
+ * To assert that a postcondition is satisfied or that some internal
+ * object/context/value is in the expected state, use BT_ASSERT().
+ */
+# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...)                           \
+       do {                                                            \
+               if (!(_cond)) {                                         \
+                       BT_LOGF_STR("Library precondition not satisfied; error is:"); \
+                       BT_LOGF((_fmt), ##__VA_ARGS__);         \
+                       BT_LOGF_STR("Aborting...");                     \
+                       abort();                                        \
+               }                                                       \
+       } while (0)
+
+/*
+ * Marks a function as being only used within a BT_CTF_ASSERT_PRE() context.
+ */
+# define BT_CTF_ASSERT_PRE_FUNC
+
+/*
+ * Prints the details of an unsatisfied precondition without immediately
+ * aborting. You should use this within a function which checks
+ * preconditions, but which is called from a BT_CTF_ASSERT_PRE() context, so
+ * that the function can still return its result for BT_CTF_ASSERT_PRE() to
+ * evaluate it.
+ *
+ * Example:
+ *
+ *     BT_CTF_ASSERT_PRE_FUNC
+ *     static inline bool check_complex_precond(...)
+ *     {
+ *         ...
+ *
+ *         if (...) {
+ *             BT_CTF_ASSERT_PRE_MSG("Invalid object: ...", ...);
+ *             return false;
+ *         }
+ *
+ *         ...
+ *     }
+ *
+ *     ...
+ *
+ *     BT_CTF_ASSERT_PRE(check_complex_precond(...),
+ *                   "Precondition is not satisfied: ...", ...);
+ */
+# define BT_CTF_ASSERT_PRE_MSG BT_LOGF
+#else
+# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...)   ((void) sizeof((void) (_cond), 0))
+# define BT_CTF_ASSERT_PRE_FUNC        BT_UNUSED
+# define BT_CTF_ASSERT_PRE_MSG(_fmt, ...)
+#endif /* BT_DEV_MODE */
+
+/*
+ * Developer mode: asserts that a given variable is not NULL.
+ */
+#define BT_CTF_ASSERT_PRE_NON_NULL(_obj, _obj_name)                            \
+       BT_CTF_ASSERT_PRE((_obj) != NULL, "%s is NULL: ", _obj_name)
+
+/*
+ * Developer mode: asserts that a given object is NOT frozen. This macro
+ * checks the `frozen` field of _obj.
+ */
+#define BT_CTF_ASSERT_PRE_HOT(_obj, _obj_name, _fmt, ...)                      \
+       BT_CTF_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name,      \
+               ##__VA_ARGS__)
+
+/*
+ * Developer mode: asserts that a given index is less than a given size.
+ */
+#define BT_CTF_ASSERT_PRE_VALID_INDEX(_index, _length)                 \
+       BT_CTF_ASSERT_PRE((_index) < (_length),                         \
+               "Index is out of bounds: index=%" PRIu64 ", "           \
+               "count=%" PRIu64, (uint64_t) (_index), (uint64_t) (_length))
+
+#endif /* BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H */
index 34ce8ce4464682497f99e31a0da31d1a295d70d0..c67184ae55d24cc56e1a69885e1a13519f2b017b 100644 (file)
@@ -92,7 +92,7 @@ static inline
 const char *bt_ctf_event_class_common_get_name(
                struct bt_ctf_event_class_common *event_class)
 {
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
        BT_ASSERT(event_class->name);
        return event_class->name->str;
 }
@@ -101,7 +101,7 @@ static inline
 int64_t bt_ctf_event_class_common_get_id(
                struct bt_ctf_event_class_common *event_class)
 {
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
        return event_class->id;
 }
 
@@ -151,7 +151,7 @@ static inline
 int bt_ctf_event_class_common_get_log_level(
                struct bt_ctf_event_class_common *event_class)
 {
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
        return event_class->log_level;
 }
 
@@ -221,7 +221,7 @@ const char *bt_ctf_event_class_common_get_emf_uri(
 {
        const char *emf_uri = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
 
        if (event_class->emf_uri->len > 0) {
                emf_uri = event_class->emf_uri->str;
@@ -282,7 +282,7 @@ struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_context_field_
 {
        struct bt_ctf_field_type_common *context_ft = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
 
        if (!event_class->context_field_type) {
                BT_LOGV("Event class has no context field type: "
@@ -350,7 +350,7 @@ static inline
 struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_payload_field_type(
                struct bt_ctf_event_class_common *event_class)
 {
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
        return event_class->payload_field_type;
 }
 
index d1d3dc9df669b19c4f6b51674b521d02ed89a4d5..97039878b53708bcd2c86bf1491e69012217798f 100644 (file)
@@ -29,7 +29,7 @@
  */
 
 #include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
 #include <babeltrace2/babeltrace-internal.h>
 #include <babeltrace2/ctf-writer/event-class-internal.h>
 #include <babeltrace2/ctf-writer/event-internal.h>
@@ -74,8 +74,8 @@ void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event,
 # define bt_ctf_event_common_set_is_frozen(_event, _is_frozen)
 #endif
 
-#define BT_ASSERT_PRE_EVENT_COMMON_HOT(_event, _name)                  \
-       BT_ASSERT_PRE_HOT((_event), (_name), ": event-addr=%p", (_event))
+#define BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(_event, _name)                      \
+       BT_CTF_ASSERT_PRE_HOT((_event), (_name), ": event-addr=%p", (_event))
 
 static inline
 struct bt_ctf_event_class_common *bt_ctf_event_common_borrow_class(
@@ -111,7 +111,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_payload(
 {
        struct bt_ctf_field_common *payload = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
 
        if (!event->payload_field) {
                BT_LOGV("Event has no current payload field: addr=%p, "
@@ -133,7 +133,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_header(
 {
        struct bt_ctf_field_common *header = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
 
        if (!event->header_field) {
                BT_LOGV("Event has no current header field: addr=%p, "
@@ -155,7 +155,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_context(
 {
        struct bt_ctf_field_common *context = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
 
        if (!event->context_field) {
                BT_LOGV("Event has no current context field: addr=%p, "
@@ -177,7 +177,7 @@ struct bt_ctf_field_common *bt_ctf_event_common_borrow_stream_event_context(
 {
        struct bt_ctf_field_common *stream_event_context = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
 
        if (!event->stream_event_context_field) {
                BT_LOGV("Event has no current stream event context field: addr=%p, "
index 9f514772adcd959523a2666251db60776f4e0313..757170fa8be6759873eed8190b0a9bd82c703132 100644 (file)
@@ -31,7 +31,7 @@
 #include <stdint.h>
 #include <stddef.h>
 
-#include <babeltrace2/assert-pre-internal.h>
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
 #include <babeltrace2/babeltrace-internal.h>
 #include <babeltrace2/ctf-writer/clock-class-internal.h>
 #include <babeltrace2/ctf-writer/field-types.h>
 #include <babeltrace2/ctf-writer/object-internal.h>
 #include <babeltrace2/types.h>
 
-#define BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(_ft, _type_id, _name)       \
-       BT_ASSERT_PRE(((struct bt_ctf_field_type_common *) (_ft))->id == (_type_id), \
+#define BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(_ft, _type_id, _name)   \
+       BT_CTF_ASSERT_PRE(((struct bt_ctf_field_type_common *) (_ft))->id == (_type_id), \
                _name " has the wrong type ID: expected-type-id=%s, "   \
                "ft-addr=%p", bt_ctf_field_type_id_string(_type_id), (_ft))
 
-#define BT_ASSERT_PRE_CTF_FT_HOT(_ft, _name)                           \
-       BT_ASSERT_PRE_HOT((_ft), (_name), ": ft-addr=%p", (_ft))
+#define BT_CTF_ASSERT_PRE_CTF_FT_HOT(_ft, _name)                               \
+       BT_CTF_ASSERT_PRE_HOT((_ft), (_name), ": ft-addr=%p", (_ft))
 
 #define BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(_ft, _index) \
        (&g_array_index(((struct bt_ctf_field_type_common_structure *) (_ft))->fields, \
index 0586fdd77662ecffb32ee647d206184d10d397b3..e9bd3962658fadea103d8a70e704af55a585bbca 100644 (file)
@@ -31,7 +31,7 @@
 #include <stdint.h>
 #include <stddef.h>
 
-#include <babeltrace2/assert-pre-internal.h>
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
 #include <babeltrace2/babeltrace-internal.h>
 #include <babeltrace2/common-internal.h>
 #include <babeltrace2/ctf-writer/field-types-internal.h>
 #include <stdint.h>
 #include <string.h>
 
-#define BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(_field, _type_id, _name) \
-       BT_ASSERT_PRE((_field)->type->id == ((int) (_type_id)),         \
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(_field, _type_id, _name) \
+       BT_CTF_ASSERT_PRE((_field)->type->id == ((int) (_type_id)),             \
                _name " has the wrong type ID: expected-type-id=%s, "   \
                "field-addr=%p",                                        \
                bt_ctf_field_type_id_string((int) (_type_id)), (_field))
 
-#define BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(_field, _name)           \
-       BT_ASSERT_PRE(bt_ctf_field_common_is_set_recursive(_field),     \
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(_field, _name)               \
+       BT_CTF_ASSERT_PRE(bt_ctf_field_common_is_set_recursive(_field), \
                _name " is not set: field-addr=%p", (_field))
 
-#define BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(_field, _name)              \
-       BT_ASSERT_PRE_HOT((_field), (_name), ": field-addr=%p", (_field))
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(_field, _name)          \
+       BT_CTF_ASSERT_PRE_HOT((_field), (_name), ": field-addr=%p", (_field))
 
 struct bt_ctf_field_common;
 
@@ -297,7 +297,7 @@ int _bt_ctf_field_common_validate_recursive(struct bt_ctf_field_common *field)
        int ret = 0;
 
        if (!field) {
-               BT_ASSERT_PRE_MSG("%s", "Invalid field: field is NULL.");
+               BT_CTF_ASSERT_PRE_MSG("%s", "Invalid field: field is NULL.");
                ret = -1;
                goto end;
        }
@@ -363,7 +363,7 @@ struct bt_ctf_field_type_common *bt_ctf_field_common_borrow_type(
 {
        struct bt_ctf_field_type_common *ret = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
        ret = field->type;
        return ret;
 }
@@ -373,8 +373,8 @@ int64_t bt_ctf_field_common_sequence_get_length(struct bt_ctf_field_common *fiel
 {
        struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
                "Field");
        return (int64_t) sequence->length;
 }
@@ -386,11 +386,11 @@ int bt_ctf_field_common_sequence_set_length(struct bt_ctf_field_common *field,
        int ret = 0;
        struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_ASSERT_PRE(((int64_t) length) >= 0,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
+       BT_CTF_ASSERT_PRE(((int64_t) length) >= 0,
                "Invalid sequence length (too large): length=%" PRId64,
                length);
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Sequence field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Sequence field");
 
        if (unlikely(length > sequence->elements->len)) {
                /* Make more room */
@@ -432,9 +432,9 @@ struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_name(
        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_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_STRUCT, "Field");
        structure_ft = BT_CTF_FROM_COMMON(field->type);
        field_name_to_index = structure_ft->field_name_to_index;
@@ -461,10 +461,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_index(
 {
        struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Structure field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_STRUCT, "Field");
-       BT_ASSERT_PRE(index < structure->fields->len,
+       BT_CTF_ASSERT_PRE(index < structure->fields->len,
                "Index is out of bound: struct-field-addr=%p, "
                "index=%" PRIu64 ", count=%u", field, index,
                structure->fields->len);
@@ -477,10 +477,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_array_borrow_field(
 {
        struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Array field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_ARRAY,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Array field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_ARRAY,
                "Field");
-       BT_ASSERT_PRE(index < array->elements->len,
+       BT_CTF_ASSERT_PRE(index < array->elements->len,
                "Index is out of bound: array-field-addr=%p, "
                "index=%" PRIu64 ", count=%u", field,
                index, array->elements->len);
@@ -493,10 +493,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_sequence_borrow_field(
 {
        struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
                "Field");
-       BT_ASSERT_PRE(index < sequence->length,
+       BT_CTF_ASSERT_PRE(index < sequence->length,
                "Index is out of bound: seq-field-addr=%p, "
                "index=%" PRIu64 ", count=%u", field, index,
                sequence->elements->len);
@@ -511,8 +511,8 @@ int bt_ctf_field_common_variant_set_tag(struct bt_ctf_field_common *variant_fiel
        int64_t choice_index;
        struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
 
-       BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
                BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
 
        /* Find matching index in variant field's type */
@@ -538,10 +538,10 @@ struct bt_ctf_field_common *bt_ctf_field_common_variant_borrow_current_field(
 {
        struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
 
-       BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
                BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_ASSERT_PRE(variant->current_field,
+       BT_CTF_ASSERT_PRE(variant->current_field,
                "Variant field has no current field: field-addr=%p", variant_field);
        return variant->current_field;
 }
@@ -552,10 +552,10 @@ int bt_ctf_field_common_variant_get_tag_signed(struct bt_ctf_field_common *varia
 {
        struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
 
-       BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
                BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_ASSERT_PRE(variant->current_field,
+       BT_CTF_ASSERT_PRE(variant->current_field,
                "Variant field has no current field: field-addr=%p", variant_field);
        *tag = variant->tag_value.i;
        return 0;
@@ -567,10 +567,10 @@ int bt_ctf_field_common_variant_get_tag_unsigned(struct bt_ctf_field_common *var
 {
        struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
 
-       BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
                BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_ASSERT_PRE(variant->current_field,
+       BT_CTF_ASSERT_PRE(variant->current_field,
                "Variant field has no current field: field-addr=%p", variant_field);
        *tag = variant->tag_value.u;
        return 0;
@@ -583,10 +583,10 @@ int bt_ctf_field_common_floating_point_get_value(struct bt_ctf_field_common *fie
        struct bt_ctf_field_common_floating_point *floating_point =
                BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Floating point number field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_FLOAT, "Field");
        *value = floating_point->payload;
        return 0;
@@ -599,9 +599,9 @@ int bt_ctf_field_common_floating_point_set_value(struct bt_ctf_field_common *fie
        struct bt_ctf_field_common_floating_point *floating_point =
                BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Floating point number field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Floating point number field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_FLOAT, "Field");
        floating_point->payload = value;
        bt_ctf_field_common_set(field, true);
@@ -613,9 +613,9 @@ const char *bt_ctf_field_common_string_get_value(struct bt_ctf_field_common *fie
 {
        struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_STRING, "Field");
        return (const char *) string->buf->data;
 }
@@ -625,9 +625,9 @@ int bt_ctf_field_common_string_clear(struct bt_ctf_field_common *field)
 {
        struct bt_ctf_field_common_string *string_field = BT_CTF_FROM_COMMON(field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_STRING, "Field");
        string_field->size = 0;
        bt_ctf_field_common_set(field, true);
@@ -642,14 +642,14 @@ int bt_ctf_field_common_string_append_len(struct bt_ctf_field_common *field,
        char *data;
        size_t new_size;
 
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_STRING, "Field");
 
        /* Make sure no null bytes are appended */
-       BT_ASSERT_PRE(memchr(value, '\0', length) == NULL,
+       BT_CTF_ASSERT_PRE(memchr(value, '\0', length) == NULL,
                "String value to append contains a null character: "
                "partial-value=\"%.32s\", length=%u", value, length);
 
@@ -671,7 +671,7 @@ static inline
 int bt_ctf_field_common_string_append(struct bt_ctf_field_common *field,
                const char *value)
 {
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
        return bt_ctf_field_common_string_append_len(field, value,
                strlen(value));
 }
@@ -680,10 +680,10 @@ static inline
 int bt_ctf_field_common_string_set_value(struct bt_ctf_field_common *field,
                const char *value)
 {
-       BT_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
                BT_CTF_FIELD_TYPE_ID_STRING, "Field");
        bt_ctf_field_common_string_clear(field);
        return bt_ctf_field_common_string_append_len(field,
@@ -784,7 +784,7 @@ void bt_ctf_field_common_string_finalize(struct bt_ctf_field_common *field)
        }
 }
 
-BT_ASSERT_PRE_FUNC
+BT_CTF_ASSERT_PRE_FUNC
 static inline bool value_is_in_range_signed(unsigned int size, int64_t value)
 {
        bool ret = true;
@@ -802,7 +802,7 @@ static inline bool value_is_in_range_signed(unsigned int size, int64_t value)
        return ret;
 }
 
-BT_ASSERT_PRE_FUNC
+BT_CTF_ASSERT_PRE_FUNC
 static inline bool value_is_in_range_unsigned(unsigned int size, uint64_t value)
 {
        bool ret = true;
index 2098253552decd9a50e63ea4e15cbb0de5be85af..0b7fd47d4561b67bc014a1d8de89d4b91b2a227d 100644 (file)
@@ -101,7 +101,7 @@ static inline
 const char *bt_ctf_stream_class_common_get_name(
                struct bt_ctf_stream_class_common *stream_class)
 {
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
        return stream_class->name->len > 0 ? stream_class->name->str : NULL;
 }
 
@@ -111,7 +111,7 @@ int64_t bt_ctf_stream_class_common_get_id(
 {
        int64_t ret;
 
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_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\"",
@@ -289,8 +289,8 @@ static inline
 struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_by_index(
                struct bt_ctf_stream_class_common *stream_class, uint64_t index)
 {
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(index < stream_class->event_classes->len,
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_ASSERT_PRE(index < stream_class->event_classes->len,
                "Index is out of bounds: index=%" PRIu64 ", "
                "count=%u",
                index, stream_class->event_classes->len);
@@ -303,8 +303,8 @@ struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_
 {
        int64_t id_key = (int64_t) id;
 
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(id_key >= 0,
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_ASSERT_PRE(id_key >= 0,
                "Invalid event class ID: %" PRIu64, id);
        return g_hash_table_lookup(stream_class->event_classes_ht,
                        &id_key);
@@ -315,7 +315,7 @@ struct bt_ctf_field_type_common *
 bt_ctf_stream_class_common_borrow_packet_context_field_type(
                struct bt_ctf_stream_class_common *stream_class)
 {
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
        return stream_class->packet_context_field_type;
 }
 
@@ -378,7 +378,7 @@ bt_ctf_stream_class_common_borrow_event_header_field_type(
 {
        struct bt_ctf_field_type_common *ret = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_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: "
@@ -454,7 +454,7 @@ bt_ctf_stream_class_common_borrow_event_context_field_type(
 {
        struct bt_ctf_field_type_common *ret = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
 
        if (!stream_class->event_context_field_type) {
                goto end;
index 456a6f4d84962a1bb2823c8b94c8b74e6c72dfcc..c7eb9faedefcd35c8f7474e6967d5d97b3617b79 100644 (file)
@@ -29,7 +29,7 @@
  */
 
 #include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
 #include <babeltrace2/babeltrace-internal.h>
 #include <babeltrace2/ctf-writer/stream-internal.h>
 #include <babeltrace2/ctf-writer/stream.h>
@@ -67,7 +67,7 @@ struct bt_ctf_stream_class_common *bt_ctf_stream_common_borrow_class(
 static inline
 const char *bt_ctf_stream_common_get_name(struct bt_ctf_stream_common *stream)
 {
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream");
        return stream->name ? stream->name->str : NULL;
 }
 
@@ -76,7 +76,7 @@ int64_t bt_ctf_stream_common_get_id(struct bt_ctf_stream_common *stream)
 {
        int64_t ret;
 
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream");
        ret = stream->id;
        if (ret < 0) {
                BT_LOGV("Stream's ID is not set: addr=%p, name=\"%s\"",
index ff313cf40301f1ba521a95e8e32e45f9268b3da7..4d3e4d1ab68ec44f9a69c7ea9964358581ef6779 100644 (file)
@@ -28,7 +28,7 @@
  * http://www.efficios.com/ctf
  */
 
-#include <babeltrace2/assert-pre-internal.h>
+#include <babeltrace2/ctf-writer/assert-pre-internal.h>
 #include <babeltrace2/babeltrace-internal.h>
 #include <babeltrace2/compat/uuid-internal.h>
 #include <babeltrace2/ctf-writer/attributes-internal.h>
@@ -79,7 +79,7 @@ void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace);
 static inline
 const char *bt_ctf_trace_common_get_name(struct bt_ctf_trace_common *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return trace->name ? trace->name->str : NULL;
 }
 
@@ -89,7 +89,7 @@ int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *
 static inline
 const unsigned char *bt_ctf_trace_common_get_uuid(struct bt_ctf_trace_common *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return trace->uuid_set ? trace->uuid : NULL;
 }
 
@@ -114,7 +114,7 @@ int64_t bt_ctf_trace_common_get_environment_field_count(
 {
        int64_t ret;
 
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        ret = bt_ctf_attributes_get_count(trace->environment);
        BT_ASSERT(ret >= 0);
        return ret;
@@ -125,7 +125,7 @@ const char *
 bt_ctf_trace_common_get_environment_field_name_by_index(
                struct bt_ctf_trace_common *trace, uint64_t index)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return bt_ctf_attributes_get_field_name(trace->environment, index);
 }
 
@@ -134,7 +134,7 @@ struct bt_ctf_private_value *
 bt_ctf_trace_common_borrow_environment_field_value_by_index(
                struct bt_ctf_trace_common *trace, uint64_t index)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return bt_ctf_attributes_borrow_field_value(trace->environment, index);
 }
 
@@ -143,8 +143,8 @@ struct bt_ctf_private_value *
 bt_ctf_trace_common_borrow_environment_field_value_by_name(
                struct bt_ctf_trace_common *trace, const char *name)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
        return bt_ctf_attributes_borrow_field_value_by_name(trace->environment,
                name);
 }
@@ -156,7 +156,7 @@ int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
 static inline
 int64_t bt_ctf_trace_common_get_clock_class_count(struct bt_ctf_trace_common *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return trace->clock_classes->len;
 }
 
@@ -164,8 +164,8 @@ static inline
 struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_index(
                struct bt_ctf_trace_common *trace, uint64_t index)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(index < trace->clock_classes->len,
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(index < trace->clock_classes->len,
                "Index is out of bounds: index=%" PRIu64 ", "
                "count=%u",
                index, trace->clock_classes->len);
@@ -175,7 +175,7 @@ struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_index(
 static inline
 int64_t bt_ctf_trace_common_get_stream_count(struct bt_ctf_trace_common *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return (int64_t) trace->streams->len;
 }
 
@@ -184,8 +184,8 @@ struct bt_ctf_stream_common *bt_ctf_trace_common_borrow_stream_by_index(
                struct bt_ctf_trace_common *trace,
                uint64_t index)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(index < trace->streams->len,
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(index < trace->streams->len,
                "Index is out of bounds: index=%" PRIu64 ", "
                "count=%u",
                index, trace->streams->len);
@@ -195,7 +195,7 @@ struct bt_ctf_stream_common *bt_ctf_trace_common_borrow_stream_by_index(
 static inline
 int64_t bt_ctf_trace_common_get_stream_class_count(struct bt_ctf_trace_common *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return (int64_t) trace->stream_classes->len;
 }
 
@@ -203,8 +203,8 @@ static inline
 struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_index(
                struct bt_ctf_trace_common *trace, uint64_t index)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(index < trace->stream_classes->len,
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(index < trace->stream_classes->len,
                "Index is out of bounds: index=%" PRIu64 ", "
                "count=%u",
                index, trace->stream_classes->len);
@@ -219,8 +219,8 @@ struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_id
        struct bt_ctf_stream_class_common *stream_class = NULL;
        int64_t id = (int64_t) id_param;
 
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(id >= 0,
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(id >= 0,
                "Invalid stream class ID: %" PRIu64, id_param);
 
        for (i = 0; i < trace->stream_classes->len; i++) {
@@ -247,8 +247,8 @@ struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_name(
        size_t i;
        struct bt_ctf_clock_class *clock_class = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
 
        for (i = 0; i < trace->clock_classes->len; i++) {
                struct bt_ctf_clock_class *cur_clk =
@@ -273,7 +273,7 @@ static inline
 enum bt_ctf_byte_order bt_ctf_trace_common_get_native_byte_order(
                struct bt_ctf_trace_common *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return trace->native_byte_order;
 }
 
@@ -285,7 +285,7 @@ static inline
 struct bt_ctf_field_type_common *bt_ctf_trace_common_borrow_packet_header_field_type(
                struct bt_ctf_trace_common *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
        return trace->packet_header_field_type;
 }
 
index fe6b88b0b993546cb4f50b60a35d047e297da98a..39b956a98a6ab4907c6ba42c2c07c44560c3bc8f 100644 (file)
@@ -1,6 +1,6 @@
-SUBDIRS = trace-ir ctf-writer prio_heap plugin graph .
+SUBDIRS = trace-ir prio_heap plugin graph
 
-lib_LTLIBRARIES = libbabeltrace2.la libbabeltrace2-ctf.la
+lib_LTLIBRARIES = libbabeltrace2.la
 
 libbabeltrace2_la_SOURCES = \
        babeltrace2.c \
@@ -17,32 +17,10 @@ libbabeltrace2_la_LIBADD = \
        graph/libgraph.la \
        plugin/libplugin.la \
        trace-ir/libtrace-ir.la \
-       ctf-writer/libctf-writer.la \
        $(top_builddir)/logging/libbabeltrace2-logging.la \
        $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/ctfser/libbabeltrace2-ctfser.la \
        $(top_builddir)/compat/libcompat.la
 
 if ENABLE_BUILT_IN_PYTHON_PLUGIN_SUPPORT
 libbabeltrace2_la_LIBADD += $(top_builddir)/python-plugin-provider/libbabeltrace2-python-plugin-provider.la
 endif
-
-# FIXME: Should we drop this? We changed the basename of the library,
-#        libbabeltrace2 is not a drop-in replacement for libbabeltrace anymore.
-#
-# Build a libbabeltrace2-ctf library for backwards compatibility.
-# CTF writer used to be in libbabeltrace2-ctf in Babeltrace 1, so this
-# file must still exist. As of Babeltrace 2, CTF writer is implemented
-# in libbabeltrace2.
-libbabeltrace2_ctf_la_SOURCES = $(libbabeltrace2_la_SOURCES)
-libbabeltrace2_ctf_la_LDFLAGS = $(LT_NO_UNDEFINED) \
-                       -version-info $(BABELTRACE_LIBRARY_VERSION)
-
-libbabeltrace2_ctf_la_LIBADD = \
-       graph/libgraph.la \
-       trace-ir/libtrace-ir.la \
-       ctf-writer/libctf-writer.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/ctfser/libbabeltrace2-ctfser.la \
-       $(top_builddir)/compat/libcompat.la
diff --git a/lib/ctf-writer/Makefile.am b/lib/ctf-writer/Makefile.am
deleted file mode 100644 (file)
index bee4b39..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-noinst_LTLIBRARIES = libctf-writer.la
-
-libctf_writer_la_SOURCES = \
-       attributes.c \
-       clock.c \
-       clock-class.c \
-       event.c \
-       event-class.c \
-       field-path.c \
-       fields.c \
-       field-types.c \
-       field-wrapper.c \
-       functor.c \
-       object.c \
-       object-pool.c \
-       resolve.c \
-       stream.c \
-       stream-class.c \
-       trace.c \
-       utils.c \
-       validation.c \
-       values.c \
-       visitor.c \
-       writer.c
-
-libctf_writer_la_LIBADD = $(UUID_LIBS)
diff --git a/lib/ctf-writer/attributes.c b/lib/ctf-writer/attributes.c
deleted file mode 100644 (file)
index a594015..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * attributes.c
- *
- * Babeltrace CTF writer - Attributes
- *
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015 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 "CTF-WRITER-ATTRS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <inttypes.h>
-
-#define BT_CTF_ATTR_NAME_INDEX         0
-#define BT_CTF_ATTR_VALUE_INDEX                1
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_create(void)
-{
-       struct bt_ctf_private_value *attr_obj;
-
-       /*
-        * Attributes: array value object of array value objects, each one
-        * containing two entries: a string value object (attributes
-        * field name), and a value object (attributes field value).
-        *
-        * Example (JSON representation):
-        *
-        *     [
-        *         ["hostname", "eeppdesk"],
-        *         ["sysname", "Linux"],
-        *         ["tracer_major", 2],
-        *         ["tracer_minor", 5]
-        *     ]
-        */
-       BT_LOGD_STR("Creating attributes object.");
-       attr_obj = bt_ctf_private_value_array_create();
-       if (!attr_obj) {
-               BT_LOGE_STR("Failed to create array value.");
-       } else {
-               BT_LOGD("Created attributes object: addr=%p",
-                       attr_obj);
-       }
-
-       return attr_obj;
-}
-
-BT_HIDDEN
-void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj)
-{
-       BT_LOGD("Destroying attributes object: addr=%p", attr_obj);
-       bt_ctf_object_put_ref(attr_obj);
-}
-
-BT_HIDDEN
-int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj)
-{
-       return bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
-}
-
-BT_HIDDEN
-const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj,
-               uint64_t index)
-{
-       const char *ret = NULL;
-       struct bt_ctf_private_value *attr_field_obj = NULL;
-       struct bt_ctf_private_value *attr_field_name_obj = NULL;
-
-       if (!attr_obj) {
-               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
-               goto end;
-       }
-
-       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "index=%" PRIu64 ", count=%" PRId64,
-                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
-               attr_obj, index);
-       if (!attr_field_obj) {
-               BT_LOGE("Cannot get attributes object's array value's element by index: "
-                       "value-addr=%p, index=%" PRIu64, attr_obj, index);
-               goto end;
-       }
-
-       attr_field_name_obj =
-               bt_ctf_private_value_array_borrow_element_by_index(
-                       attr_field_obj, BT_CTF_ATTR_NAME_INDEX);
-       if (!attr_field_name_obj) {
-               BT_LOGE("Cannot get attribute array value's element by index: "
-                       "value-addr=%p, index=%" PRIu64, attr_field_obj,
-                       (uint64_t) BT_CTF_ATTR_NAME_INDEX);
-               goto end;
-       }
-
-       ret = bt_ctf_value_string_get(
-               bt_ctf_private_value_as_value(attr_field_name_obj));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj,
-               uint64_t index)
-{
-       struct bt_ctf_private_value *value_obj = NULL;
-       struct bt_ctf_private_value *attr_field_obj = NULL;
-
-       if (!attr_obj) {
-               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
-               goto end;
-       }
-
-       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "index=%" PRIu64 ", count=%" PRId64,
-                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
-               attr_obj, index);
-       if (!attr_field_obj) {
-               BT_LOGE("Cannot get attributes object's array value's element by index: "
-                       "value-addr=%p, index=%" PRIu64, attr_obj, index);
-               goto end;
-       }
-
-       value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
-               BT_CTF_ATTR_VALUE_INDEX);
-       if (!value_obj) {
-               BT_LOGE("Cannot get attribute array value's element by index: "
-                       "value-addr=%p, index=%" PRIu64, attr_field_obj,
-                       (uint64_t) BT_CTF_ATTR_VALUE_INDEX);
-       }
-
-end:
-       return value_obj;
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_by_name(
-               struct bt_ctf_private_value *attr_obj, const char *name)
-{
-       uint64_t i;
-       int64_t attr_size;
-       struct bt_ctf_private_value *value_obj = NULL;
-       struct bt_ctf_private_value *attr_field_name_obj = NULL;
-
-       attr_size = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
-       if (attr_size < 0) {
-               BT_LOGE("Cannot get array value's size: value-addr=%p",
-                       attr_obj);
-               goto error;
-       }
-
-       for (i = 0; i < attr_size; ++i) {
-               const char *field_name;
-
-               value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_obj, i);
-               if (!value_obj) {
-                       BT_LOGE("Cannot get attributes object's array value's element by index: "
-                               "value-addr=%p, index=%" PRIu64, attr_obj, i);
-                       goto error;
-               }
-
-               attr_field_name_obj = bt_ctf_private_value_array_borrow_element_by_index(value_obj,
-                       BT_CTF_ATTR_NAME_INDEX);
-               if (!attr_field_name_obj) {
-                       BT_LOGE("Cannot get attribute array value's element by index: "
-                               "value-addr=%p, index=%" PRIu64,
-                               value_obj, (int64_t) BT_CTF_ATTR_NAME_INDEX);
-                       goto error;
-               }
-
-               field_name = bt_ctf_value_string_get(
-                       bt_ctf_private_value_as_value(attr_field_name_obj));
-
-               if (!strcmp(field_name, name)) {
-                       break;
-               }
-
-               value_obj = NULL;
-       }
-
-       return value_obj;
-
-error:
-       value_obj = NULL;
-       return value_obj;
-}
-
-BT_HIDDEN
-int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj,
-               const char *name, struct bt_ctf_private_value *value_obj)
-{
-       int ret = 0;
-       struct bt_ctf_private_value *attr_field_obj = NULL;
-
-       if (!attr_obj || !name || !value_obj) {
-               BT_LOGW("Invalid parameter: attributes object, name, or value object is NULL: "
-                       "attr-value-addr=%p, name-addr=%p, value-addr=%p",
-                       attr_obj, name, value_obj);
-               ret = -1;
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name);
-       if (attr_field_obj) {
-               ret = bt_ctf_private_value_array_set_element_by_index(
-                       attr_field_obj, BT_CTF_ATTR_VALUE_INDEX,
-                       bt_ctf_private_value_as_value(value_obj));
-               attr_field_obj = NULL;
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_private_value_array_create();
-       if (!attr_field_obj) {
-               BT_LOGE_STR("Failed to create empty array value.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_private_value_array_append_string_element(attr_field_obj, name);
-       ret |= bt_ctf_private_value_array_append_element(attr_field_obj,
-               bt_ctf_private_value_as_value(value_obj));
-       if (ret) {
-               BT_LOGE("Cannot append elements to array value: addr=%p",
-                       attr_field_obj);
-               goto end;
-       }
-
-       ret = bt_ctf_private_value_array_append_element(attr_obj,
-               bt_ctf_private_value_as_value(attr_field_obj));
-       if (ret) {
-               BT_LOGE("Cannot append element to array value: "
-                       "array-value-addr=%p, element-value-addr=%p",
-                       attr_obj, attr_field_obj);
-       }
-
-end:
-       bt_ctf_object_put_ref(attr_field_obj);
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name(
-               struct bt_ctf_private_value *attr_obj, const char *name)
-{
-       struct bt_ctf_private_value *value_obj = NULL;
-       struct bt_ctf_private_value *attr_field_obj = NULL;
-
-       if (!attr_obj || !name) {
-               BT_LOGW("Invalid parameter: attributes object or name is NULL: "
-                       "value-addr=%p, name-addr=%p", attr_obj, name);
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_attributes_borrow_field_by_name(attr_obj, name);
-       if (!attr_field_obj) {
-               BT_LOGD("Cannot find attributes object's field by name: "
-                       "value-addr=%p, name=\"%s\"", attr_obj, name);
-               goto end;
-       }
-
-       value_obj = bt_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
-               BT_CTF_ATTR_VALUE_INDEX);
-       if (!value_obj) {
-               BT_LOGE("Cannot get attribute array value's element by index: "
-                       "value-addr=%p, index=%" PRIu64, attr_field_obj,
-                       (uint64_t) BT_CTF_ATTR_VALUE_INDEX);
-       }
-
-end:
-       return value_obj;
-}
-
-BT_HIDDEN
-int bt_ctf_attributes_freeze(struct bt_ctf_private_value *attr_obj)
-{
-       uint64_t i;
-       int64_t count;
-       int ret = 0;
-
-       if (!attr_obj) {
-               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGD("Freezing attributes object: value-addr=%p", attr_obj);
-       count = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
-       BT_ASSERT(count >= 0);
-
-       /*
-        * We do not freeze the array value object itself here, since
-        * internal stuff could need to modify/add attributes. Each
-        * attribute is frozen one by one.
-        */
-       for (i = 0; i < count; ++i) {
-               struct bt_ctf_private_value *obj = NULL;
-
-               obj = bt_ctf_attributes_borrow_field_value(attr_obj, i);
-               if (!obj) {
-                       BT_LOGE("Cannot get attributes object's field value by index: "
-                               "value-addr=%p, index=%" PRIu64,
-                               attr_obj, i);
-                       ret = -1;
-                       goto end;
-               }
-
-               bt_ctf_value_freeze(bt_ctf_private_value_as_value(obj));
-       }
-
-end:
-       return ret;
-}
diff --git a/lib/ctf-writer/clock-class.c b/lib/ctf-writer/clock-class.c
deleted file mode 100644 (file)
index 9e3807c..0000000
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * clock-class.c
- *
- * Babeltrace CTF writer - Clock class
- *
- * Copyright 2013, 2014 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.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-CLOCK-CLASS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <inttypes.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-static
-void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class)
-{
-       return clock_class && clock_class->name;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class,
-               const char *name)
-{
-       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_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_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->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;
-}
-
-static
-bool validate_freq(struct bt_ctf_clock_class *clock_class,
-               const char *name, uint64_t freq)
-{
-       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_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name,
-               uint64_t freq)
-{
-       int ret;
-       struct bt_ctf_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;
-       }
-
-       clock_class = g_new0(struct bt_ctf_clock_class, 1);
-       if (!clock_class) {
-               BT_LOGE_STR("Failed to allocate one clock class.");
-               goto error;
-       }
-
-       clock_class->precision = 1;
-       clock_class->frequency = freq;
-       bt_ctf_object_init_shared(&clock_class->base, bt_ctf_clock_class_destroy);
-
-       if (name) {
-               ret = bt_ctf_clock_class_set_name(clock_class, name);
-               if (ret) {
-                       /* bt_ctf_clock_class_set_name() logs errors */
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Created clock class object: addr=%p, name=\"%s\"",
-               clock_class, name);
-       return clock_class;
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock_class);
-       return clock_class;
-}
-
-BT_HIDDEN
-const char *bt_ctf_clock_class_get_name(struct bt_ctf_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;
-}
-
-BT_HIDDEN
-const char *bt_ctf_clock_class_get_description(
-               struct bt_ctf_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->description) {
-               ret = clock_class->description->str;
-       }
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class,
-               const char *desc)
-{
-       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_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class), desc);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_clock_class_get_frequency(
-               struct bt_ctf_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_HIDDEN
-int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class,
-               uint64_t freq)
-{
-       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_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!validate_freq(clock_class, bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class), freq);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_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_HIDDEN
-int bt_ctf_clock_class_set_precision(struct bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->precision = precision;
-       BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64,
-               clock_class, bt_ctf_clock_class_get_name(clock_class),
-               precision);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class,
-               int64_t *offset_s)
-{
-       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_ctf_clock_class_get_name(clock_class),
-                       offset_s);
-               ret = -1;
-               goto end;
-       }
-
-       *offset_s = clock_class->offset_s;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_offset_s(struct bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class),
-               offset_s);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_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_ctf_clock_class_get_name(clock_class),
-                       offset);
-               ret = -1;
-               goto end;
-       }
-
-       *offset = clock_class->offset;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class,
-               int64_t offset)
-{
-       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_ctf_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_ctf_clock_class_get_name(clock_class), offset);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_clock_class_is_absolute(struct bt_ctf_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_HIDDEN
-int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_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_ctf_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_ctf_clock_class_get_name(clock_class),
-               is_absolute);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-const unsigned char *bt_ctf_clock_class_get_uuid(
-               struct bt_ctf_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_ctf_clock_class_get_name(clock_class));
-               ret = NULL;
-               goto end;
-       }
-
-       ret = clock_class->uuid;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class,
-               const unsigned char *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_ctf_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_ctf_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_ctf_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_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class)
-{
-       if (!clock_class || clock_class->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"",
-               clock_class, bt_ctf_clock_class_get_name(clock_class));
-       clock_class->frozen = 1;
-}
-
-static
-void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_clock_class *clock_class;
-
-       clock_class = container_of(obj, struct bt_ctf_clock_class, base);
-       BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"",
-               obj, bt_ctf_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);
-       }
-
-       g_free(clock_class);
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a,
-               struct bt_ctf_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;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
diff --git a/lib/ctf-writer/clock.c b/lib/ctf-writer/clock.c
deleted file mode 100644 (file)
index f270ce3..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * clock.c
- *
- * Babeltrace CTF writer - Clock
- *
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017 Philippe Proulx <pproulx@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.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-CLOCK"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <inttypes.h>
-
-static
-void bt_ctf_clock_destroy(struct bt_ctf_object *obj);
-
-struct bt_ctf_clock *bt_ctf_clock_create(const char *name)
-{
-       int ret;
-       struct bt_ctf_clock *clock = NULL;
-       unsigned char cc_uuid[BABELTRACE_UUID_LEN];
-
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       clock = g_new0(struct bt_ctf_clock, 1);
-       if (!clock) {
-               goto error;
-       }
-
-       bt_ctf_object_init_shared(&clock->base, bt_ctf_clock_destroy);
-       clock->value = 0;
-
-       /* Pre-2.0.0 backward compatibility: default frequency is 1 GHz */
-       clock->clock_class = (void *) bt_ctf_clock_class_create(name, 1000000000);
-       if (!clock->clock_class) {
-               goto error;
-       }
-
-       /* Automatically set clock class's UUID. */
-       ret = bt_uuid_generate(cc_uuid);
-       if (ret) {
-               goto error;
-       }
-
-       ret = bt_ctf_clock_class_set_uuid(clock->clock_class, cc_uuid);
-       BT_ASSERT(ret == 0);
-       return clock;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock);
-       return clock;
-}
-
-const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_name(clock->clock_class);
-}
-
-const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_description(clock->clock_class);
-}
-
-int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_description(clock->clock_class,
-               desc);
-}
-
-uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_frequency(clock->clock_class);
-}
-
-int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_frequency(clock->clock_class,
-               freq);
-}
-
-uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_precision(clock->clock_class);
-}
-
-int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_precision(clock->clock_class,
-               precision);
-}
-
-int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, int64_t *offset_s)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_offset_s(clock->clock_class,
-               offset_s);
-}
-
-int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, int64_t offset_s)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_offset_s(clock->clock_class,
-               offset_s);
-}
-
-int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, int64_t *offset)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_offset_cycles(clock->clock_class,
-               offset);
-}
-
-int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, int64_t offset)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_offset_cycles(clock->clock_class,
-               offset);
-}
-
-int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_is_absolute(clock->clock_class);
-}
-
-int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_is_absolute(clock->clock_class,
-               is_absolute);
-}
-
-const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_uuid(clock->clock_class);
-}
-
-int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, const unsigned char *uuid)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_uuid(clock->clock_class, uuid);
-}
-
-int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, int64_t time)
-{
-       int64_t value;
-       struct bt_ctf_clock_class *cc;
-
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       cc = clock->clock_class;
-
-       /* Common case where cycles are actually nanoseconds */
-       if (cc->frequency == 1000000000) {
-               value = time;
-       } else {
-               value = (uint64_t) (((double) time *
-                       (double) cc->frequency) / 1e9);
-       }
-
-       BT_ASSERT_PRE(clock->value <= value,
-               "CTF writer clock value must be updated monotonically: "
-               "prev-value=%" PRId64 ", new-value=%" PRId64,
-               clock->value, value);
-       clock->value = value;
-       return 0;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value)
-{
-       BT_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       *value = clock->value;
-       return 0;
-}
-
-static
-void bt_ctf_clock_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_clock *clock;
-
-       clock = container_of(obj, struct bt_ctf_clock, base);
-       bt_ctf_object_put_ref(clock->clock_class);
-       g_free(clock);
-}
-
-BT_HIDDEN
-void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class,
-               struct metadata_context *context)
-{
-       unsigned char *uuid;
-
-       BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, "
-               "name=\"%s\", metadata-context-addr=%p", clock_class,
-               bt_ctf_clock_class_get_name(clock_class),
-               context);
-
-       if (!clock_class || !context) {
-               BT_LOGW("Invalid parameter: clock class or metadata context is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p",
-                       clock_class,
-                       bt_ctf_clock_class_get_name(clock_class),
-                       context);
-               return;
-       }
-
-       uuid = clock_class->uuid;
-       g_string_append(context->string, "clock {\n");
-       g_string_append_printf(context->string, "\tname = %s;\n",
-               clock_class->name->str);
-
-       if (clock_class->uuid_set) {
-               g_string_append_printf(context->string,
-                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
-                       uuid[0], uuid[1], uuid[2], uuid[3],
-                       uuid[4], uuid[5], uuid[6], uuid[7],
-                       uuid[8], uuid[9], uuid[10], uuid[11],
-                       uuid[12], uuid[13], uuid[14], uuid[15]);
-       }
-
-       if (clock_class->description) {
-               g_string_append_printf(context->string, "\tdescription = \"%s\";\n",
-                       clock_class->description->str);
-       }
-
-       g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n",
-               clock_class->frequency);
-       g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n",
-               clock_class->precision);
-       g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n",
-               clock_class->offset_s);
-       g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n",
-               clock_class->offset);
-       g_string_append_printf(context->string, "\tabsolute = %s;\n",
-               clock_class->absolute ? "true" : "false");
-       g_string_append(context->string, "};\n\n");
-}
diff --git a/lib/ctf-writer/event-class.c b/lib/ctf-writer/event-class.c
deleted file mode 100644 (file)
index f918b86..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * 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 "CTF-WRITER-EVENT-CLASS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/attributes-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-BT_HIDDEN
-void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_event_class_common *event_class;
-
-       event_class = container_of(obj, struct bt_ctf_event_class_common, base);
-       BT_LOGD("Finalizing common event class: addr=%p, name=\"%s\", id=%" PRId64,
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-
-       if (event_class->name) {
-               g_string_free(event_class->name, TRUE);
-       }
-
-       if (event_class->emf_uri) {
-               g_string_free(event_class->emf_uri, TRUE);
-       }
-
-       BT_LOGD_STR("Putting context field type.");
-       bt_ctf_object_put_ref(event_class->context_field_type);
-       BT_LOGD_STR("Putting payload field type.");
-       bt_ctf_object_put_ref(event_class->payload_field_type);
-}
-
-BT_HIDDEN
-int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class,
-               const char *name, bt_ctf_object_release_func release_func,
-               bt_ctf_field_type_structure_create_func ft_struct_create_func)
-{
-       int ret = 0;
-
-       BT_LOGD("Initializing common event class object: name=\"%s\"",
-               name);
-       bt_ctf_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_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED;
-       BT_LOGD("Initialized common event class object: addr=%p, name=\"%s\"",
-               event_class, bt_ctf_event_class_common_get_name(event_class));
-       return ret;
-
-error:
-       ret = -1;
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *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_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-       event_class->frozen = 1;
-       BT_LOGD_STR("Freezing event class's context field type.");
-       bt_ctf_field_type_common_freeze(event_class->context_field_type);
-       BT_LOGD_STR("Freezing event class's payload field type.");
-       bt_ctf_field_type_common_freeze(event_class->payload_field_type);
-}
-
-BT_HIDDEN
-int bt_ctf_event_class_common_validate_single_clock_class(
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_clock_class **expected_clock_class)
-{
-       int ret = 0;
-
-       BT_ASSERT(event_class);
-       BT_ASSERT(expected_clock_class);
-       ret = bt_ctf_field_type_common_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_ctf_event_class_common_get_name(event_class),
-                       event_class->id,
-                       event_class->context_field_type);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_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_ctf_event_class_common_get_name(event_class),
-                       event_class->id,
-                       event_class->payload_field_type);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-void bt_ctf_event_class_destroy(struct bt_ctf_object *obj)
-{
-       bt_ctf_event_class_common_finalize(obj);
-       g_free(obj);
-}
-
-struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name)
-{
-       struct bt_ctf_event_class *ctf_event_class = NULL;
-       int ret;
-
-       if (!name) {
-               BT_LOGW_STR("Invalid parameter: name is NULL.");
-               goto error;
-       }
-
-       BT_LOGD("Creating event class object: name=\"%s\"",
-               name);
-       ctf_event_class = g_new0(struct bt_ctf_event_class, 1);
-       if (!ctf_event_class) {
-               BT_LOGE_STR("Failed to allocate one event class.");
-               goto error;
-       }
-
-       ret = bt_ctf_event_class_common_initialize(BT_CTF_TO_COMMON(ctf_event_class),
-               name, bt_ctf_event_class_destroy,
-               (bt_ctf_field_type_structure_create_func)
-                       bt_ctf_field_type_structure_create);
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       bt_ctf_object_put_ref(ctf_event_class);
-
-end:
-       return ctf_event_class;
-}
-
-const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_name(BT_CTF_TO_COMMON(event_class));
-}
-
-int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_id(BT_CTF_TO_COMMON(event_class));
-}
-
-int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class,
-               uint64_t id)
-{
-       return bt_ctf_event_class_common_set_id(BT_CTF_TO_COMMON(event_class), id);
-}
-
-enum bt_ctf_event_class_log_level bt_ctf_event_class_get_log_level(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_log_level(BT_CTF_TO_COMMON(event_class));
-}
-
-int bt_ctf_event_class_set_log_level(struct bt_ctf_event_class *event_class,
-               enum bt_ctf_event_class_log_level log_level)
-{
-       return bt_ctf_event_class_common_set_log_level(BT_CTF_TO_COMMON(event_class),
-               log_level);
-}
-
-const char *bt_ctf_event_class_get_emf_uri(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_emf_uri(BT_CTF_TO_COMMON(event_class));
-}
-
-int bt_ctf_event_class_set_emf_uri(struct bt_ctf_event_class *event_class,
-               const char *emf_uri)
-{
-       return bt_ctf_event_class_common_set_emf_uri(BT_CTF_TO_COMMON(event_class),
-               emf_uri);
-}
-
-struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class(
-               struct bt_ctf_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_stream_class(
-               BT_CTF_TO_COMMON(event_class)));
-}
-
-struct bt_ctf_field_type *bt_ctf_event_class_get_payload_field_type(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_payload_field_type(
-               BT_CTF_TO_COMMON(event_class)));
-}
-
-int bt_ctf_event_class_set_payload_field_type(
-               struct bt_ctf_event_class *event_class,
-               struct bt_ctf_field_type *field_type)
-{
-       return bt_ctf_event_class_common_set_payload_field_type(
-               BT_CTF_TO_COMMON(event_class), (void *) field_type);
-}
-
-struct bt_ctf_field_type *bt_ctf_event_class_get_context_field_type(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_context_field_type(
-               BT_CTF_TO_COMMON(event_class)));
-}
-
-int bt_ctf_event_class_set_context_field_type(
-               struct bt_ctf_event_class *event_class,
-               struct bt_ctf_field_type *field_type)
-{
-       return bt_ctf_event_class_common_set_context_field_type(
-               BT_CTF_TO_COMMON(event_class), (void *) field_type);
-}
-
-int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class,
-               struct bt_ctf_field_type *type,
-               const char *name)
-{
-       int ret = 0;
-
-       if (!event_class || !type) {
-               BT_LOGW("Invalid parameter: event class or field type is NULL: "
-                       "event-class-addr=%p, field-type-addr=%p",
-                       event_class, type);
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_identifier_is_valid(name)) {
-               BT_LOGW("Invalid parameter: event class's payload field type's field name is not a valid CTF identifier: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", field-name=\"%s\"",
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class),
-                       name);
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->common.frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!event_class->common.payload_field_type) {
-               BT_LOGW("Event class has no payload field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
-               event_class->common.payload_field_type) ==
-               BT_CTF_FIELD_TYPE_ID_STRUCT);
-       ret = bt_ctf_field_type_structure_add_field(
-               (void *) event_class->common.payload_field_type,
-               (void *) type, name);
-       BT_LOGV("Added field to event class's payload field type: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", field-name=\"%s\", ft-addr=%p",
-               event_class, bt_ctf_event_class_get_name(event_class),
-               bt_ctf_event_class_get_id(event_class), name, type);
-end:
-       return ret;
-}
-
-int64_t bt_ctf_event_class_get_payload_type_field_count(
-               struct bt_ctf_event_class *event_class)
-{
-       int64_t ret;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = (int64_t) -1;
-               goto end;
-       }
-
-       if (!event_class->common.payload_field_type) {
-               BT_LOGV("Event class has no payload field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class));
-               ret = (int64_t) -1;
-               goto end;
-       }
-
-       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
-               event_class->common.payload_field_type) ==
-                       BT_CTF_FIELD_TYPE_ID_STRUCT);
-       ret = bt_ctf_field_type_common_structure_get_field_count(
-               event_class->common.payload_field_type);
-end:
-       return ret;
-}
-
-int bt_ctf_event_class_get_payload_type_field_by_index(
-               struct bt_ctf_event_class *event_class,
-               const char **field_name, struct bt_ctf_field_type **field_type,
-               uint64_t index)
-{
-       int ret;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!event_class->common.payload_field_type) {
-               BT_LOGV("Event class has no payload field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", index=%" PRIu64,
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class), index);
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
-               event_class->common.payload_field_type) ==
-                       BT_CTF_FIELD_TYPE_ID_STRUCT);
-       ret = bt_ctf_field_type_structure_get_field_by_index(
-               (void *) event_class->common.payload_field_type,
-               field_name, (void *) field_type, index);
-
-end:
-       return ret;
-}
-
-struct bt_ctf_field_type *
-bt_ctf_event_class_get_payload_type_field_type_by_name(
-               struct bt_ctf_event_class *event_class, const char *name)
-{
-       GQuark name_quark;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (!event_class || !name) {
-               BT_LOGW("Invalid parameter: event class or name is NULL: "
-                       "event-class-addr=%p, name-addr=%p",
-                       event_class, name);
-               goto end;
-       }
-
-       if (!event_class->common.payload_field_type) {
-               BT_LOGV("Event class has no payload field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class));
-               goto end;
-       }
-
-       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
-               event_class->common.payload_field_type) ==
-                       BT_CTF_FIELD_TYPE_ID_STRUCT);
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGE("Cannot get GQuark: string=\"%s\"", name);
-               goto end;
-       }
-
-       /*
-        * No need to increment field_type's reference count since getting it
-        * from the structure already does.
-        */
-       field_type = (void *)
-               bt_ctf_field_type_structure_get_field_type_by_name(
-                       (void *) event_class->common.payload_field_type, name);
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       struct bt_ctf_value *attr_value = NULL;
-
-       BT_ASSERT(event_class);
-       BT_ASSERT(context);
-       BT_LOGD("Serializing event class's metadata: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", metadata-context-addr=%p",
-               event_class, bt_ctf_event_class_get_name(event_class),
-               bt_ctf_event_class_get_id(event_class), context);
-       context->current_indentation_level = 1;
-       g_string_assign(context->field_name, "");
-       g_string_append(context->string, "event {\n");
-
-       /* Serialize attributes */
-       g_string_append_printf(context->string, "\tname = \"%s\";\n",
-               event_class->common.name->str);
-       BT_ASSERT(event_class->common.id >= 0);
-       g_string_append_printf(context->string, "\tid = %" PRId64 ";\n",
-               event_class->common.id);
-       g_string_append_printf(context->string, "\tstream_id = %" PRId64 ";\n",
-               bt_ctf_stream_class_common_get_id(
-                       bt_ctf_event_class_common_borrow_stream_class(
-                               BT_CTF_TO_COMMON(event_class))));
-
-       if (event_class->common.log_level !=
-                       BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) {
-               g_string_append_printf(context->string, "\tloglevel = %d;\n",
-                       (int) event_class->common.log_level);
-       }
-
-       if (event_class->common.emf_uri->len > 0) {
-               g_string_append_printf(context->string, "\tmodel.emf.uri = \"%s\";\n",
-                       event_class->common.emf_uri->str);
-       }
-
-       /* Serialize context field type */
-       if (event_class->common.context_field_type) {
-               g_string_append(context->string, "\tcontext := ");
-               BT_LOGD_STR("Serializing event class's context field type metadata.");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) event_class->common.context_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event class's context field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";\n");
-       }
-
-       /* Serialize payload field type */
-       if (event_class->common.payload_field_type) {
-               g_string_append(context->string, "\tfields := ");
-               BT_LOGD_STR("Serializing event class's payload field type metadata.");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) event_class->common.payload_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event class's payload field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";\n");
-       }
-
-       g_string_append(context->string, "};\n\n");
-
-end:
-       context->current_indentation_level = 0;
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(attr_value);
-       return ret;
-}
-
-struct bt_ctf_field_type *bt_ctf_event_class_get_field_by_name(
-               struct bt_ctf_event_class *event_class, const char *name)
-{
-       GQuark name_quark;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (!event_class || !name) {
-               BT_LOGW("Invalid parameter: event class or name is NULL: "
-                       "event-class-addr=%p, name-addr=%p",
-                       event_class, name);
-               goto end;
-       }
-
-       if (!event_class->common.payload_field_type) {
-               BT_LOGV("Event class has no payload field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class,
-                       bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class));
-               goto end;
-       }
-
-       BT_ASSERT(event_class->common.payload_field_type->id ==
-               BT_CTF_FIELD_TYPE_ID_STRUCT);
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGE("Cannot get GQuark: string=\"%s\"", name);
-               goto end;
-       }
-
-       /*
-        * No need to increment field_type's reference count since getting it
-        * from the structure already does.
-        */
-       field_type = bt_ctf_object_get_ref(
-               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-                       event_class->common.payload_field_type, name));
-
-end:
-       return field_type;
-}
diff --git a/lib/ctf-writer/event.c b/lib/ctf-writer/event.c
deleted file mode 100644 (file)
index 62df18b..0000000
+++ /dev/null
@@ -1,900 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * 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 "CTF-WRITER-EVENT"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/attributes-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <inttypes.h>
-
-static
-int bt_ctf_event_common_validate_types_for_create(
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_validation_output *validation_output,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
-{
-       int ret;
-       enum bt_ctf_validation_flag validation_flags =
-               BT_CTF_VALIDATION_FLAG_STREAM |
-               BT_CTF_VALIDATION_FLAG_EVENT;
-       struct bt_ctf_trace_common *trace = NULL;
-       struct bt_ctf_stream_class_common *stream_class = NULL;
-       struct bt_ctf_field_type_common *packet_header_type = NULL;
-       struct bt_ctf_field_type_common *packet_context_type = NULL;
-       struct bt_ctf_field_type_common *event_header_type = NULL;
-       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
-       struct bt_ctf_field_type_common *event_context_type = NULL;
-       struct bt_ctf_field_type_common *event_payload_type = NULL;
-       int trace_valid = 0;
-       struct bt_ctf_private_value *environment = NULL;
-
-       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
-       BT_ASSERT(stream_class);
-       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
-       if (trace) {
-               BT_LOGD_STR("Event class is part of a trace.");
-               packet_header_type =
-                       bt_ctf_trace_common_borrow_packet_header_field_type(trace);
-               trace_valid = trace->valid;
-               BT_ASSERT(trace_valid);
-               environment = trace->environment;
-       }
-
-       packet_context_type =
-               bt_ctf_stream_class_common_borrow_packet_context_field_type(
-                       stream_class);
-       event_header_type =
-               bt_ctf_stream_class_common_borrow_event_header_field_type(
-                       stream_class);
-       stream_event_ctx_type =
-               bt_ctf_stream_class_common_borrow_event_context_field_type(
-                       stream_class);
-       event_context_type =
-               bt_ctf_event_class_common_borrow_context_field_type(event_class);
-       event_payload_type =
-               bt_ctf_event_class_common_borrow_payload_field_type(event_class);
-       ret = bt_ctf_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_ctf_validation_output_put_types(validation_output);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_event_common_create_fields(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_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_ctf_field_wrapper **header_field,
-               struct bt_ctf_field_common **stream_event_context_field,
-               struct bt_ctf_field_common **context_field,
-               struct bt_ctf_field_common **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_ctf_event_common_validate(struct bt_ctf_event_common *event)
-{
-       int ret = 0;
-       struct bt_ctf_stream_class_common *stream_class;
-
-       BT_ASSERT(event);
-       if (event->header_field) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       event->header_field->field);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid event's header field: "
-                               "event-addr=%p, field-addr=%p",
-                               event, event->header_field->field);
-                       goto end;
-               }
-       }
-
-       stream_class = bt_ctf_event_class_common_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_ctf_field_common_validate_recursive(
-                       event->stream_event_context_field);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid event's stream event context field: "
-                               "event-addr=%p, field-addr=%p",
-                               event, event->stream_event_context_field);
-                       goto end;
-               }
-       }
-
-       if (event->class->context_field_type) {
-               ret = bt_ctf_field_common_validate_recursive(event->context_field);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid event's payload field: "
-                               "event-addr=%p, field-addr=%p",
-                               event, event->context_field);
-                       goto end;
-               }
-       }
-
-       ret = bt_ctf_field_common_validate_recursive(event->payload_field);
-       if (ret) {
-               BT_ASSERT_PRE_MSG("Invalid event's payload field: "
-                       "event-addr=%p, field-addr=%p",
-                       event, event->payload_field);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event,
-               bool is_frozen)
-{
-       BT_ASSERT(event);
-       BT_LOGD("Freezing event: addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event, bt_ctf_event_class_common_get_name(event->class),
-               bt_ctf_event_class_common_get_id(event->class));
-
-       if (event->header_field) {
-               BT_LOGD_STR("Freezing event's header field.");
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       event->header_field->field, is_frozen);
-       }
-
-       if (event->stream_event_context_field) {
-               BT_LOGD_STR("Freezing event's stream event context field.");
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       event->stream_event_context_field, is_frozen);
-       }
-
-       if (event->context_field) {
-               BT_LOGD_STR("Freezing event's context field.");
-               bt_ctf_field_common_set_is_frozen_recursive(event->context_field,
-                       is_frozen);
-       }
-
-       if (event->payload_field) {
-               BT_LOGD_STR("Freezing event's payload field.");
-               bt_ctf_field_common_set_is_frozen_recursive(event->payload_field,
-                       is_frozen);
-       }
-
-       event->frozen = is_frozen;
-}
-
-BT_HIDDEN
-int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event,
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_clock_class *init_expected_clock_class,
-               bool is_shared_with_parent, bt_ctf_object_release_func release_func,
-               bt_ctf_validation_flag_copy_field_type_func field_type_copy_func,
-               bool must_be_in_trace,
-               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
-                       struct bt_ctf_field_type_common *packet_context_field_type,
-                       struct bt_ctf_field_type_common *event_header_field_type),
-               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_ctf_trace_common *trace = NULL;
-       struct bt_ctf_stream_class_common *stream_class = NULL;
-       struct bt_ctf_field_wrapper *event_header = NULL;
-       struct bt_ctf_field_common *stream_event_context = NULL;
-       struct bt_ctf_field_common *event_context = NULL;
-       struct bt_ctf_field_common *event_payload = NULL;
-       struct bt_ctf_validation_output validation_output = { 0 };
-       struct bt_ctf_clock_class *expected_clock_class =
-               init_expected_clock_class ? bt_ctf_object_get_ref(init_expected_clock_class) :
-               NULL;
-
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_LOGD("Initializing common event object: event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-
-       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
-       BT_ASSERT_PRE(stream_class,
-               "Event class is not part of a stream class: event-class-addr=%p",
-               event_class);
-
-       /* The event class was frozen when added to its stream class */
-       BT_ASSERT(event_class->frozen);
-       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
-
-       if (must_be_in_trace) {
-               BT_ASSERT_PRE(trace,
-                       "Event class's stream class is not part of a trace: "
-                       "ec-addr=%p, sc-addr=%p", 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.
-        */
-       if (is_shared_with_parent) {
-               bt_ctf_object_init_shared_with_parent(&event->base, release_func);
-       } else {
-               bt_ctf_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_ctf_stream_class_common_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_ctf_stream_class_common_get_id(stream_class),
-                               bt_ctf_stream_class_common_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_ctf_clock_class_get_name(expected_clock_class) :
-                                       NULL);
-                       goto error;
-               }
-       }
-
-       /* Validate the trace, the stream class, and the event class */
-       ret = bt_ctf_event_common_validate_types_for_create(
-               event_class, &validation_output, field_type_copy_func);
-       if (ret) {
-               /* bt_ctf_event_common_validate_types_for_create() logs errors */
-               goto error;
-       }
-
-       if (map_clock_classes_func) {
-               /*
-                * Safe to automatically map selected fields to the
-                * stream's clock's class here because the stream class
-                * is about to be frozen.
-                */
-               if (map_clock_classes_func(stream_class,
-                               validation_output.packet_context_type,
-                               validation_output.event_header_type)) {
-                       BT_LOGW_STR("Cannot automatically map selected stream class's "
-                               "field types to stream class's clock's class.");
-                       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.
-        */
-       event->class = bt_ctf_object_get_ref(event_class);
-
-       ret = bt_ctf_event_common_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_ctf_event_common_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_ctf_validation_replace_types(trace, stream_class, event_class,
-               &validation_output,
-               BT_CTF_VALIDATION_FLAG_STREAM | BT_CTF_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_ctf_validation_replace_types().
-        */
-       bt_ctf_validation_output_put_types(&validation_output);
-
-       /*
-        * Freeze the stream class since the event header must not be changed
-        * anymore.
-        */
-       bt_ctf_stream_class_common_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_CTF_OBJECT_MOVE_REF(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_ctf_event_class_common_get_name(event->class),
-               bt_ctf_event_class_common_get_id(event->class));
-       goto end;
-
-error:
-       bt_ctf_validation_output_put_types(&validation_output);
-       bt_ctf_object_put_ref(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;
-}
-
-int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type)
-{
-       int ret = bt_ctf_stream_class_map_clock_class(
-               BT_CTF_FROM_COMMON(stream_class),
-               BT_CTF_FROM_COMMON(packet_context_type),
-               BT_CTF_FROM_COMMON(event_header_type));
-
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
-       }
-
-       return ret;
-}
-
-static
-void destroy_event_header_field(struct bt_ctf_field_wrapper *field_wrapper)
-{
-       BT_ASSERT(field_wrapper);
-       bt_ctf_object_put_ref(field_wrapper->field);
-       bt_ctf_field_wrapper_destroy(field_wrapper);
-}
-
-static
-struct bt_ctf_field_wrapper *create_event_header_field(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_wrapper *field_wrapper = NULL;
-       struct bt_ctf_field *field = bt_ctf_field_create((void *) ft);
-
-       if (!field) {
-               goto error;
-       }
-
-       field_wrapper = bt_ctf_field_wrapper_new(NULL);
-       if (!field_wrapper) {
-               goto error;
-       }
-
-       field_wrapper->field = (void *) field;
-       field = NULL;
-       goto end;
-
-error:
-       bt_ctf_object_put_ref(field);
-
-       if (field_wrapper) {
-               destroy_event_header_field(field_wrapper);
-               field_wrapper = NULL;
-       }
-
-end:
-       return field_wrapper;
-}
-
-static
-void release_event_header_field(struct bt_ctf_field_wrapper *field_wrapper,
-               struct bt_ctf_event_common *event_common)
-{
-       BT_ASSERT(field_wrapper);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_wrapper->field);
-       bt_ctf_field_wrapper_destroy(field_wrapper);
-}
-
-static
-void bt_ctf_event_destroy(struct bt_ctf_object *obj)
-{
-       bt_ctf_event_common_finalize(obj, (void *) bt_ctf_object_put_ref,
-               (void *) release_event_header_field);
-       g_free(obj);
-}
-
-struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
-{
-       int ret;
-       struct bt_ctf_event *event = NULL;
-       struct bt_ctf_clock_class *expected_clock_class = NULL;
-
-       event = g_new0(struct bt_ctf_event, 1);
-       if (!event) {
-               BT_LOGE_STR("Failed to allocate one CTF writer event.");
-               goto error;
-       }
-
-       if (event_class) {
-               struct bt_ctf_stream_class *stream_class =
-                       BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class(
-                               BT_CTF_TO_COMMON(event_class)));
-
-               if (stream_class && stream_class->clock) {
-                       expected_clock_class = stream_class->clock->clock_class;
-               }
-       }
-
-       ret = bt_ctf_event_common_initialize(BT_CTF_TO_COMMON(event),
-               BT_CTF_TO_COMMON(event_class), expected_clock_class,
-               true, bt_ctf_event_destroy,
-               (bt_ctf_validation_flag_copy_field_type_func)
-                       bt_ctf_field_type_copy,
-               false, map_clock_classes_func,
-               (create_field_func) bt_ctf_field_create,
-               (release_field_func) bt_ctf_object_put_ref,
-               (create_header_field_func) create_event_header_field,
-               (release_header_field_func) destroy_event_header_field);
-       if (ret) {
-               /* bt_ctf_event_common_initialize() logs errors */
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event);
-
-end:
-       return event;
-}
-
-struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)));
-}
-
-BT_HIDDEN
-struct bt_ctf_stream *bt_ctf_event_borrow_stream(struct bt_ctf_event *event)
-{
-       BT_ASSERT(event);
-       return (struct bt_ctf_stream *)
-               bt_ctf_object_borrow_parent(&BT_CTF_TO_COMMON(event)->base);
-}
-
-struct bt_ctf_stream *bt_ctf_event_get_stream(struct bt_ctf_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return bt_ctf_object_get_ref(bt_ctf_event_borrow_stream(event));
-}
-
-int bt_ctf_event_set_payload(struct bt_ctf_event *event, const char *name,
-               struct bt_ctf_field *field)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_NON_NULL(field, "Payload field");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-       return bt_ctf_field_structure_set_field_by_name(
-               (void *) event->common.payload_field, name, field);
-}
-
-struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event,
-               const char *name)
-{
-       struct bt_ctf_field *field = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (name) {
-               field = bt_ctf_field_structure_get_field_by_name(
-                       BT_CTF_FROM_COMMON(event->common.payload_field), name);
-       } else {
-               field = BT_CTF_FROM_COMMON(event->common.payload_field);
-               bt_ctf_object_get_ref(field);
-       }
-
-       return field;
-}
-
-struct bt_ctf_field *bt_ctf_event_get_payload_field(
-               struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_payload(BT_CTF_TO_COMMON(event)));
-}
-
-struct bt_ctf_field *bt_ctf_event_get_header(struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_header(BT_CTF_TO_COMMON(event)));
-}
-
-struct bt_ctf_field *bt_ctf_event_get_context(struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_context(BT_CTF_TO_COMMON(event)));
-}
-
-struct bt_ctf_field *bt_ctf_event_get_stream_event_context(
-               struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_stream_event_context(
-               BT_CTF_TO_COMMON(event)));
-}
-
-BT_HIDDEN
-int bt_ctf_event_serialize(struct bt_ctf_event *event,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret = 0;
-
-       BT_ASSERT(event);
-       BT_ASSERT(ctfser);
-
-       BT_LOGV_STR("Serializing event's context field.");
-       if (event->common.context_field) {
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) event->common.context_field, ctfser,
-                       native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event's context field: "
-                               "event-addr=%p, event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64,
-                               event,
-                               bt_ctf_event_class_common_get_name(event->common.class),
-                               bt_ctf_event_class_common_get_id(event->common.class));
-                       goto end;
-               }
-       }
-
-       BT_LOGV_STR("Serializing event's payload field.");
-       if (event->common.payload_field) {
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) event->common.payload_field, ctfser,
-                       native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event's payload field: "
-                               "event-addr=%p, event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64,
-                               event,
-                               bt_ctf_event_class_common_get_name(event->common.class),
-                               bt_ctf_event_class_common_get_id(event->common.class));
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void _bt_ctf_event_freeze(struct bt_ctf_event *event)
-{
-       _bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
-}
-
-int bt_ctf_event_set_header(struct bt_ctf_event *event,
-               struct bt_ctf_field *header)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       /*
-        * Ensure the provided header's type matches the one registered to the
-        * stream class.
-        */
-       if (header) {
-               BT_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) header)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type) == 0,
-                       "Header field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event, ((struct bt_ctf_field_common *) header)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
-       } else {
-               BT_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type,
-                       "Setting no event header field, "
-                       "but event header field type is not NULL: ",
-                       "event-addr=%p, header-ft-addr=%p",
-                       event,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.header_field->field);
-       event->common.header_field->field = bt_ctf_object_get_ref(header);
-       BT_LOGV("Set event's header field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "header-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class), header);
-       return 0;
-}
-
-int bt_ctf_event_common_set_payload(struct bt_ctf_event *event,
-               struct bt_ctf_field *payload)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       if (payload) {
-               BT_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) payload)->type,
-                       event->common.class->payload_field_type) == 0,
-                       "Payload field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event,
-                       ((struct bt_ctf_field_common *) payload)->type,
-                       event->common.class->payload_field_type);
-       } else {
-               BT_ASSERT_PRE(!event->common.class->payload_field_type,
-                       "Setting no event payload field, "
-                       "but event payload field type is not NULL: ",
-                       "event-addr=%p, payload-ft-addr=%p",
-                       event, event->common.class->payload_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.payload_field);
-       event->common.payload_field = bt_ctf_object_get_ref(payload);
-       BT_LOGV("Set event's payload field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "payload-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class), payload);
-       return 0;
-}
-
-int bt_ctf_event_set_context(struct bt_ctf_event *event,
-               struct bt_ctf_field *context)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       if (context) {
-               BT_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) context)->type,
-                       event->common.class->context_field_type) == 0,
-                       "Context field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event, ((struct bt_ctf_field_common *) context)->type,
-                       event->common.class->context_field_type);
-       } else {
-               BT_ASSERT_PRE(!event->common.class->context_field_type,
-                       "Setting no event context field, "
-                       "but event context field type is not NULL: ",
-                       "event-addr=%p, context-ft-addr=%p",
-                       event, event->common.class->context_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.context_field);
-       event->common.context_field = bt_ctf_object_get_ref(context);
-       BT_LOGV("Set event's context field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "context-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class), context);
-       return 0;
-}
-
-int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
-               struct bt_ctf_field *stream_event_context)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       if (stream_event_context) {
-               BT_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) stream_event_context)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type) == 0,
-                       "Stream event context field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event,
-                       ((struct bt_ctf_field_common *) stream_event_context)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
-       } else {
-               BT_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type,
-                       "Setting no stream event context field, "
-                       "but stream event context field type is not NULL: ",
-                       "event-addr=%p, context-ft-addr=%p",
-                       event,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.stream_event_context_field);
-       event->common.stream_event_context_field = bt_ctf_object_get_ref(stream_event_context);
-       BT_LOGV("Set event's stream event context field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "stream-event-context-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class),
-               stream_event_context);
-       return 0;
-}
diff --git a/lib/ctf-writer/field-path.c b/lib/ctf-writer/field-path.c
deleted file mode 100644 (file)
index eb6c035..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * field-path.c
- *
- * Babeltrace CTF writer - Field path
- *
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * 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.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-FIELD-PATH"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/field-path-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdint.h>
-
-static
-void field_path_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_path *field_path = (struct bt_ctf_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);
-       }
-       g_free(field_path);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_path_create(void)
-{
-       struct bt_ctf_field_path *field_path = NULL;
-
-       BT_LOGD_STR("Creating empty field path object.");
-
-       field_path = g_new0(struct bt_ctf_field_path, 1);
-       if (!field_path) {
-               BT_LOGE_STR("Failed to allocate one field path.");
-               goto error;
-       }
-
-       bt_ctf_object_init_shared(&field_path->base, field_path_destroy);
-       field_path->root = BT_CTF_SCOPE_UNKNOWN;
-       field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int));
-       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;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
-       return NULL;
-}
-
-BT_HIDDEN
-void bt_ctf_field_path_clear(struct bt_ctf_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_ctf_field_path *bt_ctf_field_path_copy(
-               struct bt_ctf_field_path *path)
-{
-       struct bt_ctf_field_path *new_path;
-
-       BT_ASSERT(path);
-       BT_LOGD("Copying field path: addr=%p, index-count=%u",
-               path, path->indexes->len);
-       new_path = bt_ctf_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;
-}
-
-enum bt_ctf_scope bt_ctf_field_path_get_root_scope(
-               const struct bt_ctf_field_path *field_path)
-{
-       enum bt_ctf_scope scope = BT_CTF_SCOPE_UNKNOWN;
-
-       if (!field_path) {
-               BT_LOGW_STR("Invalid parameter: field path is NULL.");
-               goto end;
-       }
-
-       scope = field_path->root;
-
-end:
-       return scope;
-}
-
-int64_t bt_ctf_field_path_get_index_count(
-               const struct bt_ctf_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;
-}
-
-int bt_ctf_field_path_get_index(const struct bt_ctf_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;
-}
diff --git a/lib/ctf-writer/field-types.c b/lib/ctf-writer/field-types.c
deleted file mode 100644 (file)
index 64cdcd1..0000000
+++ /dev/null
@@ -1,5564 +0,0 @@
-/*
- * Copyright 2013, 2014 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.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-FIELD-TYPES"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/field-path-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <float.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-static
-void destroy_enumeration_mapping(struct bt_ctf_enumeration_mapping *mapping)
-{
-       g_free(mapping);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft,
-               bool init_bo, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       BT_ASSERT(ft && (ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN) &&
-               (ft->id < BT_CTF_FIELD_TYPE_ID_NR));
-
-       bt_ctf_object_init_shared(&ft->base, release_func);
-       ft->methods = methods;
-
-       if (init_bo) {
-               int ret;
-               const enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_NATIVE;
-
-               BT_LOGD("Setting initial field type's byte order: bo=%s",
-                       bt_ctf_byte_order_string(bo));
-               ret = bt_ctf_field_type_common_set_byte_order(ft, bo);
-               BT_ASSERT(ret == 0);
-       }
-
-       ft->alignment = 1;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_initialize(
-               struct bt_ctf_field_type_common *ft,
-               unsigned int size, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(size > 0);
-       BT_LOGD("Initializing common integer field type object: size=%u",
-               size);
-       ft->id = BT_CTF_FIELD_TYPE_ID_INTEGER;
-       int_ft->size = size;
-       int_ft->base = BT_CTF_INTEGER_BASE_DECIMAL;
-       int_ft->encoding = BT_CTF_STRING_ENCODING_NONE;
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized common integer field type object: addr=%p, size=%u",
-               ft, size);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD_STR("Initializing common floating point number field type object.");
-       ft->id = BT_CTF_FIELD_TYPE_ID_FLOAT;
-       flt_ft->exp_dig = sizeof(float) * CHAR_BIT - FLT_MANT_DIG;
-       flt_ft->mant_dig = FLT_MANT_DIG;
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized common floating point number field type object: addr=%p, "
-               "exp-size=%u, mant-size=%u", ft, flt_ft->exp_dig,
-               flt_ft->mant_dig);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *container_ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(container_ft);
-       BT_LOGD("Initializing common enumeration field type object: int-ft-addr=%p",
-               container_ft);
-       ft->id = BT_CTF_FIELD_TYPE_ID_ENUM;
-       enum_ft->container_ft = bt_ctf_object_get_ref(container_ft);
-       enum_ft->entries = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) destroy_enumeration_mapping);
-       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized common enumeration field type object: addr=%p, "
-               "int-ft-addr=%p, int-ft-size=%u", ft, container_ft,
-               bt_ctf_field_type_common_integer_get_size(container_ft));
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_string_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD_STR("Initializing common string field type object.");
-       ft->id = BT_CTF_FIELD_TYPE_ID_STRING;
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       string_ft->encoding = BT_CTF_STRING_ENCODING_UTF8;
-       ft->alignment = CHAR_BIT;
-       BT_LOGD("Initialized common string field type object: addr=%p", ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD_STR("Initializing common structure field type object.");
-       ft->id = BT_CTF_FIELD_TYPE_ID_STRUCT;
-       struct_ft->fields = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_ctf_field_type_common_structure_field));
-       struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL);
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized common structure field type object: addr=%p", ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft,
-               unsigned int length, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(element_ft);
-       BT_LOGD("Initializing common array field type object: element-ft-addr=%p, "
-               "length=%u", element_ft, length);
-       ft->id = BT_CTF_FIELD_TYPE_ID_ARRAY;
-       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
-       array_ft->length = length;
-       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized common array field type object: addr=%p, "
-               "element-ft-addr=%p, length=%u", ft, element_ft, length);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft,
-               const char *length_field_name,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(element_ft);
-       BT_ASSERT(length_field_name);
-       BT_ASSERT(bt_ctf_identifier_is_valid(length_field_name));
-       BT_LOGD("Initializing common sequence field type object: element-ft-addr=%p, "
-               "length-field-name=\"%s\"", element_ft, length_field_name);
-       ft->id = BT_CTF_FIELD_TYPE_ID_SEQUENCE;
-       seq_ft->element_ft = bt_ctf_object_get_ref(element_ft);
-       seq_ft->length_field_name = g_string_new(length_field_name);
-       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized common sequence field type object: addr=%p, "
-               "element-ft-addr=%p, length-field-name=\"%s\"",
-               ft, element_ft, length_field_name);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *tag_ft,
-               const char *tag_name,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(!tag_name || bt_ctf_identifier_is_valid(tag_name));
-       BT_LOGD("Initializing common variant field type object: "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               tag_ft, tag_name);
-       ft->id = BT_CTF_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_ctf_field_type_common_variant_choice));
-
-       if (tag_ft) {
-               var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft);
-       }
-
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       /* A variant's alignment is undefined */
-       ft->alignment = 0;
-       BT_LOGD("Initialized common variant field type object: addr=%p, "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               ft, tag_ft, tag_name);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_integer *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying integer field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting mapped clock class.");
-       bt_ctf_object_put_ref(ft->mapped_clock_class);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_floating_point *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying floating point number field type object: addr=%p", ft);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_enumeration *ft = (void *) obj;
-
-       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_ctf_object_put_ref(ft->container_ft);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_string *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying string field type object: addr=%p", ft);
-       g_free(ft);
-}
-
-static
-void bt_ctf_field_type_common_structure_field_finalize(
-               struct bt_ctf_field_type_common_structure_field *field)
-{
-       if (!field) {
-               return;
-       }
-
-       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_ctf_object_put_ref(field->type);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_structure *ft = (void *) obj;
-       uint64_t i;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying structure field type object: addr=%p", ft);
-
-       if (ft->fields) {
-               for (i = 0; i < ft->fields->len; i++) {
-                       bt_ctf_field_type_common_structure_field_finalize(
-                               BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                                       ft, i));
-               }
-
-               g_array_free(ft->fields, TRUE);
-       }
-
-       if (ft->field_name_to_index) {
-               g_hash_table_destroy(ft->field_name_to_index);
-       }
-
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_array *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying array field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting element field type.");
-       bt_ctf_object_put_ref(ft->element_ft);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_sequence *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying sequence field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting element field type.");
-       bt_ctf_object_put_ref(ft->element_ft);
-       g_string_free(ft->length_field_name, TRUE);
-       BT_LOGD_STR("Putting length field path.");
-       bt_ctf_object_put_ref(ft->length_field_path);
-       g_free(ft);
-}
-
-static
-void bt_ctf_field_type_common_variant_choice_finalize(
-               struct bt_ctf_field_type_common_variant_choice *choice)
-{
-       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_ctf_object_put_ref(choice->type);
-
-       if (choice->ranges) {
-               g_array_free(choice->ranges, TRUE);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_variant *ft = (void *) obj;
-       uint64_t i;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying variant field type object: addr=%p", ft);
-
-       if (ft->choices) {
-               for (i = 0; i < ft->choices->len; i++) {
-                       bt_ctf_field_type_common_variant_choice_finalize(
-                               BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                                       ft, i));
-               }
-
-               g_array_free(ft->choices, TRUE);
-       }
-
-       if (ft->choice_name_to_index) {
-               g_hash_table_destroy(ft->choice_name_to_index);
-       }
-
-       if (ft->tag_name) {
-               g_string_free(ft->tag_name, TRUE);
-       }
-
-       BT_LOGD_STR("Putting tag field type.");
-       bt_ctf_object_put_ref(ft->tag_ft);
-       BT_LOGD_STR("Putting tag field path.");
-       bt_ctf_object_put_ref(ft->tag_field_path);
-       g_free(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
-void check_ranges_overlap(gpointer element, gpointer query)
-{
-       struct bt_ctf_enumeration_mapping *mapping = element;
-       struct range_overlap_query *overlap_query = query;
-
-       if (mapping->range_start._signed <= overlap_query->range_end._signed
-                       && overlap_query->range_start._signed <=
-                       mapping->range_end._signed) {
-               overlap_query->overlaps = 1;
-               overlap_query->mapping_name = mapping->string;
-       }
-
-       overlap_query->overlaps |=
-               mapping->string == overlap_query->mapping_name;
-
-       if (overlap_query->overlaps) {
-               BT_LOGV("Overlapping enumeration field type mappings: "
-                       "mapping-name=\"%s\", "
-                       "mapping-a-range-start=%" PRId64 ", "
-                       "mapping-a-range-end=%" PRId64 ", "
-                       "mapping-b-range-start=%" PRId64 ", "
-                       "mapping-b-range-end=%" PRId64,
-                       g_quark_to_string(mapping->string),
-                       mapping->range_start._signed,
-                       mapping->range_end._signed,
-                       overlap_query->range_start._signed,
-                       overlap_query->range_end._signed);
-       }
-}
-
-static
-void check_ranges_overlap_unsigned(gpointer element, gpointer query)
-{
-       struct bt_ctf_enumeration_mapping *mapping = element;
-       struct range_overlap_query *overlap_query = query;
-
-       if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned
-                       && overlap_query->range_start._unsigned <=
-                       mapping->range_end._unsigned) {
-               overlap_query->overlaps = 1;
-               overlap_query->mapping_name = mapping->string;
-       }
-
-       overlap_query->overlaps |=
-               mapping->string == overlap_query->mapping_name;
-
-       if (overlap_query->overlaps) {
-               BT_LOGW("Overlapping enumeration field type mappings: "
-                       "mapping-name=\"%s\", "
-                       "mapping-a-range-start=%" PRIu64 ", "
-                       "mapping-a-range-end=%" PRIu64 ", "
-                       "mapping-b-range-start=%" PRIu64 ", "
-                       "mapping-b-range-end=%" PRIu64,
-                       g_quark_to_string(mapping->string),
-                       mapping->range_start._unsigned,
-                       mapping->range_end._unsigned,
-                       overlap_query->range_start._unsigned,
-                       overlap_query->range_end._unsigned);
-       }
-}
-
-static
-gint compare_enumeration_mappings_signed(struct bt_ctf_enumeration_mapping **a,
-               struct bt_ctf_enumeration_mapping **b)
-{
-       return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1;
-}
-
-static
-gint compare_enumeration_mappings_unsigned(struct bt_ctf_enumeration_mapping **a,
-               struct bt_ctf_enumeration_mapping **b)
-{
-       return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1;
-}
-
-static
-int add_structure_variant_member(GArray *members,
-               GHashTable *field_name_to_index,
-               struct bt_ctf_field_type_common *field_type, const char *field_name,
-               bool is_variant)
-{
-       int ret = 0;
-       GQuark name_quark = g_quark_from_string(field_name);
-       struct bt_ctf_field_type_common **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);
-               ret = -1;
-               goto end;
-       }
-
-       g_array_set_size(members, members->len + 1);
-
-       if (is_variant) {
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       &g_array_index(members,
-                               struct bt_ctf_field_type_common_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_ctf_field_type_common_variant_choice_range));
-               BT_ASSERT(choice->ranges);
-       } else {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       &g_array_index(members,
-                               struct bt_ctf_field_type_common_structure_field,
-                               members->len - 1);
-
-               member_ft = &field->type;
-               member_name = &field->name;
-       }
-
-       *member_name = name_quark;
-       *member_ft = bt_ctf_object_get_ref(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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_ctf_clock_class_get_name(int_ft->mapped_clock_class));
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-void bt_ctf_field_type_enum_iter_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
-               container_of(obj,
-                       struct bt_ctf_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_ctf_object_put_ref(iter->enumeration_ft);
-       g_free(iter);
-}
-
-static
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_find_mappings_type(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_field_type_enumeration_mapping_iterator_type iterator_type)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM,
-               "Field type");
-       iter = g_new0(struct bt_ctf_field_type_enumeration_mapping_iterator, 1);
-       if (!iter) {
-               BT_LOGE_STR("Failed to allocate one enumeration field type mapping.");
-               goto end;
-       }
-
-       bt_ctf_object_init_shared(&iter->base, bt_ctf_field_type_enum_iter_destroy);
-       iter->enumeration_ft = bt_ctf_object_get_ref(ft);
-       iter->index = -1;
-       iter->type = iterator_type;
-
-end:
-       return iter;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_find_mappings_by_name(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
-                       ft, CTF_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_ctf_object_put_ref(iter);
-       return NULL;
-}
-
-static
-struct bt_ctf_enumeration_mapping *bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_enumeration_mapping *mapping = NULL;
-
-       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_HIDDEN
-int bt_ctf_field_type_enumeration_mapping_iterator_next(
-               struct bt_ctf_field_type_enumeration_mapping_iterator *iter)
-{
-       struct bt_ctf_field_type_common_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 bt_ctf_enumeration_mapping *mapping =
-                       bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-                               BT_CTF_TO_COMMON(enum_ft), i);
-
-               switch (iter->type) {
-               case CTF_ITERATOR_BY_NAME:
-                       if (mapping->string == iter->u.name_quark) {
-                               iter->index = i;
-                               goto end;
-                       }
-                       break;
-               case CTF_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 CTF_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;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value(
-               struct bt_ctf_field_type_common *ft, int64_t value)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
-                       ft, CTF_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_ctf_field_type_common_integer_is_signed(
-                       BT_CTF_TO_COMMON(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_ctf_object_put_ref(iter);
-       return NULL;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value(
-               struct bt_ctf_field_type_common *ft, uint64_t value)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
-                       ft, CTF_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_ctf_field_type_common_integer_is_signed(
-                       BT_CTF_TO_COMMON(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_ctf_object_put_ref(iter);
-       return NULL;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
-               struct bt_ctf_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_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
-                       (void *) iter->enumeration_ft, iter->index,
-                       mapping_name, range_begin, range_end);
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get(
-               struct bt_ctf_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_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
-                       (void *) iter->enumeration_ft, iter->index,
-                       mapping_name, range_begin, range_end);
-}
-
-/*
- * Note: This algorithm is O(n^2) vs number of enumeration mappings.
- * Only used when freezing an enumeration.
- */
-static
-void bt_ctf_field_type_common_enumeration_set_range_overlap(
-               struct bt_ctf_field_type_common_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_ctf_field_type_common_integer_is_signed(
-               BT_CTF_TO_COMMON(ft->container_ft));
-
-       for (i = 0; i < len; i++) {
-               for (j = i + 1; j < len; j++) {
-                       struct bt_ctf_enumeration_mapping *mapping[2];
-
-                       mapping[0] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-                               BT_CTF_TO_COMMON(ft), i);
-                       mapping[1] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-                               BT_CTF_TO_COMMON(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;
-                               }
-                       }
-               }
-       }
-
-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.");
-       }
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       ret = bt_ctf_field_type_common_integer_validate(
-                       BT_CTF_TO_COMMON(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;
-       }
-
-       /* 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;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       /* 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);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_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);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       ret = bt_ctf_field_type_common_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);
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common *child_ft = NULL;
-       int64_t field_count =
-               bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_by_index(ft,
-                       &field_name, &child_ft, i);
-               BT_ASSERT(ret == 0);
-               ret = bt_ctf_field_type_common_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;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool bt_ctf_field_type_common_enumeration_has_overlapping_ranges(
-               struct bt_ctf_field_type_common_enumeration *enum_ft)
-{
-       if (!enum_ft->common.frozen) {
-               bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
-       }
-
-       return enum_ft->has_overlapping_ranges;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       int64_t field_count;
-       struct bt_ctf_field_type_common *child_ft = NULL;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_ctf_field_type_common_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;
-       }
-
-       /*
-        * 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_ctf_field_type_common_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;
-               goto end;
-       }
-
-       for (i = 0; i < field_count; ++i) {
-               const char *field_name;
-
-               ret = bt_ctf_field_type_common_variant_borrow_field_by_index(ft,
-                       &field_name, &child_ft, i);
-               BT_ASSERT(ret == 0);
-               ret = bt_ctf_field_type_common_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;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * 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_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-
-       BT_ASSERT(ft);
-
-       if (ft->valid) {
-               /* Already marked as valid */
-               goto end;
-       }
-
-       if (ft->methods->validate) {
-               ret = ft->methods->validate(ft);
-       }
-
-       if (ret == 0 && ft->frozen) {
-               /* Field type is valid */
-               BT_LOGV("Marking field type as valid: addr=%p", ft);
-               ft->valid = 1;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return (int) int_ft->size;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->is_signed;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft,
-               bt_bool is_signed)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       int_ft->is_signed = !!is_signed;
-       BT_LOGV("Set integer field type's signedness: addr=%p, is-signed=%d",
-               ft, is_signed);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft,
-               unsigned int size)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       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;
-       }
-
-       int_ft->size = size;
-       BT_LOGV("Set integer field type's size: addr=%p, size=%u",
-               ft, size);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->base;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_integer_base base)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       switch (base) {
-       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
-       case BT_CTF_INTEGER_BASE_BINARY:
-       case BT_CTF_INTEGER_BASE_OCTAL:
-       case BT_CTF_INTEGER_BASE_DECIMAL:
-       case BT_CTF_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;
-       }
-
-       BT_LOGV("Set integer field type's base: addr=%p, base=%s",
-               ft, bt_ctf_integer_base_string(base));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->encoding;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
-                       encoding != BT_CTF_STRING_ENCODING_ASCII &&
-                       encoding != BT_CTF_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_ctf_string_encoding_string(encoding));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->mapped_clock_class;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class *clock_class)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               goto end;
-       }
-
-       if (!bt_ctf_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_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(int_ft->mapped_clock_class);
-       int_ft->mapped_clock_class = bt_ctf_object_get_ref(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_ctf_clock_class_get_name(clock_class));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_mapped_clock_class(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_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_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
-               ft, clock_class);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end)
-{
-       int ret = 0;
-       struct bt_ctf_enumeration_mapping *mapping;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(ft,
-               index);
-       if (!mapping) {
-               /* bt_ctf_field_type_common_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end)
-{
-       int ret = 0;
-       struct bt_ctf_enumeration_mapping *mapping;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-               ft, index);
-       if (!mapping) {
-               /* bt_ctf_field_type_common_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;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       return BT_CTF_TO_COMMON(enum_ft->container_ft);
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_signed_add_mapping(
-               struct bt_ctf_field_type_common *ft, const char *string,
-               int64_t range_start, int64_t range_end)
-{
-       int ret = 0;
-       GQuark mapping_name;
-       struct bt_ctf_enumeration_mapping *mapping;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_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 bt_ctf_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 bt_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
-               struct bt_ctf_field_type_common *ft, const char *string,
-               uint64_t range_start, uint64_t range_end)
-{
-       int ret = 0;
-       GQuark mapping_name;
-       struct bt_ctf_enumeration_mapping *mapping;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_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 bt_ctf_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 bt_ctf_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;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_enumeration_get_mapping_count(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       return (int64_t) enum_ft->entries->len;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_get_exponent_digits(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
-               "Field type");
-       return (int) flt_ft->exp_dig;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_set_exponent_digits(
-               struct bt_ctf_field_type_common *ft,
-               unsigned int exponent_digits)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(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_CTF_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_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_get_mantissa_digits(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
-               "Field type");
-       return (int) flt_ft->mant_dig;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_set_mantissa_digits(
-               struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(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_CTF_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_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_replace_field(
-               struct bt_ctf_field_type_common *ft,
-               const char *field_name,
-               struct bt_ctf_field_type_common *field_type)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       GQuark name_quark;
-       uint64_t i;
-
-       BT_ASSERT(ft);
-       BT_ASSERT(field_name);
-       BT_ASSERT(field_type);
-       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_STRUCT);
-       name_quark = g_quark_from_string(field_name);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
-
-               if (field->name == name_quark) {
-                       bt_ctf_object_put_ref(field->type);
-                       field->type = bt_ctf_object_get_ref(field_type);
-               }
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *field_type,
-               const char *field_name)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: field type is not a structure field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_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;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_structure_get_field_count(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       return (int64_t) struct_ft->fields->len;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_borrow_field_by_index(
-               struct bt_ctf_field_type_common *ft,
-               const char **field_name,
-               struct bt_ctf_field_type_common **field_type, uint64_t index)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common_structure_field *field;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       BT_ASSERT_PRE(index < struct_ft->fields->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u, ft-addr=%p",
-               index, struct_ft->fields->len, ft);
-       field = BT_CTF_FIELD_TYPE_COMMON_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;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_structure_field *field;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, index);
-       field_type = field->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_tag_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common *tag_ft = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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 = BT_CTF_TO_COMMON(var_ft->tag_ft);
-
-end:
-       return tag_ft;
-}
-
-BT_HIDDEN
-const char *bt_ctf_field_type_common_variant_get_tag_name(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       const char *tag_name = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_set_tag_name(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft, bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *field_type,
-               const char *field_name)
-{
-       size_t i;
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_CTF_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_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 bt_ctf_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;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_by_name(
-               struct bt_ctf_field_type_common *ft,
-               const char *field_name)
-{
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_variant_choice *choice;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(field_name, "Name");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
-       field_type = choice->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_variant_get_field_count(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Variant field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       return (int64_t) var_ft->choices->len;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_borrow_field_by_index(
-               struct bt_ctf_field_type_common *ft,
-               const char **field_name,
-               struct bt_ctf_field_type_common **field_type, uint64_t index)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common_variant_choice *choice;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       BT_ASSERT_PRE(index < var_ft->choices->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u, ft-addr=%p",
-               index, var_ft->choices->len, ft);
-       choice = BT_CTF_FIELD_TYPE_COMMON_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_ctf_field_type_common_variant_find_choice_index(
-               struct bt_ctf_field_type_common *ft, uint64_t uval,
-               bool is_signed)
-{
-       int64_t ret;
-       uint64_t i;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(ft);
-       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_VARIANT);
-
-       if (bt_ctf_field_type_common_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_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               var_ft, i);
-
-               for (range_i = 0; range_i < choice->ranges->len; range_i++) {
-                       struct bt_ctf_field_type_common_variant_choice_range *range =
-                               &g_array_index(
-                                       choice->ranges,
-                                       struct bt_ctf_field_type_common_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;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_array_borrow_element_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
-               "Field type");
-       BT_ASSERT(array_ft && array_ft->element_ft);
-       return array_ft->element_ft;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_set_element_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: array field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_ARRAY) {
-               BT_LOGW("Invalid parameter: field type is not an array field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (array_ft->element_ft) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(array_ft->element_ft);
-       }
-
-       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
-       BT_LOGV("Set array field type's element field type: array-ft-addr=%p, "
-               "element-ft-addr=%p", ft, element_ft);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
-               "Field type");
-       return (int64_t) array_ft->length;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_sequence_borrow_element_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->element_ft;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_set_element_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: sequence field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
-               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (seq_ft->element_ft) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(seq_ft->element_ft);
-       }
-
-       seq_ft->element_ft = element_ft;
-       bt_ctf_object_get_ref(seq_ft->element_ft);
-       BT_LOGV("Set sequence field type's element field type: sequence-ft-addr=%p, "
-               "element-ft-addr=%p", ft, element_ft);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-const char *bt_ctf_field_type_common_sequence_get_length_field_name(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->length_field_name ?
-               seq_ft->length_field_name->str : NULL;
-}
-
-BT_HIDDEN
-enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRING,
-               "Field type");
-       return string_ft->encoding;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_STRING) {
-               BT_LOGW("Invalid parameter: field type is not a string field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
-                       encoding != BT_CTF_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_ctf_string_encoding_string(encoding));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *ft)
-{
-       int ret;
-       enum bt_ctf_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_ctf_field_type_common_get_type_id(ft);
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       {
-               struct bt_ctf_field_type_common *element_ft =
-                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
-
-               BT_ASSERT(element_ft);
-               ret = bt_ctf_field_type_common_get_alignment(element_ft);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       {
-               struct bt_ctf_field_type_common *element_ft =
-                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
-
-               BT_ASSERT(element_ft);
-               ret = bt_ctf_field_type_common_get_alignment(element_ft);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               int64_t i, element_count;
-
-               element_count = bt_ctf_field_type_common_structure_get_field_count(
-                       ft);
-               BT_ASSERT(element_count >= 0);
-
-               for (i = 0; i < element_count; i++) {
-                       struct bt_ctf_field_type_common *field = NULL;
-                       int field_alignment;
-
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               ft, NULL, &field, i);
-                       BT_ASSERT(ret == 0);
-                       BT_ASSERT(field);
-                       field_alignment = bt_ctf_field_type_common_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_CTF_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft,
-               unsigned int alignment)
-{
-       int ret = 0;
-       enum bt_ctf_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_ctf_field_type_common_get_type_id(ft);
-       if (type_id == BT_CTF_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_CTF_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_CTF_FIELD_TYPE_ID_VARIANT ||
-                       type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE ||
-                       type_id == BT_CTF_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_ctf_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;
-}
-
-BT_HIDDEN
-enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order(
-               struct bt_ctf_field_type_common *ft)
-{
-       enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_INTEGER:
-       {
-               struct bt_ctf_field_type_common_integer *integer =
-                       BT_CTF_FROM_COMMON(ft);
-
-               ret = integer->user_byte_order;
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_ctf_field_type_common_enumeration *enum_ft =
-                       BT_CTF_FROM_COMMON(ft);
-
-               ret = bt_ctf_field_type_common_get_byte_order(
-                       BT_CTF_TO_COMMON(enum_ft->container_ft));
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_FLOAT:
-       {
-               struct bt_ctf_field_type_common_floating_point *floating_point =
-                       BT_CTF_FROM_COMMON(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_ctf_field_type_id_string(ft->id));
-               goto end;
-       }
-
-       BT_ASSERT(ret == BT_CTF_BYTE_ORDER_NATIVE ||
-               ret == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
-               ret == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
-               ret == BT_CTF_BYTE_ORDER_NETWORK);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_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_CTF_BYTE_ORDER_NATIVE &&
-                       byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
-               BT_LOGW("Invalid parameter: invalid byte order: "
-                       "addr=%p, bo=%s", ft,
-                       bt_ctf_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_ctf_byte_order_string(byte_order));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id(
-               struct bt_ctf_field_type_common *ft)
-{
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       return ft->id;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft)
-{
-       if (!ft || ft->frozen) {
-               return;
-       }
-
-       BT_ASSERT(ft->methods->freeze);
-       ft->methods->freeze(ft);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_signed(
-               struct bt_ctf_field_type_common_variant *var_ft,
-               int64_t tag_value)
-{
-       struct bt_ctf_field_type_common *field_type = NULL;
-       GQuark field_name_quark;
-       gpointer index;
-       struct bt_ctf_field_type_common_variant_choice *choice;
-       struct range_overlap_query query = {
-               .range_start._signed = tag_value,
-               .range_end._signed = tag_value,
-               .mapping_name = 0,
-               .overlaps = 0,
-       };
-
-       g_ptr_array_foreach(var_ft->tag_ft->entries, check_ranges_overlap,
-               &query);
-       if (!query.overlaps) {
-               goto end;
-       }
-
-       field_name_quark = query.mapping_name;
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-                       GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
-               goto end;
-       }
-
-       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
-               (size_t) index);
-       field_type = choice->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_unsigned(
-               struct bt_ctf_field_type_common_variant *var_ft,
-               uint64_t tag_value)
-{
-       struct bt_ctf_field_type_common *field_type = NULL;
-       GQuark field_name_quark;
-       gpointer index;
-       struct bt_ctf_field_type_common_variant_choice *choice;
-       struct range_overlap_query query = {
-               .range_start._unsigned = tag_value,
-               .range_end._unsigned = tag_value,
-               .mapping_name = 0,
-               .overlaps = 0,
-       };
-
-       g_ptr_array_foreach(var_ft->tag_ft->entries,
-               check_ranges_overlap_unsigned, &query);
-       if (!query.overlaps) {
-               goto end;
-       }
-
-       field_name_quark = query.mapping_name;
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-               GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
-               goto end;
-       }
-
-       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
-               (size_t) index);
-       field_type = choice->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common *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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_get_field_name_index(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       int ret;
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_get_field_name_index(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       int ret;
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_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_ctf_field_type_common_sequence_set_length_field_path(
-               struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
-               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_get_ref(path);
-       BT_CTF_OBJECT_MOVE_REF(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_ctf_field_type_common_variant_set_tag_field_path(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_path *path)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_get_ref(path);
-       BT_CTF_OBJECT_MOVE_REF(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_ctf_field_type_common_variant_set_tag_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *tag_ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_CTF_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_ctf_field_type_id_string(tag_ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(var_ft->tag_ft);
-       var_ft->tag_ft = bt_ctf_object_get_ref(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;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft)
-{
-       ft->frozen = 1;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD("Freezing enumeration field type object: addr=%p", ft);
-       bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-       BT_LOGD("Freezing enumeration field type object's container field type: int-ft-addr=%p",
-               enum_ft->container_ft);
-       bt_ctf_field_type_common_freeze(BT_CTF_TO_COMMON(enum_ft->container_ft));
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       uint64_t i;
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing structure field type object: addr=%p", ft);
-       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_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_ctf_field_type_common_freeze(field->type);
-       }
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_update_choices(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(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_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
-               const char *choice_name = g_quark_to_string(choice->name);
-               struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
-                       bt_ctf_field_type_common_enumeration_find_mappings_by_name(
-                               BT_CTF_TO_COMMON(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_ctf_field_type_enumeration_mapping_iterator_next(iter) == 0) {
-                       struct bt_ctf_field_type_common_variant_choice_range range;
-
-                       if (is_signed) {
-                               ret = bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
-                                       iter, NULL,
-                                       &range.lower.i, &range.upper.i);
-                       } else {
-                               ret = bt_ctf_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_ctf_object_put_ref(iter);
-       }
-
-       var_ft->choices_up_to_date = true;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       uint64_t i;
-
-       BT_LOGD("Freezing variant field type object: addr=%p", ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_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_ctf_field_type_common_freeze(choice->type);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing array field type object: addr=%p", ft);
-       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-       BT_LOGD("Freezing array field type object's element field type: element-ft-addr=%p",
-               array_ft->element_ft);
-       bt_ctf_field_type_common_freeze(array_ft->element_ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing sequence field type object: addr=%p", ft);
-       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-       BT_LOGD("Freezing sequence field type object's element field type: element-ft-addr=%p",
-               seq_ft->element_ft);
-       bt_ctf_field_type_common_freeze(seq_ft->element_ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_set_byte_order(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       int_ft->user_byte_order = byte_order;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       bt_ctf_field_type_common_set_byte_order(BT_CTF_TO_COMMON(enum_ft->container_ft),
-               byte_order);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_set_byte_order(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       flt_ft->user_byte_order = byte_order;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       int i;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft, i);
-               struct bt_ctf_field_type_common *field_type = field->type;
-
-               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       int i;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               var_ft, i);
-               struct bt_ctf_field_type_common *field_type = choice->type;
-
-               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       bt_ctf_field_type_common_set_byte_order(array_ft->element_ft, byte_order);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       bt_ctf_field_type_common_set_byte_order(seq_ft->element_ft, byte_order);
-}
-
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_integer *int_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_integer *int_ft_b = BT_CTF_FROM_COMMON(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_ctf_byte_order_string(int_ft_a->user_byte_order),
-                       bt_ctf_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_ctf_integer_base_string(int_ft_a->base),
-                       bt_ctf_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_ctf_string_encoding_string(int_ft_a->encoding),
-                       bt_ctf_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_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_compare(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_floating_point *flt_ft_a =
-               BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_floating_point *flt_ft_b =
-               BT_CTF_FROM_COMMON(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_ctf_byte_order_string(flt_ft_a->user_byte_order),
-                       bt_ctf_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 bt_ctf_enumeration_mapping *mapping_a,
-               struct bt_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_ctf_field_type_common_enumeration *enum_ft_a =
-               BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_enumeration *enum_ft_b =
-               BT_CTF_FROM_COMMON(ft_b);
-
-       /* Container field type */
-       ret = bt_ctf_field_type_common_compare(
-               BT_CTF_TO_COMMON(enum_ft_a->container_ft),
-               BT_CTF_TO_COMMON(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 bt_ctf_enumeration_mapping *mapping_a =
-                       g_ptr_array_index(enum_ft_a->entries, i);
-               struct bt_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_string *string_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_string *string_ft_b = BT_CTF_FROM_COMMON(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_ctf_string_encoding_string(string_ft_a->encoding),
-                       bt_ctf_string_encoding_string(string_ft_b->encoding));
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int compare_structure_variant_members(
-               struct bt_ctf_field_type_common *member_a_ft,
-               struct bt_ctf_field_type_common *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_ctf_field_type_common_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_ctf_field_type_common_structure *struct_ft_a =
-               BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_structure *struct_ft_b =
-               BT_CTF_FROM_COMMON(ft_b);
-
-       /* Alignment */
-       if (bt_ctf_field_type_common_get_alignment(ft_a) !=
-                       bt_ctf_field_type_common_get_alignment(ft_b)) {
-               BT_LOGV("Structure field types differ: different alignments: "
-                       "ft-a-align=%u, ft-b-align=%u",
-                       bt_ctf_field_type_common_get_alignment(ft_a),
-                       bt_ctf_field_type_common_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_ctf_field_type_common_structure_field *field_a =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft_a, i);
-               struct bt_ctf_field_type_common_structure_field *field_b =
-                       BT_CTF_FIELD_TYPE_COMMON_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_ctf_field_type_common_variant *var_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_variant *var_ft_b = BT_CTF_FROM_COMMON(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_ctf_field_type_common_compare(BT_CTF_TO_COMMON(var_ft_a->tag_ft),
-               BT_CTF_TO_COMMON(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_ctf_field_type_common_variant_choice *choice_a =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               var_ft_a, i);
-               struct bt_ctf_field_type_common_variant_choice *choice_b =
-                       BT_CTF_FIELD_TYPE_COMMON_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_array *array_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_array *array_ft_b = BT_CTF_FROM_COMMON(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_ctf_field_type_common_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;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = -1;
-       struct bt_ctf_field_type_common_sequence *seq_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_sequence *seq_ft_b = BT_CTF_FROM_COMMON(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_ctf_field_type_common_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_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *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_ctf_field_type_id_string(ft_a->id),
-                       bt_ctf_field_type_id_string(ft_b->id));
-               goto end;
-       }
-
-       if (ft_a->id == BT_CTF_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);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft)
-{
-       int64_t field_count = -1;
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-               field_count =
-                       bt_ctf_field_type_common_structure_get_field_count(ft);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               field_count =
-                       bt_ctf_field_type_common_variant_get_field_count(ft);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       case BT_CTF_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;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index(
-               struct bt_ctf_field_type_common *ft, int index)
-{
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                       ft, NULL, &field_type, index);
-               if (ret) {
-                       field_type = NULL;
-                       goto end;
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-       {
-               int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
-                       ft, NULL, &field_type, index);
-               if (ret) {
-                       field_type = NULL;
-                       goto end;
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-               field_type =
-                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               field_type =
-                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
-               break;
-       default:
-               break;
-       }
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft,
-               const char *name)
-{
-       int field_index = -1;
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-               field_index = bt_ctf_field_type_common_structure_get_field_name_index(
-                       ft, name);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               field_index = bt_ctf_field_type_common_variant_get_field_name_index(
-                       ft, name);
-               break;
-       default:
-               break;
-       }
-
-       return field_index;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       return var_ft->tag_field_path;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->length_field_path;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_validate_single_clock_class(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class **expected_clock_class)
-{
-       int ret = 0;
-
-       if (!ft) {
-               goto end;
-       }
-
-       BT_ASSERT(expected_clock_class);
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_INTEGER:
-       {
-               struct bt_ctf_clock_class *mapped_clock_class =
-                       bt_ctf_field_type_common_integer_borrow_mapped_clock_class(ft);
-
-               if (!mapped_clock_class) {
-                       goto end;
-               }
-
-               if (!*expected_clock_class) {
-                       /* Move reference to output parameter */
-                       *expected_clock_class = bt_ctf_object_get_ref(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_ctf_clock_class_get_name(mapped_clock_class),
-                                       *expected_clock_class,
-                                       bt_ctf_clock_class_get_name(*expected_clock_class));
-                               bt_ctf_object_put_ref(mapped_clock_class);
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ENUM:
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       {
-               struct bt_ctf_field_type_common *sub_ft = NULL;
-
-               switch (ft->id) {
-               case BT_CTF_FIELD_TYPE_ID_ENUM:
-                       sub_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-                               ft);
-                       break;
-               case BT_CTF_FIELD_TYPE_ID_ARRAY:
-                       sub_ft = bt_ctf_field_type_common_array_borrow_element_field_type(
-                               ft);
-                       break;
-               case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-                       sub_ft = bt_ctf_field_type_common_sequence_borrow_element_field_type(
-                               ft);
-                       break;
-               default:
-                       BT_LOGF("Unexpected field type ID: id=%d", ft->id);
-                       abort();
-               }
-
-               BT_ASSERT(sub_ft);
-               ret = bt_ctf_field_type_common_validate_single_clock_class(sub_ft,
-                       expected_clock_class);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               uint64_t i;
-               int64_t count = bt_ctf_field_type_common_structure_get_field_count(
-                       ft);
-
-               for (i = 0; i < count; i++) {
-                       const char *name;
-                       struct bt_ctf_field_type_common *member_type;
-
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               ft, &name, &member_type, i);
-                       BT_ASSERT(ret == 0);
-                       ret = bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_VARIANT:
-       {
-               uint64_t i;
-               int64_t count = bt_ctf_field_type_common_variant_get_field_count(
-                       ft);
-
-               for (i = 0; i < count; i++) {
-                       const char *name;
-                       struct bt_ctf_field_type_common *member_type;
-
-                       ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
-                               ft, &name, &member_type, i);
-                       BT_ASSERT(ret == 0);
-                       ret = bt_ctf_field_type_common_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;
-                       }
-               }
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
-               struct bt_ctf_field_type *type);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_string_copy(
-               struct bt_ctf_field_type *type);
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_integer_methods = {
-       .freeze = bt_ctf_field_type_common_generic_freeze,
-       .validate = bt_ctf_field_type_common_integer_validate,
-       .set_byte_order = bt_ctf_field_type_common_integer_set_byte_order,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_integer_copy,
-       .compare = bt_ctf_field_type_common_integer_compare,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_floating_point_methods = {
-       .freeze = bt_ctf_field_type_common_generic_freeze,
-       .validate = NULL,
-       .set_byte_order = bt_ctf_field_type_common_floating_point_set_byte_order,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_floating_point_copy,
-       .compare = bt_ctf_field_type_common_floating_point_compare,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_enumeration_methods = {
-       .freeze = bt_ctf_field_type_common_enumeration_freeze_recursive,
-       .validate = bt_ctf_field_type_common_enumeration_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_enumeration_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_enumeration_copy_recursive,
-       .compare = bt_ctf_field_type_common_enumeration_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_string_methods = {
-       .freeze = bt_ctf_field_type_common_generic_freeze,
-       .validate = NULL,
-       .set_byte_order = NULL,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_string_copy,
-       .compare = bt_ctf_field_type_common_string_compare,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_array_methods = {
-       .freeze = bt_ctf_field_type_common_array_freeze_recursive,
-       .validate = bt_ctf_field_type_common_array_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_array_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_array_copy_recursive,
-       .compare = bt_ctf_field_type_common_array_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_sequence_methods = {
-       .freeze = bt_ctf_field_type_common_sequence_freeze_recursive,
-       .validate = bt_ctf_field_type_common_sequence_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_sequence_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_sequence_copy_recursive,
-       .compare = bt_ctf_field_type_common_sequence_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_structure_methods = {
-       .freeze = bt_ctf_field_type_common_structure_freeze_recursive,
-       .validate = bt_ctf_field_type_common_structure_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_structure_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_structure_copy_recursive,
-       .compare = bt_ctf_field_type_common_structure_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_variant_methods = {
-       .freeze = bt_ctf_field_type_common_variant_freeze_recursive,
-       .validate = bt_ctf_field_type_common_variant_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_variant_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_variant_copy_recursive,
-       .compare = bt_ctf_field_type_common_variant_compare_recursive,
-};
-
-typedef int (*bt_ctf_field_type_serialize_func)(struct bt_ctf_field_type_common *,
-               struct metadata_context *);
-
-BT_HIDDEN
-int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type,
-               struct metadata_context *context)
-{
-       int ret;
-       struct bt_ctf_field_type_common *type_common = (void *) type;
-       bt_ctf_field_type_serialize_func serialize_func;
-
-       BT_ASSERT(type);
-       BT_ASSERT(context);
-
-       /* Make sure field type is valid before serializing it */
-       ret = bt_ctf_field_type_common_validate((void *) type);
-       if (ret) {
-               BT_LOGW("Cannot serialize field type's metadata: field type is invalid: "
-                       "addr=%p", type);
-               goto end;
-       }
-
-       serialize_func = type_common->spec.writer.serialize_func;
-       ret = serialize_func((void *) type, context);
-
-end:
-       return ret;
-}
-
-static
-const char *get_encoding_string(enum bt_ctf_string_encoding encoding)
-{
-       const char *encoding_string;
-
-       switch (encoding) {
-       case BT_CTF_STRING_ENCODING_NONE:
-               encoding_string = "none";
-               break;
-       case BT_CTF_STRING_ENCODING_ASCII:
-               encoding_string = "ASCII";
-               break;
-       case BT_CTF_STRING_ENCODING_UTF8:
-               encoding_string = "UTF8";
-               break;
-       default:
-               encoding_string = "unknown";
-               break;
-       }
-
-       return encoding_string;
-}
-
-static
-const char *get_integer_base_string(enum bt_ctf_integer_base base)
-{
-       const char *base_string;
-
-       switch (base) {
-       case BT_CTF_INTEGER_BASE_DECIMAL:
-       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
-               base_string = "decimal";
-               break;
-       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
-               base_string = "hexadecimal";
-               break;
-       case BT_CTF_INTEGER_BASE_OCTAL:
-               base_string = "octal";
-               break;
-       case BT_CTF_INTEGER_BASE_BINARY:
-               base_string = "binary";
-               break;
-       default:
-               base_string = "unknown";
-               break;
-       }
-
-       return base_string;
-}
-
-static
-void append_field_name(struct metadata_context *context,
-               const char *name)
-{
-       g_string_append_c(context->string, ' ');
-
-       if (!bt_ctf_identifier_is_valid(name) || *name == '_') {
-               g_string_append_c(context->string, '_');
-       }
-
-       g_string_append(context->string, name);
-}
-
-static
-int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       struct bt_ctf_field_type_common_integer *integer = BT_CTF_FROM_COMMON(type);
-       int ret = 0;
-
-       BT_LOGD("Serializing CTF writer integer field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       g_string_append_printf(context->string,
-               "integer { size = %u; align = %u; signed = %s; encoding = %s; base = %s; byte_order = %s",
-               integer->size, type->alignment,
-               (integer->is_signed ? "true" : "false"),
-               get_encoding_string(integer->encoding),
-               get_integer_base_string(integer->base),
-               bt_ctf_get_byte_order_string(integer->user_byte_order));
-       if (integer->mapped_clock_class) {
-               const char *clock_name = bt_ctf_clock_class_get_name(
-                       integer->mapped_clock_class);
-
-               BT_ASSERT(clock_name);
-               g_string_append_printf(context->string,
-                       "; map = clock.%s.value", clock_name);
-       }
-
-       g_string_append(context->string, "; }");
-       return ret;
-}
-
-static
-int bt_ctf_field_type_enumeration_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       size_t entry;
-       int ret;
-       struct bt_ctf_field_type_common_enumeration *enumeration =
-               BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_type_common *container_type;
-       int container_signed;
-
-       BT_LOGD("Serializing CTF writer enumeration field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       container_type =
-               bt_ctf_field_type_common_enumeration_borrow_container_field_type(type);
-       BT_ASSERT(container_type);
-       container_signed = bt_ctf_field_type_common_integer_is_signed(
-               container_type);
-       BT_ASSERT(container_signed >= 0);
-       g_string_append(context->string, "enum : ");
-       BT_LOGD_STR("Serializing CTF writer enumeration field type's container field type's metadata.");
-       ret = bt_ctf_field_type_serialize_recursive(
-               (void *) enumeration->container_ft, context);
-       if (ret) {
-               BT_LOGW("Cannot serialize CTF writer enumeration field type's container field type's metadata: "
-                       "container-ft-addr=%p", enumeration->container_ft);
-               goto end;
-       }
-
-       g_string_append(context->string, " { ");
-       for (entry = 0; entry < enumeration->entries->len; entry++) {
-               struct bt_ctf_enumeration_mapping *mapping =
-                       enumeration->entries->pdata[entry];
-               const char *label = g_quark_to_string(mapping->string);
-
-               g_string_append(context->string, "\"");
-
-               if (!bt_ctf_identifier_is_valid(label) || label[0] == '_') {
-                       g_string_append(context->string, "_");
-               }
-
-               g_string_append_printf(context->string, "%s\" = ", label);
-
-               if (container_signed) {
-                       if (mapping->range_start._signed ==
-                               mapping->range_end._signed) {
-                               g_string_append_printf(context->string,
-                                       "%" PRId64,
-                                       mapping->range_start._signed);
-                       } else {
-                               g_string_append_printf(context->string,
-                                       "%" PRId64 " ... %" PRId64,
-                                       mapping->range_start._signed,
-                                       mapping->range_end._signed);
-                       }
-               } else {
-                       if (mapping->range_start._unsigned ==
-                               mapping->range_end._unsigned) {
-                               g_string_append_printf(context->string,
-                                       "%" PRIu64,
-                                       mapping->range_start._unsigned);
-                       } else {
-                               g_string_append_printf(context->string,
-                                       "%" PRIu64 " ... %" PRIu64,
-                                       mapping->range_start._unsigned,
-                                       mapping->range_end._unsigned);
-                       }
-               }
-
-               g_string_append(context->string,
-                       ((entry != (enumeration->entries->len - 1)) ?
-                       ", " : " }"));
-       }
-
-       if (context->field_name->len) {
-               append_field_name(context,
-                       context->field_name->str);
-               g_string_assign(context->field_name, "");
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       struct bt_ctf_field_type_common_floating_point *floating_point =
-               BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer floating point number field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       g_string_append_printf(context->string,
-               "floating_point { exp_dig = %u; mant_dig = %u; byte_order = %s; align = %u; }",
-               floating_point->exp_dig,
-               floating_point->mant_dig,
-               bt_ctf_get_byte_order_string(floating_point->user_byte_order),
-               type->alignment);
-       return 0;
-}
-
-static
-int bt_ctf_field_type_structure_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       size_t i;
-       unsigned int indent;
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *structure = BT_CTF_FROM_COMMON(type);
-       GString *structure_field_name = context->field_name;
-
-       BT_LOGD("Serializing CTF writer structure field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       context->field_name = g_string_new("");
-
-       context->current_indentation_level++;
-       g_string_append(context->string, "struct {\n");
-
-       for (i = 0; i < structure->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               structure, i);
-
-               BT_LOGD("Serializing CTF writer structure field type's field metadata: "
-                       "index=%zu, "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, field, g_quark_to_string(field->name));
-
-               for (indent = 0; indent < context->current_indentation_level;
-                       indent++) {
-                       g_string_append_c(context->string, '\t');
-               }
-
-               g_string_assign(context->field_name,
-                       g_quark_to_string(field->name));
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) field->type, context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize CTF writer structure field type's field's metadata: "
-                               "index=%zu, "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, field->type,
-                               g_quark_to_string(field->name));
-                       goto end;
-               }
-
-               if (context->field_name->len) {
-                       append_field_name(context,
-                               context->field_name->str);
-               }
-               g_string_append(context->string, ";\n");
-       }
-
-       context->current_indentation_level--;
-       for (indent = 0; indent < context->current_indentation_level;
-               indent++) {
-               g_string_append_c(context->string, '\t');
-       }
-
-       g_string_append_printf(context->string, "} align(%u)",
-                type->alignment);
-
-end:
-       g_string_free(context->field_name, TRUE);
-       context->field_name = structure_field_name;
-       return ret;
-}
-
-static
-int bt_ctf_field_type_variant_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       size_t i;
-       unsigned int indent;
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *variant = BT_CTF_FROM_COMMON(type);
-       GString *variant_field_name = context->field_name;
-
-       BT_LOGD("Serializing CTF writer variant field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       context->field_name = g_string_new("");
-       if (variant->tag_name->len > 0) {
-               g_string_append(context->string, "variant <");
-               append_field_name(context, variant->tag_name->str);
-               g_string_append(context->string, "> {\n");
-       } else {
-               g_string_append(context->string, "variant {\n");
-       }
-
-       context->current_indentation_level++;
-       for (i = 0; i < variant->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *field =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               variant, i);
-
-               BT_LOGD("Serializing CTF writer variant field type's field metadata: "
-                       "index=%zu, "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, field, g_quark_to_string(field->name));
-
-               g_string_assign(context->field_name,
-                       g_quark_to_string(field->name));
-               for (indent = 0; indent < context->current_indentation_level;
-                       indent++) {
-                       g_string_append_c(context->string, '\t');
-               }
-
-               g_string_assign(context->field_name,
-                       g_quark_to_string(field->name));
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) field->type, context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize CTF writer variant field type's field's metadata: "
-                               "index=%zu, "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, field->type,
-                               g_quark_to_string(field->name));
-                       goto end;
-               }
-
-               if (context->field_name->len) {
-                       append_field_name(context,
-                               context->field_name->str);
-                       g_string_append_c(context->string, ';');
-               }
-
-               g_string_append_c(context->string, '\n');
-       }
-
-       context->current_indentation_level--;
-       for (indent = 0; indent < context->current_indentation_level;
-               indent++) {
-               g_string_append_c(context->string, '\t');
-       }
-
-       g_string_append(context->string, "}");
-
-end:
-       g_string_free(context->field_name, TRUE);
-       context->field_name = variant_field_name;
-       return ret;
-}
-
-static
-int bt_ctf_field_type_array_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_array *array = BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer array field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       BT_LOGD_STR("Serializing CTF writer array field type's element field type's metadata.");
-       ret = bt_ctf_field_type_serialize_recursive(
-               (void *) array->element_ft, context);
-       if (ret) {
-               BT_LOGW("Cannot serialize CTF writer array field type's element field type's metadata: "
-                       "element-ft-addr=%p", array->element_ft);
-               goto end;
-       }
-
-       if (context->field_name->len) {
-               append_field_name(context,
-                       context->field_name->str);
-
-               g_string_append_printf(context->string, "[%u]", array->length);
-               g_string_assign(context->field_name, "");
-       } else {
-               g_string_append_printf(context->string, "[%u]", array->length);
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_type_sequence_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *sequence = BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer sequence field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       BT_LOGD_STR("Serializing CTF writer sequence field type's element field type's metadata.");
-       ret = bt_ctf_field_type_serialize_recursive(
-               (void *) sequence->element_ft, context);
-       if (ret) {
-               BT_LOGW("Cannot serialize CTF writer sequence field type's element field type's metadata: "
-                       "element-ft-addr=%p", sequence->element_ft);
-               goto end;
-       }
-
-       if (context->field_name->len) {
-               append_field_name(context, context->field_name->str);
-               g_string_assign(context->field_name, "");
-       }
-       g_string_append(context->string, "[");
-       append_field_name(context, sequence->length_field_name->str);
-       g_string_append(context->string, "]");
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       struct bt_ctf_field_type_common_string *string = BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer string field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       g_string_append_printf(context->string,
-               "string { encoding = %s; }",
-               get_encoding_string(string->encoding));
-       return 0;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size)
-{
-       struct bt_ctf_field_type_common_integer *integer = NULL;
-
-       BT_LOGD("Creating CTF writer integer field type object: size=%u", size);
-
-       if (size == 0 || size > 64) {
-               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
-                       "size=%u", size);
-               goto error;
-       }
-
-       integer = g_new0(struct bt_ctf_field_type_common_integer, 1);
-       if (!integer) {
-               BT_LOGE_STR("Failed to allocate one integer field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_integer_initialize(BT_CTF_TO_COMMON(integer),
-               size, bt_ctf_field_type_common_integer_destroy,
-               &bt_ctf_field_type_integer_methods);
-       integer->common.spec.writer.serialize_func =
-               bt_ctf_field_type_integer_serialize;
-       BT_LOGD("Created CTF writer integer field type object: addr=%p, size=%u",
-               integer, size);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(integer);
-
-end:
-       return (void *) integer;
-}
-
-int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_integer_get_size((void *) ft);
-}
-
-bt_bool bt_ctf_field_type_integer_is_signed(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_integer_is_signed((void *) ft);
-}
-
-int bt_ctf_field_type_integer_set_is_signed(struct bt_ctf_field_type *ft,
-               bt_bool is_signed)
-{
-       return bt_ctf_field_type_common_integer_set_is_signed((void *) ft,
-               is_signed);
-}
-
-int bt_ctf_field_type_integer_set_size(struct bt_ctf_field_type *ft,
-               unsigned int size)
-{
-       return bt_ctf_field_type_common_integer_set_size((void *) ft, size);
-}
-
-enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_integer_get_base((void *) ft);
-}
-
-int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *ft,
-               enum bt_ctf_integer_base base)
-{
-       return bt_ctf_field_type_common_integer_set_base((void *) ft,
-               (int) base);
-}
-
-enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_integer_get_encoding((void *) ft);
-}
-
-int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       return bt_ctf_field_type_common_integer_set_encoding((void *) ft,
-               (int) encoding);
-}
-
-struct bt_ctf_clock_class *bt_ctf_field_type_integer_get_mapped_clock_class(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
-               (void *) ft));
-}
-
-int bt_ctf_field_type_integer_set_mapped_clock_class(
-               struct bt_ctf_field_type *ft,
-               struct bt_ctf_clock_class *clock_class)
-{
-       return bt_ctf_field_type_common_integer_set_mapped_clock_class((void *) ft,
-               clock_class);
-}
-
-int bt_ctf_field_type_enumeration_signed_get_mapping_by_index(
-               struct bt_ctf_field_type *ft, uint64_t index,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end)
-{
-       return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
-               (void *) ft, index, mapping_name, range_begin, range_end);
-}
-
-int bt_ctf_field_type_enumeration_unsigned_get_mapping_by_index(
-               struct bt_ctf_field_type *ft, uint64_t index,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end)
-{
-       return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
-               (void *) ft, index, mapping_name, range_begin, range_end);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create(
-               struct bt_ctf_field_type *container_ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enumeration = NULL;
-       struct bt_ctf_field_type_common *int_ft = (void *) container_ft;
-
-       BT_LOGD("Creating CTF writer 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_CTF_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_ctf_field_type_id_string(int_ft->id));
-               goto error;
-       }
-
-       enumeration = g_new0(struct bt_ctf_field_type_common_enumeration, 1);
-       if (!enumeration) {
-               BT_LOGE_STR("Failed to allocate one enumeration field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_enumeration_initialize(BT_CTF_TO_COMMON(enumeration),
-               int_ft, bt_ctf_field_type_common_enumeration_destroy_recursive,
-               &bt_ctf_field_type_enumeration_methods);
-       enumeration->common.spec.writer.serialize_func =
-               bt_ctf_field_type_enumeration_serialize_recursive;
-       BT_LOGD("Created CTF writer enumeration field type object: addr=%p, "
-               "int-ft-addr=%p, int-ft-size=%u",
-               enumeration, container_ft,
-               bt_ctf_field_type_integer_get_size(container_ft));
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
-
-end:
-       return (void *) enumeration;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-                       (void *) ft));
-}
-
-int bt_ctf_field_type_enumeration_signed_add_mapping(
-               struct bt_ctf_field_type *ft, const char *string,
-               int64_t range_start, int64_t range_end)
-{
-       return bt_ctf_field_type_common_enumeration_signed_add_mapping(
-               (void *) ft, string, range_start, range_end);
-}
-
-int bt_ctf_field_type_enumeration_unsigned_add_mapping(
-               struct bt_ctf_field_type *ft, const char *string,
-               uint64_t range_start, uint64_t range_end)
-{
-       return bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
-               (void *) ft, string, range_start, range_end);
-}
-
-int64_t bt_ctf_field_type_enumeration_get_mapping_count(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_enumeration_get_mapping_count((void *) ft);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void)
-{
-       struct bt_ctf_field_type_common_floating_point *floating_point =
-               g_new0(struct bt_ctf_field_type_common_floating_point, 1);
-
-       BT_LOGD_STR("Creating CTF writer floating point number field type object.");
-
-       if (!floating_point) {
-               BT_LOGE_STR("Failed to allocate one floating point number field type.");
-               goto end;
-       }
-
-       bt_ctf_field_type_common_floating_point_initialize(
-               BT_CTF_TO_COMMON(floating_point),
-               bt_ctf_field_type_common_floating_point_destroy,
-               &bt_ctf_field_type_floating_point_methods);
-       floating_point->common.spec.writer.serialize_func =
-               bt_ctf_field_type_floating_point_serialize;
-       BT_LOGD("Created CTF writer 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_ctf_field_type_floating_point_get_exponent_digits(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_floating_point_get_exponent_digits(
-               (void *) ft);
-}
-
-int bt_ctf_field_type_floating_point_set_exponent_digits(
-               struct bt_ctf_field_type *ft, unsigned int exponent_digits)
-{
-       return bt_ctf_field_type_common_floating_point_set_exponent_digits(
-               (void *) ft, exponent_digits);
-}
-
-int bt_ctf_field_type_floating_point_get_mantissa_digits(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_floating_point_get_mantissa_digits(
-               (void *) ft);
-}
-
-int bt_ctf_field_type_floating_point_set_mantissa_digits(
-               struct bt_ctf_field_type *ft, unsigned int mantissa_digits)
-{
-       return bt_ctf_field_type_common_floating_point_set_mantissa_digits(
-               (void *) ft, mantissa_digits);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void)
-{
-       struct bt_ctf_field_type_common_structure *structure =
-               g_new0(struct bt_ctf_field_type_common_structure, 1);
-
-       BT_LOGD_STR("Creating CTF writer structure field type object.");
-
-       if (!structure) {
-               BT_LOGE_STR("Failed to allocate one structure field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_structure_initialize(BT_CTF_TO_COMMON(structure),
-               bt_ctf_field_type_common_structure_destroy_recursive,
-               &bt_ctf_field_type_structure_methods);
-       structure->common.spec.writer.serialize_func =
-               bt_ctf_field_type_structure_serialize_recursive;
-       BT_LOGD("Created CTF writer structure field type object: addr=%p",
-               structure);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
-
-end:
-       return (void *) structure;
-}
-
-int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *ft,
-               struct bt_ctf_field_type *field_type,
-               const char *field_name)
-{
-       return bt_ctf_field_type_common_structure_add_field((void *) ft,
-               (void *) field_type, field_name);
-}
-
-int64_t bt_ctf_field_type_structure_get_field_count(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_structure_get_field_count((void *) ft);
-}
-
-int bt_ctf_field_type_structure_get_field_by_index(
-               struct bt_ctf_field_type *ft,
-               const char **field_name,
-               struct bt_ctf_field_type **field_type, uint64_t index)
-{
-       int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-               (void *) ft, field_name, (void *) field_type, index);
-
-       if (ret == 0 && field_type) {
-               bt_ctf_object_get_ref(*field_type);
-       }
-
-       return ret;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name(
-               struct bt_ctf_field_type *ft, const char *name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               (void *) ft, name));
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_create(
-       struct bt_ctf_field_type *tag_ft, const char *tag_name)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = NULL;
-
-       BT_LOGD("Creating CTF writer variant field type object: "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               tag_ft, tag_name);
-
-       if (tag_name && !bt_ctf_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_ctf_field_type_common_variant, 1);
-       if (!var_ft) {
-               BT_LOGE_STR("Failed to allocate one variant field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_variant_initialize(BT_CTF_TO_COMMON(var_ft),
-               (void *) tag_ft, tag_name,
-               bt_ctf_field_type_common_variant_destroy_recursive,
-               &bt_ctf_field_type_variant_methods);
-       var_ft->common.spec.writer.serialize_func =
-               bt_ctf_field_type_variant_serialize_recursive;
-       BT_LOGD("Created CTF writer variant field type object: addr=%p, "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               var_ft, tag_ft, tag_name);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(var_ft);
-
-end:
-       return (void *) var_ft;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_tag_field_type(
-               (void *) ft));
-}
-
-const char *bt_ctf_field_type_variant_get_tag_name(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_variant_get_tag_name((void *) ft);
-}
-
-int bt_ctf_field_type_variant_set_tag_name(
-               struct bt_ctf_field_type *ft, const char *name)
-{
-       return bt_ctf_field_type_common_variant_set_tag_name((void *) ft, name);
-}
-
-int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *ft,
-               struct bt_ctf_field_type *field_type,
-               const char *field_name)
-{
-       return bt_ctf_field_type_common_variant_add_field((void *) ft,
-               (void *) field_type, field_name);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name(
-               struct bt_ctf_field_type *ft,
-               const char *field_name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_field_type_by_name(
-               (void *) ft, field_name));
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag(
-               struct bt_ctf_field_type *ft,
-               struct bt_ctf_field *tag_field)
-{
-       int ret;
-       int64_t choice_index;
-       struct bt_ctf_field *container;
-       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
-       struct bt_ctf_field_type *ret_ft = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
-               (struct bt_ctf_field_common *) tag_field,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((struct bt_ctf_field_common *) tag_field,
-               "Tag field");
-
-       container = bt_ctf_field_enumeration_borrow_container(tag_field);
-       BT_ASSERT(container);
-
-       if (var_ft->tag_ft->container_ft->is_signed) {
-               int64_t val;
-
-               ret = bt_ctf_field_integer_signed_get_value(container,
-                       &val);
-               BT_ASSERT(ret == 0);
-               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
-                       (void *) ft, (uint64_t) val, true);
-       } else {
-               uint64_t val;
-
-               ret = bt_ctf_field_integer_unsigned_get_value(container,
-                       &val);
-               BT_ASSERT(ret == 0);
-               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
-                       (void *) ft, val, false);
-       }
-
-       if (choice_index < 0) {
-               BT_LIB_LOGW("Cannot find variant field type's field: "
-                       "var-ft-addr=%p, tag-field-addr=%p", ft, tag_field);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_variant_get_field_by_index(ft, NULL,
-               &ret_ft, choice_index);
-       BT_ASSERT(ret == 0);
-
-end:
-       return ret_ft;
-}
-
-int64_t bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_variant_get_field_count((void *) ft);
-}
-
-int bt_ctf_field_type_variant_get_field_by_index(struct bt_ctf_field_type *ft,
-               const char **field_name, struct bt_ctf_field_type **field_type,
-               uint64_t index)
-{
-       int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
-               (void *) ft, field_name, (void *) field_type, index);
-
-       if (ret == 0 && field_type) {
-               bt_ctf_object_get_ref(*field_type);
-       }
-
-       return ret;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_array_create(
-               struct bt_ctf_field_type *element_ft, unsigned int length)
-{
-       struct bt_ctf_field_type_common_array *array = NULL;
-
-       BT_LOGD("Creating CTF writer 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_ctf_field_type_common_array, 1);
-       if (!array) {
-               BT_LOGE_STR("Failed to allocate one array field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_array_initialize(BT_CTF_TO_COMMON(array),
-               (void *) element_ft, length,
-               bt_ctf_field_type_common_array_destroy_recursive,
-               &bt_ctf_field_type_array_methods);
-       array->common.spec.writer.serialize_func =
-               bt_ctf_field_type_array_serialize_recursive;
-       BT_LOGD("Created CTF writer array field type object: addr=%p, "
-               "element-ft-addr=%p, length=%u",
-               array, element_ft, length);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
-
-end:
-       return (void *) array;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_array_borrow_element_field_type(
-               (void *) ft));
-}
-
-int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_array_get_length((void *) ft);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
-               struct bt_ctf_field_type *element_ft,
-               const char *length_field_name)
-{
-       struct bt_ctf_field_type_common_sequence *sequence = NULL;
-
-       BT_LOGD("Creating CTF writer 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_ctf_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_ctf_field_type_common_sequence, 1);
-       if (!sequence) {
-               BT_LOGE_STR("Failed to allocate one sequence field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
-               (void *) element_ft, length_field_name,
-               bt_ctf_field_type_common_sequence_destroy_recursive,
-               &bt_ctf_field_type_sequence_methods);
-       sequence->common.spec.writer.serialize_func =
-               bt_ctf_field_type_sequence_serialize_recursive;
-       BT_LOGD("Created CTF writer sequence field type object: addr=%p, "
-               "element-ft-addr=%p, length-field-name=\"%s\"",
-               sequence, element_ft, length_field_name);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(sequence);
-
-end:
-       return (void *) sequence;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_sequence_borrow_element_field_type(
-               (void *) ft));
-}
-
-const char *bt_ctf_field_type_sequence_get_length_field_name(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_sequence_get_length_field_name((void *) ft);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_string_create(void)
-{
-       struct bt_ctf_field_type_common_string *string =
-               g_new0(struct bt_ctf_field_type_common_string, 1);
-
-       BT_LOGD_STR("Creating CTF writer string field type object.");
-
-       if (!string) {
-               BT_LOGE_STR("Failed to allocate one string field type.");
-               return NULL;
-       }
-
-       bt_ctf_field_type_common_string_initialize(BT_CTF_TO_COMMON(string),
-               bt_ctf_field_type_common_string_destroy,
-               &bt_ctf_field_type_string_methods);
-       string->common.spec.writer.serialize_func =
-               bt_ctf_field_type_string_serialize;
-       BT_LOGD("Created CTF writer string field type object: addr=%p", string);
-       return (void *) string;
-}
-
-enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_string_get_encoding((void *) ft);
-}
-
-int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       return bt_ctf_field_type_common_string_set_encoding((void *) ft,
-               (int) encoding);
-}
-
-int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_get_alignment((void *) ft);
-}
-
-int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *ft,
-               unsigned int alignment)
-{
-       return bt_ctf_field_type_common_set_alignment((void *) ft, alignment);
-}
-
-enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_get_byte_order((void *) ft);
-}
-
-int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       return bt_ctf_field_type_common_set_byte_order((void *) ft,
-               (int) byte_order);
-}
-
-enum bt_ctf_field_type_id bt_ctf_field_type_get_type_id(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_get_type_id((void *) ft);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft)
-{
-       return (void *) bt_ctf_field_type_common_copy((void *) ft);
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = (void *) ft;
-       struct bt_ctf_field_type_common_integer *copy_ft;
-
-       BT_LOGD("Copying CTF writer integer field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_integer_create(int_ft->size);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer integer field type.");
-               goto end;
-       }
-
-       copy_ft->mapped_clock_class = bt_ctf_object_get_ref(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 CTF writer integer field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       size_t i;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) ft;
-       struct bt_ctf_field_type_common_enumeration *copy_ft = NULL;
-       struct bt_ctf_field_type_common_enumeration *container_copy_ft;
-
-       BT_LOGD("Copying CTF writer enumeration field type's: addr=%p", ft);
-
-       /* Copy the source enumeration's container */
-       BT_LOGD_STR("Copying CTF writer enumeration field type's container field type.");
-       container_copy_ft = BT_CTF_FROM_COMMON(bt_ctf_field_type_common_copy(
-               BT_CTF_TO_COMMON(enum_ft->container_ft)));
-       if (!container_copy_ft) {
-               BT_LOGE_STR("Cannot copy CTF writer enumeration field type's container field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_ctf_field_type_enumeration_create(
-               (void *) container_copy_ft);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer enumeration field type.");
-               goto end;
-       }
-
-       /* Copy all enumaration entries */
-       for (i = 0; i < enum_ft->entries->len; i++) {
-               struct bt_ctf_enumeration_mapping *mapping = g_ptr_array_index(
-                       enum_ft->entries, i);
-               struct bt_ctf_enumeration_mapping *copy_mapping = g_new0(
-                       struct bt_ctf_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 CTF writer enumeration field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(container_copy_ft);
-       return (void *) copy_ft;
-
-error:
-       bt_ctf_object_put_ref(container_copy_ft);
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common_floating_point *copy_ft;
-
-       BT_LOGD("Copying CTF writer floating point number field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_floating_point_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer 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 CTF writer floating point number field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       int64_t i;
-       GHashTableIter iter;
-       gpointer key, value;
-       struct bt_ctf_field_type_common_structure *struct_ft = (void *) ft;
-       struct bt_ctf_field_type_common_structure *copy_ft;
-
-       BT_LOGD("Copying CTF writer structure field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_structure_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer 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_ctf_field_type_common_structure_field *entry, *copy_entry;
-               struct bt_ctf_field_type_common *field_ft_copy;
-
-               entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                       struct_ft, i);
-               copy_entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                       copy_ft, i);
-               BT_LOGD("Copying CTF writer 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_ctf_field_type_copy(
-                       (void *) entry->type);
-               if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy CTF writer 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 CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-
-error:
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       int64_t i;
-       GHashTableIter iter;
-       gpointer key, value;
-       struct bt_ctf_field_type_common *tag_ft_copy = NULL;
-       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
-       struct bt_ctf_field_type_common_variant *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer variant field type's: addr=%p", ft);
-       if (var_ft->tag_ft) {
-               BT_LOGD_STR("Copying CTF writer variant field type's tag field type.");
-               tag_ft_copy = bt_ctf_field_type_common_copy(
-                       BT_CTF_TO_COMMON(var_ft->tag_ft));
-               if (!tag_ft_copy) {
-                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field type.");
-                       goto end;
-               }
-       }
-
-       copy_ft = (void *) bt_ctf_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 CTF writer 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_ctf_field_type_common_variant_choice *entry, *copy_entry;
-               struct bt_ctf_field_type_common *field_ft_copy;
-               uint64_t range_i;
-
-               entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i);
-               copy_entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                       copy_ft, i);
-               BT_LOGD("Copying CTF writer 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_ctf_field_type_copy(
-                       (void *) entry->type);
-               if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy CTF writer 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_ctf_field_type_common_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 CTF writer variant field type's tag field path.");
-               copy_ft->tag_field_path = bt_ctf_field_path_copy(
-                       var_ft->tag_field_path);
-               if (!copy_ft->tag_field_path) {
-                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field path.");
-                       goto error;
-               }
-       }
-
-       copy_ft->choices_up_to_date = var_ft->choices_up_to_date;
-       BT_LOGD("Copied CTF writer variant field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(tag_ft_copy);
-       return (void *) copy_ft;
-
-error:
-       bt_ctf_object_put_ref(tag_ft_copy);
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common *container_ft_copy = NULL;
-       struct bt_ctf_field_type_common_array *array_ft = (void *) ft;
-       struct bt_ctf_field_type_common_array *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer array field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying CTF writer array field type's element field type.");
-       container_ft_copy = bt_ctf_field_type_common_copy(array_ft->element_ft);
-       if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy CTF writer array field type's element field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_ctf_field_type_array_create(
-               (void *) container_ft_copy, array_ft->length);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer array field type.");
-               goto end;
-       }
-
-       BT_LOGD("Copied CTF writer array field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(container_ft_copy);
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common *container_ft_copy = NULL;
-       struct bt_ctf_field_type_common_sequence *seq_ft = (void *) ft;
-       struct bt_ctf_field_type_common_sequence *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer sequence field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying CTF writer sequence field type's element field type.");
-       container_ft_copy = bt_ctf_field_type_common_copy(seq_ft->element_ft);
-       if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy CTF writer sequence field type's element field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_ctf_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 CTF writer sequence field type.");
-               goto end;
-       }
-
-       if (seq_ft->length_field_path) {
-               BT_LOGD_STR("Copying CTF writer sequence field type's length field path.");
-               copy_ft->length_field_path = bt_ctf_field_path_copy(
-                       seq_ft->length_field_path);
-               if (!copy_ft->length_field_path) {
-                       BT_LOGE_STR("Cannot copy CTF writer sequence field type's length field path.");
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied CTF writer sequence field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(container_ft_copy);
-       return (void *) copy_ft;
-error:
-       bt_ctf_object_put_ref(container_ft_copy);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_string_copy(struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common_string *string_ft = (void *) ft;
-       struct bt_ctf_field_type_common_string *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer string field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_string_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer string field type.");
-               goto end;
-       }
-
-       copy_ft->encoding = string_ft->encoding;
-       BT_LOGD("Copied CTF writer string field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
diff --git a/lib/ctf-writer/field-wrapper.c b/lib/ctf-writer/field-wrapper.c
deleted file mode 100644 (file)
index f5629fc..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 "CTF-WRITER-FIELD-WRAPPER"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <glib.h>
-
-BT_HIDDEN
-struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data)
-{
-       struct bt_ctf_field_wrapper *field_wrapper =
-               g_new0(struct bt_ctf_field_wrapper, 1);
-
-       BT_LOGD_STR("Creating empty field wrapper object.");
-
-       if (!field_wrapper) {
-               BT_LOGE("Failed to allocate one field wrapper.");
-               goto end;
-       }
-
-       bt_ctf_object_init_unique(&field_wrapper->base);
-       BT_LOGD("Created empty field wrapper object: addr=%p",
-               field_wrapper);
-
-end:
-       return field_wrapper;
-}
-
-BT_HIDDEN
-void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field_wrapper)
-{
-       BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper);
-       BT_ASSERT(!field_wrapper->field);
-       BT_LOGD_STR("Putting stream class.");
-       g_free(field_wrapper);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create(
-               struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_wrapper *field_wrapper = NULL;
-
-       BT_ASSERT(pool);
-       BT_ASSERT(ft);
-       field_wrapper = bt_ctf_object_pool_create_object(pool);
-       if (!field_wrapper) {
-               BT_LIB_LOGE("Cannot allocate one field wrapper from field wrapper pool: "
-                       "%![pool-]+o", pool);
-               goto error;
-       }
-
-       BT_ASSERT(field_wrapper->field);
-       goto end;
-
-error:
-       if (field_wrapper) {
-               bt_ctf_field_wrapper_destroy(field_wrapper);
-               field_wrapper = NULL;
-       }
-
-end:
-       return field_wrapper;
-}
diff --git a/lib/ctf-writer/fields.c b/lib/ctf-writer/fields.c
deleted file mode 100644 (file)
index a0f00a9..0000000
+++ /dev/null
@@ -1,1860 +0,0 @@
-/*
- * Copyright 2013, 2014 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.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-FIELDS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/fcntl-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <float.h>
-#include <inttypes.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-#define BT_ASSERT_PRE_CTF_FIELD_IS_INT_OR_ENUM(_field, _name)          \
-       BT_ASSERT_PRE((_field)->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || \
-               (_field)->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,        \
-               _name " is not an integer or an enumeration field: "    \
-               "field-addr=%p", (_field))
-
-BT_HIDDEN
-struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common *copy = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT(field_type_common_has_known_id(field->type));
-       BT_ASSERT(field->methods->copy);
-       copy = field->methods->copy(field);
-       if (!copy) {
-               BT_LOGW("Cannot create field: ft-addr=%p", field->type);
-               goto end;
-       }
-
-       bt_ctf_field_common_set(copy, field->payload_set);
-
-end:
-       return copy;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_release_func)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *structure_type =
-               BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-       size_t i;
-
-       BT_LOGD("Initializing common structure field object: ft-addr=%p", type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       structure->fields = g_ptr_array_new_with_free_func(field_release_func);
-       g_ptr_array_set_size(structure->fields, structure_type->fields->len);
-
-       /* Create all fields contained in the structure field. */
-       for (i = 0; i < structure_type->fields->len; i++) {
-               struct bt_ctf_field_common *field;
-               struct bt_ctf_field_type_common_structure_field *struct_field =
-                       BT_CTF_FIELD_TYPE_COMMON_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;
-               }
-
-               g_ptr_array_index(structure->fields, i) = field;
-       }
-
-       BT_LOGD("Initialized common structure field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_release_func)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *variant_type =
-               BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-       size_t i;
-
-       BT_LOGD("Initializing common variant field object: ft-addr=%p", type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       ret = bt_ctf_field_type_common_variant_update_choices(type);
-       if (ret) {
-               BT_LOGE("Cannot update common 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_ctf_field_common *field;
-               struct bt_ctf_field_type_common_variant_choice *var_choice =
-                       BT_CTF_FIELD_TYPE_COMMON_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 common variant field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods)
-{
-       int ret = 0;
-       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Initializing common string field object: ft-addr=%p", type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, 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 common string field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_destroy_func)
-{
-       struct bt_ctf_field_type_common_array *array_type = BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-       unsigned int array_length;
-       int ret = 0;
-       uint64_t i;
-
-       BT_LOGD("Initializing common array field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       array_length = array_type->length;
-       array->elements = g_ptr_array_sized_new(array_length);
-       if (!array->elements) {
-               ret = -1;
-               goto end;
-       }
-
-       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 common array field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               GDestroyNotify field_destroy_func)
-{
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-       int ret = 0;
-
-       BT_LOGD("Initializing common sequence field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       sequence->elements = g_ptr_array_new();
-       if (!sequence->elements) {
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_set_free_func(sequence->elements, field_destroy_func);
-       BT_LOGD("Initialized common sequence field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field)
-{
-       return (field && field->payload_set) ? 0 : -1;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < structure->fields->len; i++) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) structure->fields->pdata[i]);
-
-               if (ret) {
-                       int this_ret;
-                       const char *name;
-
-                       this_ret = bt_ctf_field_type_common_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-addr=%p, field-name=\"%s\", "
-                               "index=%" PRId64 ", field-addr=%p",
-                               field, name, i, structure->fields->pdata[i]);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int ret = 0;
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       if (!variant->current_field) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_common_validate_recursive(variant->current_field);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array->elements->len; i++) {
-               ret = bt_ctf_field_common_validate_recursive((void *) array->elements->pdata[i]);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid array field's element field: "
-                               "array-field-addr=%p, " PRId64 ", "
-                               "elem-field-addr=%p",
-                               field, i, array->elements->pdata[i]);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field)
-{
-       size_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) sequence->elements->pdata[i]);
-               if (ret) {
-                       BT_ASSERT_PRE_MSG("Invalid sequence field's element field: "
-                               "seq-field-addr=%p, " PRId64 ", "
-                               "elem-field-addr=%p",
-                               field, i, sequence->elements->pdata[i]);
-                       goto end;
-               }
-       }
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field)
-{
-       BT_ASSERT(field);
-       field->payload_set = false;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field)
-{
-       int64_t i;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < structure->fields->len; i++) {
-               struct bt_ctf_field_common *member = structure->fields->pdata[i];
-
-               if (!member) {
-                       /*
-                        * Structure members are lazily initialized;
-                        * skip if this member has not been allocated
-                        * yet.
-                        */
-                       continue;
-               }
-
-               bt_ctf_field_common_reset_recursive(member);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-       variant->current_field = NULL;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field)
-{
-       size_t i;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array->elements->len; i++) {
-               struct bt_ctf_field_common *member = array->elements->pdata[i];
-
-               if (!member) {
-                       /*
-                        * Array elements are lazily initialized; skip
-                        * if this member has not been allocated yet.
-                        */
-                       continue;
-               }
-
-               bt_ctf_field_common_reset_recursive(member);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-       uint64_t i;
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               if (sequence->elements->pdata[i]) {
-                       bt_ctf_field_common_reset_recursive(
-                               sequence->elements->pdata[i]);
-               }
-       }
-
-       sequence->length = 0;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field,
-               bool is_frozen)
-{
-       field->frozen = is_frozen;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_structure_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       uint64_t i;
-       struct bt_ctf_field_common_structure *structure_field =
-               BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing structure field object: addr=%p", field);
-
-       for (i = 0; i < structure_field->fields->len; i++) {
-               struct bt_ctf_field_common *struct_field =
-                       g_ptr_array_index(structure_field->fields, i);
-
-               BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64,
-                       struct_field, i);
-               bt_ctf_field_common_set_is_frozen_recursive(struct_field,
-                       is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_variant_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       uint64_t i;
-       struct bt_ctf_field_common_variant *variant_field = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing variant field object: addr=%p", field);
-
-       for (i = 0; i < variant_field->fields->len; i++) {
-               struct bt_ctf_field_common *var_field =
-                       g_ptr_array_index(variant_field->fields, i);
-
-               BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64,
-                       var_field, i);
-               bt_ctf_field_common_set_is_frozen_recursive(var_field, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_array_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       int64_t i;
-       struct bt_ctf_field_common_array *array_field = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing array field object: addr=%p", field);
-
-       for (i = 0; i < array_field->elements->len; i++) {
-               struct bt_ctf_field_common *elem_field =
-                       g_ptr_array_index(array_field->elements, i);
-
-               BT_LOGD("Freezing array field object's element field: "
-                       "element-field-addr=%p, index=%" PRId64,
-                       elem_field, i);
-               bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_sequence_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       int64_t i;
-       struct bt_ctf_field_common_sequence *sequence_field =
-               BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing sequence field object: addr=%p", field);
-
-       for (i = 0; i < sequence_field->length; i++) {
-               struct bt_ctf_field_common *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_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field,
-               bool is_frozen)
-{
-       if (!field) {
-               goto end;
-       }
-
-       BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d",
-               field, is_frozen);
-       BT_ASSERT(field_type_common_has_known_id(field->type));
-       BT_ASSERT(field->methods->set_is_frozen);
-       field->methods->set_is_frozen(field, is_frozen);
-
-end:
-       return;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field)
-{
-       return field && field->payload_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_structure_is_set_recursive(
-               struct bt_ctf_field_common *field)
-{
-       bt_bool is_set = BT_FALSE;
-       size_t i;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < structure->fields->len; i++) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       structure->fields->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-       bt_bool is_set = BT_FALSE;
-
-       BT_ASSERT(field);
-
-       if (variant->current_field) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       variant->current_field);
-       }
-
-       return is_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       size_t i;
-       bt_bool is_set = BT_FALSE;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array->elements->len; i++) {
-               is_set = bt_ctf_field_common_is_set_recursive(array->elements->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       size_t i;
-       bt_bool is_set = BT_FALSE;
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       if (!sequence->elements) {
-               goto end;
-       }
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       sequence->elements->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
-
-static struct bt_ctf_field_common_methods bt_ctf_field_integer_methods = {
-       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
-       .validate = bt_ctf_field_common_generic_validate,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_generic_is_set,
-       .reset = bt_ctf_field_common_generic_reset,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_floating_point_methods = {
-       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
-       .validate = bt_ctf_field_common_generic_validate,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_generic_is_set,
-       .reset = bt_ctf_field_common_generic_reset,
-};
-
-static
-void bt_ctf_field_enumeration_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen);
-
-static
-int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field);
-
-static
-bt_bool bt_ctf_field_enumeration_is_set_recursive(
-               struct bt_ctf_field_common *field);
-
-static
-void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field);
-
-static struct bt_ctf_field_common_methods bt_ctf_field_enumeration_methods = {
-       .set_is_frozen = bt_ctf_field_enumeration_set_is_frozen_recursive,
-       .validate = bt_ctf_field_enumeration_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_enumeration_is_set_recursive,
-       .reset = bt_ctf_field_enumeration_reset_recursive,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_string_methods = {
-       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
-       .validate = bt_ctf_field_common_generic_validate,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_generic_is_set,
-       .reset = bt_ctf_field_common_generic_reset,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_structure_methods = {
-       .set_is_frozen = bt_ctf_field_common_structure_set_is_frozen_recursive,
-       .validate = bt_ctf_field_common_structure_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_structure_is_set_recursive,
-       .reset = bt_ctf_field_common_structure_reset_recursive,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_sequence_methods = {
-       .set_is_frozen = bt_ctf_field_common_sequence_set_is_frozen_recursive,
-       .validate = bt_ctf_field_common_sequence_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_sequence_is_set_recursive,
-       .reset = bt_ctf_field_common_sequence_reset_recursive,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_array_methods = {
-       .set_is_frozen = bt_ctf_field_common_array_set_is_frozen_recursive,
-       .validate = bt_ctf_field_common_array_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_array_is_set_recursive,
-       .reset = bt_ctf_field_common_array_reset_recursive,
-};
-
-static
-void bt_ctf_field_variant_set_is_frozen_recursive(struct bt_ctf_field_common *field,
-               bool is_frozen);
-
-static
-int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field);
-
-static
-bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field);
-
-static
-void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field);
-
-static struct bt_ctf_field_common_methods bt_ctf_field_variant_methods = {
-       .set_is_frozen = bt_ctf_field_variant_set_is_frozen_recursive,
-       .validate = bt_ctf_field_variant_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_variant_is_set_recursive,
-       .reset = bt_ctf_field_variant_reset_recursive,
-};
-
-static
-struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_enumeration_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_floating_point_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_structure_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *(* const field_create_funcs[])(struct bt_ctf_field_type *) = {
-       [BT_CTF_FIELD_TYPE_ID_INTEGER] =        bt_ctf_field_integer_create,
-       [BT_CTF_FIELD_TYPE_ID_ENUM] =           bt_ctf_field_enumeration_create,
-       [BT_CTF_FIELD_TYPE_ID_FLOAT] =          bt_ctf_field_floating_point_create,
-       [BT_CTF_FIELD_TYPE_ID_STRUCT] =         bt_ctf_field_structure_create,
-       [BT_CTF_FIELD_TYPE_ID_VARIANT] =        bt_ctf_field_variant_create,
-       [BT_CTF_FIELD_TYPE_ID_ARRAY] =          bt_ctf_field_array_create,
-       [BT_CTF_FIELD_TYPE_ID_SEQUENCE] =       bt_ctf_field_sequence_create,
-       [BT_CTF_FIELD_TYPE_ID_STRING] =         bt_ctf_field_string_create,
-};
-
-typedef int (*bt_ctf_field_serialize_recursive_func)(
-               struct bt_ctf_field_common *, struct bt_ctfser *,
-               enum bt_ctf_byte_order);
-
-static
-void bt_ctf_field_integer_destroy(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer integer field object: addr=%p", field);
-       bt_ctf_field_common_integer_finalize((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer floating point field object: addr=%p",
-               field);
-       bt_ctf_field_common_floating_point_finalize((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_enumeration_destroy_recursive(struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_enumeration *enumeration = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Destroying CTF writer enumeration field object: addr=%p",
-               field);
-       BT_LOGD_STR("Putting container field.");
-       bt_ctf_object_put_ref(enumeration->container);
-       bt_ctf_field_common_finalize((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_structure_destroy_recursive(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer structure field object: addr=%p", field);
-       bt_ctf_field_common_structure_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_variant_destroy_recursive(struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Destroying CTF writer variant field object: addr=%p", field);
-       BT_LOGD_STR("Putting tag field.");
-       bt_ctf_object_put_ref(variant->tag);
-       bt_ctf_field_common_variant_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_array_destroy_recursive(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer array field object: addr=%p", field);
-       bt_ctf_field_common_array_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_sequence_destroy_recursive(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer sequence field object: addr=%p", field);
-       bt_ctf_field_common_sequence_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_string_destroy(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer string field object: addr=%p", field);
-       bt_ctf_field_common_string_finalize((void *) field);
-       g_free(field);
-}
-
-BT_HIDDEN
-int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       struct bt_ctf_field_common *field_common = (void *) field;
-       bt_ctf_field_serialize_recursive_func serialize_func;
-
-       BT_ASSERT(ctfser);
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT(field_common->spec.writer.serialize_func);
-       serialize_func = field_common->spec.writer.serialize_func;
-       return serialize_func(field_common, ctfser,
-               native_byte_order);
-}
-
-static
-int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret;
-       struct bt_ctf_field_type_common_integer *int_type =
-               BT_CTF_FROM_COMMON(field->type);
-       struct bt_ctf_field_common_integer *int_field =
-               BT_CTF_FROM_COMMON(field);
-       enum bt_ctf_byte_order byte_order;
-
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field");
-       BT_LOGV("Serializing CTF writer integer field: addr=%p, native-bo=%s",
-               field,
-               bt_ctf_byte_order_string(native_byte_order));
-       byte_order = int_type->user_byte_order;
-       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
-               byte_order = native_byte_order;
-       }
-
-       if (int_type->is_signed) {
-               ret = bt_ctfser_write_signed_int(ctfser,
-                       int_field->payload.signd, int_type->common.alignment,
-                       int_type->size,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       } else {
-               ret = bt_ctfser_write_unsigned_int(ctfser,
-                       int_field->payload.unsignd, int_type->common.alignment,
-                       int_type->size,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       }
-
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot serialize integer field: ret=%d", ret);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_enumeration_serialize_recursive(
-               struct bt_ctf_field_common *field, struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       BT_LOGV("Serializing enumeration field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-       BT_LOGV_STR("Serializing enumeration field's payload field.");
-       return bt_ctf_field_serialize_recursive(
-               (void *) enumeration->container, ctfser, native_byte_order);
-}
-
-static
-int bt_ctf_field_floating_point_serialize(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret = -1;
-       struct bt_ctf_field_type_common_floating_point *flt_type =
-               BT_CTF_FROM_COMMON(field->type);
-       struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field);
-       enum bt_ctf_byte_order byte_order;
-
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
-       BT_LOGV("Serializing floating point number field: "
-               "addr=%p, native-bo=%s", field,
-               bt_ctf_byte_order_string(native_byte_order));
-
-       byte_order = flt_type->user_byte_order;
-       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
-               byte_order = native_byte_order;
-       }
-
-       if (flt_type->mant_dig == FLT_MANT_DIG) {
-               ret = bt_ctfser_write_float32(ctfser, flt_field->payload,
-                       flt_type->common.alignment,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       } else if (flt_type->mant_dig == DBL_MANT_DIG) {
-               ret = bt_ctfser_write_float64(ctfser, flt_field->payload,
-                       flt_type->common.alignment,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       } else {
-               abort();
-       }
-
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot serialize floating point number field: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_structure_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int64_t i;
-       int ret;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing structure field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-       ret = bt_ctfser_align_offset_in_current_packet(ctfser,
-               field->type->alignment);
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot align offset before serializing structure field: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       for (i = 0; i < structure->fields->len; i++) {
-               struct bt_ctf_field_common *member = g_ptr_array_index(
-                       structure->fields, i);
-               const char *field_name = NULL;
-
-               BT_LOGV("Serializing structure field's field: ser-offset=%" PRIu64 ", "
-                       "field-addr=%p, index=%" PRIu64,
-                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
-                       member, i);
-
-               if (unlikely(!member)) {
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               field->type, &field_name, NULL, i);
-                       BT_ASSERT(ret == 0);
-                       BT_LOGW("Cannot serialize structure field's field: field is not set: "
-                               "struct-field-addr=%p, "
-                               "field-name=\"%s\", index=%" PRId64,
-                               field, field_name, i);
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = bt_ctf_field_serialize_recursive((void *) member, ctfser,
-                       native_byte_order);
-               if (unlikely(ret)) {
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               field->type, &field_name, NULL, i);
-                       BT_ASSERT(ret == 0);
-                       BT_LOGW("Cannot serialize structure field's field: "
-                               "struct-field-addr=%p, field-addr=%p, "
-                               "field-name=\"%s\", index=%" PRId64,
-                               field->type, member, field_name, i);
-                       break;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_variant_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing variant field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-       BT_LOGV_STR("Serializing variant field's payload field.");
-       return bt_ctf_field_serialize_recursive(
-               (void *) variant->current_field, ctfser, native_byte_order);
-}
-
-static
-int bt_ctf_field_array_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing array field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-
-       for (i = 0; i < array->elements->len; i++) {
-               struct bt_ctf_field_common *elem_field =
-                       g_ptr_array_index(array->elements, i);
-
-               BT_LOGV("Serializing array field's element field: "
-                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
-                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
-                       elem_field, i);
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) elem_field, ctfser, native_byte_order);
-               if (unlikely(ret)) {
-                       BT_LOGW("Cannot serialize array field's element field: "
-                               "array-field-addr=%p, field-addr=%p, "
-                               "index=%" PRId64, field, elem_field, i);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_sequence_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing sequence field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               struct bt_ctf_field_common *elem_field =
-                       g_ptr_array_index(sequence->elements, i);
-
-               BT_LOGV("Serializing sequence field's element field: "
-                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
-                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
-                       elem_field, i);
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) elem_field, ctfser, native_byte_order);
-               if (unlikely(ret)) {
-                       BT_LOGW("Cannot serialize sequence field's element field: "
-                               "sequence-field-addr=%p, field-addr=%p, "
-                               "index=%" PRId64, field, elem_field, i);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_string_serialize(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret;
-       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
-       BT_LOGV("Serializing string field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string((int) native_byte_order));
-       ret = bt_ctfser_write_string(ctfser, (const char *) string->buf->data);
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot serialize string field: ret=%d", ret);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field *field = NULL;
-       enum bt_ctf_field_type_id type_id;
-
-       BT_ASSERT_PRE_NON_NULL(type, "Field type");
-       BT_ASSERT(field_type_common_has_known_id((void *) type));
-       BT_ASSERT_PRE(bt_ctf_field_type_common_validate((void *) type) == 0,
-               "Field type is invalid: ft-addr=%p", type);
-       type_id = bt_ctf_field_type_get_type_id(type);
-       field = field_create_funcs[type_id](type);
-       if (!field) {
-               goto end;
-       }
-
-       bt_ctf_field_type_common_freeze((void *) type);
-
-end:
-       return field;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_borrow_type((void *) field));
-}
-
-enum bt_ctf_field_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_common *field_common = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       return (int) field_common->type->id;
-}
-
-int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field,
-               struct bt_ctf_field *length_field)
-{
-       int ret;
-       struct bt_ctf_field_common *common_length_field = (void *) length_field;
-       uint64_t length;
-
-       BT_ASSERT_PRE_NON_NULL(length_field, "Length field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) length_field, "Length field");
-       BT_ASSERT_PRE(common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER ||
-                       common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,
-               "Length field must be an integer or enumeration field: field-addr=%p",
-               length_field);
-
-       if (common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
-               struct bt_ctf_field_enumeration *enumeration = (void *)
-                       length_field;
-
-               length_field = (void *) enumeration->container;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_get_value(length_field, &length);
-       BT_ASSERT(ret == 0);
-       return bt_ctf_field_common_sequence_set_length((void *) field,
-               length, (bt_ctf_field_common_create_func) bt_ctf_field_create);
-}
-
-struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
-               struct bt_ctf_field *field, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_index(
-               (void *) field, index));
-}
-
-struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name(
-               struct bt_ctf_field *field, const char *name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_name(
-               (void *) field, name));
-}
-
-struct bt_ctf_field *bt_ctf_field_array_get_field(
-               struct bt_ctf_field *field, uint64_t index)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_field_common_array_borrow_field((void *) field, index));
-}
-
-struct bt_ctf_field *bt_ctf_field_sequence_get_field(
-               struct bt_ctf_field *field, uint64_t index)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_field_common_sequence_borrow_field((void *) field, index));
-}
-
-struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field,
-               struct bt_ctf_field *tag_field)
-{
-       struct bt_ctf_field_variant *variant_field = (void *) field;
-       struct bt_ctf_field_enumeration *enum_field = (void *) tag_field;
-       struct bt_ctf_field_type_common_variant *variant_ft;
-       struct bt_ctf_field_type_common_enumeration *tag_ft;
-       struct bt_ctf_field *current_field = NULL;
-       bt_bool is_signed;
-       uint64_t tag_uval;
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Variant field");
-       BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) tag_field, "Tag field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
-               (struct bt_ctf_field_common *) tag_field,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
-               (struct bt_ctf_field_common *) field,
-               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_ASSERT_PRE(
-               bt_ctf_field_common_validate_recursive((void *) tag_field) == 0,
-               "Tag field is invalid: field-addr=%p", tag_field);
-       variant_ft = BT_CTF_FROM_COMMON(variant_field->common.common.type);
-       BT_ASSERT_PRE(bt_ctf_field_type_common_compare(
-               BT_CTF_TO_COMMON(variant_ft->tag_ft), enum_field->common.type) == 0,
-               "Unexpected tag field's type: expected-ft-addr=%p, "
-               "tag-ft-addr=%p", variant_ft->tag_ft,
-               enum_field->common.type);
-       tag_ft = BT_CTF_FROM_COMMON(enum_field->common.type);
-       is_signed = tag_ft->container_ft->is_signed;
-
-       if (is_signed) {
-               int64_t tag_ival;
-
-               ret = bt_ctf_field_integer_signed_get_value(
-                       (void *) enum_field->container, &tag_ival);
-               tag_uval = (uint64_t) tag_ival;
-       } else {
-               ret = bt_ctf_field_integer_unsigned_get_value(
-                       (void *) enum_field->container, &tag_uval);
-       }
-
-       BT_ASSERT(ret == 0);
-       ret = bt_ctf_field_common_variant_set_tag((void *) field, tag_uval,
-               is_signed);
-       if (ret) {
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(variant_field->tag);
-       variant_field->tag = bt_ctf_object_get_ref(tag_field);
-       current_field = bt_ctf_field_variant_get_current_field(field);
-       BT_ASSERT(current_field);
-
-end:
-       return current_field;
-}
-
-struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
-               struct bt_ctf_field *variant_field)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_variant_borrow_current_field(
-               (void *) variant_field));
-}
-
-BT_HIDDEN
-struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
-               struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Enumeration field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID((struct bt_ctf_field_common *) field,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Field");
-       BT_ASSERT(enumeration->container);
-       return (void *) enumeration->container;
-}
-
-struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
-               struct bt_ctf_field *field)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_enumeration_borrow_container(field));
-}
-
-int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field,
-               int64_t *value)
-{
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       BT_ASSERT_PRE(bt_ctf_field_type_common_integer_is_signed(
-               integer->common.type),
-               "Field's type is unsigned: field-addr=%p", field);
-       *value = integer->payload.signd;
-       return 0;
-}
-
-int bt_ctf_field_integer_signed_set_value(struct bt_ctf_field *field,
-               int64_t value)
-{
-       int ret = 0;
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-       struct bt_ctf_field_type_common_integer *integer_type;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
-       BT_ASSERT_PRE(
-               bt_ctf_field_type_common_integer_is_signed(integer->common.type),
-               "Field's type is unsigned: field-addr=%p", field);
-       BT_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value),
-               "Value is out of bounds: value=%" PRId64 ", field-addr=%p",
-               value, field);
-       integer->payload.signd = value;
-       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
-       return ret;
-}
-
-int bt_ctf_field_integer_unsigned_get_value(struct bt_ctf_field *field,
-               uint64_t *value)
-{
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       BT_ASSERT_PRE(
-               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
-               "Field's type is signed: field-addr=%p", field);
-       *value = integer->payload.unsignd;
-       return 0;
-}
-
-int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field,
-               uint64_t value)
-{
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-       struct bt_ctf_field_type_common_integer *integer_type;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
-       BT_ASSERT_PRE(
-               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
-               "Field's type is signed: field-addr=%p", field);
-       BT_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value),
-               "Value is out of bounds: value=%" PRIu64 ", field-addr=%p",
-               value, field);
-       integer->payload.unsignd = value;
-       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
-       return 0;
-}
-
-int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field,
-               double *value)
-{
-       return bt_ctf_field_common_floating_point_get_value((void *) field, value);
-}
-
-int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field,
-               double value)
-{
-       return bt_ctf_field_common_floating_point_set_value((void *) field, value);
-}
-
-const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field)
-{
-       return bt_ctf_field_common_string_get_value((void *) field);
-}
-
-int bt_ctf_field_string_set_value(struct bt_ctf_field *field, const char *value)
-{
-       return bt_ctf_field_common_string_set_value((void *) field, value);
-}
-
-int bt_ctf_field_string_append(struct bt_ctf_field *field, const char *value)
-{
-       return bt_ctf_field_common_string_append((void *) field, value);
-}
-
-int bt_ctf_field_string_append_len(struct bt_ctf_field *field,
-               const char *value, unsigned int length)
-{
-       return bt_ctf_field_common_string_append_len((void *) field, value, length);
-}
-
-struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field)
-{
-       return (void *) bt_ctf_field_common_copy((void *) field);
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_integer *integer =
-               g_new0(struct bt_ctf_field_common_integer, 1);
-
-       BT_LOGD("Creating CTF writer integer field object: ft-addr=%p", type);
-
-       if (integer) {
-               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(integer), (void *) type,
-                       true,
-                       (bt_ctf_object_release_func) bt_ctf_field_integer_destroy,
-                       &bt_ctf_field_integer_methods);
-               integer->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_integer_serialize;
-               BT_LOGD("Created CTF writer 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_ctf_field *bt_ctf_field_enumeration_create(
-               struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) type;
-       struct bt_ctf_field_enumeration *enumeration = g_new0(
-               struct bt_ctf_field_enumeration, 1);
-
-       BT_LOGD("Creating CTF writer enumeration field object: ft-addr=%p", type);
-
-       if (!enumeration) {
-               BT_LOGE_STR("Failed to allocate one enumeration field.");
-               goto end;
-       }
-
-       bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(enumeration),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_enumeration_destroy_recursive,
-               &bt_ctf_field_enumeration_methods);
-       enumeration->container = (void *) bt_ctf_field_create(
-               BT_CTF_FROM_COMMON(enum_ft->container_ft));
-       if (!enumeration->container) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
-               goto end;
-       }
-
-       enumeration->common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func)
-                       bt_ctf_field_enumeration_serialize_recursive;
-       BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p",
-               enumeration, type);
-
-end:
-       return (void *) enumeration;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_floating_point_create(
-               struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_floating_point *floating_point;
-
-       BT_LOGD("Creating CTF writer floating point number field object: ft-addr=%p", type);
-       floating_point = g_new0(struct bt_ctf_field_common_floating_point, 1);
-
-       if (floating_point) {
-               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(floating_point),
-                       (void *) type,
-                       true, (bt_ctf_object_release_func)
-                               bt_ctf_field_floating_point_destroy,
-                       &bt_ctf_field_floating_point_methods);
-               floating_point->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_floating_point_serialize;
-               BT_LOGD("Created CTF writer 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
-struct bt_ctf_field *bt_ctf_field_structure_create(
-               struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_structure *structure = g_new0(
-               struct bt_ctf_field_common_structure, 1);
-       int iret;
-
-       BT_LOGD("Creating CTF writer structure field object: ft-addr=%p", type);
-
-       if (!structure) {
-               BT_LOGE_STR("Failed to allocate one structure field.");
-               goto end;
-       }
-
-       iret = bt_ctf_field_common_structure_initialize(BT_CTF_TO_COMMON(structure),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_structure_destroy_recursive,
-               &bt_ctf_field_structure_methods,
-               (bt_ctf_field_common_create_func) bt_ctf_field_create,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       structure->common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_structure_serialize_recursive;
-       if (iret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
-               goto end;
-       }
-
-       BT_LOGD("Created CTF writer structure field object: addr=%p, ft-addr=%p",
-               structure, type);
-
-end:
-       return (void *) structure;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = (void *) type;
-       struct bt_ctf_field_variant *variant = g_new0(
-               struct bt_ctf_field_variant, 1);
-
-       BT_LOGD("Creating CTF writer variant field object: ft-addr=%p", type);
-
-       if (!variant) {
-               BT_LOGE_STR("Failed to allocate one variant field.");
-               goto end;
-       }
-
-       bt_ctf_field_common_variant_initialize(BT_CTF_TO_COMMON(BT_CTF_TO_COMMON(variant)),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_variant_destroy_recursive,
-               &bt_ctf_field_variant_methods,
-               (bt_ctf_field_common_create_func) bt_ctf_field_create,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       variant->tag = (void *) bt_ctf_field_create(
-               BT_CTF_FROM_COMMON(var_ft->tag_ft));
-       variant->common.common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive;
-       BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p",
-               variant, type);
-
-end:
-       return (void *) variant;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_array *array =
-               g_new0(struct bt_ctf_field_common_array, 1);
-       int ret;
-
-       BT_LOGD("Creating CTF writer 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_ctf_field_common_array_initialize(BT_CTF_TO_COMMON(array),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_array_destroy_recursive,
-               &bt_ctf_field_array_methods,
-               (bt_ctf_field_common_create_func) bt_ctf_field_create,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       array->common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_array_serialize_recursive;
-       if (ret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
-               goto end;
-       }
-
-       BT_LOGD("Created CTF writer array field object: addr=%p, ft-addr=%p",
-               array, type);
-
-end:
-       return (void *) array;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_sequence *sequence = g_new0(
-               struct bt_ctf_field_common_sequence, 1);
-
-       BT_LOGD("Creating CTF writer sequence field object: ft-addr=%p", type);
-
-       if (sequence) {
-               bt_ctf_field_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
-                       (void *) type,
-                       true, (bt_ctf_object_release_func)
-                               bt_ctf_field_sequence_destroy_recursive,
-                       &bt_ctf_field_sequence_methods,
-                       (GDestroyNotify) bt_ctf_object_put_ref);
-               sequence->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_sequence_serialize_recursive;
-               BT_LOGD("Created CTF writer sequence field object: addr=%p, ft-addr=%p",
-                       sequence, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one sequence field.");
-       }
-
-       return (void *) sequence;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_string *string = g_new0(
-               struct bt_ctf_field_common_string, 1);
-
-       BT_LOGD("Creating CTF writer string field object: ft-addr=%p", type);
-
-       if (string) {
-               bt_ctf_field_common_string_initialize(BT_CTF_TO_COMMON(string),
-                       (void *) type,
-                       true, (bt_ctf_object_release_func)
-                               bt_ctf_field_string_destroy,
-                       &bt_ctf_field_string_methods);
-               string->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_string_serialize;
-               BT_LOGD("Created CTF writer string field object: addr=%p, ft-addr=%p",
-                       string, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one string field.");
-       }
-
-       return (void *) string;
-}
-
-static
-void bt_ctf_field_enumeration_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       (void *) enumeration->container, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen((void *) field, is_frozen);
-}
-
-static
-int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int ret = -1;
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) enumeration->container);
-       }
-
-       return ret;
-}
-
-static
-bt_bool bt_ctf_field_enumeration_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       bt_bool is_set = BT_FALSE;
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       (void *) enumeration->container);
-       }
-
-       return is_set;
-}
-
-static
-void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               bt_ctf_field_common_reset_recursive(
-                       (void *) enumeration->container);
-       }
-
-       bt_ctf_field_common_generic_reset((void *) field);
-}
-
-static
-void bt_ctf_field_variant_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       (void *) variant->tag, is_frozen);
-       }
-
-       bt_ctf_field_common_variant_set_is_frozen_recursive((void *) field,
-               is_frozen);
-}
-
-static
-int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int ret;
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) variant->tag);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       ret = bt_ctf_field_common_variant_validate_recursive((void *) field);
-
-end:
-       return ret;
-}
-
-static
-bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       bt_bool is_set;
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       (void *) variant->tag);
-               if (is_set) {
-                       goto end;
-               }
-       }
-
-       is_set = bt_ctf_field_common_variant_is_set_recursive((void *) field);
-
-end:
-       return is_set;
-}
-
-static
-void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               bt_ctf_field_common_reset_recursive(
-                       (void *) variant->tag);
-       }
-
-       bt_ctf_field_common_variant_reset_recursive((void *) field);
-}
-
-BT_ASSERT_PRE_FUNC
-static inline bool field_to_set_has_expected_type(
-               struct bt_ctf_field_common *struct_field,
-               const char *name, struct bt_ctf_field_common *value)
-{
-       bool ret = true;
-       struct bt_ctf_field_type_common *expected_field_type = NULL;
-
-       expected_field_type =
-               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-                       struct_field->type, name);
-
-       if (bt_ctf_field_type_common_compare(expected_field_type, value->type)) {
-               BT_ASSERT_PRE_MSG("Value field's type is different from the expected field type: "
-                       "value-ft-addr=%p, expected-ft-addr=%p", value->type,
-                       expected_field_type);
-               ret = false;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
-               const char *name, struct bt_ctf_field *value)
-{
-       int ret = 0;
-       GQuark field_quark;
-       struct bt_ctf_field_common *common_field = (void *) field;
-       struct bt_ctf_field_common_structure *structure =
-               BT_CTF_FROM_COMMON(common_field);
-       struct bt_ctf_field_common *common_value = (void *) value;
-       size_t index;
-       GHashTable *field_name_to_index;
-       struct bt_ctf_field_type_common_structure *structure_ft;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Parent field");
-       BT_ASSERT_PRE_NON_NULL(name, "Field name");
-       BT_ASSERT_PRE_NON_NULL(value, "Value field");
-       BT_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(common_field,
-               BT_CTF_FIELD_TYPE_ID_STRUCT, "Parent field");
-       BT_ASSERT_PRE(field_to_set_has_expected_type(common_field,
-               name, common_value),
-               "Value field's type is different from the expected field type.");
-       field_quark = g_quark_from_string(name);
-       structure_ft = BT_CTF_FROM_COMMON(common_field->type);
-       field_name_to_index = structure_ft->field_name_to_index;
-       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, "
-                       "field-ft-addr=%p, name=\"%s\"",
-                       field, common_field->type, common_value->type, name);
-               ret = -1;
-               goto end;
-       }
-       bt_ctf_object_get_ref(value);
-       BT_CTF_OBJECT_MOVE_REF(structure->fields->pdata[index], value);
-
-end:
-       return ret;
-}
diff --git a/lib/ctf-writer/functor.c b/lib/ctf-writer/functor.c
deleted file mode 100644 (file)
index e8ad20f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * functor.c
- *
- * Babeltrace CTF Writer
- *
- * Copyright 2013, 2014 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 <glib.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-
-BT_HIDDEN
-void value_exists(gpointer element, gpointer search_query)
-{
-       if (element == ((struct bt_ctf_search_query *)search_query)->value) {
-               ((struct bt_ctf_search_query *)search_query)->found = 1;
-       }
-}
diff --git a/lib/ctf-writer/object-pool.c b/lib/ctf-writer/object-pool.c
deleted file mode 100644 (file)
index e62356b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
- * 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.
- */
-
-#define BT_LOG_TAG "OBJECT-POOL"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <stdint.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/object-pool-internal.h>
-
-int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool,
-               bt_ctf_object_pool_new_object_func new_object_func,
-               bt_ctf_object_pool_destroy_object_func destroy_object_func,
-               void *data)
-{
-       int ret = 0;
-
-       BT_ASSERT(new_object_func);
-       BT_ASSERT(destroy_object_func);
-       BT_LOGD("Initializing object pool: addr=%p, data-addr=%p",
-               pool, data);
-       pool->objects = g_ptr_array_new();
-       if (!pool->objects) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       pool->funcs.new_object = new_object_func;
-       pool->funcs.destroy_object = destroy_object_func;
-       pool->data = data;
-       pool->size = 0;
-       BT_LIB_LOGD("Initialized object pool: %!+o", pool);
-       goto end;
-
-error:
-       if (pool) {
-               bt_ctf_object_pool_finalize(pool);
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
-void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool)
-{
-       uint64_t i;
-
-       BT_ASSERT(pool);
-       BT_LIB_LOGD("Finalizing object pool: %!+o", pool);
-
-       if (pool->objects) {
-               for (i = 0; i < pool->size; i++) {
-                       void *obj = pool->objects->pdata[i];
-
-                       if (obj) {
-                               pool->funcs.destroy_object(obj, pool->data);
-                       }
-               }
-
-               g_ptr_array_free(pool->objects, TRUE);
-               pool->objects = NULL;
-       }
-}
diff --git a/lib/ctf-writer/object.c b/lib/ctf-writer/object.c
deleted file mode 100644 (file)
index b618512..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 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.
- *
- * 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 <babeltrace2/ctf-writer/object-internal.h>
-
-void *bt_ctf_object_get_ref(void *obj)
-{
-       if (unlikely(!obj)) {
-               goto end;
-       }
-
-       bt_ctf_object_get_no_null_check(obj);
-
-end:
-       return obj;
-}
-
-void bt_ctf_object_put_ref(void *obj)
-{
-       if (unlikely(!obj)) {
-               return;
-       }
-
-       bt_ctf_object_put_no_null_check(obj);
-}
diff --git a/lib/ctf-writer/resolve.c b/lib/ctf-writer/resolve.c
deleted file mode 100644 (file)
index bbb81ac..0000000
+++ /dev/null
@@ -1,1339 +0,0 @@
-/*
- * resolve.c
- *
- * Babeltrace - CTF writer: 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 "CTF-WRITER-RESOLVE"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/field-path-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/resolve-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.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_ctf_field_type_common *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_ctf_private_value *environment;
-       struct bt_ctf_field_type_common *scopes[6];
-
-       /* Root scope being visited */
-       enum bt_ctf_scope root_scope;
-       type_stack *type_stack;
-       struct bt_ctf_field_type_common *cur_field_type;
-};
-
-/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
-static const char * const absolute_path_prefixes[] = {
-       [BT_CTF_SCOPE_ENV]                              = "env.",
-       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]              = "trace.packet.header.",
-       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = "stream.packet.context.",
-       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]              = "stream.event.header.",
-       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]             = "stream.event.context.",
-       [BT_CTF_SCOPE_EVENT_CONTEXT]            = "event.context.",
-       [BT_CTF_SCOPE_EVENT_FIELDS]                     = "event.fields.",
-};
-
-/* Number of path tokens used for the absolute prefixes */
-static const int absolute_path_prefix_ptoken_counts[] = {
-       [BT_CTF_SCOPE_ENV]                      = 1,
-       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]      = 3,
-       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = 3,
-       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]      = 3,
-       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]     = 3,
-       [BT_CTF_SCOPE_EVENT_CONTEXT]            = 2,
-       [BT_CTF_SCOPE_EVENT_FIELDS]             = 2,
-};
-
-/*
- * Destroys a type stack frame.
- */
-static
-void type_stack_destroy_notify(gpointer data)
-{
-       struct type_stack_frame *frame = data;
-
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common *get_type_from_ctx(struct resolve_context *ctx,
-               enum bt_ctf_scope scope)
-{
-       BT_ASSERT(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER &&
-               scope <= BT_CTF_SCOPE_EVENT_FIELDS);
-
-       return ctx->scopes[scope - BT_CTF_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_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
-{
-       enum bt_ctf_scope scope;
-       enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN;
-       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
-               sizeof(*absolute_path_prefixes);
-
-       for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_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_ctf_scope_string(scope));
-                       continue;
-               }
-
-               /* Found it! */
-               ret = scope;
-               BT_LOGV("Found root scope from absolute path: "
-                       "path=\"%s\", scope=%s", pathstr,
-                       bt_ctf_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_ctf_field_path *field_path,
-               struct bt_ctf_field_type_common *type, int src_index)
-{
-       int ret = 0;
-       GList *cur_ptoken = ptokens;
-       bt_bool first_level_done = BT_FALSE;
-
-       /* Get our own reference */
-       bt_ctf_object_get_ref(type);
-
-       /* Locate target */
-       while (cur_ptoken) {
-               int child_index;
-               struct bt_ctf_field_type_common *child_type;
-               const char *field_name = ptoken_get_string(cur_ptoken);
-               enum bt_ctf_field_type_id type_id =
-                       bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_ARRAY ||
-                               type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
-                       child_index = -1;
-               } else {
-                       child_index = bt_ctf_field_type_common_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_ctf_field_type_common_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_ctf_object_get_ref(child_type);
-               BT_CTF_OBJECT_MOVE_REF(type, child_type);
-       }
-
-end:
-       bt_ctf_object_put_ref(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_ctf_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       GList *cur_ptoken;
-       struct bt_ctf_field_type_common *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_ctf_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_ctf_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       int parent_pos_in_stack;
-       struct bt_ctf_field_path *tail_field_path = bt_ctf_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_ctf_field_type_common *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_ctf_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_ctf_field_type_common *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_CTF_SCOPE_TRACE_PACKET_HEADER) {
-                       struct bt_ctf_field_type_common *root_type;
-                       bt_ctf_field_path_clear(field_path);
-
-                       BT_LOGV("Looking into potential root scope: scope=%s",
-                               bt_ctf_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_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_path *pathstr_to_field_path(const char *pathstr,
-               struct resolve_context *ctx)
-{
-       int ret;
-       enum bt_ctf_scope root_scope;
-       GList *ptokens = NULL;
-       struct bt_ctf_field_path *field_path = NULL;
-
-       /* Create field path */
-       field_path = bt_ctf_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_CTF_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_ctf_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_ctf_scope_string(ctx->root_scope),
-                               bt_ctf_scope_string(field_path->root));
-                       goto end;
-               }
-       } else if (root_scope == BT_CTF_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_ctf_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_ctf_scope_string(root_scope));
-                       goto end;
-               }
-       }
-
-       if (ret == 0) {
-               GString *field_path_pretty =
-                       bt_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:
-       if (ret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_type_common *field_path_to_field_type(
-               struct bt_ctf_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int i;
-       struct bt_ctf_field_type_common *type;
-
-       /* Start with root type */
-       type = get_type_from_ctx(ctx, field_path->root);
-       bt_ctf_object_get_ref(type);
-       if (!type) {
-               /* Error: root type is not available */
-               BT_LOGW("Root field type is not available: root-scope=%s",
-                       bt_ctf_scope_string(field_path->root));
-               goto error;
-       }
-
-       /* Locate target */
-       for (i = 0; i < field_path->indexes->len; i++) {
-               struct bt_ctf_field_type_common *child_type;
-               int child_index =
-                       g_array_index(field_path->indexes, int, i);
-
-               /* Get child field type */
-               child_type = bt_ctf_field_type_common_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_ctf_object_get_ref(child_type);
-               BT_CTF_OBJECT_MOVE_REF(type, child_type);
-       }
-
-       return type;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx)
-{
-       int i;
-       struct bt_ctf_field_path *field_path;
-
-       /* Create field path */
-       field_path = bt_ctf_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_CTF_OBJECT_PUT_REF_AND_RESET(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.
- */
-static
-int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1,
-               struct bt_ctf_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_ctf_field_path_string(field_path1);
-               GString *field_path2_pretty =
-                       bt_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->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_ctf_field_path *target_field_path,
-               struct bt_ctf_field_type_common *target_type,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       struct bt_ctf_field_path *ctx_field_path;
-       int target_field_path_len = target_field_path->indexes->len;
-       int lca_index;
-       enum bt_ctf_field_type_id ctx_cur_field_type_id;
-       enum bt_ctf_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_ctf_scope_string(target_field_path->root),
-                       bt_ctf_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_ctf_field_type_common_get_type_id(
-               ctx->cur_field_type);
-       target_type_id = bt_ctf_field_type_common_get_type_id(target_type);
-
-       switch (ctx_cur_field_type_id) {
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               if (target_type_id != BT_CTF_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_ctf_field_type_id_string(target_type_id));
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               if (target_type_id != BT_CTF_FIELD_TYPE_ID_INTEGER ||
-                               bt_ctf_field_type_common_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_ctf_field_type_id_string(target_type_id));
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       default:
-               abort();
-       }
-
-end:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(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_ctf_field_type_common *type,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       const char *pathstr;
-       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
-       struct bt_ctf_field_path *target_field_path = NULL;
-       struct bt_ctf_field_type_common *target_type = NULL;
-       GString *target_field_path_pretty = NULL;
-       const char *target_field_path_pretty_str;
-
-
-       /* Get path string */
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               pathstr =
-                       bt_ctf_field_type_common_sequence_get_length_field_name(type);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               pathstr =
-                       bt_ctf_field_type_common_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_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_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_CTF_FIELD_TYPE_ID_SEQUENCE:
-               ret = bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_VARIANT:
-               ret = bt_ctf_field_type_common_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_ctf_field_type_common_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_CTF_OBJECT_PUT_REF_AND_RESET(target_field_path);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(target_type);
-       return ret;
-}
-
-/*
- * Resolves a field type `type`.
- *
- * `type` is owned by the caller.
- */
-static
-int resolve_type(struct bt_ctf_field_type_common *type, struct resolve_context *ctx)
-{
-       int ret = 0;
-       enum bt_ctf_field_type_id type_id;
-
-       if (!type) {
-               /* Type is not available; still valid */
-               goto end;
-       }
-
-       type_id = bt_ctf_field_type_common_get_type_id(type);
-       ctx->cur_field_type = type;
-
-       /* Resolve sequence/variant field type */
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       case BT_CTF_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_CTF_FIELD_TYPE_ID_STRUCT:
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       case BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common *child_type =
-                               bt_ctf_field_type_common_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_CTF_FIELD_TYPE_ID_ARRAY||
-                                       type_id == BT_CTF_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_ctf_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_CTF_SCOPE_UNKNOWN;
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_resolve_types(
-               struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *event_payload_type,
-               enum bt_ctf_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_CTF_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_CTF_RESOLVE_FLAG_PACKET_HEADER) {
-               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_PACKET_CONTEXT) {
-               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_EVENT_HEADER) {
-               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) {
-               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_EVENT_CONTEXT) {
-               ret = resolve_root_type(BT_CTF_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_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) {
-               ret = resolve_root_type(BT_CTF_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;
-}
diff --git a/lib/ctf-writer/stream-class.c b/lib/ctf-writer/stream-class.c
deleted file mode 100644 (file)
index bcb79f5..0000000
+++ /dev/null
@@ -1,1145 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * 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 "CTF-WRITER-STREAM-CLASS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/visitor-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class,
-               const char *name, bt_ctf_object_release_func release_func)
-{
-       BT_LOGD("Initializing common stream class object: name=\"%s\"", name);
-
-       bt_ctf_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_ctf_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 common stream class object: addr=%p, name=\"%s\"",
-               stream_class, name);
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class)
-{
-       BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-       bt_ctf_object_put_ref(stream_class->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);
-       }
-
-       BT_LOGD_STR("Putting event header field type.");
-       bt_ctf_object_put_ref(stream_class->event_header_field_type);
-       BT_LOGD_STR("Putting packet context field type.");
-       bt_ctf_object_put_ref(stream_class->packet_context_field_type);
-       BT_LOGD_STR("Putting event context field type.");
-       bt_ctf_object_put_ref(stream_class->event_context_field_type);
-}
-
-static
-void event_class_exists(gpointer element, gpointer query)
-{
-       struct bt_ctf_event_class_common *event_class_a = element;
-       struct bt_ctf_search_query *search_query = query;
-       struct bt_ctf_event_class_common *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_ctf_event_class_common_get_id(event_class_a);
-       id_b = bt_ctf_event_class_common_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_ctf_event_class_common_get_name(event_class_a));
-               search_query->found = 1;
-               goto end;
-       }
-
-end:
-       return;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_add_event_class(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_event_class_common *event_class,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
-{
-       int ret = 0;
-       int64_t *event_id = NULL;
-       struct bt_ctf_trace_common *trace = NULL;
-       struct bt_ctf_stream_class_common *old_stream_class = NULL;
-       struct bt_ctf_validation_output validation_output = { 0 };
-       struct bt_ctf_field_type_common *packet_header_type = NULL;
-       struct bt_ctf_field_type_common *packet_context_type = NULL;
-       struct bt_ctf_field_type_common *event_header_type = NULL;
-       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
-       struct bt_ctf_field_type_common *event_context_type = NULL;
-       struct bt_ctf_field_type_common *event_payload_type = NULL;
-       const enum bt_ctf_validation_flag validation_flags =
-               BT_CTF_VALIDATION_FLAG_EVENT;
-       struct bt_ctf_clock_class *expected_clock_class = NULL;
-
-       BT_ASSERT(copy_field_type_func);
-
-       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_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class),
-               event_class,
-               bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-       trace = bt_ctf_stream_class_common_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_ctf_trace_add_stream_class() or
-                * bt_ctf_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_ctf_object_get_ref(stream_class->clock_class);
-
-               /*
-                * At this point, `expected_clock_class` can be NULL,
-                * and bt_ctf_event_class_validate_single_clock_class()
-                * below can set it.
-                */
-               ret = bt_ctf_event_class_common_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_ctf_stream_class_common_get_id(stream_class),
-                               bt_ctf_stream_class_common_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_ctf_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;
-       }
-
-       /* Check for duplicate event classes */
-       struct bt_ctf_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;
-       }
-
-       old_stream_class = bt_ctf_event_class_common_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_ctf_stream_class_common_get_name(old_stream_class),
-                       bt_ctf_stream_class_common_get_id(old_stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       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_ctf_trace_common_borrow_packet_header_field_type(trace);
-               packet_context_type =
-                       bt_ctf_stream_class_common_borrow_packet_context_field_type(
-                               stream_class);
-               event_header_type =
-                       bt_ctf_stream_class_common_borrow_event_header_field_type(
-                               stream_class);
-               stream_event_ctx_type =
-                       bt_ctf_stream_class_common_borrow_event_context_field_type(
-                               stream_class);
-               event_context_type =
-                       bt_ctf_event_class_common_borrow_context_field_type(
-                               event_class);
-               event_payload_type =
-                       bt_ctf_event_class_common_borrow_payload_field_type(
-                               event_class);
-               ret = bt_ctf_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,
-                       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 class: ret=%d", ret);
-                       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_ctf_event_class_common_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_ctf_event_class_common_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_ctf_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_ctf_validation_replace_types(NULL, NULL, event_class,
-                       &validation_output, validation_flags);
-               event_class->valid = 1;
-
-               /*
-                * Put what was not moved in
-                * bt_ctf_validation_replace_types().
-                */
-               bt_ctf_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_ctf_event_class_common_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_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
-       }
-
-       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_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class),
-               event_class,
-               bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-
-end:
-       bt_ctf_validation_output_put_types(&validation_output);
-       bt_ctf_object_put_ref(expected_clock_class);
-       g_free(event_id);
-       return ret;
-}
-
-static
-int64_t get_event_class_count(void *element)
-{
-       return bt_ctf_stream_class_get_event_class_count(
-                       (struct bt_ctf_stream_class *) element);
-}
-
-static
-void *get_event_class(void *element, int i)
-{
-       return bt_ctf_stream_class_get_event_class_by_index(
-                       (struct bt_ctf_stream_class *) element, i);
-}
-
-static
-int visit_event_class(void *object, bt_ctf_visitor visitor,void *data)
-{
-       struct bt_ctf_visitor_object obj = {
-               .object = object,
-               .type = BT_CTF_VISITOR_OBJECT_TYPE_EVENT_CLASS
-       };
-
-       return visitor(&obj, data);
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class,
-               bt_ctf_visitor visitor, void *data)
-{
-       int ret;
-       struct bt_ctf_visitor_object obj = {
-               .object = stream_class,
-               .type = BT_CTF_VISITOR_OBJECT_TYPE_STREAM_CLASS
-       };
-
-       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;
-       }
-
-       ret = bt_ctf_visitor_helper(&obj, get_event_class_count,
-                       get_event_class,
-                       visit_event_class, visitor, data);
-       BT_LOGV("bt_ctf_visitor_helper() returned: ret=%d", ret);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
-               bt_ctf_visitor visitor, void *data)
-{
-       return bt_ctf_stream_class_common_visit(BT_CTF_FROM_COMMON(stream_class),
-               visitor, data);
-}
-
-BT_HIDDEN
-void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class)
-{
-       if (!stream_class || stream_class->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-       stream_class->frozen = 1;
-       bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
-       bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
-       bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
-       bt_ctf_clock_class_freeze(stream_class->clock_class);
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_validate_single_clock_class(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_clock_class **expected_clock_class)
-{
-       int ret;
-       uint64_t i;
-
-       BT_ASSERT(stream_class);
-       BT_ASSERT(expected_clock_class);
-       ret = bt_ctf_field_type_common_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_ctf_stream_class_common_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->packet_context_field_type);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_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_ctf_stream_class_common_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->event_header_field_type);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_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_ctf_stream_class_common_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->event_context_field_type);
-               goto end;
-       }
-
-       for (i = 0; i < stream_class->event_classes->len; i++) {
-               struct bt_ctf_event_class_common *event_class =
-                       g_ptr_array_index(stream_class->event_classes, i);
-
-               BT_ASSERT(event_class);
-               ret = bt_ctf_event_class_common_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_ctf_stream_class_common_get_name(stream_class),
-                               stream_class->id);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int init_event_header(struct bt_ctf_stream_class *stream_class)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *event_header_type =
-               bt_ctf_field_type_structure_create();
-       struct bt_ctf_field_type *_uint32_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
-       struct bt_ctf_field_type *_uint64_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
-
-       if (!event_header_type) {
-               BT_LOGE_STR("Cannot create empty structure field type.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(event_header_type,
-               _uint32_t, "id");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `id` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(event_header_type,
-               _uint64_t, "timestamp");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(stream_class->common.event_header_field_type);
-       stream_class->common.event_header_field_type =
-               (void *) event_header_type;
-       event_header_type = NULL;
-
-end:
-       if (ret) {
-               bt_ctf_object_put_ref(event_header_type);
-       }
-
-       bt_ctf_object_put_ref(_uint32_t);
-       bt_ctf_object_put_ref(_uint64_t);
-       return ret;
-}
-
-static
-int init_packet_context(struct bt_ctf_stream_class *stream_class)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *packet_context_type =
-               bt_ctf_field_type_structure_create();
-       struct bt_ctf_field_type *_uint64_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
-       struct bt_ctf_field_type *ts_begin_end_uint64_t;
-
-       if (!packet_context_type) {
-               BT_LOGE_STR("Cannot create empty structure field type.");
-               ret = -1;
-               goto end;
-       }
-
-       ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
-       if (!ts_begin_end_uint64_t) {
-               BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * We create a stream packet context as proposed in the CTF
-        * specification.
-        */
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               ts_begin_end_uint64_t, "timestamp_begin");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               ts_begin_end_uint64_t, "timestamp_end");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               _uint64_t, "content_size");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               _uint64_t, "packet_size");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               _uint64_t, "events_discarded");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(stream_class->common.packet_context_field_type);
-       stream_class->common.packet_context_field_type =
-               (void *) packet_context_type;
-       packet_context_type = NULL;
-
-end:
-       if (ret) {
-               bt_ctf_object_put_ref(packet_context_type);
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(_uint64_t);
-       bt_ctf_object_put_ref(ts_begin_end_uint64_t);
-       return ret;
-}
-
-static
-void bt_ctf_stream_class_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_stream_class *stream_class;
-
-       stream_class = (void *) obj;
-       BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_get_name(stream_class),
-               bt_ctf_stream_class_get_id(stream_class));
-       bt_ctf_stream_class_common_finalize(BT_CTF_TO_COMMON(stream_class));
-       bt_ctf_object_put_ref(stream_class->clock);
-       g_free(stream_class);
-}
-
-struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name)
-{
-       struct bt_ctf_stream_class *stream_class;
-       int ret;
-
-       BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name);
-       stream_class = g_new0(struct bt_ctf_stream_class, 1);
-       if (!stream_class) {
-               BT_LOGE_STR("Failed to allocate one CTF writer stream class.");
-               goto error;
-       }
-
-       ret = bt_ctf_stream_class_common_initialize(BT_CTF_TO_COMMON(stream_class),
-               name, bt_ctf_stream_class_destroy);
-       if (ret) {
-               /* bt_ctf_stream_class_common_initialize() logs errors */
-               goto error;
-       }
-
-       ret = init_event_header(stream_class);
-       if (ret) {
-               BT_LOGE_STR("Cannot initialize stream class's event header field type.");
-               goto error;
-       }
-
-       ret = init_packet_context(stream_class);
-       if (ret) {
-               BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
-               goto error;
-       }
-
-       BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"",
-               stream_class, name);
-       return stream_class;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_class);
-       return stream_class;
-}
-
-static
-int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *parent_ft, const char *field_name)
-{
-       struct bt_ctf_clock_class *mapped_clock_class = NULL;
-       int ret = 0;
-       struct bt_ctf_field_type *ft =
-               bt_ctf_field_type_structure_get_field_type_by_name(parent_ft,
-                       field_name);
-
-       BT_ASSERT(stream_class->clock);
-
-       if (!ft) {
-               /* Field does not exist: not an error */
-               goto end;
-       }
-
-       BT_ASSERT(((struct bt_ctf_field_type_common *) ft)->id ==
-               BT_CTF_FIELD_TYPE_ID_INTEGER);
-       mapped_clock_class =
-               bt_ctf_field_type_integer_get_mapped_clock_class(ft);
-       if (!mapped_clock_class) {
-               struct bt_ctf_field_type *ft_copy;
-
-               if (!stream_class->clock) {
-                       BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
-                               "stream-class-addr=%p, stream-class-name=\"%s\", "
-                               "stream-class-id=%" PRId64 ", ft-addr=%p",
-                               stream_class,
-                               bt_ctf_stream_class_get_name(stream_class),
-                               bt_ctf_stream_class_get_id(stream_class), ft);
-                       ret = -1;
-                       goto end;
-               }
-
-               ft_copy = bt_ctf_field_type_copy(ft);
-               if (!ft_copy) {
-                       BT_LOGE("Failed to copy integer field type: ft-addr=%p",
-                               ft);
-               }
-
-               ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
-                       (void *) ft_copy, stream_class->clock->clock_class);
-               BT_ASSERT(ret == 0);
-
-               ret = bt_ctf_field_type_common_structure_replace_field(
-                       (void *) parent_ft, field_name, (void *) ft_copy);
-               bt_ctf_object_put_ref(ft_copy);
-               BT_LOGV("Automatically mapped field type to stream class's clock class: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", ft-addr=%p, "
-                       "ft-copy-addr=%p",
-                       stream_class,
-                       bt_ctf_stream_class_get_name(stream_class),
-                       bt_ctf_stream_class_get_id(stream_class), ft, ft_copy);
-       }
-
-end:
-       bt_ctf_object_put_ref(ft);
-       bt_ctf_object_put_ref(mapped_clock_class);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_map_clock_class(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *packet_context_type,
-               struct bt_ctf_field_type *event_header_type)
-{
-       int ret = 0;
-
-       BT_ASSERT(stream_class);
-
-       if (!stream_class->clock) {
-               /* No clock class to map to */
-               goto end;
-       }
-
-       if (packet_context_type) {
-               if (try_map_clock_class(stream_class, packet_context_type,
-                               "timestamp_begin")) {
-                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
-                       ret = -1;
-                       goto end;
-               }
-
-               if (try_map_clock_class(stream_class, packet_context_type,
-                               "timestamp_end")) {
-                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       if (event_header_type) {
-               if (try_map_clock_class(stream_class, event_header_type,
-                               "timestamp")) {
-                       BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
-               struct bt_ctf_stream_class *stream_class)
-{
-       struct bt_ctf_clock *clock = NULL;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               goto end;
-       }
-
-       if (!stream_class->clock) {
-               BT_LOGV("Stream class has no clock: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_get_name(stream_class),
-                       bt_ctf_stream_class_get_id(stream_class));
-               goto end;
-       }
-
-       clock = bt_ctf_object_get_ref(stream_class->clock);
-
-end:
-       return clock;
-}
-
-int bt_ctf_stream_class_set_clock(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_clock *clock)
-{
-       int ret = 0;
-
-       if (!stream_class || !clock) {
-               BT_LOGW("Invalid parameter: stream class or clock is NULL: "
-                       "stream-class-addr=%p, clock-addr=%p",
-                       stream_class, clock);
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->common.frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_get_name(stream_class),
-                       bt_ctf_stream_class_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       /* Replace the current clock of this stream class. */
-       bt_ctf_object_put_ref(stream_class->clock);
-       stream_class->clock = bt_ctf_object_get_ref(clock);
-       BT_LOGV("Set stream class's clock: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "clock-addr=%p, clock-name=\"%s\"",
-               stream_class,
-               bt_ctf_stream_class_get_name(stream_class),
-               bt_ctf_stream_class_get_id(stream_class),
-               stream_class->clock,
-               bt_ctf_clock_get_name(stream_class->clock));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       size_t i;
-       struct bt_ctf_trace *trace;
-       struct bt_ctf_field_type *packet_header_type = NULL;
-
-       BT_LOGD("Serializing stream class's metadata: "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
-               stream_class,
-               bt_ctf_stream_class_get_name(stream_class),
-               bt_ctf_stream_class_get_id(stream_class), context);
-       g_string_assign(context->field_name, "");
-       context->current_indentation_level = 1;
-       if (!stream_class->common.id_set) {
-               BT_LOGW_STR("Stream class's ID is not set.");
-               ret = -1;
-               goto end;
-       }
-
-       g_string_append(context->string, "stream {\n");
-
-       /*
-        * The reference to the trace is only borrowed since the
-        * serialization of the stream class might have been triggered
-        * by the trace's destruction. In such a case, the trace's
-        * reference count would, unexepectedly, go through the sequence
-        * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
-        * and serialization.
-        */
-       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
-               BT_CTF_TO_COMMON(stream_class)));
-       BT_ASSERT(trace);
-       packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace);
-       trace = NULL;
-       if (packet_header_type) {
-               struct bt_ctf_field_type *stream_id_type;
-
-               stream_id_type =
-                       bt_ctf_field_type_structure_get_field_type_by_name(
-                               packet_header_type, "stream_id");
-               if (stream_id_type) {
-                       /*
-                        * Only set the stream's id if the trace's packet header
-                        * contains a stream_id field. This field is only
-                        * needed if the trace contains only one stream
-                        * class.
-                        */
-                       g_string_append_printf(context->string,
-                               "\tid = %" PRId64 ";\n",
-                               stream_class->common.id);
-               }
-               bt_ctf_object_put_ref(stream_id_type);
-       }
-       if (stream_class->common.event_header_field_type) {
-               BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
-               g_string_append(context->string, "\tevent.header := ");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) stream_class->common.event_header_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";");
-       }
-
-
-       if (stream_class->common.packet_context_field_type) {
-               BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
-               g_string_append(context->string, "\n\n\tpacket.context := ");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) stream_class->common.packet_context_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";");
-       }
-
-       if (stream_class->common.event_context_field_type) {
-               BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
-               g_string_append(context->string, "\n\n\tevent.context := ");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) stream_class->common.event_context_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";");
-       }
-
-       g_string_append(context->string, "\n};\n\n");
-
-       for (i = 0; i < stream_class->common.event_classes->len; i++) {
-               struct bt_ctf_event_class *event_class =
-                       stream_class->common.event_classes->pdata[i];
-
-               ret = bt_ctf_event_class_serialize(event_class, context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event class's metadata: "
-                               "event-class-addr=%p, event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64,
-                               event_class,
-                               bt_ctf_event_class_get_name(event_class),
-                               bt_ctf_event_class_get_id(event_class));
-                       goto end;
-               }
-       }
-
-end:
-       bt_ctf_object_put_ref(packet_header_type);
-       context->current_indentation_level = 0;
-       return ret;
-}
-
-struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(bt_ctf_stream_class_common_borrow_trace(
-               BT_CTF_TO_COMMON(stream_class)));
-}
-
-const char *bt_ctf_stream_class_get_name(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_stream_class_common_get_name(BT_CTF_TO_COMMON(stream_class));
-}
-
-int bt_ctf_stream_class_set_name(
-               struct bt_ctf_stream_class *stream_class, const char *name)
-{
-       return bt_ctf_stream_class_common_set_name(BT_CTF_TO_COMMON(stream_class),
-               name);
-}
-
-int64_t bt_ctf_stream_class_get_id(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_stream_class_common_get_id(BT_CTF_TO_COMMON(stream_class));
-}
-
-int bt_ctf_stream_class_set_id(
-               struct bt_ctf_stream_class *stream_class, uint64_t id)
-{
-       return bt_ctf_stream_class_common_set_id(BT_CTF_TO_COMMON(stream_class), id);
-}
-
-struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_packet_context_field_type(
-                       BT_CTF_TO_COMMON(stream_class)));
-}
-
-int bt_ctf_stream_class_set_packet_context_type(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *packet_context_type)
-{
-       return bt_ctf_stream_class_common_set_packet_context_field_type(
-               BT_CTF_TO_COMMON(stream_class), (void *) packet_context_type);
-}
-
-struct bt_ctf_field_type *
-bt_ctf_stream_class_get_event_header_type(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_header_field_type(
-                       BT_CTF_TO_COMMON(stream_class)));
-}
-
-int bt_ctf_stream_class_set_event_header_type(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *event_header_type)
-{
-       return bt_ctf_stream_class_common_set_event_header_field_type(
-               BT_CTF_TO_COMMON(stream_class), (void *) event_header_type);
-}
-
-struct bt_ctf_field_type *
-bt_ctf_stream_class_get_event_context_type(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_context_field_type(
-                       BT_CTF_TO_COMMON(stream_class)));
-}
-
-int bt_ctf_stream_class_set_event_context_type(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *event_context_type)
-{
-       return bt_ctf_stream_class_common_set_event_context_field_type(
-               BT_CTF_TO_COMMON(stream_class), (void *) event_context_type);
-}
-
-int64_t bt_ctf_stream_class_get_event_class_count(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_stream_class_common_get_event_class_count(
-               BT_CTF_TO_COMMON(stream_class));
-}
-
-struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
-               struct bt_ctf_stream_class *stream_class, uint64_t index)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_class_by_index(
-                       BT_CTF_TO_COMMON(stream_class), index));
-}
-
-struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
-               struct bt_ctf_stream_class *stream_class, uint64_t id)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_class_by_id(
-                       BT_CTF_TO_COMMON(stream_class), id));
-}
-
-int bt_ctf_stream_class_add_event_class(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_stream_class_common_add_event_class(
-               BT_CTF_TO_COMMON(stream_class), BT_CTF_TO_COMMON(event_class),
-               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy);
-}
diff --git a/lib/ctf-writer/stream.c b/lib/ctf-writer/stream.c
deleted file mode 100644 (file)
index 4f0eee0..0000000
+++ /dev/null
@@ -1,1953 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * 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 "CTF-WRITER-STREAM"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/stream.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <unistd.h>
-
-BT_HIDDEN
-void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream)
-{
-       BT_LOGD("Finalizing common stream object: addr=%p, name=\"%s\"",
-               stream, bt_ctf_stream_common_get_name(stream));
-
-       if (stream->name) {
-               g_string_free(stream->name, TRUE);
-       }
-}
-
-BT_HIDDEN
-int bt_ctf_stream_common_initialize(
-               struct bt_ctf_stream_common *stream,
-               struct bt_ctf_stream_class_common *stream_class, const char *name,
-               uint64_t id, bt_ctf_object_release_func release_func)
-{
-       int ret = 0;
-       struct bt_ctf_trace_common *trace = NULL;
-
-       bt_ctf_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 common stream object: stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-name=\"%s\", "
-               "stream-id=%" PRIu64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               name, id);
-       trace = bt_ctf_stream_class_common_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_ctf_stream_class_common_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;
-
-               for (i = 0; i < trace->streams->len; i++) {
-                       struct bt_ctf_stream_common *trace_stream =
-                               g_ptr_array_index(trace->streams, i);
-
-                       if (trace_stream->stream_class != (void *) stream_class) {
-                               continue;
-                       }
-
-                       if (trace_stream->id == id) {
-                               BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID.");
-                               goto error;
-                       }
-               }
-       }
-
-       /*
-        * Acquire reference to parent since stream will become publicly
-        * reachable; it needs its parent to remain valid.
-        */
-       bt_ctf_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;
-               }
-       }
-
-       BT_LOGD("Set common stream's trace parent: trace-addr=%p", trace);
-
-       /* Add this stream to the trace's streams */
-       BT_LOGD("Created common stream object: addr=%p", stream);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-void bt_ctf_stream_destroy(struct bt_ctf_object *obj);
-
-static
-int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
-
-static
-int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (!field) {
-               BT_LOGW_STR("Invalid parameter: field is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       field_type = bt_ctf_field_get_type(field);
-       BT_ASSERT(field_type);
-
-       if (bt_ctf_field_type_get_type_id(field_type) !=
-                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               /* Not an integer and the value is unset, error. */
-               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
-                       "field-addr=%p, ft-addr=%p, ft-id=%s",
-                       field, field_type,
-                       bt_ctf_field_type_id_string((int)
-                               bt_ctf_field_type_get_type_id(field_type)));
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_ctf_field_type_integer_is_signed(field_type)) {
-               ret = bt_ctf_field_integer_signed_set_value(field, (int64_t) value);
-               if (ret) {
-                       /* Value is out of range, error. */
-                       BT_LOGW("Cannot set signed integer field's value: "
-                               "addr=%p, value=%" PRId64,
-                               field, (int64_t) value);
-                       goto end;
-               }
-       } else {
-               ret = bt_ctf_field_integer_unsigned_set_value(field, value);
-               if (ret) {
-                       /* Value is out of range, error. */
-                       BT_LOGW("Cannot set unsigned integer field's value: "
-                               "addr=%p, value=%" PRIu64,
-                               field, value);
-                       goto end;
-               }
-       }
-end:
-       bt_ctf_object_put_ref(field_type);
-       return ret;
-}
-
-static
-int set_packet_header_magic(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_header, "magic");
-       const uint32_t magic_value = 0xc1fc1fc1;
-
-       BT_ASSERT(stream);
-
-       if (!magic_field) {
-               /* No magic field found. Not an error, skip. */
-               BT_LOGV("No field named `magic` in packet header: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_set_value(magic_field,
-               (uint64_t) magic_value);
-
-       if (ret) {
-               BT_LOGW("Cannot set packet header field's `magic` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       magic_field, (uint64_t) magic_value);
-       } else {
-               BT_LOGV("Set packet header field's `magic` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       magic_field, (uint64_t) magic_value);
-       }
-end:
-       bt_ctf_object_put_ref(magic_field);
-       return ret;
-}
-
-static
-int set_packet_header_uuid(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       int64_t i;
-       struct bt_ctf_trace *trace = NULL;
-       struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_header, "uuid");
-
-       BT_ASSERT(stream);
-
-       if (!uuid_field) {
-               /* No uuid field found. Not an error, skip. */
-               BT_LOGV("No field named `uuid` in packet header: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       trace = (struct bt_ctf_trace *)
-               bt_ctf_object_get_parent(&stream->common.base);
-
-       for (i = 0; i < 16; i++) {
-               struct bt_ctf_field *uuid_element =
-                       bt_ctf_field_array_get_field(uuid_field, i);
-
-               ret = bt_ctf_field_integer_unsigned_set_value(
-                       uuid_element, (uint64_t) trace->common.uuid[i]);
-               bt_ctf_object_put_ref(uuid_element);
-               if (ret) {
-                       BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
-                               "value=%" PRIu64 ", index=%" PRId64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               uuid_element, (uint64_t) trace->common.uuid[i], i);
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Set packet header field's `uuid` field's value: "
-               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), uuid_field);
-
-end:
-       bt_ctf_object_put_ref(uuid_field);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
-       return ret;
-}
-static
-int set_packet_header_stream_id(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       uint32_t stream_id;
-       struct bt_ctf_field *stream_id_field =
-               bt_ctf_field_structure_get_field_by_name(
-                       stream->packet_header, "stream_id");
-
-       if (!stream_id_field) {
-               /* No stream_id field found. Not an error, skip. */
-               BT_LOGV("No field named `stream_id` in packet header: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       stream_id = stream->common.stream_class->id;
-       ret = bt_ctf_field_integer_unsigned_set_value(stream_id_field,
-               (uint64_t) stream_id);
-       if (ret) {
-               BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       stream_id_field, (uint64_t) stream_id);
-       } else {
-               BT_LOGV("Set packet header field's `stream_id` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       stream_id_field, (uint64_t) stream_id);
-       }
-
-end:
-       bt_ctf_object_put_ref(stream_id_field);
-       return ret;
-}
-
-static
-int auto_populate_packet_header(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-
-       if (!stream->packet_header) {
-               goto end;
-       }
-
-       ret = set_packet_header_magic(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet header's magic number field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = set_packet_header_uuid(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet header's UUID field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = set_packet_header_stream_id(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet header's stream class ID field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       BT_LOGV("Automatically populated stream's packet header's known fields: "
-               "stream-addr=%p, stream-name=\"%s\"",
-               stream, bt_ctf_stream_get_name(stream));
-
-end:
-       return ret;
-}
-
-static
-int set_packet_context_packet_size(struct bt_ctf_stream *stream,
-               uint64_t packet_size_bits)
-{
-       int ret = 0;
-       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "packet_size");
-
-       ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, packet_size_bits);
-       } else {
-               BT_LOGV("Set packet context field's `packet_size` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, packet_size_bits);
-       }
-
-       bt_ctf_object_put_ref(field);
-       return ret;
-}
-
-static
-int set_packet_context_content_size(struct bt_ctf_stream *stream,
-               uint64_t content_size_bits)
-{
-       int ret = 0;
-       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "content_size");
-
-       BT_ASSERT(stream);
-
-       if (!field) {
-               /* No content size field found. Not an error, skip. */
-               BT_LOGV("No field named `content_size` in packet context: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, content_size_bits);
-       } else {
-               BT_LOGV("Set packet context field's `content_size` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, content_size_bits);
-       }
-
-end:
-       bt_ctf_object_put_ref(field);
-       return ret;
-}
-
-static
-int set_packet_context_events_discarded(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "events_discarded");
-
-       BT_ASSERT(stream);
-
-       if (!field) {
-               /* No discarded events count field found. Not an error, skip. */
-               BT_LOGV("No field named `events_discarded` in packet context: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       /*
-        * If the field is set by the user, make sure that the value is
-        * greater than or equal to the stream's current count of
-        * discarded events. We do not allow wrapping here. If it's
-        * valid, update the stream's current count.
-        */
-       if (bt_ctf_field_is_set_recursive(field)) {
-               uint64_t user_val;
-
-               ret = bt_ctf_field_integer_unsigned_get_value(field,
-                       &user_val);
-               if (ret) {
-                       BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
-                               stream, bt_ctf_stream_get_name(stream), field);
-                       goto end;
-               }
-
-               if (user_val < stream->discarded_events) {
-                       BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: "
-                               "value is lesser than the stream's current discarded events count: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
-                               "value=%" PRIu64 ", "
-                               "stream-discarded-events-count=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream), field,
-                               user_val, stream->discarded_events);
-                       goto end;
-               }
-
-               stream->discarded_events = user_val;
-       } else {
-               ret = bt_ctf_field_integer_unsigned_set_value(field,
-                       stream->discarded_events);
-               if (ret) {
-                       BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               field, stream->discarded_events);
-               } else {
-                       BT_LOGV("Set packet context field's `events_discarded` field's value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               field, stream->discarded_events);
-               }
-       }
-
-end:
-       bt_ctf_object_put_ref(field);
-       return ret;
-}
-
-static
-void update_clock_value(uint64_t *val, uint64_t new_val,
-               unsigned int new_val_size)
-{
-       const uint64_t pow2 = 1ULL << new_val_size;
-       const uint64_t mask = pow2 - 1;
-       uint64_t val_masked;
-
-#ifdef BT_LOG_ENABLED_VERBOSE
-       uint64_t old_val = *val;
-#endif
-
-       if (new_val_size == 64) {
-               *val = new_val;
-               goto end;
-       }
-
-       val_masked = *val & mask;
-
-       if (new_val < val_masked) {
-               /* Wrapped once */
-               new_val |= pow2;
-       }
-
-       *val &= ~mask;
-       *val |= new_val;
-
-end:
-       BT_LOGV("Updated clock value: old-val=%" PRIu64 ", new-val=%" PRIu64,
-               old_val, *val);
-       return;
-}
-
-static
-int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val)
-{
-       int ret = 0;
-       struct bt_ctf_field_common *field_common = (void *) field;
-
-       if (!field) {
-               goto end;
-       }
-
-       switch (bt_ctf_field_get_type_id(field)) {
-       case BT_CTF_FIELD_TYPE_ID_INTEGER:
-       {
-               struct bt_ctf_clock_class *cc =
-                       bt_ctf_field_type_integer_get_mapped_clock_class(
-                               (void *) field_common->type);
-               int val_size;
-               uint64_t uval;
-
-               if (!cc) {
-                       goto end;
-               }
-
-               bt_ctf_object_put_ref(cc);
-               val_size = bt_ctf_field_type_integer_get_size(
-                       (void *) field_common->type);
-               BT_ASSERT(val_size >= 1);
-
-               if (bt_ctf_field_type_integer_is_signed(
-                               (void *) field_common->type)) {
-                       int64_t ival;
-
-                       ret = bt_ctf_field_integer_signed_get_value(field, &ival);
-                       uval = (uint64_t) ival;
-               } else {
-                       ret = bt_ctf_field_integer_unsigned_get_value(field, &uval);
-               }
-
-               if (ret) {
-                       /* Not set */
-                       goto end;
-               }
-
-               update_clock_value(val, uval, val_size);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_ctf_field *int_field =
-                       bt_ctf_field_enumeration_get_container(field);
-
-               BT_ASSERT(int_field);
-               ret = visit_field_update_clock_value(int_field, val);
-               bt_ctf_object_put_ref(int_field);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       {
-               uint64_t i;
-               int64_t len = bt_ctf_field_type_array_get_length(
-                       (void *) field_common->type);
-
-               BT_ASSERT(len >= 0);
-
-               for (i = 0; i < len; i++) {
-                       struct bt_ctf_field *elem_field =
-                               bt_ctf_field_array_get_field(field, i);
-
-                       BT_ASSERT(elem_field);
-                       ret = visit_field_update_clock_value(elem_field, val);
-                       bt_ctf_object_put_ref(elem_field);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       {
-               uint64_t i;
-               int64_t len = bt_ctf_field_common_sequence_get_length(
-                       (void *) field);
-
-               if (len < 0) {
-                       ret = -1;
-                       goto end;
-               }
-
-               for (i = 0; i < len; i++) {
-                       struct bt_ctf_field *elem_field =
-                               bt_ctf_field_sequence_get_field(field, i);
-
-                       BT_ASSERT(elem_field);
-                       ret = visit_field_update_clock_value(elem_field, val);
-                       bt_ctf_object_put_ref(elem_field);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               uint64_t i;
-               int64_t len = bt_ctf_field_type_structure_get_field_count(
-                       (void *) field_common->type);
-
-               BT_ASSERT(len >= 0);
-
-               for (i = 0; i < len; i++) {
-                       struct bt_ctf_field *member_field =
-                               bt_ctf_field_structure_get_field_by_index(field, i);
-
-                       BT_ASSERT(member_field);
-                       ret = visit_field_update_clock_value(member_field, val);
-                       bt_ctf_object_put_ref(member_field);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-       {
-               struct bt_ctf_field *cur_field =
-                       bt_ctf_field_variant_get_current_field(field);
-
-               if (!cur_field) {
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = visit_field_update_clock_value(cur_field, val);
-               bt_ctf_object_put_ref(cur_field);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-int visit_event_update_clock_value(struct bt_ctf_event *event, uint64_t *val)
-{
-       int ret = 0;
-       struct bt_ctf_field *field;
-
-       field = bt_ctf_event_get_header(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's header.");
-               goto end;
-       }
-
-       field = bt_ctf_event_get_stream_event_context(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's stream event context.");
-               goto end;
-       }
-
-       field = bt_ctf_event_get_context(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's context.");
-               goto end;
-       }
-
-       field = bt_ctf_event_get_payload_field(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's payload.");
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int set_packet_context_timestamps(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       uint64_t val;
-       uint64_t cur_clock_value;
-       uint64_t init_clock_value = 0;
-       struct bt_ctf_field *ts_begin_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "timestamp_begin");
-       struct bt_ctf_field *ts_end_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "timestamp_end");
-       struct bt_ctf_field_common *packet_context =
-               (void *) stream->packet_context;
-       uint64_t i;
-       int64_t len;
-
-       if (ts_begin_field && bt_ctf_field_is_set_recursive(ts_begin_field)) {
-               /* Use provided `timestamp_begin` value as starting value */
-               ret = bt_ctf_field_integer_unsigned_get_value(ts_begin_field, &val);
-               BT_ASSERT(ret == 0);
-               init_clock_value = val;
-       } else if (stream->last_ts_end != -1ULL) {
-               /* Use last packet's ending timestamp as starting value */
-               init_clock_value = stream->last_ts_end;
-       }
-
-       cur_clock_value = init_clock_value;
-
-       if (stream->last_ts_end != -1ULL &&
-                       cur_clock_value < stream->last_ts_end) {
-               BT_LOGW("Packet's initial timestamp is less than previous "
-                       "packet's final timestamp: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "cur-packet-ts-begin=%" PRIu64 ", "
-                       "prev-packet-ts-end=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       cur_clock_value, stream->last_ts_end);
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Visit all the packet context fields, followed by all the
-        * fields of all the events, in order, updating our current
-        * clock value as we visit.
-        *
-        * While visiting the packet context fields, do not consider
-        * `timestamp_begin` and `timestamp_end` because this function's
-        * purpose is to set them anyway. Also do not consider
-        * `packet_size`, `content_size`, `events_discarded`, and
-        * `packet_seq_num` if they are not set because those are
-        * autopopulating fields.
-        */
-       len = bt_ctf_field_type_structure_get_field_count(
-               (void *) packet_context->type);
-       BT_ASSERT(len >= 0);
-
-       for (i = 0; i < len; i++) {
-               const char *member_name;
-               struct bt_ctf_field *member_field;
-
-               ret = bt_ctf_field_type_structure_get_field_by_index(
-                       (void *) packet_context->type, &member_name, NULL, i);
-               BT_ASSERT(ret == 0);
-
-               if (strcmp(member_name, "timestamp_begin") == 0 ||
-                               strcmp(member_name, "timestamp_end") == 0) {
-                       continue;
-               }
-
-               member_field = bt_ctf_field_structure_get_field_by_index(
-                       stream->packet_context, i);
-               BT_ASSERT(member_field);
-
-               if (strcmp(member_name, "packet_size") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               if (strcmp(member_name, "content_size") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               if (strcmp(member_name, "events_discarded") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               if (strcmp(member_name, "packet_seq_num") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               ret = visit_field_update_clock_value(member_field,
-                       &cur_clock_value);
-               bt_ctf_object_put_ref(member_field);
-               if (ret) {
-                       BT_LOGW("Cannot automatically update clock value "
-                               "in stream's packet context: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "field-name=\"%s\"",
-                               stream, bt_ctf_stream_get_name(stream),
-                               member_name);
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < stream->events->len; i++) {
-               struct bt_ctf_event *event = g_ptr_array_index(stream->events, i);
-
-               BT_ASSERT(event);
-               ret = visit_event_update_clock_value(event, &cur_clock_value);
-               if (ret) {
-                       BT_LOGW("Cannot automatically update clock value "
-                               "in stream's packet context: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "index=%" PRIu64 ", event-addr=%p, "
-                               "event-class-id=%" PRId64 ", "
-                               "event-class-name=\"%s\"",
-                               stream, bt_ctf_stream_get_name(stream),
-                               i, event,
-                               bt_ctf_event_class_common_get_id(event->common.class),
-                               bt_ctf_event_class_common_get_name(event->common.class));
-                       goto end;
-               }
-       }
-
-       /*
-        * Everything is visited, thus the current clock value
-        * corresponds to the ending timestamp. Validate this value
-        * against the provided value of `timestamp_end`, if any,
-        * otherwise set it.
-        */
-       if (ts_end_field && bt_ctf_field_is_set_recursive(ts_end_field)) {
-               ret = bt_ctf_field_integer_unsigned_get_value(ts_end_field, &val);
-               BT_ASSERT(ret == 0);
-
-               if (val < cur_clock_value) {
-                       BT_LOGW("Packet's final timestamp is less than "
-                               "computed packet's final timestamp: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "cur-packet-ts-end=%" PRIu64 ", "
-                               "computed-packet-ts-end=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               val, cur_clock_value);
-                       ret = -1;
-                       goto end;
-               }
-
-               stream->last_ts_end = val;
-       }
-
-       if (ts_end_field && !bt_ctf_field_is_set_recursive(ts_end_field)) {
-               ret = set_integer_field_value(ts_end_field, cur_clock_value);
-               BT_ASSERT(ret == 0);
-               stream->last_ts_end = cur_clock_value;
-       }
-
-       if (!ts_end_field) {
-               stream->last_ts_end = cur_clock_value;
-       }
-
-       /* Set `timestamp_begin` field to initial clock value */
-       if (ts_begin_field && !bt_ctf_field_is_set_recursive(ts_begin_field)) {
-               ret = set_integer_field_value(ts_begin_field, init_clock_value);
-               BT_ASSERT(ret == 0);
-       }
-
-end:
-       bt_ctf_object_put_ref(ts_begin_field);
-       bt_ctf_object_put_ref(ts_end_field);
-       return ret;
-}
-
-static
-int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts,
-               uint64_t packet_size_bits, uint64_t content_size_bits)
-{
-       int ret = 0;
-
-       if (!stream->packet_context) {
-               goto end;
-       }
-
-       ret = set_packet_context_packet_size(stream, packet_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's packet size field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = set_packet_context_content_size(stream, content_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's content size field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       if (set_ts) {
-               ret = set_packet_context_timestamps(stream);
-               if (ret) {
-                       BT_LOGW("Cannot set packet context's timestamp fields: "
-                               "stream-addr=%p, stream-name=\"%s\"",
-                               stream, bt_ctf_stream_get_name(stream));
-                       goto end;
-               }
-       }
-
-       ret = set_packet_context_events_discarded(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's discarded events count field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       BT_LOGV("Automatically populated stream's packet context's known fields: "
-               "stream-addr=%p, stream-name=\"%s\"",
-               stream, bt_ctf_stream_get_name(stream));
-
-end:
-       return ret;
-}
-
-static
-void release_event(struct bt_ctf_event *event)
-{
-       if (bt_ctf_object_get_ref_count(&event->common.base)) {
-               /*
-                * The event is being orphaned, but it must guarantee the
-                * existence of its event class for the duration of its
-                * lifetime.
-                */
-               bt_ctf_object_get_ref(event->common.class);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(event->common.base.parent);
-       } else {
-               bt_ctf_object_try_spec_release(&event->common.base);
-       }
-}
-
-static
-int create_stream_file(struct bt_ctf_writer *writer,
-               struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       GString *filename = g_string_new(NULL);
-       int64_t stream_class_id;
-       char *file_path = NULL;
-
-       BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
-               "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
-               writer, stream, bt_ctf_stream_get_name(stream),
-               stream->common.stream_class,
-               stream->common.stream_class->name->str);
-
-       if (stream->common.name && stream->common.name->len > 0) {
-               /* Use stream name's base name as prefix */
-               gchar *basename = g_path_get_basename(stream->common.name->str);
-
-               BT_ASSERT(basename);
-
-               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
-                       g_string_assign(filename, "stream");
-               } else {
-                       g_string_assign(filename, basename);
-               }
-
-               g_free(basename);
-               goto append_ids;
-       }
-
-       if (stream->common.stream_class->name &&
-                       stream->common.stream_class->name->len > 0) {
-               /* Use stream class name's base name as prefix */
-               gchar *basename =
-                       g_path_get_basename(
-                               stream->common.stream_class->name->str);
-
-               BT_ASSERT(basename);
-
-               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
-                       g_string_assign(filename, "stream");
-               } else {
-                       g_string_assign(filename, basename);
-               }
-
-               g_free(basename);
-               goto append_ids;
-       }
-
-       /* Default to using `stream-` as prefix */
-       g_string_assign(filename, "stream");
-
-append_ids:
-       stream_class_id = bt_ctf_stream_class_common_get_id(stream->common.stream_class);
-       BT_ASSERT(stream_class_id >= 0);
-       BT_ASSERT(stream->common.id >= 0);
-       g_string_append_printf(filename, "-%" PRId64 "-%" PRId64,
-               stream_class_id, stream->common.id);
-
-       file_path = g_build_filename(writer->path->str, filename->str, NULL);
-       if (file_path == NULL) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctfser_init(&stream->ctfser, file_path);
-       g_free(file_path);
-       if (ret) {
-               /* bt_ctfser_init() logs errors */
-               goto end;
-       }
-
-       BT_LOGD("Created stream file for writing: "
-               "stream-addr=%p, stream-name=\"%s\", "
-               "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream),
-               filename->str);
-
-end:
-       g_string_free(filename, TRUE);
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_stream *bt_ctf_stream_create_with_id(
-               struct bt_ctf_stream_class *stream_class,
-               const char *name, uint64_t id)
-{
-       int ret;
-       int fd;
-       struct bt_ctf_stream *stream = NULL;
-       struct bt_ctf_trace *trace = NULL;
-       struct bt_ctf_writer *writer = NULL;
-
-       BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-name=\"%s\", "
-               "stream-id=%" PRIu64,
-               stream_class, bt_ctf_stream_class_get_name(stream_class),
-               name, id);
-       stream = g_new0(struct bt_ctf_stream, 1);
-       if (!stream) {
-               BT_LOGE_STR("Failed to allocate one stream.");
-               goto error;
-       }
-
-       if (id == -1ULL) {
-               id = stream_class->next_stream_id;
-       }
-
-       ret = bt_ctf_stream_common_initialize(BT_CTF_TO_COMMON(stream),
-               BT_CTF_TO_COMMON(stream_class), name, id, bt_ctf_stream_destroy);
-       if (ret) {
-               /* bt_ctf_stream_common_initialize() logs errors */
-               goto error;
-       }
-
-       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
-               BT_CTF_TO_COMMON(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_ctf_stream_class_get_name(stream_class),
-                       name);
-               goto error;
-       }
-
-       writer = (struct bt_ctf_writer *)
-               bt_ctf_object_get_parent(&trace->common.base);
-       stream->last_ts_end = -1ULL;
-       BT_LOGD("CTF writer stream object belongs writer's trace: "
-               "writer-addr=%p", writer);
-       BT_ASSERT(writer);
-
-       if (stream_class->common.packet_context_field_type) {
-               BT_LOGD("Creating stream's packet context field: "
-                       "ft-addr=%p",
-                       stream_class->common.packet_context_field_type);
-               stream->packet_context = bt_ctf_field_create(
-                       (void *) stream_class->common.packet_context_field_type);
-               if (!stream->packet_context) {
-                       BT_LOGW_STR("Cannot create stream's packet context field.");
-                       goto error;
-               }
-
-               /* Initialize events_discarded */
-               ret = try_set_structure_field_integer(
-                       stream->packet_context, "events_discarded", 0);
-               if (ret < 0) {
-                       BT_LOGW("Cannot set `events_discarded` field in packet context: "
-                               "ret=%d, packet-context-field-addr=%p",
-                               ret, stream->packet_context);
-                       goto error;
-               }
-       }
-
-       stream->events = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) release_event);
-       if (!stream->events) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       if (trace->common.packet_header_field_type) {
-               BT_LOGD("Creating stream's packet header field: "
-                       "ft-addr=%p", trace->common.packet_header_field_type);
-               stream->packet_header =
-                       bt_ctf_field_create(
-                               (void *) trace->common.packet_header_field_type);
-               if (!stream->packet_header) {
-                       BT_LOGW_STR("Cannot create stream's packet header field.");
-                       goto error;
-               }
-       }
-
-       /*
-        * Attempt to populate the default trace packet header fields
-        * (magic, uuid and stream_id). This will _not_ fail shall the
-        * fields not be found or be of an incompatible type; they will
-        * simply not be populated automatically. The user will have to
-        * make sure to set the trace packet header fields himself
-        * before flushing.
-        */
-       ret = auto_populate_packet_header(stream);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically populate the stream's packet header.");
-               goto error;
-       }
-
-       /* Create file associated with this stream */
-       fd = create_stream_file(writer, stream);
-       if (fd < 0) {
-               BT_LOGW_STR("Cannot create stream file.");
-               goto error;
-       }
-
-       /* Freeze the writer */
-       BT_LOGD_STR("Freezing stream's CTF writer.");
-       bt_ctf_writer_freeze(writer);
-
-       /* Add this stream to the trace's streams */
-       g_ptr_array_add(trace->common.streams, stream);
-       stream_class->next_stream_id++;
-       BT_LOGD("Created stream object: addr=%p", stream);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
-
-end:
-       bt_ctf_object_put_ref(writer);
-       return stream;
-}
-
-struct bt_ctf_stream *bt_ctf_stream_create(
-               struct bt_ctf_stream_class *stream_class,
-               const char *name, uint64_t id_param)
-{
-       return bt_ctf_stream_create_with_id(stream_class,
-               name, id_param);
-}
-
-int bt_ctf_stream_get_discarded_events_count(
-               struct bt_ctf_stream *stream, uint64_t *count)
-{
-       int ret = 0;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!count) {
-               BT_LOGW_STR("Invalid parameter: count is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       *count = (uint64_t) stream->discarded_events;
-
-end:
-       return ret;
-}
-
-static
-int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream,
-       uint64_t count)
-{
-       int ret = 0;
-       struct bt_ctf_field *events_discarded_field = NULL;
-
-       if (!stream->packet_context) {
-               goto end;
-       }
-
-       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "events_discarded");
-       if (!events_discarded_field) {
-               goto end;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_set_value(
-               events_discarded_field, count);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's `events_discarded` field: "
-                       "field-addr=%p, value=%" PRIu64,
-                       events_discarded_field, count);
-               goto end;
-       }
-
-end:
-       bt_ctf_object_put_ref(events_discarded_field);
-       return ret;
-}
-
-void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
-               uint64_t event_count)
-{
-       int ret;
-       uint64_t new_count;
-       struct bt_ctf_field *events_discarded_field = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               goto end;
-       }
-
-       BT_LOGV("Appending discarded events to stream: "
-               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
-               stream, bt_ctf_stream_get_name(stream), event_count);
-
-       if (!stream->packet_context) {
-               BT_LOGW_STR("Invalid parameter: stream has no packet context field.");
-               goto end;
-       }
-
-       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "events_discarded");
-       if (!events_discarded_field) {
-               BT_LOGW_STR("No field named `events_discarded` in stream's packet context.");
-               goto end;
-       }
-
-       new_count = stream->discarded_events + event_count;
-       if (new_count < stream->discarded_events) {
-               BT_LOGW("New discarded events count is less than the stream's current discarded events count: "
-                       "cur-count=%" PRIu64 ", new-count=%" PRIu64,
-                       stream->discarded_events, new_count);
-               goto end;
-       }
-
-       ret = set_packet_context_events_discarded_field(stream, new_count);
-       if (ret) {
-               /* set_packet_context_events_discarded_field() logs errors */
-               goto end;
-       }
-
-       stream->discarded_events = new_count;
-       BT_LOGV("Appended discarded events to stream: "
-               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
-               stream, bt_ctf_stream_get_name(stream), event_count);
-
-end:
-       bt_ctf_object_put_ref(events_discarded_field);
-}
-
-static int auto_populate_event_header(struct bt_ctf_stream *stream,
-               struct bt_ctf_event *event)
-{
-       int ret = 0;
-       struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
-       struct bt_ctf_clock_class *mapped_clock_class = NULL;
-       struct bt_ctf_stream_class *stream_class =
-               BT_CTF_FROM_COMMON(bt_ctf_stream_common_borrow_class(
-                       BT_CTF_TO_COMMON(stream)));
-       int64_t event_class_id;
-
-       BT_ASSERT(event);
-
-       if (!event->common.header_field) {
-               goto end;
-       }
-
-       if (event->common.frozen) {
-               BT_LOGW_STR("Cannot populate event header field: event is frozen.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Automatically populating event's header field: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), event);
-
-       id_field = bt_ctf_field_structure_get_field_by_name(
-               (void *) event->common.header_field->field, "id");
-       event_class_id = bt_ctf_event_class_common_get_id(event->common.class);
-       BT_ASSERT(event_class_id >= 0);
-
-       if (id_field && bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               ret = set_integer_field_value(id_field, event_class_id);
-               if (ret) {
-                       BT_LOGW("Cannot set event header's `id` field's value: "
-                               "addr=%p, value=%" PRIu64, id_field,
-                               event_class_id);
-                       goto end;
-               }
-       }
-
-       /*
-        * The conditions to automatically set the timestamp are:
-        *
-        * 1. The event header field "timestamp" exists and is an
-        *    integer field.
-        * 2. This stream's class has a registered clock (set with
-        *    bt_ctf_stream_class_set_clock()).
-        * 3. The "timestamp" field is not set.
-        */
-       timestamp_field = bt_ctf_field_structure_get_field_by_name(
-                       (void *) event->common.header_field->field, "timestamp");
-       if (timestamp_field && stream_class->clock &&
-                       bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER &&
-                       !bt_ctf_field_is_set_recursive(timestamp_field)) {
-               mapped_clock_class =
-                       bt_ctf_field_type_integer_get_mapped_clock_class(
-                               (void *) ((struct bt_ctf_field_common *) timestamp_field)->type);
-               if (mapped_clock_class) {
-                       uint64_t timestamp;
-
-                       BT_ASSERT(mapped_clock_class ==
-                               stream_class->clock->clock_class);
-                       ret = bt_ctf_clock_get_value(
-                               stream_class->clock,
-                               &timestamp);
-                       BT_ASSERT(ret == 0);
-                       ret = set_integer_field_value(timestamp_field,
-                                       timestamp);
-                       if (ret) {
-                               BT_LOGW("Cannot set event header's `timestamp` field's value: "
-                                       "addr=%p, value=%" PRIu64,
-                                       timestamp_field, timestamp);
-                               goto end;
-                       }
-               }
-       }
-
-       BT_LOGV("Automatically populated event's header field: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), event);
-
-end:
-       bt_ctf_object_put_ref(id_field);
-       bt_ctf_object_put_ref(timestamp_field);
-       bt_ctf_object_put_ref(mapped_clock_class);
-       return ret;
-}
-
-int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
-               struct bt_ctf_event *event)
-{
-       int ret = 0;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!event) {
-               BT_LOGW_STR("Invalid parameter: event is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Appending event to stream: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream, bt_ctf_stream_get_name(stream), event,
-               bt_ctf_event_class_common_get_name(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
-               bt_ctf_event_class_common_get_id(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
-
-       /*
-        * The event is not supposed to have a parent stream at this
-        * point. The only other way an event can have a parent stream
-        * is if it was assigned when setting a packet to the event,
-        * in which case the packet's stream is not a writer stream,
-        * and thus the user is trying to append an event which belongs
-        * to another stream.
-        */
-       if (event->common.base.parent) {
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_set_parent(&event->common.base, &stream->common.base);
-       BT_LOGV_STR("Automatically populating the header of the event to append.");
-       ret = auto_populate_event_header(stream, event);
-       if (ret) {
-               /* auto_populate_event_header() reports errors */
-               goto error;
-       }
-
-       /* Make sure the various scopes of the event are set */
-       BT_LOGV_STR("Validating event to append.");
-       BT_ASSERT_PRE(bt_ctf_event_common_validate(BT_CTF_TO_COMMON(event)) == 0,
-               "Invalid event: event-addr=%p", event);
-
-       /* Save the new event and freeze it */
-       BT_LOGV_STR("Freezing the event to append.");
-       bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
-       g_ptr_array_add(stream->events, event);
-
-       /*
-        * Event had to hold a reference to its event class as long as it wasn't
-        * part of the same trace hierarchy. From now on, the event and its
-        * class share the same lifetime guarantees and the reference is no
-        * longer needed.
-        */
-       BT_LOGV_STR("Putting the event's class.");
-       bt_ctf_object_put_ref(event->common.class);
-       BT_LOGV("Appended event to stream: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream, bt_ctf_stream_get_name(stream), event,
-               bt_ctf_event_class_common_get_name(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
-               bt_ctf_event_class_common_get_id(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
-
-end:
-       return ret;
-
-error:
-       /*
-        * Orphan the event; we were not successful in associating it to
-        * a stream.
-        */
-       bt_ctf_object_set_parent(&event->common.base, NULL);
-       return ret;
-}
-
-struct bt_ctf_field *bt_ctf_stream_get_packet_context(struct bt_ctf_stream *stream)
-{
-       struct bt_ctf_field *packet_context = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               goto end;
-       }
-
-       packet_context = stream->packet_context;
-       if (packet_context) {
-               bt_ctf_object_get_ref(packet_context);
-       }
-end:
-       return packet_context;
-}
-
-int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
-               struct bt_ctf_field *field)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *field_type;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       field_type = bt_ctf_field_get_type(field);
-       if (bt_ctf_field_type_common_compare((void *) field_type,
-                       stream->common.stream_class->packet_context_field_type)) {
-               BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "packet-context-field-addr=%p, "
-                       "packet-context-ft-addr=%p",
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, field_type);
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(field_type);
-       bt_ctf_object_put_ref(stream->packet_context);
-       stream->packet_context = bt_ctf_object_get_ref(field);
-       BT_LOGV("Set stream's packet context field: "
-               "stream-addr=%p, stream-name=\"%s\", "
-               "packet-context-field-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), field);
-end:
-       return ret;
-}
-
-struct bt_ctf_field *bt_ctf_stream_get_packet_header(struct bt_ctf_stream *stream)
-{
-       struct bt_ctf_field *packet_header = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               goto end;
-       }
-
-       packet_header = stream->packet_header;
-       if (packet_header) {
-               bt_ctf_object_get_ref(packet_header);
-       }
-end:
-       return packet_header;
-}
-
-int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
-               struct bt_ctf_field *field)
-{
-       int ret = 0;
-       struct bt_ctf_trace *trace = NULL;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       trace = (struct bt_ctf_trace *)
-               bt_ctf_object_get_parent(&stream->common.base);
-
-       if (!field) {
-               if (trace->common.packet_header_field_type) {
-                       BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "packet-header-field-addr=%p, "
-                               "expected-ft-addr=%p",
-                               stream, bt_ctf_stream_get_name(stream),
-                               field, trace->common.packet_header_field_type);
-                       ret = -1;
-                       goto end;
-               }
-
-               goto skip_validation;
-       }
-
-       field_type = bt_ctf_field_get_type(field);
-       BT_ASSERT(field_type);
-
-       if (bt_ctf_field_type_common_compare((void *) field_type,
-                       trace->common.packet_header_field_type)) {
-               BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "packet-header-field-addr=%p, "
-                       "packet-header-ft-addr=%p",
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, field_type);
-               ret = -1;
-               goto end;
-       }
-
-skip_validation:
-       bt_ctf_object_put_ref(stream->packet_header);
-       stream->packet_header = bt_ctf_object_get_ref(field);
-       BT_LOGV("Set stream's packet header field: "
-               "stream-addr=%p, stream-name=\"%s\", "
-               "packet-header-field-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), field);
-end:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
-       bt_ctf_object_put_ref(field_type);
-       return ret;
-}
-
-static
-void reset_structure_field(struct bt_ctf_field *structure, const char *name)
-{
-       struct bt_ctf_field *member;
-
-       member = bt_ctf_field_structure_get_field_by_name(structure, name);
-       if (member) {
-               bt_ctf_field_common_reset_recursive((void *) member);
-               bt_ctf_object_put_ref(member);
-       }
-}
-
-int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       size_t i;
-       uint64_t packet_context_offset_bits = 0;
-       struct bt_ctf_trace *trace;
-       enum bt_ctf_byte_order native_byte_order;
-       bool has_packet_size = false;
-       uint64_t packet_size_bits = 0;
-       uint64_t content_size_bits = 0;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end_no_stream;
-       }
-
-       if (stream->packet_context) {
-               struct bt_ctf_field *packet_size_field;
-
-               packet_size_field = bt_ctf_field_structure_get_field_by_name(
-                               stream->packet_context, "packet_size");
-               has_packet_size = (packet_size_field != NULL);
-               bt_ctf_object_put_ref(packet_size_field);
-       }
-
-       if (stream->flushed_packet_count == 1) {
-               if (!stream->packet_context) {
-                       BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
-                       ret = -1;
-                       goto end;
-               }
-
-               if (!has_packet_size) {
-                       BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Flushing stream's current packet: stream-addr=%p, "
-               "stream-name=\"%s\", packet-index=%u", stream,
-               bt_ctf_stream_get_name(stream), stream->flushed_packet_count);
-       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
-               stream->common.stream_class));
-       BT_ASSERT(trace);
-       native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
-
-       ret = auto_populate_packet_header(stream);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically populate the stream's packet header field.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Initialize packet/content sizes to `0`; we will overwrite later */
-       ret = auto_populate_packet_context(stream, true, 0, 0);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctfser_open_packet(&stream->ctfser);
-       if (ret) {
-               /* bt_ctfser_open_packet() logs errors */
-               ret = -1;
-               goto end;
-       }
-
-       if (stream->packet_header) {
-               BT_LOGV_STR("Serializing packet header field (initial).");
-               ret = bt_ctf_field_serialize_recursive(stream->packet_header,
-                       &stream->ctfser, native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream's packet header field: "
-                               "field-addr=%p", stream->packet_header);
-                       goto end;
-               }
-       }
-
-       if (stream->packet_context) {
-               /* Save packet context's position to overwrite it later */
-               packet_context_offset_bits =
-                       bt_ctfser_get_offset_in_current_packet_bits(
-                               &stream->ctfser);
-
-               /* Write packet context */
-               BT_LOGV_STR("Serializing packet context field (initial).");
-               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
-                       &stream->ctfser, native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream's packet context field: "
-                               "field-addr=%p", stream->packet_context);
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Serializing events: count=%u", stream->events->len);
-
-       for (i = 0; i < stream->events->len; i++) {
-               struct bt_ctf_event *event = g_ptr_array_index(
-                       stream->events, i);
-               struct bt_ctf_event_class *event_class =
-                       BT_CTF_FROM_COMMON(bt_ctf_event_common_borrow_class(
-                               BT_CTF_TO_COMMON(event)));
-
-               BT_LOGV("Serializing event: index=%zu, event-addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-                       "ser-offset=%" PRIu64,
-                       i, event, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class),
-                       bt_ctfser_get_offset_in_current_packet_bits(
-                               &stream->ctfser));
-
-               /* Write event header */
-               if (event->common.header_field) {
-                       BT_LOGV_STR("Serializing event's header field.");
-                       ret = bt_ctf_field_serialize_recursive(
-                               (void *) event->common.header_field->field,
-                               &stream->ctfser, native_byte_order);
-                       if (ret) {
-                               BT_LOGW("Cannot serialize event's header field: "
-                                       "field-addr=%p",
-                                       event->common.header_field->field);
-                               goto end;
-                       }
-               }
-
-               /* Write stream event context */
-               if (event->common.stream_event_context_field) {
-                       BT_LOGV_STR("Serializing event's stream event context field.");
-                       ret = bt_ctf_field_serialize_recursive(
-                               (void *) event->common.stream_event_context_field,
-                               &stream->ctfser, native_byte_order);
-                       if (ret) {
-                               BT_LOGW("Cannot serialize event's stream event context field: "
-                                       "field-addr=%p",
-                                       event->common.stream_event_context_field);
-                               goto end;
-                       }
-               }
-
-               /* Write event content */
-               ret = bt_ctf_event_serialize(event, &stream->ctfser,
-                       native_byte_order);
-               if (ret) {
-                       /* bt_ctf_event_serialize() logs errors */
-                       goto end;
-               }
-       }
-
-       content_size_bits = bt_ctfser_get_offset_in_current_packet_bits(
-               &stream->ctfser);
-
-       if (!has_packet_size && content_size_bits % 8 != 0) {
-               BT_LOGW("Stream's packet context field type has no `packet_size` field, "
-                       "but current content size is not a multiple of 8 bits: "
-                       "content-size=%" PRIu64 ", "
-                       "packet-size=%" PRIu64,
-                       content_size_bits,
-                       packet_size_bits);
-               ret = -1;
-               goto end;
-       }
-
-       /* Set packet size; make it a multiple of 8 */
-       packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7);
-
-       if (stream->packet_context) {
-               /*
-                * The whole packet is serialized at this point. Make
-                * sure that, if `packet_size` is missing, the current
-                * content size is equal to the current packet size.
-                */
-               struct bt_ctf_field *field =
-                       bt_ctf_field_structure_get_field_by_name(
-                               stream->packet_context, "content_size");
-
-               bt_ctf_object_put_ref(field);
-               if (!field) {
-                       if (content_size_bits != packet_size_bits) {
-                               BT_LOGW("Stream's packet context's `content_size` field is missing, "
-                                       "but current packet's content size is not equal to its packet size: "
-                                       "content-size=%" PRIu64 ", "
-                                       "packet-size=%" PRIu64,
-                                       bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser),
-                                       packet_size_bits);
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               /*
-                * Overwrite the packet context now that the stream
-                * position's packet and content sizes have the correct
-                * values.
-                */
-               bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
-                       packet_context_offset_bits);
-               ret = auto_populate_packet_context(stream, false,
-                       packet_size_bits, content_size_bits);
-               if (ret) {
-                       BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
-                       ret = -1;
-                       goto end;
-               }
-
-               BT_LOGV("Rewriting (serializing) packet context field.");
-               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
-                       &stream->ctfser, native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream's packet context field: "
-                               "field-addr=%p", stream->packet_context);
-                       goto end;
-               }
-       }
-
-       g_ptr_array_set_size(stream->events, 0);
-       stream->flushed_packet_count++;
-       bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8);
-
-end:
-       /* Reset automatically-set fields. */
-       if (stream->packet_context) {
-               reset_structure_field(stream->packet_context, "timestamp_begin");
-               reset_structure_field(stream->packet_context, "timestamp_end");
-               reset_structure_field(stream->packet_context, "packet_size");
-               reset_structure_field(stream->packet_context, "content_size");
-               reset_structure_field(stream->packet_context, "events_discarded");
-       }
-
-       if (ret == 0) {
-               BT_LOGV("Flushed stream's current packet: "
-                       "content-size=%" PRIu64 ", packet-size=%" PRIu64,
-                       content_size_bits, packet_size_bits);
-       }
-
-end_no_stream:
-       return ret;
-}
-
-static
-void bt_ctf_stream_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_stream *stream = (void *) obj;
-
-       BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"",
-               stream, bt_ctf_stream_get_name(stream));
-
-       bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream));
-       bt_ctfser_fini(&stream->ctfser);
-
-       if (stream->events) {
-               BT_LOGD_STR("Putting events.");
-               g_ptr_array_free(stream->events, TRUE);
-       }
-
-       BT_LOGD_STR("Putting packet header field.");
-       bt_ctf_object_put_ref(stream->packet_header);
-       BT_LOGD_STR("Putting packet context field.");
-       bt_ctf_object_put_ref(stream->packet_context);
-       g_free(stream);
-}
-
-static
-int _set_structure_field_integer(struct bt_ctf_field *structure, char *name,
-               uint64_t value, bt_bool force)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *field_type = NULL;
-       struct bt_ctf_field *integer;
-
-       BT_ASSERT(structure);
-       BT_ASSERT(name);
-
-       integer = bt_ctf_field_structure_get_field_by_name(structure, name);
-       if (!integer) {
-               /* Field not found, not an error. */
-               BT_LOGV("Field not found: struct-field-addr=%p, "
-                       "name=\"%s\", force=%d", structure, name, force);
-               goto end;
-       }
-
-       /* Make sure the payload has not already been set. */
-       if (!force && bt_ctf_field_is_set_recursive(integer)) {
-               /* Payload already set, not an error */
-               BT_LOGV("Field's payload is already set: struct-field-addr=%p, "
-                       "name=\"%s\", force=%d", structure, name, force);
-               goto end;
-       }
-
-       field_type = bt_ctf_field_get_type(integer);
-       BT_ASSERT(field_type);
-       if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               /*
-                * The user most likely meant for us to populate this field
-                * automatically. However, we can only do this if the field
-                * is an integer. Return an error.
-                */
-               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
-                       "field-addr=%p, ft-addr=%p, ft-id=%s",
-                       integer, field_type,
-                       bt_ctf_field_type_id_string((int)
-                               bt_ctf_field_type_get_type_id(field_type)));
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_ctf_field_type_integer_is_signed(field_type)) {
-               ret = bt_ctf_field_integer_signed_set_value(integer,
-                       (int64_t) value);
-       } else {
-               ret = bt_ctf_field_integer_unsigned_set_value(integer, value);
-       }
-       ret = !ret ? 1 : ret;
-end:
-       bt_ctf_object_put_ref(integer);
-       bt_ctf_object_put_ref(field_type);
-       return ret;
-}
-
-/*
- * Returns the following codes:
- * 1 if the field was found and set,
- * 0 if nothing was done (field not found, or was already set),
- * <0 if an error was encoutered
- */
-static
-int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name,
-               uint64_t value)
-{
-       return _set_structure_field_integer(structure, name, value, BT_FALSE);
-}
-
-struct bt_ctf_stream_class *bt_ctf_stream_get_class(
-               struct bt_ctf_stream *stream)
-{
-       return bt_ctf_object_get_ref(bt_ctf_stream_common_borrow_class(BT_CTF_TO_COMMON(stream)));
-}
-
-const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
-{
-       return bt_ctf_stream_common_get_name(BT_CTF_TO_COMMON(stream));
-}
-
-int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream)
-{
-       return bt_ctf_stream_common_get_id(BT_CTF_TO_COMMON(stream));
-}
diff --git a/lib/ctf-writer/trace.c b/lib/ctf-writer/trace.c
deleted file mode 100644 (file)
index e9db29a..0000000
+++ /dev/null
@@ -1,1883 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * 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 "CTF-WRITER-TRACE"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/attributes-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/visitor-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define DEFAULT_IDENTIFIER_SIZE                128
-#define DEFAULT_METADATA_STRING_SIZE   4096
-
-BT_HIDDEN
-int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace,
-               bt_ctf_object_release_func release_func)
-{
-       int ret = 0;
-
-       BT_LOGD_STR("Initializing common trace object.");
-       trace->native_byte_order = BT_CTF_BYTE_ORDER_UNSPECIFIED;
-       bt_ctf_object_init_shared_with_parent(&trace->base, release_func);
-       trace->clock_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       if (!trace->clock_classes) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       trace->streams = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_ctf_object_try_spec_release);
-       if (!trace->streams) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       trace->stream_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_ctf_object_try_spec_release);
-       if (!trace->stream_classes) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       /* Create the environment array object */
-       trace->environment = bt_ctf_attributes_create();
-       if (!trace->environment) {
-               BT_LOGE_STR("Cannot create empty attributes object.");
-               goto error;
-       }
-
-       BT_LOGD("Initialized common trace object: addr=%p", trace);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace)
-{
-       BT_LOGD("Finalizing common trace object: addr=%p, name=\"%s\"",
-               trace, bt_ctf_trace_common_get_name(trace));
-
-       if (trace->environment) {
-               BT_LOGD_STR("Destroying environment attributes.");
-               bt_ctf_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_ctf_object_put_ref(trace->packet_header_field_type);
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *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_ctf_trace_common_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_HIDDEN
-int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace,
-               const unsigned char *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_ctf_trace_common_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_ctf_trace_common_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_HIDDEN
-int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace,
-               const char *name, struct bt_ctf_private_value *value)
-{
-       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 (!value) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_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_ctf_trace_common_get_name(trace), name);
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_value_is_integer(bt_ctf_private_value_as_value(value)) &&
-                       !bt_ctf_value_is_string(bt_ctf_private_value_as_value(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_ctf_trace_common_get_name(trace), name,
-                       bt_ctf_value_type_string(
-                               bt_ctf_value_get_type(
-                                       bt_ctf_private_value_as_value(value))));
-               ret = -1;
-               goto end;
-       }
-
-       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_ctf_private_value *attribute =
-                       bt_ctf_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_ctf_trace_common_get_name(trace), name);
-                       ret = -1;
-                       goto end;
-               }
-
-               bt_ctf_value_freeze(bt_ctf_private_value_as_value(value));
-       }
-
-       ret = bt_ctf_attributes_set_field_value(trace->environment, name,
-               value);
-       if (ret) {
-               BT_LOGE("Cannot set environment field's value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace), name);
-       } else {
-               BT_LOGV("Set environment field's value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\", value-addr=%p",
-                       trace, bt_ctf_trace_common_get_name(trace), name, value);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace,
-               const char *name, const char *value)
-{
-       int ret = 0;
-       struct bt_ctf_private_value *env_value_string_obj = NULL;
-
-       if (!value) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       env_value_string_obj = bt_ctf_private_value_string_create_init(value);
-       if (!env_value_string_obj) {
-               BT_LOGE_STR("Cannot create string value object.");
-               ret = -1;
-               goto end;
-       }
-
-       /* bt_ctf_trace_common_set_environment_field() logs errors */
-       ret = bt_ctf_trace_common_set_environment_field(trace, name,
-               env_value_string_obj);
-
-end:
-       bt_ctf_object_put_ref(env_value_string_obj);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field_integer(
-               struct bt_ctf_trace_common *trace, const char *name, int64_t value)
-{
-       int ret = 0;
-       struct bt_ctf_private_value *env_value_integer_obj = NULL;
-
-       env_value_integer_obj = bt_ctf_private_value_integer_create_init(value);
-       if (!env_value_integer_obj) {
-               BT_LOGE_STR("Cannot create integer value object.");
-               ret = -1;
-               goto end;
-       }
-
-       /* bt_ctf_trace_common_set_environment_field() logs errors */
-       ret = bt_ctf_trace_common_set_environment_field(trace, name,
-               env_value_integer_obj);
-
-end:
-       bt_ctf_object_put_ref(env_value_integer_obj);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_clock_class *clock_class)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_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_ctf_trace_common_get_name(trace),
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       /* Check for duplicate clock classes */
-       if (bt_ctf_trace_common_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_ctf_trace_common_get_name(trace),
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_get_ref(clock_class);
-       g_ptr_array_add(trace->clock_classes, clock_class);
-
-       if (trace->frozen) {
-               BT_LOGV_STR("Freezing added clock class because trace is frozen.");
-               bt_ctf_clock_class_freeze(clock_class);
-       }
-
-       BT_LOGV("Added clock class to trace: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "clock-class-addr=%p, clock-class-name=\"%s\"",
-               trace, bt_ctf_trace_common_get_name(trace),
-               clock_class, bt_ctf_clock_class_get_name(clock_class));
-
-end:
-       return ret;
-}
-
-static
-bool packet_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_field_type_common *packet_header_type)
-{
-       int ret;
-       bool is_valid = true;
-       struct bt_ctf_field_type_common *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;
-               }
-
-               /* No packet header field type: valid at this point */
-               goto end;
-       }
-
-       /* Packet header field type, if it exists, must be a structure */
-       if (packet_header_type->id != BT_CTF_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_ctf_field_type_id_string(packet_header_type->id));
-               goto invalid;
-       }
-
-       /*
-        * 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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_header_type, "magic");
-       if (field_type) {
-               const char *field_name;
-
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_field_type_common_integer_get_size(field_type));
-                       goto invalid;
-               }
-
-               ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                       packet_header_type, &field_name, NULL, 0);
-               BT_ASSERT(ret == 0);
-
-               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;
-               }
-       }
-
-       /*
-        * 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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_header_type, "uuid");
-       if (field_type) {
-               struct bt_ctf_field_type_common *elem_ft;
-
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_field_type_common_array_get_length(field_type));
-                       goto invalid;
-               }
-
-               elem_ft = bt_ctf_field_type_common_array_borrow_element_field_type(field_type);
-               BT_ASSERT(elem_ft);
-
-               if (elem_ft->id != BT_CTF_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_ctf_field_type_id_string(elem_ft->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_field_type_common_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_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_header_type, "packet_seq_num");
-       if (field_type) {
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *packet_context_type,
-               bool check_ts_begin_end_mapped)
-{
-       bool is_valid = true;
-       struct bt_ctf_field_type_common *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_CTF_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_ctf_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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "packet_size");
-       if (field_type) {
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "content_size");
-       if (field_type) {
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "events_discarded");
-       if (field_type) {
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "timestamp_begin");
-       if (field_type) {
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_clock_class *clock_class =
-                               bt_ctf_field_type_common_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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "timestamp_end");
-       if (field_type) {
-               if (field_type->id != BT_CTF_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_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_ctf_clock_class *clock_class =
-                               bt_ctf_field_type_common_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_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *event_header_type)
-{
-       bool is_valid = true;
-       struct bt_ctf_field_type_common *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_ctf_stream_class_common_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_CTF_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_ctf_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_ctf_field_type_common_structure_borrow_field_type_by_name(
-               event_header_type, "id");
-       if (field_type) {
-               struct bt_ctf_field_type_common *int_ft;
-
-               if (field_type->id == BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       int_ft = field_type;
-               } else if (field_type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
-                       int_ft = bt_ctf_field_type_common_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_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               BT_ASSERT(int_ft);
-               if (bt_ctf_field_type_common_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_ctf_trace_common *trace)
-{
-       int ret = 0;
-
-       if (trace->packet_header_field_type) {
-               struct bt_ctf_clock_class *clock_class = NULL;
-
-               ret = bt_ctf_field_type_common_validate_single_clock_class(
-                       trace->packet_header_field_type,
-                       &clock_class);
-               bt_ctf_object_put_ref(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_ctf_trace_common_get_name(trace),
-                               clock_class ?
-                                       bt_ctf_clock_class_get_name(clock_class) :
-                                       NULL);
-                       ret = -1;
-               }
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func,
-               struct bt_ctf_clock_class *init_expected_clock_class,
-               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
-                       struct bt_ctf_field_type_common *packet_context_field_type,
-                       struct bt_ctf_field_type_common *event_header_field_type),
-               bool check_ts_begin_end_mapped)
-{
-       int ret;
-       int64_t i;
-       int64_t stream_id;
-       struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
-       struct bt_ctf_validation_output *ec_validation_outputs = NULL;
-       const enum bt_ctf_validation_flag trace_sc_validation_flags =
-               BT_CTF_VALIDATION_FLAG_TRACE |
-               BT_CTF_VALIDATION_FLAG_STREAM;
-       const enum bt_ctf_validation_flag ec_validation_flags =
-               BT_CTF_VALIDATION_FLAG_EVENT;
-       struct bt_ctf_field_type_common *packet_header_type = NULL;
-       struct bt_ctf_field_type_common *packet_context_type = NULL;
-       struct bt_ctf_field_type_common *event_header_type = NULL;
-       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
-       int64_t event_class_count;
-       struct bt_ctf_trace_common *current_parent_trace = NULL;
-       struct bt_ctf_clock_class *expected_clock_class =
-               bt_ctf_object_get_ref(init_expected_clock_class);
-
-       BT_ASSERT(copy_field_type_func);
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               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_ctf_trace_common_get_name(trace),
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-
-       current_parent_trace = bt_ctf_stream_class_common_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_ctf_trace_common_get_name(current_parent_trace));
-               ret = -1;
-               goto end;
-       }
-
-       event_class_count =
-               bt_ctf_stream_class_common_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_ctf_stream_class_common_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_ctf_stream_class_common_validate_single_clock_class()
-                * succeeds below, the call to
-                * bt_ctf_stream_class_map_clock_class() at the end of this
-                * function is safe because it maps to the same, single
-                * clock class.
-                */
-               ret = bt_ctf_stream_class_common_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_ctf_stream_class_common_get_id(stream_class),
-                               bt_ctf_stream_class_common_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_ctf_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_ctf_trace_common_borrow_packet_header_field_type(trace);
-       packet_context_type =
-               bt_ctf_stream_class_common_borrow_packet_context_field_type(stream_class);
-       event_header_type =
-               bt_ctf_stream_class_common_borrow_event_header_field_type(stream_class);
-       stream_event_ctx_type =
-               bt_ctf_stream_class_common_borrow_event_context_field_type(stream_class);
-
-       BT_LOGD("Validating trace and stream class field types.");
-       ret = bt_ctf_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, 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 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_ctf_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_ctf_event_class_common *event_class =
-                       bt_ctf_stream_class_common_borrow_event_class_by_index(
-                               stream_class, i);
-               struct bt_ctf_field_type_common *event_context_type = NULL;
-               struct bt_ctf_field_type_common *event_payload_type = NULL;
-
-               event_context_type =
-                       bt_ctf_event_class_common_borrow_context_field_type(
-                               event_class);
-               event_payload_type =
-                       bt_ctf_event_class_common_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_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-               ret = bt_ctf_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, copy_field_type_func);
-
-               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_ctf_stream_class_common_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_ctf_stream_class_common_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_ctf_stream_class_common_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,
-                       check_ts_begin_end_mapped)) {
-               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;
-       }
-
-       /*
-        * Now is the time to automatically map specific field types of
-        * the stream class's packet context and event header field
-        * types to the stream class's clock's class if they are not
-        * mapped to a clock class yet. We do it here because we know
-        * that after this point, everything is frozen so it won't be
-        * possible for the user to modify the stream class's clock, or
-        * to map those field types to other clock classes.
-        */
-       if (map_clock_classes_func) {
-               if (map_clock_classes_func(stream_class,
-                               trace_sc_validation_output.packet_context_type,
-                               trace_sc_validation_output.event_header_type)) {
-                       /* map_clock_classes_func() logs errors */
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       bt_ctf_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_ctf_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_ctf_validation_replace_types().
-        */
-       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
-
-       for (i = 0; i < event_class_count; i++) {
-               struct bt_ctf_event_class_common *event_class =
-                       bt_ctf_stream_class_common_borrow_event_class_by_index(
-                               stream_class, i);
-
-               bt_ctf_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_ctf_validation_replace_types().
-                */
-               bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
-       }
-
-       /*
-        * Freeze the trace and the stream class.
-        */
-       bt_ctf_stream_class_common_freeze(stream_class);
-       bt_ctf_trace_common_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_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
-       }
-
-       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_ctf_trace_common_get_name(trace),
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-
-end:
-       if (ret) {
-               bt_ctf_object_set_parent(&stream_class->base, NULL);
-
-               if (ec_validation_outputs) {
-                       for (i = 0; i < event_class_count; i++) {
-                               bt_ctf_validation_output_put_types(
-                                       &ec_validation_outputs[i]);
-                       }
-               }
-       }
-
-       g_free(ec_validation_outputs);
-       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
-       bt_ctf_object_put_ref(expected_clock_class);
-       return ret;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_clock_class *clock_class)
-{
-       struct bt_ctf_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;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
-               enum bt_ctf_byte_order byte_order, bool allow_unspecified)
-{
-       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_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) {
-               BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
-               BT_LOGW("Invalid parameter: invalid byte order: "
-                       "addr=%p, name=\"%s\", bo=%s",
-                       trace, bt_ctf_trace_common_get_name(trace),
-                       bt_ctf_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_ctf_trace_common_get_name(trace),
-               bt_ctf_byte_order_string(byte_order));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_field_type_common *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_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       /* packet_header_type must be a structure. */
-       if (packet_header_type &&
-                       packet_header_type->id != BT_CTF_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_ctf_trace_common_get_name(trace),
-                       packet_header_type,
-                       bt_ctf_field_type_id_string(packet_header_type->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(trace->packet_header_field_type);
-       trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type);
-       BT_LOGV("Set trace's packet header field type: "
-               "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
-               trace, bt_ctf_trace_common_get_name(trace), packet_header_type);
-end:
-       return ret;
-}
-
-static
-int64_t get_stream_class_count(void *element)
-{
-       return bt_ctf_trace_get_stream_class_count(
-                       (struct bt_ctf_trace *) element);
-}
-
-static
-void *get_stream_class(void *element, int i)
-{
-       return bt_ctf_trace_get_stream_class_by_index(
-                       (struct bt_ctf_trace *) element, i);
-}
-
-static
-int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
-{
-       return bt_ctf_stream_class_visit(object, visitor, data);
-}
-
-int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
-               bt_ctf_visitor visitor, void *data)
-{
-       int ret;
-       struct bt_ctf_visitor_object obj = {
-               .object = trace,
-               .type = BT_CTF_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_ctf_trace_get_name(trace));
-       ret = bt_ctf_visitor_helper(&obj, get_stream_class_count,
-                       get_stream_class, visit_stream_class, visitor, data);
-end:
-       return ret;
-}
-
-static
-void bt_ctf_trace_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_trace *trace = (void *) obj;
-
-       BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"",
-               trace, bt_ctf_trace_get_name(trace));
-       bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace));
-       g_free(trace);
-}
-
-BT_HIDDEN
-struct bt_ctf_trace *bt_ctf_trace_create(void)
-{
-       struct bt_ctf_trace *trace = NULL;
-       int ret;
-
-       BT_LOGD_STR("Creating CTF writer trace object.");
-       trace = g_new0(struct bt_ctf_trace, 1);
-       if (!trace) {
-               BT_LOGE_STR("Failed to allocate one CTF writer trace.");
-               goto error;
-       }
-
-       ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace),
-               bt_ctf_trace_destroy);
-       if (ret) {
-               /* bt_ctf_trace_common_initialize() logs errors */
-               goto error;
-       }
-
-       BT_LOGD("Created CTF writer trace object: addr=%p", trace);
-       return trace;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
-       return trace;
-}
-
-const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace));
-}
-
-int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace,
-               const unsigned char *uuid)
-{
-       return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid);
-}
-
-int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
-               const char *name, const char *value)
-{
-       return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace),
-               name, value);
-}
-
-int bt_ctf_trace_set_environment_field_integer(
-               struct bt_ctf_trace *trace, const char *name, int64_t value)
-{
-       return bt_ctf_trace_common_set_environment_field_integer(
-               BT_CTF_TO_COMMON(trace), name, value);
-}
-
-int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace));
-}
-
-const char *
-bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
-               uint64_t index)
-{
-       return bt_ctf_trace_common_get_environment_field_name_by_index(
-               BT_CTF_TO_COMMON(trace), index);
-}
-
-struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name(
-               struct bt_ctf_trace *trace, const char *name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name(
-               BT_CTF_TO_COMMON(trace), name));
-}
-
-BT_HIDDEN
-int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
-               struct bt_ctf_clock_class *clock_class)
-{
-       return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace),
-               (void *) clock_class);
-}
-
-BT_HIDDEN
-int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace));
-}
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-static
-int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type)
-{
-       int ret = bt_ctf_stream_class_map_clock_class(
-               BT_CTF_FROM_COMMON(stream_class),
-               BT_CTF_FROM_COMMON(packet_context_type),
-               BT_CTF_FROM_COMMON(event_header_type));
-
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
-       }
-
-       return ret;
-}
-
-int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
-               struct bt_ctf_stream_class *stream_class)
-{
-       int ret = 0;
-       struct bt_ctf_clock_class *expected_clock_class = NULL;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->clock) {
-               struct bt_ctf_clock_class *stream_clock_class =
-                       stream_class->clock->clock_class;
-
-               /*
-                * Make sure this clock was also added to the
-                * trace (potentially through its CTF writer
-                * owner).
-                */
-               size_t i;
-
-               for (i = 0; i < trace->common.clock_classes->len; i++) {
-                       if (trace->common.clock_classes->pdata[i] ==
-                                       stream_clock_class) {
-                               /* Found! */
-                               break;
-                       }
-               }
-
-               if (i == trace->common.clock_classes->len) {
-                       /* Not found */
-                       BT_LOGW("Stream class's clock's class is not part of the trace: "
-                               "clock-class-addr=%p, clock-class-name=\"%s\"",
-                               stream_clock_class,
-                               bt_ctf_clock_class_get_name(stream_clock_class));
-                       ret = -1;
-                       goto end;
-               }
-
-               if (stream_class->common.clock_class &&
-                               stream_class->common.clock_class !=
-                               stream_class->clock->clock_class) {
-                       /*
-                        * Stream class already has an expected clock
-                        * class, but it does not match its clock's
-                        * class.
-                        */
-                       BT_LOGW("Invalid parameter: stream class's clock's "
-                               "class does not match 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_ctf_stream_class_get_id(stream_class),
-                               bt_ctf_stream_class_get_name(stream_class),
-                               stream_class->common.clock_class,
-                               bt_ctf_clock_class_get_name(stream_class->common.clock_class));
-               } else if (!stream_class->common.clock_class) {
-                       /*
-                        * Set expected clock class to stream class's
-                        * clock's class.
-                        */
-                       expected_clock_class = stream_class->clock->clock_class;
-               }
-       }
-
-
-       ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace),
-               BT_CTF_TO_COMMON(stream_class),
-               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy,
-               expected_clock_class, map_clock_classes_func,
-               false);
-
-end:
-       return ret;
-}
-
-int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace));
-}
-
-struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace));
-}
-
-struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
-               struct bt_ctf_trace *trace, uint64_t id)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id(
-               BT_CTF_TO_COMMON(trace), id));
-}
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
-               struct bt_ctf_trace *trace, const char *name)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace),
-                       name));
-}
-
-static
-int append_trace_metadata(struct bt_ctf_trace *trace,
-               struct metadata_context *context)
-{
-       unsigned char *uuid = trace->common.uuid;
-       int ret = 0;
-
-       if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE ||
-                       trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) {
-               BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; "
-                       "set it with bt_ctf_trace_set_native_byte_order(): "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       g_string_append(context->string, "trace {\n");
-       g_string_append(context->string, "\tmajor = 1;\n");
-       g_string_append(context->string, "\tminor = 8;\n");
-       BT_ASSERT(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
-               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
-               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
-
-       if (trace->common.uuid_set) {
-               g_string_append_printf(context->string,
-                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
-                       uuid[0], uuid[1], uuid[2], uuid[3],
-                       uuid[4], uuid[5], uuid[6], uuid[7],
-                       uuid[8], uuid[9], uuid[10], uuid[11],
-                       uuid[12], uuid[13], uuid[14], uuid[15]);
-       }
-
-       g_string_append_printf(context->string, "\tbyte_order = %s;\n",
-               bt_ctf_get_byte_order_string(trace->common.native_byte_order));
-
-       if (trace->common.packet_header_field_type) {
-               g_string_append(context->string, "\tpacket.header := ");
-               context->current_indentation_level++;
-               g_string_assign(context->field_name, "");
-               BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) trace->common.packet_header_field_type,
-                       context);
-               if (ret) {
-                       goto end;
-               }
-               context->current_indentation_level--;
-       }
-
-       g_string_append(context->string, ";\n};\n\n");
-end:
-       return ret;
-}
-
-static
-void append_env_metadata(struct bt_ctf_trace *trace,
-               struct metadata_context *context)
-{
-       int64_t i;
-       int64_t env_size;
-
-       env_size = bt_ctf_attributes_get_count(trace->common.environment);
-       if (env_size <= 0) {
-               return;
-       }
-
-       g_string_append(context->string, "env {\n");
-
-       for (i = 0; i < env_size; i++) {
-               struct bt_ctf_private_value *env_field_value_obj = NULL;
-               const char *entry_name;
-
-               entry_name = bt_ctf_attributes_get_field_name(
-                       trace->common.environment, i);
-               env_field_value_obj = bt_ctf_attributes_borrow_field_value(
-                       trace->common.environment, i);
-
-               BT_ASSERT(entry_name);
-               BT_ASSERT(env_field_value_obj);
-
-               switch (bt_ctf_value_get_type(
-                       bt_ctf_private_value_as_value(env_field_value_obj))) {
-               case BT_CTF_VALUE_TYPE_INTEGER:
-               {
-                       int64_t int_value;
-
-                       int_value = bt_ctf_value_integer_get(
-                               bt_ctf_private_value_as_value(
-                                       env_field_value_obj));
-                       g_string_append_printf(context->string,
-                               "\t%s = %" PRId64 ";\n", entry_name,
-                               int_value);
-                       break;
-               }
-               case BT_CTF_VALUE_TYPE_STRING:
-               {
-                       const char *str_value;
-                       char *escaped_str = NULL;
-
-                       str_value = bt_ctf_value_string_get(
-                               bt_ctf_private_value_as_value(
-                                       env_field_value_obj));
-                       escaped_str = g_strescape(str_value, NULL);
-                       if (!escaped_str) {
-                               BT_LOGE("Cannot escape string: string=\"%s\"",
-                                       str_value);
-                               continue;
-                       }
-
-                       g_string_append_printf(context->string,
-                               "\t%s = \"%s\";\n", entry_name, escaped_str);
-                       free(escaped_str);
-                       break;
-               }
-               default:
-                       continue;
-               }
-       }
-
-       g_string_append(context->string, "};\n\n");
-}
-
-char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
-{
-       char *metadata = NULL;
-       struct metadata_context *context = NULL;
-       int err = 0;
-       size_t i;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               goto end;
-       }
-
-       context = g_new0(struct metadata_context, 1);
-       if (!context) {
-               BT_LOGE_STR("Failed to allocate one metadata context.");
-               goto end;
-       }
-
-       context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
-       context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
-       g_string_append(context->string, "/* CTF 1.8 */\n\n");
-       if (append_trace_metadata(trace, context)) {
-               /* append_trace_metadata() logs errors */
-               goto error;
-       }
-       append_env_metadata(trace, context);
-       g_ptr_array_foreach(trace->common.clock_classes,
-               (GFunc) bt_ctf_clock_class_serialize, context);
-
-       for (i = 0; i < trace->common.stream_classes->len; i++) {
-               /* bt_ctf_stream_class_serialize() logs details */
-               err = bt_ctf_stream_class_serialize(
-                       trace->common.stream_classes->pdata[i], context);
-               if (err) {
-                       /* bt_ctf_stream_class_serialize() logs errors */
-                       goto error;
-               }
-       }
-
-       metadata = context->string->str;
-
-error:
-       g_string_free(context->string, err ? TRUE : FALSE);
-       g_string_free(context->field_name, TRUE);
-       g_free(context);
-
-end:
-       return metadata;
-}
-
-enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
-               struct bt_ctf_trace *trace)
-{
-       return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace));
-}
-
-int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
-               enum bt_ctf_byte_order byte_order)
-{
-       return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace),
-               (int) byte_order, false);
-}
-
-struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type(
-               struct bt_ctf_trace *trace)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type(
-               BT_CTF_TO_COMMON(trace)));
-}
-
-int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace,
-               struct bt_ctf_field_type *packet_header_type)
-{
-       return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace),
-               (void *) packet_header_type);
-}
-
-const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace));
-}
diff --git a/lib/ctf-writer/utils.c b/lib/ctf-writer/utils.c
deleted file mode 100644 (file)
index fbf515b..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * utils.c
- *
- * Babeltrace CTF writer - 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.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-UTILS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <glib.h>
-#include <stdlib.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_ctf_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-writer/validation.c b/lib/ctf-writer/validation.c
deleted file mode 100644 (file)
index 97a279a..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * validation.c
- *
- * Babeltrace - CTF writer: 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 "CTF-WRITER-VALIDATION"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/resolve-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctf-writer/values-internal.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_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *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_ctf_resolve_types(environment, packet_header_type,
-               packet_context_type, event_header_type, stream_event_ctx_type,
-               event_context_type, event_payload_type,
-               BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT |
-               BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *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_ctf_resolve_types(environment, packet_header_type,
-               packet_context_type, event_header_type, stream_event_ctx_type,
-               NULL, NULL,
-               BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT |
-               BT_CTF_RESOLVE_FLAG_EVENT_HEADER |
-               BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_field_type_common_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_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *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_ctf_resolve_types(environment, packet_header_type,
-               NULL, NULL, NULL, NULL, NULL,
-               BT_CTF_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_ctf_field_type_common_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_ctf_field_type_common *type)
-{
-       int ret = 0;
-       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
-
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               ret = 1;
-               goto end;
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               int i;
-               int field_count = bt_ctf_field_type_common_get_field_count(type);
-
-               if (field_count < 0) {
-                       ret = -1;
-                       goto end;
-               }
-
-               for (i = 0; i < field_count; ++i) {
-                       struct bt_ctf_field_type_common *child_type =
-                               bt_ctf_field_type_common_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_ctf_validate_class_types(struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *event_payload_type,
-               int trace_valid, int stream_class_valid, int event_class_valid,
-               struct bt_ctf_validation_output *output,
-               enum bt_ctf_validation_flag validate_flags,
-               bt_ctf_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_CTF_VALIDATION_FLAG_TRACE;
-       }
-
-       if (stream_class_valid) {
-               output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
-       }
-
-       if (event_class_valid) {
-               output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
-       }
-
-       /* Own the type parameters */
-       bt_ctf_object_get_ref(packet_header_type);
-       bt_ctf_object_get_ref(packet_context_type);
-       bt_ctf_object_get_ref(event_header_type);
-       bt_ctf_object_get_ref(stream_event_ctx_type);
-       bt_ctf_object_get_ref(event_context_type);
-       bt_ctf_object_get_ref(event_payload_type);
-
-       /* Validate trace */
-       if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) {
-               struct bt_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common_freeze(packet_header_type_copy);
-               }
-
-skip_packet_header_type_copy:
-               /* Put original reference and move copy */
-               BT_CTF_OBJECT_MOVE_REF(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_CTF_VALIDATION_FLAG_TRACE;
-               }
-       }
-
-       /* Validate stream class */
-       if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) &&
-                       !stream_class_valid) {
-               struct bt_ctf_field_type_common *packet_context_type_copy = NULL;
-               struct bt_ctf_field_type_common *event_header_type_copy = NULL;
-               struct bt_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common_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_ctf_object_get_ref(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_ctf_field_type_common_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_ctf_object_get_ref(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_ctf_field_type_common_freeze(stream_event_ctx_type_copy);
-               }
-
-skip_stream_event_ctx_type_copy:
-               /* Put original references and move copies */
-               BT_CTF_OBJECT_MOVE_REF(packet_context_type, packet_context_type_copy);
-               BT_CTF_OBJECT_MOVE_REF(event_header_type, event_header_type_copy);
-               BT_CTF_OBJECT_MOVE_REF(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_CTF_VALIDATION_FLAG_STREAM;
-               }
-
-               goto sc_validation_done;
-
-sc_validation_error:
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type_copy);
-               ret = -1;
-               goto error;
-       }
-
-sc_validation_done:
-       /* Validate event class */
-       if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) &&
-                       !event_class_valid) {
-               struct bt_ctf_field_type_common *event_context_type_copy = NULL;
-               struct bt_ctf_field_type_common *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_ctf_object_get_ref(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_ctf_field_type_common_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_ctf_object_get_ref(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_ctf_field_type_common_freeze(event_payload_type_copy);
-               }
-
-skip_event_payload_type_copy:
-               /* Put original references and move copies */
-               BT_CTF_OBJECT_MOVE_REF(event_context_type, event_context_type_copy);
-               BT_CTF_OBJECT_MOVE_REF(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_CTF_VALIDATION_FLAG_EVENT;
-               }
-
-               goto ec_validation_done;
-
-ec_validation_error:
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(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_CTF_OBJECT_MOVE_REF(output->packet_header_type, packet_header_type);
-       BT_CTF_OBJECT_MOVE_REF(output->packet_context_type, packet_context_type);
-       BT_CTF_OBJECT_MOVE_REF(output->event_header_type, event_header_type);
-       BT_CTF_OBJECT_MOVE_REF(output->stream_event_ctx_type, stream_event_ctx_type);
-       BT_CTF_OBJECT_MOVE_REF(output->event_context_type, event_context_type);
-       BT_CTF_OBJECT_MOVE_REF(output->event_payload_type, event_payload_type);
-       return ret;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type);
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_validation_output *output,
-               enum bt_ctf_validation_flag replace_flags)
-{
-       if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) {
-               bt_ctf_field_type_common_freeze(trace->packet_header_field_type);
-               BT_CTF_OBJECT_MOVE_REF(trace->packet_header_field_type,
-                       output->packet_header_type);
-       }
-
-       if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) {
-               bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
-               bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
-               bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
-               BT_CTF_OBJECT_MOVE_REF(stream_class->packet_context_field_type,
-                       output->packet_context_type);
-               BT_CTF_OBJECT_MOVE_REF(stream_class->event_header_field_type,
-                       output->event_header_type);
-               BT_CTF_OBJECT_MOVE_REF(stream_class->event_context_field_type,
-                       output->stream_event_ctx_type);
-       }
-
-       if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) {
-               bt_ctf_field_type_common_freeze(event_class->context_field_type);
-               bt_ctf_field_type_common_freeze(event_class->payload_field_type);
-               BT_CTF_OBJECT_MOVE_REF(event_class->context_field_type, output->event_context_type);
-               BT_CTF_OBJECT_MOVE_REF(event_class->payload_field_type, output->event_payload_type);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_validation_output_put_types(
-               struct bt_ctf_validation_output *output)
-{
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->stream_event_ctx_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_payload_type);
-}
diff --git a/lib/ctf-writer/values.c b/lib/ctf-writer/values.c
deleted file mode 100644 (file)
index 7c45daf..0000000
+++ /dev/null
@@ -1,1347 +0,0 @@
-/*
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015 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 "CTF-WRITER-VALUES"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <string.h>
-#include <inttypes.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/compat/glib-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-
-#define BT_CTF_VALUE_FROM_CONCRETE(_concrete) ((struct bt_ctf_value *) (_concrete))
-#define BT_CTF_VALUE_TO_BOOL(_base) ((struct bt_ctf_value_bool *) (_base))
-#define BT_CTF_VALUE_TO_INTEGER(_base) ((struct bt_ctf_value_integer *) (_base))
-#define BT_CTF_VALUE_TO_REAL(_base) ((struct bt_ctf_value_real *) (_base))
-#define BT_CTF_VALUE_TO_STRING(_base) ((struct bt_ctf_value_string *) (_base))
-#define BT_CTF_VALUE_TO_ARRAY(_base) ((struct bt_ctf_value_array *) (_base))
-#define BT_CTF_VALUE_TO_MAP(_base) ((struct bt_ctf_value_map *) (_base))
-
-#define BT_ASSERT_PRE_VALUE_IS_TYPE(_value, _type)                     \
-       BT_ASSERT_PRE(((struct bt_ctf_value *) (_value))->type == (_type),      \
-               "Value has the wrong type ID: expected-type=%d, "       \
-               "%![value-]+v", (_type),        \
-               (_value))
-
-#define BT_ASSERT_PRE_VALUE_HOT(_value, _name)                         \
-       BT_ASSERT_PRE_HOT(((struct bt_ctf_value *) (_value)), (_name),  \
-               ": %!+v", (_value))
-
-#define BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count)            \
-       BT_ASSERT_PRE((_index) < (_count),                              \
-               "Index is out of bound: "                               \
-               "index=%" PRIu64 ", count=%u", (_index), (_count));
-
-struct bt_ctf_value {
-       struct bt_ctf_object base;
-       enum bt_ctf_value_type type;
-       bt_bool frozen;
-};
-
-static
-void bt_ctf_value_null_instance_release_func(struct bt_ctf_object *obj)
-{
-       BT_LOGW("Releasing the null value singleton: addr=%p", obj);
-}
-
-static
-struct bt_ctf_value bt_ctf_value_null_instance = {
-       .base = {
-               .is_shared = true,
-               .ref_count = 1,
-               .release_func = bt_ctf_value_null_instance_release_func,
-               .spec_release_func = NULL,
-               .parent_is_owner_listener_func = NULL,
-               .parent = NULL,
-       },
-       .type = BT_CTF_VALUE_TYPE_NULL,
-       .frozen = BT_TRUE,
-};
-
-struct bt_ctf_value *const bt_ctf_value_null = &bt_ctf_value_null_instance;
-struct bt_ctf_private_value *const bt_ctf_private_value_null =
-       (void *) &bt_ctf_value_null_instance;
-
-struct bt_ctf_value_bool {
-       struct bt_ctf_value base;
-       bt_bool value;
-};
-
-struct bt_ctf_value_integer {
-       struct bt_ctf_value base;
-       int64_t value;
-};
-
-struct bt_ctf_value_real {
-       struct bt_ctf_value base;
-       double value;
-};
-
-struct bt_ctf_value_string {
-       struct bt_ctf_value base;
-       GString *gstr;
-};
-
-struct bt_ctf_value_array {
-       struct bt_ctf_value base;
-       GPtrArray *garray;
-};
-
-struct bt_ctf_value_map {
-       struct bt_ctf_value base;
-       GHashTable *ght;
-};
-
-static
-void bt_ctf_value_destroy(struct bt_ctf_object *obj);
-
-static
-void bt_ctf_value_string_destroy(struct bt_ctf_value *object)
-{
-       g_string_free(BT_CTF_VALUE_TO_STRING(object)->gstr, TRUE);
-       BT_CTF_VALUE_TO_STRING(object)->gstr = NULL;
-}
-
-static
-void bt_ctf_value_array_destroy(struct bt_ctf_value *object)
-{
-       /*
-        * Pointer array's registered value destructor will take care
-        * of putting each contained object.
-        */
-       g_ptr_array_free(BT_CTF_VALUE_TO_ARRAY(object)->garray, TRUE);
-       BT_CTF_VALUE_TO_ARRAY(object)->garray = NULL;
-}
-
-static
-void bt_ctf_value_map_destroy(struct bt_ctf_value *object)
-{
-       /*
-        * Hash table's registered value destructor will take care of
-        * putting each contained object. Keys are GQuarks and cannot
-        * be destroyed anyway.
-        */
-       g_hash_table_destroy(BT_CTF_VALUE_TO_MAP(object)->ght);
-       BT_CTF_VALUE_TO_MAP(object)->ght = NULL;
-}
-
-static
-void (* const destroy_funcs[])(struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              NULL,
-       [BT_CTF_VALUE_TYPE_BOOL] =              NULL,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   NULL,
-       [BT_CTF_VALUE_TYPE_REAL] =              NULL,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_destroy,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_destroy,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_destroy,
-};
-
-static
-struct bt_ctf_private_value *bt_ctf_value_null_copy(const struct bt_ctf_value *null_obj)
-{
-       return (void *) bt_ctf_value_null;
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_bool_copy(const struct bt_ctf_value *bool_obj)
-{
-       return bt_ctf_private_value_bool_create_init(
-               BT_CTF_VALUE_TO_BOOL(bool_obj)->value);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_integer_copy(
-               const struct bt_ctf_value *integer_obj)
-{
-       return bt_ctf_private_value_integer_create_init(
-               BT_CTF_VALUE_TO_INTEGER(integer_obj)->value);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_real_copy(const struct bt_ctf_value *real_obj)
-{
-       return bt_ctf_private_value_real_create_init(
-               BT_CTF_VALUE_TO_REAL(real_obj)->value);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_string_copy(const struct bt_ctf_value *string_obj)
-{
-       return bt_ctf_private_value_string_create_init(
-               BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_array_copy(const struct bt_ctf_value *array_obj)
-{
-       int i;
-       int ret;
-       struct bt_ctf_private_value *copy_obj;
-       struct bt_ctf_value_array *typed_array_obj;
-
-       BT_LOGD("Copying array value: addr=%p", array_obj);
-       typed_array_obj = BT_CTF_VALUE_TO_ARRAY(array_obj);
-       copy_obj = bt_ctf_private_value_array_create();
-       if (!copy_obj) {
-               BT_LOGE_STR("Cannot create empty array value.");
-               goto end;
-       }
-
-       for (i = 0; i < typed_array_obj->garray->len; ++i) {
-               struct bt_ctf_private_value *element_obj_copy = NULL;
-               struct bt_ctf_value *element_obj =
-                       bt_ctf_value_array_borrow_element_by_index(
-                               array_obj, i);
-
-               BT_ASSERT(element_obj);
-               BT_LOGD("Copying array value's element: element-addr=%p, "
-                       "index=%d", element_obj, i);
-               ret = bt_ctf_value_copy(&element_obj_copy, element_obj);
-               if (ret) {
-                       BT_LOGE("Cannot copy array value's element: "
-                               "array-addr=%p, index=%d",
-                               array_obj, i);
-                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
-                       goto end;
-               }
-
-               BT_ASSERT(element_obj_copy);
-               ret = bt_ctf_private_value_array_append_element(copy_obj,
-                       (void *) element_obj_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
-               if (ret) {
-                       BT_LOGE("Cannot append to array value: addr=%p",
-                               array_obj);
-                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
-                       goto end;
-               }
-       }
-
-       BT_LOGD("Copied array value: original-addr=%p, copy-addr=%p",
-               array_obj, copy_obj);
-
-end:
-       return copy_obj;
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_map_copy(const struct bt_ctf_value *map_obj)
-{
-       int ret;
-       GHashTableIter iter;
-       gpointer key, element_obj;
-       struct bt_ctf_private_value *copy_obj;
-       struct bt_ctf_private_value *element_obj_copy = NULL;
-       struct bt_ctf_value_map *typed_map_obj;
-
-       BT_LOGD("Copying map value: addr=%p", map_obj);
-       typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
-       copy_obj = bt_ctf_private_value_map_create();
-       if (!copy_obj) {
-               goto end;
-       }
-
-       g_hash_table_iter_init(&iter, typed_map_obj->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
-               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
-
-               BT_ASSERT(key_str);
-               BT_LOGD("Copying map value's element: element-addr=%p, "
-                       "key=\"%s\"", element_obj, key_str);
-               ret = bt_ctf_value_copy(&element_obj_copy, element_obj);
-               if (ret) {
-                       BT_LOGE("Cannot copy map value's element: "
-                               "map-addr=%p, key=\"%s\"",
-                               map_obj, key_str);
-                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
-                       goto end;
-               }
-
-               BT_ASSERT(element_obj_copy);
-               ret = bt_ctf_private_value_map_insert_entry(copy_obj, key_str,
-                       (void *) element_obj_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
-               if (ret) {
-                       BT_LOGE("Cannot insert into map value: addr=%p, key=\"%s\"",
-                               map_obj, key_str);
-                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
-                       goto end;
-               }
-       }
-
-       BT_LOGD("Copied map value: addr=%p", map_obj);
-
-end:
-       return copy_obj;
-}
-
-static
-struct bt_ctf_private_value *(* const copy_funcs[])(const struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_copy,
-       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_copy,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_copy,
-       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_copy,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_copy,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_copy,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_copy,
-};
-
-static
-bt_bool bt_ctf_value_null_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       /*
-        * Always BT_TRUE since bt_ctf_value_compare() already checks if both
-        * object_a and object_b have the same type, and in the case of
-        * null value objects, they're always the same if it is so.
-        */
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_bool_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (BT_CTF_VALUE_TO_BOOL(object_a)->value !=
-                       BT_CTF_VALUE_TO_BOOL(object_b)->value) {
-               BT_LOGV("Boolean value objects are different: "
-                       "bool-a-val=%d, bool-b-val=%d",
-                       BT_CTF_VALUE_TO_BOOL(object_a)->value,
-                       BT_CTF_VALUE_TO_BOOL(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_integer_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (BT_CTF_VALUE_TO_INTEGER(object_a)->value !=
-                       BT_CTF_VALUE_TO_INTEGER(object_b)->value) {
-               BT_LOGV("Integer value objects are different: "
-                       "int-a-val=%" PRId64 ", int-b-val=%" PRId64,
-                       BT_CTF_VALUE_TO_INTEGER(object_a)->value,
-                       BT_CTF_VALUE_TO_INTEGER(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_real_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (BT_CTF_VALUE_TO_REAL(object_a)->value !=
-                       BT_CTF_VALUE_TO_REAL(object_b)->value) {
-               BT_LOGV("Real number value objects are different: "
-                       "real-a-val=%f, real-b-val=%f",
-                       BT_CTF_VALUE_TO_REAL(object_a)->value,
-                       BT_CTF_VALUE_TO_REAL(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_string_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (strcmp(BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
-                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str) != 0) {
-               BT_LOGV("String value objects are different: "
-                       "string-a-val=\"%s\", string-b-val=\"%s\"",
-                       BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
-                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_array_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       int i;
-       bt_bool ret = BT_TRUE;
-       const struct bt_ctf_value_array *array_obj_a =
-               BT_CTF_VALUE_TO_ARRAY(object_a);
-
-       if (bt_ctf_value_array_get_size(object_a) !=
-                       bt_ctf_value_array_get_size(object_b)) {
-               BT_LOGV("Array values are different: size mismatch "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
-                       object_a, object_b,
-                       bt_ctf_value_array_get_size(object_a),
-                       bt_ctf_value_array_get_size(object_b));
-               ret = BT_FALSE;
-               goto end;
-       }
-
-       for (i = 0; i < array_obj_a->garray->len; ++i) {
-               struct bt_ctf_value *element_obj_a;
-               struct bt_ctf_value *element_obj_b;
-
-               element_obj_a = bt_ctf_value_array_borrow_element_by_index(
-                       object_a, i);
-               element_obj_b = bt_ctf_value_array_borrow_element_by_index(
-                       object_b, i);
-
-               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
-                       BT_LOGV("Array values's elements are different: "
-                               "value-a-addr=%p, value-b-addr=%p, index=%d",
-                               element_obj_a, element_obj_b, i);
-                       ret = BT_FALSE;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool bt_ctf_value_map_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       bt_bool ret = BT_TRUE;
-       GHashTableIter iter;
-       gpointer key, element_obj_a;
-       const struct bt_ctf_value_map *map_obj_a = BT_CTF_VALUE_TO_MAP(object_a);
-
-       if (bt_ctf_value_map_get_size(object_a) !=
-                       bt_ctf_value_map_get_size(object_b)) {
-               BT_LOGV("Map values are different: size mismatch "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
-                       object_a, object_b,
-                       bt_ctf_value_map_get_size(object_a),
-                       bt_ctf_value_map_get_size(object_b));
-               ret = BT_FALSE;
-               goto end;
-       }
-
-       g_hash_table_iter_init(&iter, map_obj_a->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
-               struct bt_ctf_value *element_obj_b;
-               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
-
-               element_obj_b = bt_ctf_value_map_borrow_entry_value(object_b,
-                       key_str);
-
-               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
-                       BT_LOGV("Map values's elements are different: "
-                               "value-a-addr=%p, value-b-addr=%p, key=\"%s\"",
-                               element_obj_a, element_obj_b, key_str);
-                       ret = BT_FALSE;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool (* const compare_funcs[])(const struct bt_ctf_value *,
-               const struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_compare,
-       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_compare,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_compare,
-       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_compare,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_compare,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_compare,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_compare,
-};
-
-static
-void bt_ctf_value_null_freeze(struct bt_ctf_value *object)
-{
-}
-
-static
-void bt_ctf_value_generic_freeze(struct bt_ctf_value *object)
-{
-       object->frozen = BT_TRUE;
-}
-
-static
-void bt_ctf_value_array_freeze(struct bt_ctf_value *object)
-{
-       int i;
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(object);
-
-       for (i = 0; i < typed_array_obj->garray->len; ++i) {
-               bt_ctf_value_freeze(g_ptr_array_index(typed_array_obj->garray, i));
-       }
-
-       bt_ctf_value_generic_freeze(object);
-}
-
-static
-void bt_ctf_value_map_freeze(struct bt_ctf_value *object)
-{
-       GHashTableIter iter;
-       gpointer key, element_obj;
-       const struct bt_ctf_value_map *map_obj = BT_CTF_VALUE_TO_MAP(object);
-
-       g_hash_table_iter_init(&iter, map_obj->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
-               bt_ctf_value_freeze(element_obj);
-       }
-
-       bt_ctf_value_generic_freeze(object);
-}
-
-static
-void (* const freeze_funcs[])(struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_freeze,
-       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_freeze,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_freeze,
-};
-
-static
-void bt_ctf_value_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_value *value;
-
-       value = container_of(obj, struct bt_ctf_value, base);
-       BT_LOGD("Destroying value: addr=%p", value);
-
-       if (bt_ctf_value_is_null(value)) {
-               BT_LOGD_STR("Not destroying the null value singleton.");
-               return;
-       }
-
-       if (destroy_funcs[value->type]) {
-               destroy_funcs[value->type](value);
-       }
-
-       g_free(value);
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object)
-{
-       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
-
-       BT_ASSERT(object);
-
-       if (object->frozen) {
-               goto end;
-       }
-
-       BT_LOGD("Freezing value: addr=%p", object);
-       freeze_funcs[object->type](object);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object)
-{
-       BT_ASSERT_PRE_NON_NULL(object, "Value object");
-       return object->type;
-}
-
-static
-struct bt_ctf_value bt_ctf_value_create_base(enum bt_ctf_value_type type)
-{
-       struct bt_ctf_value value;
-
-       value.type = type;
-       value.frozen = BT_FALSE;
-       bt_ctf_object_init_shared(&value.base, bt_ctf_value_destroy);
-       return value;
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val)
-{
-       struct bt_ctf_value_bool *bool_obj;
-
-       BT_LOGD("Creating boolean value object: val=%d", val);
-       bool_obj = g_new0(struct bt_ctf_value_bool, 1);
-       if (!bool_obj) {
-               BT_LOGE_STR("Failed to allocate one boolean value object.");
-               goto end;
-       }
-
-       bool_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_BOOL);
-       bool_obj->value = val;
-       BT_LOGD("Created boolean value object: addr=%p", bool_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(bool_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void)
-{
-       return bt_ctf_private_value_bool_create_init(BT_FALSE);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(int64_t val)
-{
-       struct bt_ctf_value_integer *integer_obj;
-
-       BT_LOGD("Creating integer value object: val=%" PRId64, val);
-       integer_obj = g_new0(struct bt_ctf_value_integer, 1);
-       if (!integer_obj) {
-               BT_LOGE_STR("Failed to allocate one integer value object.");
-               goto end;
-       }
-
-       integer_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_INTEGER);
-       integer_obj->value = val;
-       BT_LOGD("Created integer value object: addr=%p",
-               integer_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(integer_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void)
-{
-       return bt_ctf_private_value_integer_create_init(0);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val)
-{
-       struct bt_ctf_value_real *real_obj;
-
-       BT_LOGD("Creating real number value object: val=%f", val);
-       real_obj = g_new0(struct bt_ctf_value_real, 1);
-       if (!real_obj) {
-               BT_LOGE_STR("Failed to allocate one real number value object.");
-               goto end;
-       }
-
-       real_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_REAL);
-       real_obj->value = val;
-       BT_LOGD("Created real number value object: addr=%p",
-               real_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(real_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_real_create(void)
-{
-       return bt_ctf_private_value_real_create_init(0.);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(const char *val)
-{
-       struct bt_ctf_value_string *string_obj = NULL;
-
-       if (!val) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               goto end;
-       }
-
-       BT_LOGD("Creating string value object: val-len=%zu", strlen(val));
-       string_obj = g_new0(struct bt_ctf_value_string, 1);
-       if (!string_obj) {
-               BT_LOGE_STR("Failed to allocate one string object.");
-               goto end;
-       }
-
-       string_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_STRING);
-       string_obj->gstr = g_string_new(val);
-       if (!string_obj->gstr) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               g_free(string_obj);
-               string_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created string value object: addr=%p",
-               string_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(string_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_string_create(void)
-{
-       return bt_ctf_private_value_string_create_init("");
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_array_create(void)
-{
-       struct bt_ctf_value_array *array_obj;
-
-       BT_LOGD_STR("Creating empty array value object.");
-       array_obj = g_new0(struct bt_ctf_value_array, 1);
-       if (!array_obj) {
-               BT_LOGE_STR("Failed to allocate one array object.");
-               goto end;
-       }
-
-       array_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_ARRAY);
-       array_obj->garray = bt_g_ptr_array_new_full(0,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       if (!array_obj->garray) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               g_free(array_obj);
-               array_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created array value object: addr=%p",
-               array_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(array_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_map_create(void)
-{
-       struct bt_ctf_value_map *map_obj;
-
-       BT_LOGD_STR("Creating empty map value object.");
-       map_obj = g_new0(struct bt_ctf_value_map, 1);
-       if (!map_obj) {
-               BT_LOGE_STR("Failed to allocate one map object.");
-               goto end;
-       }
-
-       map_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_MAP);
-       map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-               NULL, (GDestroyNotify) bt_ctf_object_put_ref);
-       if (!map_obj->ght) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               g_free(map_obj);
-               map_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created map value object: addr=%p",
-               map_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(map_obj);
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
-       return BT_CTF_VALUE_TO_BOOL(bool_obj)->value;
-}
-
-BT_HIDDEN
-void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj, bt_bool val)
-{
-       BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
-       BT_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object");
-       BT_CTF_VALUE_TO_BOOL(bool_obj)->value = val;
-       BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d",
-               bool_obj, val);
-}
-
-BT_HIDDEN
-int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
-       return BT_CTF_VALUE_TO_INTEGER(integer_obj)->value;
-}
-
-BT_HIDDEN
-void bt_ctf_private_value_integer_set(struct bt_ctf_private_value *integer_obj,
-               int64_t val)
-{
-       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
-       BT_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object");
-       BT_CTF_VALUE_TO_INTEGER(integer_obj)->value = val;
-       BT_LOGV("Set integer value's raw value: value-addr=%p, value=%" PRId64,
-               integer_obj, val);
-}
-
-BT_HIDDEN
-double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
-       return BT_CTF_VALUE_TO_REAL(real_obj)->value;
-}
-
-BT_HIDDEN
-void bt_ctf_private_value_real_set(struct bt_ctf_private_value *real_obj, double val)
-{
-       BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
-       BT_ASSERT_PRE_VALUE_HOT(real_obj, "Value object");
-       BT_CTF_VALUE_TO_REAL(real_obj)->value = val;
-       BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f",
-               real_obj, val);
-}
-
-BT_HIDDEN
-const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
-       return BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_string_set(
-               struct bt_ctf_private_value *string_obj, const char *val)
-{
-       BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
-       BT_ASSERT_PRE_VALUE_HOT(string_obj, "Value object");
-       g_string_assign(BT_CTF_VALUE_TO_STRING(string_obj)->gstr, val);
-       BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p",
-               string_obj, val);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       return (uint64_t) BT_CTF_VALUE_TO_ARRAY(array_obj)->garray->len;
-}
-
-BT_HIDDEN
-struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index(
-               const struct bt_ctf_value *array_obj,
-               uint64_t index)
-{
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(array_obj);
-
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
-               typed_array_obj->garray->len);
-       return g_ptr_array_index(typed_array_obj->garray, index);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index(
-               const struct bt_ctf_private_value *array_obj,
-               uint64_t index)
-{
-       return (void *) bt_ctf_value_array_borrow_element_by_index(
-               (void *) array_obj, index);
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_element(
-               struct bt_ctf_private_value *array_obj,
-               struct bt_ctf_value *element_obj)
-{
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(array_obj);
-
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
-       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
-       g_ptr_array_add(typed_array_obj->garray, element_obj);
-       bt_ctf_object_get_ref(element_obj);
-       BT_LOGV("Appended element to array value: array-value-addr=%p, "
-               "element-value-addr=%p, new-size=%u",
-               array_obj, element_obj, typed_array_obj->garray->len);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element(
-               struct bt_ctf_private_value *array_obj, bt_bool val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *bool_obj = NULL;
-
-       bool_obj = bt_ctf_private_value_bool_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) bool_obj);
-       bt_ctf_object_put_ref(bool_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element(
-               struct bt_ctf_private_value *array_obj, int64_t val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *integer_obj = NULL;
-
-       integer_obj = bt_ctf_private_value_integer_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) integer_obj);
-       bt_ctf_object_put_ref(integer_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element(
-               struct bt_ctf_private_value *array_obj, double val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *real_obj = NULL;
-
-       real_obj = bt_ctf_private_value_real_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) real_obj);
-       bt_ctf_object_put_ref(real_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element(
-               struct bt_ctf_private_value *array_obj, const char *val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *string_obj = NULL;
-
-       string_obj = bt_ctf_private_value_string_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) string_obj);
-       bt_ctf_object_put_ref(string_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element(
-               struct bt_ctf_private_value *array_obj)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *empty_array_obj = NULL;
-
-       empty_array_obj = bt_ctf_private_value_array_create();
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) empty_array_obj);
-       bt_ctf_object_put_ref(empty_array_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element(
-               struct bt_ctf_private_value *array_obj)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *map_obj = NULL;
-
-       map_obj = bt_ctf_private_value_map_create();
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) map_obj);
-       bt_ctf_object_put_ref(map_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index(
-               struct bt_ctf_private_value *array_obj, uint64_t index,
-               struct bt_ctf_value *element_obj)
-{
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(array_obj);
-
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
-       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
-       BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
-               typed_array_obj->garray->len);
-       bt_ctf_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index));
-       g_ptr_array_index(typed_array_obj->garray, index) = element_obj;
-       bt_ctf_object_get_ref(element_obj);
-       BT_LOGV("Set array value's element: array-value-addr=%p, "
-               "index=%" PRIu64 ", element-value-addr=%p",
-               array_obj, index, element_obj);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       return (uint64_t) g_hash_table_size(BT_CTF_VALUE_TO_MAP(map_obj)->ght);
-}
-
-BT_HIDDEN
-struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(const struct bt_ctf_value *map_obj,
-               const char *key)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       return g_hash_table_lookup(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)));
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value(
-               const struct bt_ctf_private_value *map_obj, const char *key)
-{
-       return (void *) bt_ctf_value_map_borrow_entry_value((void *) map_obj, key);
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj, const char *key)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       return bt_g_hash_table_contains(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)));
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry(
-               struct bt_ctf_private_value *map_obj,
-               const char *key, struct bt_ctf_value *element_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Map value object");
-       BT_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       BT_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object");
-       g_hash_table_insert(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)), element_obj);
-       bt_ctf_object_get_ref(element_obj);
-       BT_LOGV("Inserted value into map value: map-value-addr=%p, "
-               "key=\"%s\", element-value-addr=%p",
-               map_obj, key, element_obj);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, bt_bool val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *bool_obj = NULL;
-
-       bool_obj = bt_ctf_private_value_bool_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) bool_obj);
-       bt_ctf_object_put_ref(bool_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, int64_t val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *integer_obj = NULL;
-
-       integer_obj = bt_ctf_private_value_integer_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) integer_obj);
-       bt_ctf_object_put_ref(integer_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, double val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *real_obj = NULL;
-
-       real_obj = bt_ctf_private_value_real_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) real_obj);
-       bt_ctf_object_put_ref(real_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry(
-               struct bt_ctf_private_value *map_obj, const char *key,
-               const char *val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *string_obj = NULL;
-
-       string_obj = bt_ctf_private_value_string_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) string_obj);
-       bt_ctf_object_put_ref(string_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry(
-               struct bt_ctf_private_value *map_obj, const char *key)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *array_obj = NULL;
-
-       array_obj = bt_ctf_private_value_array_create();
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) array_obj);
-       bt_ctf_object_put_ref(array_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry(
-               struct bt_ctf_private_value *map_obj, const char *key)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *empty_map_obj = NULL;
-
-       empty_map_obj = bt_ctf_private_value_map_create();
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) empty_map_obj);
-       bt_ctf_object_put_ref(empty_map_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(const struct bt_ctf_value *map_obj,
-               bt_ctf_value_map_foreach_entry_cb cb, void *data)
-{
-       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
-       gpointer key, element_obj;
-       GHashTableIter iter;
-       struct bt_ctf_value_map *typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
-
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_NON_NULL(cb, "Callback");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       g_hash_table_iter_init(&iter, typed_map_obj->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
-               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
-
-               if (!cb(key_str, element_obj, data)) {
-                       BT_LOGV("User canceled the loop: key=\"%s\", "
-                               "value-addr=%p, data=%p",
-                               key_str, element_obj, data);
-                       ret = BT_CTF_VALUE_STATUS_CANCELED;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry(
-               const struct bt_ctf_private_value *map_obj,
-               bt_ctf_private_value_map_foreach_entry_cb cb, void *data)
-{
-       return bt_ctf_value_map_foreach_entry((void *) map_obj,
-               (bt_ctf_value_map_foreach_entry_cb) cb, data);
-}
-
-struct extend_map_element_data {
-       struct bt_ctf_private_value *extended_obj;
-       enum bt_ctf_value_status status;
-};
-
-static
-bt_bool extend_map_element(const char *key,
-               struct bt_ctf_value *extension_obj_elem, void *data)
-{
-       bt_bool ret = BT_TRUE;
-       struct extend_map_element_data *extend_data = data;
-       struct bt_ctf_private_value *extension_obj_elem_copy = NULL;
-
-       /* Copy object which is to replace the current one */
-       extend_data->status = bt_ctf_value_copy(&extension_obj_elem_copy,
-               extension_obj_elem);
-       if (extend_data->status) {
-               BT_LOGE("Cannot copy map element: addr=%p",
-                       extension_obj_elem);
-               goto error;
-       }
-
-       BT_ASSERT(extension_obj_elem_copy);
-
-       /* Replace in extended object */
-       extend_data->status = bt_ctf_private_value_map_insert_entry(
-               extend_data->extended_obj, key,
-               (void *) extension_obj_elem_copy);
-       if (extend_data->status) {
-               BT_LOGE("Cannot replace value in extended value: key=\"%s\", "
-                       "extended-value-addr=%p, element-value-addr=%p",
-                       key, extend_data->extended_obj,
-                       extension_obj_elem_copy);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_ASSERT(extend_data->status != BT_CTF_VALUE_STATUS_OK);
-       ret = BT_FALSE;
-
-end:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_map_extend(
-               struct bt_ctf_private_value **extended_map_obj,
-               const struct bt_ctf_value *base_map_obj,
-               const struct bt_ctf_value *extension_obj)
-{
-       struct extend_map_element_data extend_data = {
-               .extended_obj = NULL,
-               .status = BT_CTF_VALUE_STATUS_OK,
-       };
-
-       BT_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object");
-       BT_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object");
-       BT_ASSERT_PRE_NON_NULL(extended_map_obj,
-               "Extended value object (output)");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_CTF_VALUE_TYPE_MAP);
-       BT_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_CTF_VALUE_TYPE_MAP);
-       BT_LOGD("Extending map value: base-value-addr=%p, extension-value-addr=%p",
-               base_map_obj, extension_obj);
-       *extended_map_obj = NULL;
-
-       /* Create copy of base map object to start with */
-       extend_data.status = bt_ctf_value_copy(extended_map_obj, base_map_obj);
-       if (extend_data.status) {
-               BT_LOGE("Cannot copy base value: base-value-addr=%p",
-                       base_map_obj);
-               goto error;
-       }
-
-       BT_ASSERT(extended_map_obj);
-
-       /*
-        * For each key in the extension map object, replace this key
-        * in the copied map object.
-        */
-       extend_data.extended_obj = *extended_map_obj;
-
-       if (bt_ctf_value_map_foreach_entry(extension_obj, extend_map_element,
-                       &extend_data)) {
-               BT_LOGE("Cannot iterate on the extension object's elements: "
-                       "extension-value-addr=%p", extension_obj);
-               goto error;
-       }
-
-       if (extend_data.status) {
-               BT_LOGE("Failed to successfully iterate on the extension object's elements: "
-                       "extension-value-addr=%p", extension_obj);
-               goto error;
-       }
-
-       BT_LOGD("Extended map value: extended-value-addr=%p",
-               *extended_map_obj);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(*extended_map_obj);
-       *extended_map_obj = NULL;
-
-end:
-       return extend_data.status;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy_obj,
-               const struct bt_ctf_value *object)
-{
-       enum bt_ctf_value_status status = BT_CTF_VALUE_STATUS_OK;
-
-       BT_ASSERT_PRE_NON_NULL(object, "Value object");
-       BT_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)");
-       BT_LOGD("Copying value object: addr=%p", object);
-       *copy_obj = copy_funcs[object->type](object);
-       if (*copy_obj) {
-               BT_LOGD("Copied value object: copy-value-addr=%p",
-                       copy_obj);
-       } else {
-               status = BT_CTF_VALUE_STATUS_NOMEM;
-               *copy_obj = NULL;
-               BT_LOGE_STR("Failed to copy value object.");
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a,
-       const struct bt_ctf_value *object_b)
-{
-       bt_bool ret = BT_FALSE;
-
-       BT_ASSERT_PRE_NON_NULL(object_a, "Value object A");
-       BT_ASSERT_PRE_NON_NULL(object_b, "Value object B");
-
-       if (object_a->type != object_b->type) {
-               BT_LOGV("Values are different: type mismatch: "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-type=%d, value-b-type=%d",
-                       object_a, object_b, object_a->type, object_b->type);
-               goto end;
-       }
-
-       ret = compare_funcs[object_a->type](object_a, object_b);
-
-end:
-       return ret;
-}
diff --git a/lib/ctf-writer/visitor.c b/lib/ctf-writer/visitor.c
deleted file mode 100644 (file)
index 707cc7a..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * visitor.c
- *
- * Babeltrace CTF writer - 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 <babeltrace2/ctf-writer/visitor-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-
-BT_HIDDEN
-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,
-               bt_ctf_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_CTF_OBJECT_PUT_REF_AND_RESET(child);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       return ret;
-}
-
-enum bt_ctf_visitor_object_type bt_ctf_visitor_object_get_type(
-               struct bt_ctf_visitor_object *object)
-{
-       enum bt_ctf_visitor_object_type ret = BT_CTF_VISITOR_OBJECT_TYPE_UNKNOWN;
-
-       if (!object) {
-               goto end;
-       }
-
-       ret = object->type;
-end:
-       return ret;
-}
-
-void *bt_ctf_visitor_object_get_object(struct bt_ctf_visitor_object *object)
-{
-       void *ret = NULL;
-
-       if (!object) {
-               goto end;
-       }
-
-       ret = object->object;
-end:
-       return ret;
-}
diff --git a/lib/ctf-writer/writer.c b/lib/ctf-writer/writer.c
deleted file mode 100644 (file)
index e0215d3..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * writer.c
- *
- * Babeltrace CTF Writer
- *
- * Copyright 2013, 2014 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.
- */
-
-#define BT_LOG_TAG "CTF-WRITER"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-static
-void bt_ctf_writer_destroy(struct bt_ctf_object *obj);
-
-static
-int init_trace_packet_header(struct bt_ctf_trace *trace)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *_uint32_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
-       struct bt_ctf_field_type *_uint8_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
-       struct bt_ctf_field_type *trace_packet_header_type =
-               bt_ctf_field_type_structure_create();
-       struct bt_ctf_field_type *uuid_array_type =
-               bt_ctf_field_type_array_create(_uint8_t, 16);
-
-       if (!trace_packet_header_type || !uuid_array_type) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
-               _uint32_t, "magic");
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
-               uuid_array_type, "uuid");
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
-               _uint32_t, "stream_id");
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_set_packet_header_field_type(trace,
-               trace_packet_header_type);
-       if (ret) {
-               goto end;
-       }
-end:
-       bt_ctf_object_put_ref(uuid_array_type);
-       bt_ctf_object_put_ref(_uint32_t);
-       bt_ctf_object_put_ref(_uint8_t);
-       bt_ctf_object_put_ref(trace_packet_header_type);
-       return ret;
-}
-
-struct bt_ctf_writer *bt_ctf_writer_create(const char *path)
-{
-       int ret;
-       struct bt_ctf_writer *writer = NULL;
-       unsigned char uuid[16];
-       char *metadata_path = NULL;
-
-       if (!path) {
-               goto error;
-       }
-
-       writer = g_new0(struct bt_ctf_writer, 1);
-       if (!writer) {
-               goto error;
-       }
-
-       metadata_path = g_build_filename(path, "metadata", NULL);
-
-       bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy);
-       writer->path = g_string_new(path);
-       if (!writer->path) {
-               goto error_destroy;
-       }
-
-       writer->trace = bt_ctf_trace_create();
-       if (!writer->trace) {
-               goto error_destroy;
-       }
-
-       ret = init_trace_packet_header(writer->trace);
-       if (ret) {
-               goto error_destroy;
-       }
-
-       /* Generate a UUID for this writer's trace */
-       ret = bt_uuid_generate(uuid);
-       if (ret) {
-               BT_LOGE_STR("Cannot generate UUID for CTF writer's trace.");
-               goto error_destroy;
-       }
-
-       ret = bt_ctf_trace_set_uuid(writer->trace, uuid);
-       if (ret) {
-               goto error_destroy;
-       }
-
-       bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base);
-       bt_ctf_object_put_ref(writer->trace);
-
-       /* Default to little-endian */
-       ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE);
-       BT_ASSERT(ret == 0);
-
-       /* Create trace directory if necessary and open a metadata file */
-       if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) {
-               perror("g_mkdir_with_parents");
-               goto error_destroy;
-       }
-
-       writer->metadata_fd = open(metadata_path,
-               O_WRONLY | O_CREAT | O_TRUNC,
-               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-       if (writer->metadata_fd < 0) {
-               perror("open");
-               goto error_destroy;
-       }
-
-       g_free(metadata_path);
-       return writer;
-
-error_destroy:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(writer);
-error:
-       g_free(metadata_path);
-       return writer;
-}
-
-void bt_ctf_writer_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_writer *writer;
-
-       writer = container_of(obj, struct bt_ctf_writer, base);
-       bt_ctf_writer_flush_metadata(writer);
-       if (writer->path) {
-               g_string_free(writer->path, TRUE);
-       }
-
-       if (writer->metadata_fd > 0) {
-               if (close(writer->metadata_fd)) {
-                       perror("close");
-               }
-       }
-
-       bt_ctf_object_try_spec_release(&writer->trace->common.base);
-       g_free(writer);
-}
-
-struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer)
-{
-       struct bt_ctf_trace *trace = NULL;
-
-       if (!writer) {
-               goto end;
-       }
-
-       trace = writer->trace;
-       bt_ctf_object_get_ref(trace);
-end:
-       return trace;
-}
-
-struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer,
-               struct bt_ctf_stream_class *stream_class)
-{
-       struct bt_ctf_stream *stream = NULL;
-       int stream_class_count;
-       bt_bool stream_class_found = BT_FALSE;
-       int i;
-
-       if (!writer || !stream_class) {
-               goto error;
-       }
-
-       /* Make sure the stream class is part of the writer's trace */
-       stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace);
-       if (stream_class_count < 0) {
-               goto error;
-       }
-
-       for (i = 0; i < stream_class_count; i++) {
-               struct bt_ctf_stream_class *existing_stream_class =
-                       bt_ctf_trace_get_stream_class_by_index(
-                               writer->trace, i);
-
-               if (existing_stream_class == stream_class) {
-                       stream_class_found = BT_TRUE;
-               }
-
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class);
-
-               if (stream_class_found) {
-                       break;
-               }
-       }
-
-       if (!stream_class_found) {
-               int ret = bt_ctf_trace_add_stream_class(writer->trace,
-                       stream_class);
-
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL);
-       if (!stream) {
-               goto error;
-       }
-
-       return stream;
-
-error:
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
-       return stream;
-}
-
-int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer,
-               const char *name,
-               const char *value)
-{
-       int ret = -1;
-
-       if (!writer || !name || !value) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_set_environment_field_string(writer->trace,
-               name, value);
-end:
-       return ret;
-}
-
-int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer,
-               const char *name, int64_t value)
-{
-       int ret = -1;
-
-       if (!writer || !name) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name,
-               value);
-end:
-       return ret;
-}
-
-int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer,
-               struct bt_ctf_clock *clock)
-{
-       int ret = -1;
-
-       if (!writer || !clock) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class);
-end:
-       return ret;
-}
-
-char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer)
-{
-       char *metadata_string = NULL;
-
-       if (!writer) {
-               goto end;
-       }
-
-       metadata_string = bt_ctf_trace_get_metadata_string(
-               writer->trace);
-end:
-       return metadata_string;
-}
-
-void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer)
-{
-       int ret;
-       char *metadata_string = NULL;
-
-       if (!writer) {
-               goto end;
-       }
-
-       metadata_string = bt_ctf_trace_get_metadata_string(
-               writer->trace);
-       if (!metadata_string) {
-               goto end;
-       }
-
-       if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) {
-               perror("lseek");
-               goto end;
-       }
-
-       if (ftruncate(writer->metadata_fd, 0)) {
-               perror("ftruncate");
-               goto end;
-       }
-
-       ret = write(writer->metadata_fd, metadata_string,
-               strlen(metadata_string));
-       if (ret < 0) {
-               perror("write");
-               goto end;
-       }
-end:
-       g_free(metadata_string);
-}
-
-int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer,
-               enum bt_ctf_byte_order byte_order)
-{
-       int ret = 0;
-
-       if (!writer || writer->frozen) {
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
-               if (BYTE_ORDER == LITTLE_ENDIAN) {
-                       byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
-               } else {
-                       byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
-               }
-       }
-
-       ret = bt_ctf_trace_set_native_byte_order(writer->trace,
-               byte_order);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_writer_freeze(struct bt_ctf_writer *writer)
-{
-       writer->frozen = 1;
-}
-
-static
-const unsigned int field_type_aliases_alignments[] = {
-       [FIELD_TYPE_ALIAS_UINT5_T] = 1,
-       [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
-       [FIELD_TYPE_ALIAS_UINT27_T] = 1,
-       [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
-};
-
-static
-const unsigned int field_type_aliases_sizes[] = {
-       [FIELD_TYPE_ALIAS_UINT5_T] = 5,
-       [FIELD_TYPE_ALIAS_UINT8_T] = 8,
-       [FIELD_TYPE_ALIAS_UINT16_T] = 16,
-       [FIELD_TYPE_ALIAS_UINT27_T] = 27,
-       [FIELD_TYPE_ALIAS_UINT32_T] = 32,
-       [FIELD_TYPE_ALIAS_UINT64_T] = 64,
-};
-
-BT_HIDDEN
-struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
-{
-       int ret;
-       unsigned int alignment, size;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (alias >= NR_FIELD_TYPE_ALIAS) {
-               goto end;
-       }
-
-       alignment = field_type_aliases_alignments[alias];
-       size = field_type_aliases_sizes[alias];
-       field_type = bt_ctf_field_type_integer_create(size);
-       ret = bt_ctf_field_type_set_alignment(field_type, alignment);
-       if (ret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type);
-       }
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order)
-{
-       const char *string;
-
-       switch (byte_order) {
-       case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
-               string = "le";
-               break;
-       case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
-               string = "be";
-               break;
-       case BT_CTF_BYTE_ORDER_NATIVE:
-               string = "native";
-               break;
-       default:
-               abort();
-       }
-
-       return string;
-}
index 4ef581b29a18a11f96ed0e0752ff8bced7f7d912..9cb75b00039ca013824433d2346beca064e8475b 100644 (file)
@@ -7,21 +7,23 @@ LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 libtestcommon_la_SOURCES = common.c common.h
 noinst_LTLIBRARIES = libtestcommon.la
 
-# -Wl,--no-as-needed is needed for recent gold linker who seems to think
-# it knows better and considers libraries with constructors having
-# side-effects as dead code.
-COMMON_TEST_LDADD = $(LIBTAP) $(builddir)/libtestcommon.la \
-       $(top_builddir)/lib/libbabeltrace2.la
+COMMON_TEST_LDADD = $(LIBTAP) $(builddir)/libtestcommon.la
 
 test_bitfield_LDADD = $(LIBTAP) $(builddir)/libtestcommon.la
 
-test_ctf_writer_LDADD = $(COMMON_TEST_LDADD)
+test_ctf_writer_LDADD = \
+       $(COMMON_TEST_LDADD) \
+       $(top_builddir)/ctf-writer/libbabeltrace2-ctf-writer.la
 
-test_bt_values_LDADD = $(COMMON_TEST_LDADD)
+test_bt_values_LDADD = $(COMMON_TEST_LDADD) \
+       $(top_builddir)/lib/libbabeltrace2.la
 
-test_trace_ir_ref_LDADD = $(COMMON_TEST_LDADD)
+test_trace_ir_ref_LDADD = $(COMMON_TEST_LDADD) \
+       $(top_builddir)/lib/libbabeltrace2.la \
+       $(top_builddir)/ctf-writer/libbabeltrace2-ctf-writer.la
 
-test_graph_topo_LDADD = $(COMMON_TEST_LDADD)
+test_graph_topo_LDADD = $(COMMON_TEST_LDADD) \
+       $(top_builddir)/lib/libbabeltrace2.la
 
 noinst_PROGRAMS = test_bitfield test_ctf_writer test_bt_values \
        test_trace_ir_ref test_graph_topo
@@ -34,7 +36,8 @@ test_graph_topo_SOURCES = test_graph_topo.c
 
 if !ENABLE_BUILT_IN_PLUGINS
 noinst_PROGRAMS += test_plugin
-test_plugin_LDADD = $(COMMON_TEST_LDADD)
+test_plugin_LDADD = $(COMMON_TEST_LDADD) \
+       $(top_builddir)/lib/libbabeltrace2.la
 test_plugin_SOURCES = test_plugin.c
 SUBDIRS += test-plugin-plugins
 endif
index f4837c9081ec9acaeabb2600743dd062d336af93..99a1d3749a6afbb3e8b17424734391158437d841 100644 (file)
 #include <babeltrace2/object-internal.h>
 #include <babeltrace2/compat/stdlib-internal.h>
 #include <babeltrace2/assert-internal.h>
+#include <babeltrace2/ctf-writer/writer.h>
+#include <babeltrace2/ctf-writer/clock.h>
+#include <babeltrace2/ctf-writer/clock-class.h>
+#include <babeltrace2/ctf-writer/stream.h>
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/event-types.h>
+#include <babeltrace2/ctf-writer/event-fields.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/trace.h>
 #include "common.h"
 
 #define NR_TESTS 37
This page took 0.47131 seconds and 4 git commands to generate.