From a0197f124aa95c055299c31d44be2a0566113fad Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 3 Nov 2023 18:32:50 +0000 Subject: [PATCH] Add common `ctf::ir` CTF IR classes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This patch adds common CTF IR class templates to the new `src/plugins/ctf/common/metadata/ctf-ir.hpp` header. The purpose of those new class templates is to have a common CTF IR class hierarchy for all the `ctf` plugin component classes. This CTF IR model is based on the CTF 2 model. Although the file looks intimidating, it's pretty straightforward: • The class hierarchy, under the `ctf::ir` namespace, (omitting template parameters) is as such: TraceCls DataStreamCls EventRecordCls ClkCls FieldLoc StructFieldMemberCls VariantFcOpt Fc FixedLenBitArrayFc FixedLenBitMapFc FixedLenBoolFc FixedLenFloatFc FixedLenIntFc FixedLenUIntFc FixedLenSIntFc VarLengthIntFc VarLengthUIntFc VarLengthSIntFc StrFc NullTerminatedStrFc NonNullTerminatedStrFc StaticLenStrFc DynLenStrFc BlobFc StaticLenBlobFc DynLenBlobFc ArrayFc StaticLenArrayFc DynLenArrayFc StructFc OptionalFc OptionalWithBoolSelFc OptionalWithIntSelFc OptionalWithUIntSelFc OptionalWithSIntSelFc VariantFc VariantWithUIntSelFc VariantWithSIntSelFc • Each class template has the `UserMixinsT` template parameter. `UserMixinsT` is expected to be a user mixin container, a type defining the following nested types (user mixins): ‣ `ClkCls` ‣ `DataStreamCls` ‣ `DynLenArrayFc` ‣ `DynLenBlobFc` ‣ `DynLenStrFc` ‣ `EventRecordCls` ‣ `Fc` ‣ `FieldLoc` ‣ `FixedLenBitArrayFc` ‣ `FixedLenBitMapFc` ‣ `FixedLenBoolFc` ‣ `FixedLenIntFc` ‣ `FixedLenUIntFc` ‣ `OptionalFc` ‣ `OptionalWithBoolSelFc` ‣ `OptionalWithSIntSelFc` ‣ `OptionalWithUIntSelFc` ‣ `StaticLenArrayFc` ‣ `StaticLenBlobFc` ‣ `StaticLenStrFc` ‣ `StructFc` ‣ `StructFieldMemberCls` ‣ `TraceCls` ‣ `VariantFcOpt` ‣ `VariantWithSIntSelFc` ‣ `VariantWithUIntSelFc` ‣ `VarLenIntFc` ‣ `VarLenUIntFc` • Most class templates inherit a given user mixin. For example, `FixedLenBoolFc` inherits `UserMixinsT::FixedLenBoolFc`. This makes it possible for the user to inject data and methods into the class while keeping the hierarchy and common features. • A class template which inherits a user mixin M has a constructor which accepts an instance of M by value to initialize this part of the object. If a class template C which inherits a user mixin also inherits another class template inheriting another user mixin, then the constructor of C accepts both mixins. For example, FixedLenUIntFc::FixedLenUIntFc() accepts three mixins: field class, fixed-length bit array field class, and fixed-length integer field class. • `Fc` has the typical asXyz() and isXyz() methods. To make isXyz() methods more efficient, `FcType` enumerators are bitwise compositions of `FcTypeTraits` values (traits/features). • The `FcVisitor` and `ConstFcVisitor` base classes are available to visit field classes through the virtual Fc::accept() methods. • There are a few internal mixins to share common members: `WithAttrsMixin`: Optional attributes. `WithPrefDispBaseMixin`: Preferred display base. `WithMappingsMixin`: Integer mappings. `WithLibCls`: libbabeltrace2 class. `UIntFcMixin`: Unsigned integer field roles. `StaticLenFcMixin`: Integral length. `DynLenFcMixin`: Length field location. • The API offers `DefUserMixins` which defines empty user mixins to act as a base user mixin container structure. Now, this is how you would use this API: • Define your own user mixin container structure which inherits `ctf::ir::DefUserMixins`, defining the user mixins you need to add data and methods to specific common classes. • Define aliases for each `ctf::ir` class template you need, using your user mixin container structure as the `UserMixinsT` template parameter. • Create convenient object creation functions to construct specific CTF IR objects from parameters, hiding the internal user mixin details. As an example, this builds and works as expected: #include #include #include "plugins/ctf/common/metadata/ctf-ir.hpp" // user mixin container struct MyMixins : ctf::ir::DefUserMixins { // structure field class mixin class StructFc { public: explicit StructFc(std::string favoriteKebSinger) : _mFavoriteKebSinger {std::move(favoriteKebSinger)} { } const std::string& favoriteKebSinger() const noexcept { return _mFavoriteKebSinger; } private: std::string _mFavoriteKebSinger; }; }; // custom object aliases using MyNullTerminatedStrFc = ctf::ir::NullTerminatedStrFc; using MyStructFc = ctf::ir::StructFc; using MyTraceCls = ctf::ir::TraceCls; int main() { // create structure field class, constructing a `MyMixins::StructFc` MyStructFc::MemberClasses memberClasses; memberClasses.emplace_back( MyMixins::StructFieldMemberCls {}, "meow", bt2c::makeUnique(MyMixins::Fc {})); auto pktHeaderFc = bt2c::makeUnique( MyMixins::Fc {}, MyMixins::StructFc {"Claude Dubois"}, std::move(memberClasses) ); // create trace class MyTraceCls tc { MyMixins::TraceCls {}, bt2s::nullopt, bt2s::nullopt, bt2s::nullopt, {}, std::move(pktHeaderFc) }; // read custom user property std::cout << tc.pktHeaderFc()->favoriteKebSinger() << '\n'; } Signed-off-by: Philippe Proulx Change-Id: Ib4785c9a2f675bdc1415b149e9b57de1339f475e Reviewed-on: https://review.lttng.org/c/babeltrace/+/7708 Reviewed-on: https://review.lttng.org/c/babeltrace/+/12253 CI-Build: Simon Marchi Tested-by: jenkins --- src/Makefile.am | 2 + src/plugins/ctf/common/metadata/ctf-ir.cpp | 18 + src/plugins/ctf/common/metadata/ctf-ir.hpp | 4531 ++++++++++++++++++++ 3 files changed, 4551 insertions(+) create mode 100644 src/plugins/ctf/common/metadata/ctf-ir.cpp create mode 100644 src/plugins/ctf/common/metadata/ctf-ir.hpp diff --git a/src/Makefile.am b/src/Makefile.am index 075e6695..a1455b93 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -677,6 +677,8 @@ endif # ctf plugin plugins_ctf_babeltrace_plugin_ctf_la_SOURCES = \ + plugins/ctf/common/metadata/ctf-ir.hpp \ + plugins/ctf/common/metadata/ctf-ir.cpp \ plugins/ctf/common/metadata/int-range.hpp \ plugins/ctf/common/metadata/int-range-set.hpp \ plugins/ctf/common/src/bfcr/bfcr.cpp \ diff --git a/src/plugins/ctf/common/metadata/ctf-ir.cpp b/src/plugins/ctf/common/metadata/ctf-ir.cpp new file mode 100644 index 00000000..b35447b0 --- /dev/null +++ b/src/plugins/ctf/common/metadata/ctf-ir.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023-2024 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#include "ctf-ir.hpp" + +namespace ctf { +namespace ir { + +const char * const ClkOrigin::_unixEpochNs = "babeltrace.org,2020"; +const char * const ClkOrigin::_unixEpochName = "unix-epoch"; +const char * const ClkOrigin::_unixEpochUid = ""; +const char * const defaultBlobMediaType = "application/octet-stream"; + +} /* namespace ir */ +} /* namespace ctf */ diff --git a/src/plugins/ctf/common/metadata/ctf-ir.hpp b/src/plugins/ctf/common/metadata/ctf-ir.hpp new file mode 100644 index 00000000..17073f6c --- /dev/null +++ b/src/plugins/ctf/common/metadata/ctf-ir.hpp @@ -0,0 +1,4531 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2022-2024 Philippe Proulx + */ + +#ifndef BABELTRACE_PLUGINS_CTF_COMMON_METADATA_CTF_IR_HPP +#define BABELTRACE_PLUGINS_CTF_COMMON_METADATA_CTF_IR_HPP + +#include +#include +#include +#include +#include +#include + +#include "common/assert.h" +#include "cpp-common/bt2/clock-class.hpp" +#include "cpp-common/bt2/field-class.hpp" +#include "cpp-common/bt2/trace-ir.hpp" +#include "cpp-common/bt2c/data-len.hpp" +#include "cpp-common/bt2s/make-unique.hpp" +#include "cpp-common/bt2s/optional.hpp" +#include "cpp-common/vendor/wise-enum/wise_enum.h" + +#include "int-range-set.hpp" + +namespace ctf { +namespace ir { + +/* + * This is the common CTF IR API, that is, the intermediate + * representation of CTF metadata objects for the whole `ctf` plugin. + * + * CLASS HIERARCHY + * ━━━━━━━━━━━━━━━ + * The class hierarchy (omitting template parameters) is as such: + * + * TraceCls + * DataStreamCls + * EventRecordCls + * ClkCls + * FieldLoc + * StructFieldMemberCls + * VariantFcOpt + * Fc + * FixedLenBitArrayFc + * FixedLenBitMapFc + * FixedLenBoolFc + * FixedLenFloatFc + * FixedLenIntFc + * FixedLenUIntFc + * FixedLenSIntFc + * VarLengthIntFc + * VarLengthUIntFc + * VarLengthSIntFc + * StrFc + * NullTerminatedStrFc + * NonNullTerminatedStrFc + * StaticLenStrFc + * DynLenStrFc + * BlobFc + * StaticLenBlobFc + * DynLenBlobFc + * ArrayFc + * StaticLenArrayFc + * DynLenArrayFc + * StructFc + * OptionalFc + * OptionalWithBoolSelFc + * OptionalWithIntSelFc + * OptionalWithUIntSelFc + * OptionalWithSIntSelFc + * VariantFc + * VariantWithUIntSelFc + * VariantWithSIntSelFc + * + * The `FcVisitor` and `ConstFcVisitor` base classes are available to + * visit field classes through the virtual Fc::accept() methods. + * + * Each class template has the `UserMixinsT` template parameter. + * + * USER MIXINS + * ━━━━━━━━━━━ + * `UserMixinsT` is expected to be a user mixin container, a type which + * defines the following nested types (user mixins): + * + * • `ClkCls` + * • `DataStreamCls` + * • `DynLenArrayFc` + * • `DynLenBlobFc` + * • `DynLenStrFc` + * • `EventRecordCls` + * • `Fc` + * • `FieldLoc` + * • `FixedLenBitArrayFc` + * • `FixedLenBitMapFc` + * • `FixedLenBoolFc` + * • `FixedLenIntFc` + * • `FixedLenUIntFc` + * • `OptionalFc` + * • `OptionalWithBoolSelFc` + * • `OptionalWithSIntSelFc` + * • `OptionalWithUIntSelFc` + * • `StaticLenArrayFc` + * • `StaticLenBlobFc` + * • `StaticLenStrFc` + * • `StructFc` + * • `StructFieldMemberCls` + * • `TraceCls` + * • `VariantFcOpt` + * • `VariantWithSIntSelFc` + * • `VariantWithUIntSelFc` + * • `VarLenIntFc` + * • `VarLenUIntFc` + * + * Most class templates inherit a given user mixin. For example, + * `FixedLenBoolFc` inherits `UserMixinsT::FixedLenBoolFc`. This makes + * it possible for the user to inject data and methods into the class + * while keeping the hierarchy and common features. + * + * A class template which inherits a user mixin M has a constructor + * which accepts an instance of M by value to initialize this part of + * the object. + * + * If a class template C which inherits a user mixin also inherits + * another class template inheriting another user mixin, then the + * constructor of C accepts both mixins. For example, + * FixedLenUIntFc::FixedLenUIntFc() accepts three mixins: field class, + * fixed-length bit array field class, and fixed-length integer + * field class. + * + * A mixin must be copy-constructible to make the Fc::clone() + * method work. + * + * The API offers `DefUserMixins` which defines empty user mixins to act + * as a base user mixin container structure. + * + * USAGE + * ━━━━━ + * This is how you would use this API: + * + * • Define your own user mixin container structure which inherits + * `DefUserMixins`, defining the user mixins you need to add data and + * methods to specific common classes. + * + * • Define aliases for each `ctf::ir` type you need, using your user + * mixin container structure as the `UserMixinsT` template parameter + * when needed. + * + * • Create convenient object creation functions to construct specific + * CTF IR objects from parameters, hiding the internal user + * mixin details. + */ + +template +class FixedLenBitArrayFc; + +template +class FixedLenBitMapFc; + +template +class FixedLenBoolFc; + +template +class FixedLenFloatFc; + +template +class FixedLenIntFc; + +template +class FixedLenUIntFc; + +template +class FixedLenSIntFc; + +template +class VarLenIntFc; + +template +class VarLenSIntFc; + +template +class VarLenUIntFc; + +template +class StrFc; + +template +class NullTerminatedStrFc; + +template +class NonNullTerminatedStrFc; + +template +class StaticLenStrFc; + +template +class DynLenStrFc; + +template +class BlobFc; + +template +class StaticLenBlobFc; + +template +class DynLenBlobFc; + +template +class ArrayFc; + +template +class StaticLenArrayFc; + +template +class DynLenArrayFc; + +template +class StructFc; + +template +class OptionalFc; + +template +class OptionalWithBoolSelFc; + +template +class OptionalWithUIntSelFc; + +template +class OptionalWithSIntSelFc; + +template +class VariantWithUIntSelFc; + +template +class VariantWithSIntSelFc; + +/* + * Visitor of `Fc`. + * + * See `ConstFcVisitor` which visits `const Fc`. + */ +template +class FcVisitor +{ +protected: + explicit FcVisitor() = default; + +public: + virtual ~FcVisitor() = default; + + virtual void visit(FixedLenBitArrayFc&) + { + } + + virtual void visit(FixedLenBitMapFc&) + { + } + + virtual void visit(FixedLenBoolFc&) + { + } + + virtual void visit(FixedLenFloatFc&) + { + } + + virtual void visit(FixedLenUIntFc&) + { + } + + virtual void visit(FixedLenSIntFc&) + { + } + + virtual void visit(VarLenSIntFc&) + { + } + + virtual void visit(VarLenUIntFc&) + { + } + + virtual void visit(NullTerminatedStrFc&) + { + } + + virtual void visit(StaticLenStrFc&) + { + } + + virtual void visit(DynLenStrFc&) + { + } + + virtual void visit(StaticLenBlobFc&) + { + } + + virtual void visit(DynLenBlobFc&) + { + } + + virtual void visit(StaticLenArrayFc&) + { + } + + virtual void visit(DynLenArrayFc&) + { + } + + virtual void visit(StructFc&) + { + } + + virtual void visit(OptionalWithBoolSelFc&) + { + } + + virtual void visit(OptionalWithUIntSelFc&) + { + } + + virtual void visit(OptionalWithSIntSelFc&) + { + } + + virtual void visit(VariantWithUIntSelFc&) + { + } + + virtual void visit(VariantWithSIntSelFc&) + { + } +}; + +/* + * Visitor of `const Fc`. + * + * See `FcVisitor` which visits `Fc`. + */ +template +class ConstFcVisitor +{ +protected: + explicit ConstFcVisitor() = default; + +public: + virtual ~ConstFcVisitor() = default; + + virtual void visit(const FixedLenBitArrayFc&) + { + } + + virtual void visit(const FixedLenBitMapFc&) + { + } + + virtual void visit(const FixedLenBoolFc&) + { + } + + virtual void visit(const FixedLenFloatFc&) + { + } + + virtual void visit(const FixedLenUIntFc&) + { + } + + virtual void visit(const FixedLenSIntFc&) + { + } + + virtual void visit(const VarLenSIntFc&) + { + } + + virtual void visit(const VarLenUIntFc&) + { + } + + virtual void visit(const NullTerminatedStrFc&) + { + } + + virtual void visit(const StaticLenStrFc&) + { + } + + virtual void visit(const DynLenStrFc&) + { + } + + virtual void visit(const StaticLenBlobFc&) + { + } + + virtual void visit(const DynLenBlobFc&) + { + } + + virtual void visit(const StaticLenArrayFc&) + { + } + + virtual void visit(const DynLenArrayFc&) + { + } + + virtual void visit(const StructFc&) + { + } + + virtual void visit(const OptionalWithBoolSelFc&) + { + } + + virtual void visit(const OptionalWithUIntSelFc&) + { + } + + virtual void visit(const OptionalWithSIntSelFc&) + { + } + + virtual void visit(const VariantWithUIntSelFc&) + { + } + + virtual void visit(const VariantWithSIntSelFc&) + { + } +}; + +namespace internal { + +/* clang-format off */ + +/* + * To make the Fc::isXyz() methods more efficient, `FcType` + * enumerators (below) are bitwise compositions of `FcTypeTraits` values + * (traits/features). The isXyz() methods only check if specific bits of + * the field class type are set. + */ +struct FcTypeTraits final +{ + enum { + FixedOrStaticLen = 1 << 0, + VarOrDynLen = 1 << 1, + BitArray = 1 << 2, + BitMap = 1 << 3, + Bool = 1 << 4, + Int = 1 << 5, + UInt = (1 << 6) | Int, + SInt = (1 << 7) | Int, + Float = 1 << 8, + Str = 1 << 9, + NullTerminated = 1 << 10, + NonNullTerminated = 1 << 11, + Blob = 1 << 12, + Array = 1 << 13, + Struct = 1 << 14, + BoolSel = 1 << 15, + IntSel = 1 << 16, + UIntSel = (1 << 17) | IntSel, + SIntSel = (1 << 18) | IntSel, + Optional = 1 << 19, + Variant = 1 << 20, + }; +}; + +/* clang-format on */ + +} /* namespace internal */ + +/* clang-format off */ + +/* + * Field class type. + */ +WISE_ENUM_CLASS(FcType, + (FixedLenBitArray, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::BitArray), + + (FixedLenBitMap, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::BitArray | + internal::FcTypeTraits::BitMap), + + (FixedLenBool, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::BitArray | + internal::FcTypeTraits::Bool), + + (FixedLenUInt, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::BitArray | + internal::FcTypeTraits::UInt), + + (FixedLenSInt, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::BitArray | + internal::FcTypeTraits::SInt), + + (FixedLenFloat, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::BitArray | + internal::FcTypeTraits::Float), + + (VarLenUInt, internal::FcTypeTraits::VarOrDynLen | + internal::FcTypeTraits::UInt), + + (VarLenSInt, internal::FcTypeTraits::VarOrDynLen | + internal::FcTypeTraits::SInt), + + (NullTerminatedStr, internal::FcTypeTraits::NullTerminated | + internal::FcTypeTraits::Str), + + (StaticLenStr, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::NonNullTerminated | + internal::FcTypeTraits::Str), + + (DynLenStr, internal::FcTypeTraits::VarOrDynLen | + internal::FcTypeTraits::NonNullTerminated | + internal::FcTypeTraits::Str), + + (StaticLenBlob, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::Blob), + + (DynLenBlob, internal::FcTypeTraits::VarOrDynLen | + internal::FcTypeTraits::Blob), + + (StaticLenArray, internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::Array), + + (DynLenArray, internal::FcTypeTraits::VarOrDynLen | + internal::FcTypeTraits::Array), + + (Struct, internal::FcTypeTraits::Struct), + + (OptionalWithBoolSel, internal::FcTypeTraits::Optional | + internal::FcTypeTraits::BoolSel), + + (OptionalWithUIntSel, internal::FcTypeTraits::Optional | + internal::FcTypeTraits::UIntSel), + + (OptionalWithSIntSel, internal::FcTypeTraits::Optional | + internal::FcTypeTraits::SIntSel), + + (VariantWithUIntSel, internal::FcTypeTraits::Variant | + internal::FcTypeTraits::UIntSel), + + (VariantWithSIntSel, internal::FcTypeTraits::Variant | + internal::FcTypeTraits::SIntSel) +) + +/* clang-format on */ + +/* + * Optional attributes. + */ +using OptAttrs = bt2::ConstMapValue::Shared; + +namespace internal { + +/* + * Internal mixin for classes with an optional equivalent libbabeltrace2 + * class. + */ +template +class WithLibCls +{ +public: + /* + * Equivalent libbabeltrace2 class (borrowed). + */ + const bt2::OptionalBorrowedObject libCls() const noexcept + { + return _mLibCls; + } + + /* + * Equivalent libbabeltrace2 class (borrowed). + */ + bt2::OptionalBorrowedObject libCls() noexcept + { + return _mLibCls; + } + + /* + * Sets the equivalent libbabeltrace2 class to `libCls` (borrowed). + */ + void libCls(const ClsT libCls) noexcept + { + _mLibCls = libCls; + } + +private: + /* Equivalent libbabeltrace2 class (borrowed) */ + bt2::OptionalBorrowedObject _mLibCls; +}; + +/* + * Internal mixin for classes with attributes. + */ +class WithAttrsMixin +{ +protected: + explicit WithAttrsMixin(OptAttrs attrs) : _mAttrs {std::move(attrs)} + { + } + +public: + /* + * Attributes of this object. + */ + const OptAttrs& attrs() const noexcept + { + return _mAttrs; + } + +protected: + /* + * Moves the attributes to the caller. + */ + OptAttrs _takeAttrs() noexcept + { + return std::move(_mAttrs); + } + +private: + /* Attributes of this object */ + OptAttrs _mAttrs; +}; + +} /* namespace internal */ + +/* + * Field class base. + * + * Specific properties: + * + * • Alignment of instances. + * • Attributes. + */ +template +class Fc : + public internal::WithAttrsMixin, + public internal::WithLibCls, + public UserMixinsT::Fc +{ +public: + using Type = FcType; + using UP = std::unique_ptr; + +protected: + explicit Fc(const FcType type, typename UserMixinsT::Fc mixin, const unsigned int align, + OptAttrs&& attrs) : + internal::WithAttrsMixin {std::move(attrs)}, + UserMixinsT::Fc {std::move(mixin)}, _mType {type}, _mAlign {align} + { + } + +public: + /* Disable copy/move operations to make this API simpler */ + Fc(const Fc&) = delete; + Fc(Fc&&) = delete; + Fc& operator=(const Fc&) = delete; + Fc& operator=(Fc&&) = delete; + + virtual ~Fc() = default; + + Type type() const noexcept + { + return _mType; + } + + /* + * Alignment (bits) of instances of this field class. + */ + unsigned int align() const noexcept + { + return _mAlign; + } + + /* + * Moves the attributes of this field class to the caller. + */ + OptAttrs takeAttrs() noexcept + { + return this->_takeAttrs(); + } + + /* + * Clones this field class and returns the clone. + */ + virtual UP clone() const = 0; + + /* + * Accepts a visitor to visit this field class. + */ + virtual void accept(FcVisitor&) = 0; + + /* + * Accepts a visitor to visit this constant field class. + */ + virtual void accept(ConstFcVisitor&) const = 0; + + /* Casting methods below */ + FixedLenBitArrayFc& asFixedLenBitArray() noexcept; + const FixedLenBitArrayFc& asFixedLenBitArray() const noexcept; + FixedLenBitMapFc& asFixedLenBitMap() noexcept; + const FixedLenBitMapFc& asFixedLenBitMap() const noexcept; + FixedLenBoolFc& asFixedLenBool() noexcept; + const FixedLenBoolFc& asFixedLenBool() const noexcept; + FixedLenFloatFc& asFixedLenFloat() noexcept; + const FixedLenFloatFc& asFixedLenFloat() const noexcept; + FixedLenIntFc& asFixedLenInt() noexcept; + const FixedLenIntFc& asFixedLenInt() const noexcept; + FixedLenSIntFc& asFixedLenSInt() noexcept; + const FixedLenSIntFc& asFixedLenSInt() const noexcept; + FixedLenUIntFc& asFixedLenUInt() noexcept; + const FixedLenUIntFc& asFixedLenUInt() const noexcept; + VarLenIntFc& asVarLenInt() noexcept; + const VarLenIntFc& asVarLenInt() const noexcept; + VarLenUIntFc& asVarLenUInt() noexcept; + const VarLenUIntFc& asVarLenUInt() const noexcept; + VarLenSIntFc& asVarLenSInt() noexcept; + const VarLenSIntFc& asVarLenSInt() const noexcept; + StrFc& asStr() noexcept; + const StrFc& asStr() const noexcept; + NullTerminatedStrFc& asNullTerminatedStr() noexcept; + const NullTerminatedStrFc& asNullTerminatedStr() const noexcept; + NonNullTerminatedStrFc& asNonNullTerminatedStr() noexcept; + const NonNullTerminatedStrFc& asNonNullTerminatedStr() const noexcept; + StaticLenStrFc& asStaticLenStr() noexcept; + const StaticLenStrFc& asStaticLenStr() const noexcept; + DynLenStrFc& asDynLenStr() noexcept; + const DynLenStrFc& asDynLenStr() const noexcept; + BlobFc& asBlob() noexcept; + const BlobFc& asBlob() const noexcept; + StaticLenBlobFc& asStaticLenBlob() noexcept; + const StaticLenBlobFc& asStaticLenBlob() const noexcept; + DynLenBlobFc& asDynLenBlob() noexcept; + const DynLenBlobFc& asDynLenBlob() const noexcept; + ArrayFc& asArray() noexcept; + const ArrayFc& asArray() const noexcept; + StaticLenArrayFc& asStaticLenArray() noexcept; + const StaticLenArrayFc& asStaticLenArray() const noexcept; + DynLenArrayFc& asDynLenArray() noexcept; + const DynLenArrayFc& asDynLenArray() const noexcept; + StructFc& asStruct() noexcept; + const StructFc& asStruct() const noexcept; + OptionalFc& asOptional() noexcept; + const OptionalFc& asOptional() const noexcept; + OptionalWithBoolSelFc& asOptionalWithBoolSel() noexcept; + const OptionalWithBoolSelFc& asOptionalWithBoolSel() const noexcept; + OptionalWithUIntSelFc& asOptionalWithUIntSel() noexcept; + const OptionalWithUIntSelFc& asOptionalWithUIntSel() const noexcept; + OptionalWithSIntSelFc& asOptionalWithSIntSel() noexcept; + const OptionalWithSIntSelFc& asOptionalWithSIntSel() const noexcept; + VariantWithUIntSelFc& asVariantWithUIntSel() noexcept; + const VariantWithUIntSelFc& asVariantWithUIntSel() const noexcept; + VariantWithSIntSelFc& asVariantWithSIntSel() noexcept; + const VariantWithSIntSelFc& asVariantWithSIntSel() const noexcept; + + bool isFixedLenBitArray() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::BitArray); + } + + bool isFixedLenBitMap() const noexcept + { + return _mType == Type::FixedLenBitMap; + } + + bool isFixedLenBool() const noexcept + { + return _mType == Type::FixedLenBool; + } + + bool isFixedLenFloat() const noexcept + { + return _mType == Type::FixedLenFloat; + } + + bool isInt() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::Int); + } + + bool isUInt() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::UInt); + } + + bool isSInt() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::SInt); + } + + bool isFixedLenInt() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::FixedOrStaticLen | + internal::FcTypeTraits::Int); + } + + bool isFixedLenUInt() const noexcept + { + return _mType == Type::FixedLenUInt; + } + + bool isFixedLenSInt() const noexcept + { + return _mType == Type::FixedLenSInt; + } + + bool isVarLenInt() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::VarOrDynLen | + internal::FcTypeTraits::Int); + } + + bool isVarLenUInt() const noexcept + { + return _mType == Type::VarLenUInt; + } + + bool isVarLenSInt() const noexcept + { + return _mType == Type::VarLenSInt; + } + + bool isStr() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::Str); + } + + bool isNullTerminatedStr() const noexcept + { + return _mType == Type::NullTerminatedStr; + } + + bool isNonNullTerminatedStr() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::NonNullTerminated); + } + + bool isStaticLenStr() const noexcept + { + return _mType == Type::StaticLenStr; + } + + bool isDynLenStr() const noexcept + { + return _mType == Type::DynLenStr; + } + + bool isBlob() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::Blob); + } + + bool isStaticLenBlob() const noexcept + { + return _mType == Type::StaticLenBlob; + } + + bool isDynLenBlob() const noexcept + { + return _mType == Type::DynLenBlob; + } + + bool isArray() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::Array); + } + + bool isStaticLenArray() const noexcept + { + return _mType == Type::StaticLenArray; + } + + bool isDynLenArray() const noexcept + { + return _mType == Type::DynLenArray; + } + + bool isStruct() const noexcept + { + return _mType == Type::Struct; + } + + bool isOptional() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::Optional); + } + + bool isOptionalWithBoolSel() const noexcept + { + return _mType == Type::OptionalWithBoolSel; + } + + bool isOptionalWithIntSel() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::Optional | + internal::FcTypeTraits::IntSel); + } + + bool isOptionalWithUIntSel() const noexcept + { + return _mType == Type::OptionalWithUIntSel; + } + + bool isOptionalWithSIntSel() const noexcept + { + return _mType == Type::OptionalWithSIntSel; + } + + bool isVariant() const noexcept + { + return this->_hasTypeTrait(internal::FcTypeTraits::Variant); + } + + bool isVariantWithUIntSel() const noexcept + { + return _mType == Type::VariantWithUIntSel; + } + + bool isVariantWithSIntSel() const noexcept + { + return _mType == Type::VariantWithSIntSel; + } + +private: + /* + * Returns whether or not this field class has the type trait + * `typeTrait` (one or more bitwise-OR combined `FcTypeTraits` + * enumerators). + */ + bool _hasTypeTrait(const int typeTrait) const noexcept + { + return (static_cast(_mType) & typeTrait) == typeTrait; + } + + /* Type of this field class */ + Type _mType; + + /* Alignment (bits) of instances of this field class */ + unsigned int _mAlign; +}; + +/* clang-format off */ + +/* + * Byte order. + */ +WISE_ENUM_CLASS(ByteOrder, + /* Big-endian */ + Big, + + /* Little-endian */ + Little +) + +/* + * Bit order. + */ +WISE_ENUM_CLASS(BitOrder, + /* First to last */ + FirstToLast, + + /* Last to first */ + LastToFirst +) + +/* clang-format on */ + +/* + * Fixed-length bit array field class. + * + * Specific properties over `Fc`: + * + * • Length of instances. + * • Byte order of instances. + * • Bit order of instances. + */ +template +class FixedLenBitArrayFc : public Fc, public UserMixinsT::FixedLenBitArrayFc +{ +protected: + explicit FixedLenBitArrayFc(const FcType type, typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc mixin, + const unsigned int align, const bt2c::DataLen len, + const ByteOrder byteOrder, const bt2s::optional& bitOrder, + OptAttrs&& attrs) : + Fc {type, std::move(fcMixin), align, std::move(attrs)}, + UserMixinsT::FixedLenBitArrayFc(std::move(mixin)), _mLen {len}, _mByteOrder {byteOrder}, + _mBitOrder {bitOrder ? *bitOrder : + (byteOrder == ByteOrder::Big ? BitOrder::LastToFirst : + BitOrder::FirstToLast)} + { + using namespace bt2c::literals::datalen; + + BT_ASSERT(len > 0_bits && len <= 64_bits); + BT_ASSERT(align > 0); + } + +public: + explicit FixedLenBitArrayFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc mixin, + const unsigned int align, const bt2c::DataLen len, + const ByteOrder byteOrder, + const bt2s::optional& bitOrder = bt2s::nullopt, + OptAttrs attrs = OptAttrs {}) : + FixedLenBitArrayFc {FcType::FixedLenBitArray, + std::move(fcMixin), + std::move(mixin), + align, + len, + byteOrder, + bitOrder, + std::move(attrs)} + { + } + + /* + * Length of instances of this field class. + */ + const bt2c::DataLen len() const noexcept + { + return _mLen; + } + + /* + * Byte order of instances of this field class. + */ + ByteOrder byteOrder() const noexcept + { + return _mByteOrder; + } + + /* + * Bit order of instances of this field class. + */ + BitOrder bitOrder() const noexcept + { + return _mBitOrder; + } + + /* + * Returns whether or not the bits of instances of a fixed-length + * bit array field class having the byte order `byteOrder` and the + * bit order `bitOrder` (deduced from `byteOrder` if + * `bt2s::nullopt`) are reversed, that is, in an unnatural way. + */ + static bool isRev(const ByteOrder byteOrder, const bt2s::optional& bitOrder) noexcept + { + if (!bitOrder) { + return false; + } + + return (byteOrder == ByteOrder::Big && *bitOrder == BitOrder::FirstToLast) || + (byteOrder == ByteOrder::Little && *bitOrder == BitOrder::LastToFirst); + } + + /* + * Like isRev() above, but using the properties of this field class. + */ + bool isRev() const noexcept + { + return FixedLenBitArrayFc::isRev(_mByteOrder, _mBitOrder); + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->align(), _mLen, + _mByteOrder, _mBitOrder, this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } + +private: + /* Length of instances of this field class */ + bt2c::DataLen _mLen; + + /* Byte order of instances of this field class */ + ByteOrder _mByteOrder; + + /* Bit order of instances of this field class */ + BitOrder _mBitOrder; +}; + +/* + * Fixed-length bit map field class. + * + * Specific property over `FixedLenBitArrayFc`: + * + * • Flags of instances. + */ +template +class FixedLenBitMapFc final : + public FixedLenBitArrayFc, + public UserMixinsT::FixedLenBitMapFc +{ +public: + using Flags = std::unordered_map; + + explicit FixedLenBitMapFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc fixedLenBitArrayFcMixin, + typename UserMixinsT::FixedLenBitMapFc mixin, + const unsigned int align, const bt2c::DataLen len, + const ByteOrder byteOrder, Flags flags, + const bt2s::optional& bitOrder = bt2s::nullopt, + OptAttrs attrs = OptAttrs {}) : + FixedLenBitArrayFc {FcType::FixedLenBitMap, + std::move(fcMixin), + std::move(fixedLenBitArrayFcMixin), + align, + len, + byteOrder, + bitOrder, + std::move(attrs)}, + UserMixinsT::FixedLenBitMapFc(std::move(mixin)), _mFlags {std::move(flags)} + { + BT_ASSERT(!_mFlags.empty()); + } + + /* + * Flags of this fixed-length bit map field class. + */ + const Flags& flags() const noexcept + { + return _mFlags; + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, this->align(), this->len(), + this->byteOrder(), _mFlags, this->bitOrder(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } + +private: + Flags _mFlags; +}; + +/* + * Fixed-length boolean field class. + */ +template +class FixedLenBoolFc final : + public FixedLenBitArrayFc, + public UserMixinsT::FixedLenBoolFc +{ +public: + explicit FixedLenBoolFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc fixedLenBitArrayFcMixin, + typename UserMixinsT::FixedLenBoolFc mixin, const unsigned int align, + const bt2c::DataLen len, const ByteOrder byteOrder, + const bt2s::optional& bitOrder = bt2s::nullopt, + OptAttrs attrs = OptAttrs {}) : + FixedLenBitArrayFc {FcType::FixedLenBool, + std::move(fcMixin), + std::move(fixedLenBitArrayFcMixin), + align, + len, + byteOrder, + bitOrder, + std::move(attrs)}, + UserMixinsT::FixedLenBoolFc {std::move(mixin)} + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, this->align(), this->len(), + this->byteOrder(), this->bitOrder(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Fixed-length floating-point number field class. + */ +template +class FixedLenFloatFc final : public FixedLenBitArrayFc +{ +public: + explicit FixedLenFloatFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc fixedLenBitArrayFcMixin, + const unsigned int align, const bt2c::DataLen len, + const ByteOrder byteOrder, + const bt2s::optional& bitOrder = bt2s::nullopt, + OptAttrs attrs = OptAttrs {}) : + FixedLenBitArrayFc {FcType::FixedLenFloat, + std::move(fcMixin), + std::move(fixedLenBitArrayFcMixin), + align, + len, + byteOrder, + bitOrder, + std::move(attrs)} + { + using namespace bt2c::literals::datalen; + + BT_ASSERT(len == 32_bits || len == 64_bits); + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->align(), this->len(), + this->byteOrder(), this->bitOrder(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* clang-format off */ + +/* + * Display base. + */ +WISE_ENUM_CLASS(DispBase, + /* Binary */ + (Bin, 2), + + /* Octal */ + (Oct, 8), + + /* Decimal */ + (Dec, 10), + + /* Hexadecimal */ + (Hex, 16) +) + +/* clang-format on */ + +namespace internal { + +/* + * Internal mixin for integer field classes with a preferred display + * base. + */ +class WithPrefDispBaseMixin +{ +protected: + explicit WithPrefDispBaseMixin(const DispBase prefDispBase) : _mPrefDispBase {prefDispBase} + { + } + +public: + /* + * Preferred display base of instances of this field class. + */ + DispBase prefDispBase() const noexcept + { + return _mPrefDispBase; + } + +private: + /* Preferred display base of instances of this field class */ + DispBase _mPrefDispBase; +}; + +/* + * Internal mixin for integer field classes with mappings. + */ +template +class WithMappingsMixin +{ +public: + using Mappings = std::unordered_map; + using Val = typename MappingRangeSetT::Val; + +protected: + explicit WithMappingsMixin(Mappings&& mappings) : _mMappings {std::move(mappings)} + { + } + +public: + /* + * Mappings of instances of this integer field class. + */ + const Mappings& mappings() const noexcept + { + return _mMappings; + } + +private: + /* Mappings of instances of this integer field class */ + Mappings _mMappings; +}; + +} /* namespace internal */ + +/* + * Fixed-length integer field class base. + * + * Specific property over `FixedLenBitArrayFc`: + * + * • Preferred display base of instances. + */ +template +class FixedLenIntFc : + public FixedLenBitArrayFc, + public internal::WithPrefDispBaseMixin, + public UserMixinsT::FixedLenIntFc +{ +protected: + explicit FixedLenIntFc(const FcType type, typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc fixedLenBitArrayFcMixin, + typename UserMixinsT::FixedLenIntFc mixin, const unsigned int align, + const bt2c::DataLen len, const ByteOrder byteOrder, + const bt2s::optional& bitOrder, const DispBase prefDispBase, + OptAttrs&& attrs) : + FixedLenBitArrayFc { + type, std::move(fcMixin), std::move(fixedLenBitArrayFcMixin), align, len, byteOrder, + bitOrder, std::move(attrs)}, + internal::WithPrefDispBaseMixin {prefDispBase}, + UserMixinsT::FixedLenIntFc {std::move(mixin)} + { + } +}; + +/* clang-format off */ + +/* + * Unsigned integer field role. + */ +WISE_ENUM_CLASS(UIntFieldRole, + /* Packet magic number */ + (PktMagicNumber, 1 << 1), + + /* Data stream class ID */ + (DataStreamClsId, 1 << 2), + + /* Data stream ID */ + (DataStreamId, 1 << 3), + + /* Total length of packet */ + (PktTotalLen, 1 << 4), + + /* Content length of packet */ + (PktContentLen, 1 << 5), + + /* Default clock timestamp */ + (DefClkTs, 1 << 6), + + /* Default clock timestamp at end of packet */ + (PktEndDefClkTs, 1 << 7), + + /* Discarded event record counter snapshot */ + (DiscEventRecordCounterSnap, 1 << 8), + + /* Packet sequence number */ + (PktSeqNum, 1 << 9), + + /* Event record class ID */ + (EventRecordClsId, 1 << 10) +) + +/* clang-format on */ + +/* + * Set of unsigned integer field roles. + */ +using UIntFieldRoles = std::set; + +namespace internal { + +/* + * Internal mixin for unsigned integer field class classes. + */ +class UIntFcMixin +{ +protected: + explicit UIntFcMixin(UIntFieldRoles roles) : _mRoles {std::move(roles)} + { + } + +public: + /* + * Roles of instances of this unsigned integer field class. + */ + const UIntFieldRoles& roles() const noexcept + { + return _mRoles; + } + + /* + * Returns whether or not the instances of this field class have the + * role `role`. + */ + bool hasRole(const UIntFieldRole role) const noexcept + { + return _mRoles.count(role) == 1; + } + +private: + /* Roles of instances of this unsigned integer field class */ + UIntFieldRoles _mRoles; +}; + +} /* namespace internal */ + +/* + * Fixed-length unsigned integer field class. + * + * Specific properties over `FixedLenIntFc`: + * + * • Mappings. + * • Roles of instances. + */ +template +class FixedLenUIntFc final : + public FixedLenIntFc, + public internal::WithMappingsMixin, + public internal::UIntFcMixin, + public UserMixinsT::FixedLenUIntFc +{ +public: + using typename internal::WithMappingsMixin::Mappings; + + explicit FixedLenUIntFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc fixedLenBitArrayFcMixin, + typename UserMixinsT::FixedLenIntFc fixedLenIntFcMixin, + typename UserMixinsT::FixedLenUIntFc mixin, const unsigned int align, + const bt2c::DataLen len, const ByteOrder byteOrder, + const bt2s::optional& bitOrder = bt2s::nullopt, + const DispBase prefDispBase = DispBase::Dec, Mappings mappings = {}, + UIntFieldRoles roles = {}, OptAttrs attrs = OptAttrs {}) : + FixedLenIntFc {FcType::FixedLenUInt, + std::move(fcMixin), + std::move(fixedLenBitArrayFcMixin), + std::move(fixedLenIntFcMixin), + align, + len, + byteOrder, + bitOrder, + prefDispBase, + std::move(attrs)}, + internal::WithMappingsMixin {std::move(mappings)}, + internal::UIntFcMixin {std::move(roles)}, UserMixinsT::FixedLenUIntFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique( + *this, *this, *this, *this, this->align(), this->len(), this->byteOrder(), + this->bitOrder(), this->prefDispBase(), this->mappings(), this->roles(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Fixed-length signed integer field class. + * + * Specific property over `FixedLenIntFc`: + * + * • Mappings. + */ +template +class FixedLenSIntFc final : + public FixedLenIntFc, + public internal::WithMappingsMixin +{ +public: + using typename internal::WithMappingsMixin::Mappings; + + explicit FixedLenSIntFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::FixedLenBitArrayFc fixedLenBitArrayFcMixin, + typename UserMixinsT::FixedLenIntFc fixedLenIntFcMixin, + const unsigned int align, const bt2c::DataLen len, + const ByteOrder byteOrder, + const bt2s::optional& bitOrder = bt2s::nullopt, + const DispBase prefDispBase = DispBase::Dec, Mappings mappings = {}, + OptAttrs attrs = OptAttrs {}) : + FixedLenIntFc {FcType::FixedLenSInt, + std::move(fcMixin), + std::move(fixedLenBitArrayFcMixin), + std::move(fixedLenIntFcMixin), + align, + len, + byteOrder, + bitOrder, + prefDispBase, + std::move(attrs)}, + internal::WithMappingsMixin {std::move(mappings)} + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique( + *this, *this, *this, this->align(), this->len(), this->byteOrder(), this->bitOrder(), + this->prefDispBase(), this->mappings(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Variable-length integer field class base. + */ +template +class VarLenIntFc : + public Fc, + public internal::WithPrefDispBaseMixin, + public UserMixinsT::VarLenIntFc +{ +protected: + explicit VarLenIntFc(const FcType type, typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::VarLenIntFc mixin, const DispBase prefDispBase, + OptAttrs&& attrs) : + Fc {type, std::move(fcMixin), 8, std::move(attrs)}, + internal::WithPrefDispBaseMixin {prefDispBase}, UserMixinsT::VarLenIntFc {std::move(mixin)} + { + } +}; + +/* + * Variable-length unsigned integer field class. + * + * Specific properties over `VarLenIntFc`: + * + * • Mappings. + * • Roles of instances. + */ +template +class VarLenUIntFc final : + public VarLenIntFc, + public internal::WithMappingsMixin, + public internal::UIntFcMixin, + public UserMixinsT::VarLenUIntFc +{ +public: + using typename internal::WithMappingsMixin::Mappings; + + explicit VarLenUIntFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::VarLenIntFc varLenIntFcMixin, + typename UserMixinsT::VarLenUIntFc mixin, const DispBase prefDispBase, + Mappings mappings = {}, UIntFieldRoles roles = {}, + OptAttrs attrs = OptAttrs {}) : + VarLenIntFc {FcType::VarLenUInt, std::move(fcMixin), + std::move(varLenIntFcMixin), prefDispBase, std::move(attrs)}, + internal::WithMappingsMixin {std::move(mappings)}, + internal::UIntFcMixin {std::move(roles)}, UserMixinsT::VarLenUIntFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, this->prefDispBase(), + this->mappings(), this->roles(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Variable-length signed integer field class. + * + * Specific property over `VarLenIntFc`: + * + * • Mappings. + */ +template +class VarLenSIntFc final : + public VarLenIntFc, + public internal::WithMappingsMixin +{ +public: + using typename internal::WithMappingsMixin::Mappings; + + explicit VarLenSIntFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::VarLenIntFc varLenIntFcMixin, + const DispBase prefDispBase, Mappings mappings = {}, + OptAttrs attrs = OptAttrs {}) : + VarLenIntFc {FcType::VarLenSInt, std::move(fcMixin), + std::move(varLenIntFcMixin), prefDispBase, std::move(attrs)}, + internal::WithMappingsMixin {std::move(mappings)} + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->prefDispBase(), this->mappings(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* clang-format off */ + +/* + * String encoding. + */ +WISE_ENUM_CLASS(StrEncoding, + /* UTF-8 */ + Utf8, + + /* UTF-16BE */ + Utf16Be, + + /* UTF-16LE */ + Utf16Le, + + /* UTF-32BE */ + Utf32Be, + + /* UTF-32LE */ + Utf32Le +) + +/* clang-format on */ + +/* + * String field class base. + * + * Specific property over `Fc`: + * + * • Encoding of instances. + */ +template +class StrFc : public Fc +{ +protected: + explicit StrFc(const FcType type, typename UserMixinsT::Fc fcMixin, const StrEncoding encoding, + OptAttrs&& attrs) : + Fc {type, std::move(fcMixin), 8, std::move(attrs)}, + _mEncoding {encoding} + { + } + +public: + /* + * Encoding of instances of this string field class. + */ + StrEncoding encoding() const noexcept + { + return _mEncoding; + } + +private: + /* Encoding of instances of this string field class */ + StrEncoding _mEncoding; +}; + +/* + * Null-terminated string field class. + */ +template +class NullTerminatedStrFc final : public StrFc +{ +public: + explicit NullTerminatedStrFc(typename UserMixinsT::Fc fcMixin, + const StrEncoding encoding = StrEncoding::Utf8, + OptAttrs attrs = OptAttrs {}) : + StrFc {FcType::NullTerminatedStr, std::move(fcMixin), encoding, + std::move(attrs)} + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, this->encoding(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* clang-format off */ + +/* + * Scope. + */ +WISE_ENUM_CLASS(Scope, + /* Packet header */ + PktHeader, + + /* Packet context */ + PktCtx, + + /* Event record header */ + EventRecordHeader, + + /* Common event record context */ + CommonEventRecordCtx, + + /* Specific event record context */ + SpecEventRecordCtx, + + /* Event record payload */ + EventRecordPayload +) + +/* clang-format on */ + +/* + * Field location. + * + * A field location may be: + * + * Absolute: + * Has an origin and no `bt2s::nullopt` items. + * + * Relative: + * Has no origin and may contain `bt2s::nullopt` items. + * + * A `bt2s::nullopt` item means "go to parent structure field" + * (CTF 2 strategy). + */ +template +class FieldLoc final : public UserMixinsT::FieldLoc +{ +public: + using Items = std::vector>; + + explicit FieldLoc(typename UserMixinsT::FieldLoc mixin, bt2s::optional origin, + Items items) : + UserMixinsT::FieldLoc {std::move(mixin)}, + _mOrigin {std::move(origin)}, _mItems {std::move(items)} + { + } + + /* + * Origin of this field location, or `bt2s::nullopt` if it's a + * relative field location. + */ + const bt2s::optional& origin() const noexcept + { + return _mOrigin; + } + + /* + * Path item of this field location. + */ + const Items& items() const noexcept + { + return _mItems; + } + + Items::const_reference operator[](const Items::size_type index) const noexcept + { + return _mItems[index]; + } + + Items::size_type size() const noexcept + { + return _mItems.size(); + } + + Items::const_iterator begin() const noexcept + { + return _mItems.begin(); + } + + Items::const_iterator end() const noexcept + { + return _mItems.end(); + } + +private: + /* Origin of this field location */ + bt2s::optional _mOrigin; + + /* Path items of this field location */ + Items _mItems; +}; + +namespace internal { + +/* + * Internal mixin for static-length field class classes. + */ +class StaticLenFcMixin +{ +protected: + explicit StaticLenFcMixin(const std::size_t len) : _mLen {len} + { + } + +public: + /* + * Length (bytes or elements) of instances of this field class. + */ + std::size_t len() const noexcept + { + return _mLen; + } + +private: + /* Length of instances of this field class */ + std::size_t _mLen; +}; + +/* + * Internal mixin for dynamic-length field class classes. + */ +template +class DynLenFcMixin +{ +protected: + explicit DynLenFcMixin(FieldLoc lenFieldLoc) : + _mLenFieldLoc {std::move(lenFieldLoc)} + { + } + +public: + /* + * Length field location of instances of this field class. + */ + const FieldLoc& lenFieldLoc() const noexcept + { + return _mLenFieldLoc; + } + + /* + * Sets the length field location of instances of this field class + * to `loc`. + */ + void lenFieldLoc(FieldLoc loc) noexcept + { + _mLenFieldLoc = std::move(loc); + } + +private: + /* Length field location of instances of this field class */ + FieldLoc _mLenFieldLoc; +}; + +} /* namespace internal */ + +/* + * Non-null-terminated string field class base. + */ +template +class NonNullTerminatedStrFc : public StrFc +{ +protected: + explicit NonNullTerminatedStrFc(const FcType type, typename UserMixinsT::Fc fcMixin, + const StrEncoding strEncoding, OptAttrs&& attrs) : + StrFc {type, std::move(fcMixin), strEncoding, std::move(attrs)} + { + } +}; + +/* + * Static-length string field class. + * + * Specific property over `NonNullTerminatedStrFc`: + * + * • Length (number of bytes) of instances. + */ +template +class StaticLenStrFc final : + public NonNullTerminatedStrFc, + public internal::StaticLenFcMixin, + public UserMixinsT::StaticLenStrFc +{ +public: + explicit StaticLenStrFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::StaticLenStrFc mixin, const std::size_t len, + const StrEncoding encoding = StrEncoding::Utf8, + OptAttrs attrs = OptAttrs {}) : + NonNullTerminatedStrFc {FcType::StaticLenStr, std::move(fcMixin), encoding, + std::move(attrs)}, + internal::StaticLenFcMixin {len}, UserMixinsT::StaticLenStrFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->len(), this->encoding(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Dynamic-length string field class. + * + * Specific property over `NonNullTerminatedStrFc`: + * + * • Length field location of instances. + */ +template +class DynLenStrFc final : + public NonNullTerminatedStrFc, + public internal::DynLenFcMixin, + public UserMixinsT::DynLenStrFc +{ +public: + explicit DynLenStrFc(typename UserMixinsT::Fc fcMixin, typename UserMixinsT::DynLenStrFc mixin, + FieldLoc lenFieldLoc, + const StrEncoding encoding = StrEncoding::Utf8, + OptAttrs attrs = OptAttrs {}) : + NonNullTerminatedStrFc {FcType::DynLenStr, std::move(fcMixin), encoding, + std::move(attrs)}, + internal::DynLenFcMixin {std::move(lenFieldLoc)}, + UserMixinsT::DynLenStrFc {std::move(mixin)} + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->lenFieldLoc(), this->encoding(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +extern const char * const defaultBlobMediaType; + +/* + * BLOB field class base. + * + * Specific property over `Fc`: + * + * • Media type of instances. + */ +template +class BlobFc : public Fc +{ +protected: + explicit BlobFc(const FcType type, typename UserMixinsT::Fc fcMixin, std::string&& mediaType, + OptAttrs&& attrs) : + Fc {type, std::move(fcMixin), 8, std::move(attrs)}, + _mMediaType {std::move(mediaType)} + { + } + +public: + /* + * Media type of instances of this field class. + */ + const std::string& mediaType() const noexcept + { + return _mMediaType; + } + +private: + /* Media type of instances of this field class */ + std::string _mMediaType; +}; + +/* + * Static-length BLOB field class. + * + * Specific properties over `BlobFc`: + * + * • Length (number of bytes) of instances. + * + * • Whether or not instances have the "metadata stream UUID" role. + */ +template +class StaticLenBlobFc final : + public BlobFc, + public internal::StaticLenFcMixin, + public UserMixinsT::StaticLenBlobFc +{ +public: + explicit StaticLenBlobFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::StaticLenBlobFc mixin, const std::size_t len, + std::string mediaType = defaultBlobMediaType, + const bool hasMetadataStreamUuidRole = false, + OptAttrs attrs = OptAttrs {}) : + BlobFc {FcType::StaticLenBlob, std::move(fcMixin), std::move(mediaType), + std::move(attrs)}, + internal::StaticLenFcMixin {len}, UserMixinsT::StaticLenBlobFc(std::move(mixin)), + _mHasMetadataStreamUuidRole {hasMetadataStreamUuidRole} + { + } + + bool hasMetadataStreamUuidRole() const noexcept + { + return _mHasMetadataStreamUuidRole; + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->len(), this->mediaType(), + _mHasMetadataStreamUuidRole, this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } + +private: + bool _mHasMetadataStreamUuidRole; +}; + +/* + * Dynamic-length BLOB field class. + * + * Specific property over `BlobFc`: + * + * • Length field location of instances. + */ +template +class DynLenBlobFc final : + public BlobFc, + public internal::DynLenFcMixin, + public UserMixinsT::DynLenBlobFc +{ +public: + explicit DynLenBlobFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::DynLenBlobFc mixin, + FieldLoc lenFieldLoc, + std::string mediaType = defaultBlobMediaType, + OptAttrs attrs = OptAttrs {}) : + BlobFc {FcType::DynLenBlob, std::move(fcMixin), std::move(mediaType), + std::move(attrs)}, + internal::DynLenFcMixin {std::move(lenFieldLoc)}, + UserMixinsT::DynLenBlobFc {std::move(mixin)} + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->lenFieldLoc(), this->mediaType(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Array field class base. + * + * Specific properties over `Fc`: + * + * • Class of element fields. + * • Minimum alignment of instances. + */ +template +class ArrayFc : public Fc +{ +protected: + explicit ArrayFc(const FcType type, typename UserMixinsT::Fc fcMixin, + typename Fc::UP&& elemFc, const unsigned int minAlign, + OptAttrs&& attrs) : + Fc {type, std::move(fcMixin), ArrayFc::_effectiveAlign(*elemFc, minAlign), + std::move(attrs)}, + _mElemFc {std::move(elemFc)}, _mMinAlign {minAlign} + { + BT_ASSERT(_mElemFc); + } + +public: + /* + * Class of the element fields of instances of this field class. + */ + const Fc& elemFc() const noexcept + { + return *_mElemFc; + } + + /* + * Class of the element fields of instances of this field class. + */ + Fc& elemFc() noexcept + { + return *_mElemFc; + } + + /* + * Sets the class of the element fields of instances of this field + * class. + */ + void elemFc(typename Fc::UP elemFc) noexcept + { + _mElemFc = std::move(elemFc); + } + + /* + * Moves the class of the element fields of instances of this field + * class to the caller. + */ + typename Fc::UP takeElemFc() noexcept + { + return std::move(_mElemFc); + } + + /* + * Minimum alignment (bits) of instances of this field class. + */ + unsigned int minAlign() const noexcept + { + return _mMinAlign; + } + +private: + /* + * Returns the effective alignment of an array field of which: + * + * • The minimum alignment is `minAlign` bits. + * • The elements are instances of `elemFc`. + */ + static unsigned int _effectiveAlign(const Fc& elemFc, + const unsigned int minAlign) noexcept + { + return std::max(elemFc.align(), minAlign); + } + + /* Class of the element fields of instances of this field class */ + typename Fc::UP _mElemFc; + + /* Minimum alignment (bits) of instances of this field class */ + unsigned int _mMinAlign; +}; + +/* + * Static-length array field class. + * + * Specific property over `ArrayFc`: + * + * • Length (number of elements) of instances. + */ +template +class StaticLenArrayFc final : + public ArrayFc, + public internal::StaticLenFcMixin, + public UserMixinsT::StaticLenArrayFc +{ +public: + explicit StaticLenArrayFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::StaticLenArrayFc mixin, const std::size_t len, + typename Fc::UP elemFc, const unsigned int minAlign = 1, + OptAttrs attrs = OptAttrs {}) : + ArrayFc {FcType::StaticLenArray, std::move(fcMixin), std::move(elemFc), + minAlign, std::move(attrs)}, + internal::StaticLenFcMixin {len}, UserMixinsT::StaticLenArrayFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique( + *this, *this, this->len(), this->elemFc().clone(), this->minAlign(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Dynamic-length array field class. + * + * Specific property over `ArrayFc`: + * + * • Length field location of instances. + */ +template +class DynLenArrayFc final : + public ArrayFc, + public internal::DynLenFcMixin, + public UserMixinsT::DynLenArrayFc +{ +public: + explicit DynLenArrayFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::DynLenArrayFc mixin, + FieldLoc lenFieldLoc, typename Fc::UP elemFc, + const unsigned int minAlign = 1, OptAttrs attrs = OptAttrs {}) : + ArrayFc {FcType::DynLenArray, std::move(fcMixin), std::move(elemFc), minAlign, + std::move(attrs)}, + internal::DynLenFcMixin {std::move(lenFieldLoc)}, + UserMixinsT::DynLenArrayFc {std::move(mixin)} + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, this->lenFieldLoc(), + this->elemFc().clone(), this->minAlign(), + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Structure field member class. + */ +template +class StructFieldMemberCls final : + public internal::WithAttrsMixin, + public UserMixinsT::StructFieldMemberCls +{ +public: + explicit StructFieldMemberCls(typename UserMixinsT::StructFieldMemberCls mixin, + std::string name, typename Fc::UP fc, + OptAttrs attrs = OptAttrs {}) : + internal::WithAttrsMixin {std::move(attrs)}, + UserMixinsT::StructFieldMemberCls(std::move(mixin)), _mName {std::move(name)}, + _mFc {std::move(fc)} + { + BT_ASSERT(_mFc); + } + + /* + * Builds a member class from `other`, cloning its field class. + */ + StructFieldMemberCls(const StructFieldMemberCls& other) : + internal::WithAttrsMixin {other.attrs()}, UserMixinsT::StructFieldMemberCls(other), + _mName {other.name()}, _mFc {other.fc().clone()} + { + } + + /* + * Name of this member class. + */ + const std::string& name() const noexcept + { + return _mName; + } + + /* + * Field class of this member class. + */ + const Fc& fc() const noexcept + { + return *_mFc; + } + + /* + * Field class of this member class. + */ + Fc& fc() noexcept + { + return *_mFc; + } + + /* + * Moves the field class of this member class to the caller. + */ + typename Fc::UP takeFc() noexcept + { + return std::move(_mFc); + } + + /* + * Sets the field class of this member class. + */ + void fc(typename Fc::UP fc) noexcept + { + _mFc = std::move(fc); + } + +private: + std::string _mName; + typename Fc::UP _mFc; +}; + +/* + * Structure field class. + * + * Specific properties over `Fc`: + * + * • Minimum alignment of instances. + * • Classes of members of instances. + */ +template +class StructFc final : public Fc, public UserMixinsT::StructFc +{ +public: + using MemberClasses = std::vector>; + + explicit StructFc(typename UserMixinsT::Fc fcMixin, typename UserMixinsT::StructFc mixin, + MemberClasses memberClasses = {}, const unsigned int minAlign = 1, + OptAttrs attrs = OptAttrs {}) : + Fc {FcType::Struct, std::move(fcMixin), + StructFc::_effectiveAlign(memberClasses, minAlign), std::move(attrs)}, + UserMixinsT::StructFc(std::move(mixin)), _mMemberClasses {std::move(memberClasses)}, + _mMinAlign {minAlign} + { + } + + /* + * Classes of members of instances of this field class. + */ + const MemberClasses& memberClasses() const noexcept + { + return _mMemberClasses; + } + + typename MemberClasses::const_reference + operator[](const typename MemberClasses::size_type index) const noexcept + { + return _mMemberClasses[index]; + } + + typename MemberClasses::reference + operator[](const typename MemberClasses::size_type index) noexcept + { + return _mMemberClasses[index]; + } + + const typename MemberClasses::value_type *operator[](const std::string& name) const noexcept + { + return this->_memberClsByName(*this, name); + } + + typename MemberClasses::value_type *operator[](const std::string& name) noexcept + { + return this->_memberClsByName(*this, name); + } + + typename MemberClasses::size_type size() const noexcept + { + return _mMemberClasses.size(); + } + + bool isEmpty() const noexcept + { + return _mMemberClasses.empty(); + } + + typename MemberClasses::const_iterator begin() const noexcept + { + return _mMemberClasses.begin(); + } + + typename MemberClasses::iterator begin() noexcept + { + return _mMemberClasses.begin(); + } + + typename MemberClasses::const_iterator end() const noexcept + { + return _mMemberClasses.end(); + } + + typename MemberClasses::iterator end() noexcept + { + return _mMemberClasses.end(); + } + + typename MemberClasses::const_reverse_iterator rbegin() const noexcept + { + return _mMemberClasses.rbegin(); + } + + typename MemberClasses::reverse_iterator rbegin() noexcept + { + return _mMemberClasses.rbegin(); + } + + typename MemberClasses::const_reverse_iterator rend() const noexcept + { + return _mMemberClasses.rend(); + } + + typename MemberClasses::reverse_iterator rend() noexcept + { + return _mMemberClasses.rend(); + } + + /* + * Minimum alignment (bits) of instances of this field class. + */ + unsigned int minAlign() const noexcept + { + return _mMinAlign; + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, _mMemberClasses, _mMinAlign, + this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } + +private: + /* + * Returns the effective alignment of a structure field of which: + * + * • The minimum alignment is `minAlign` bits. + * • The members are instances of `memberClasses`. + */ + static unsigned int _effectiveAlign(const MemberClasses& memberClasses, + const unsigned int minAlign) noexcept + { + auto align = minAlign; + + for (auto& memberCls : memberClasses) { + align = std::max(align, memberCls.fc().align()); + } + + return align; + } + + template + static ValT *_memberClsByName(StructFcT& structFc, const std::string& name) noexcept + { + for (auto& memberCls : structFc._mMemberClasses) { + if (memberCls.name() == name) { + return &memberCls; + } + } + + return nullptr; + } + + /* Classes of members of instances of this field class */ + MemberClasses _mMemberClasses; + + /* Minimum alignment (bits) of instances of this field class */ + unsigned int _mMinAlign; +}; + +/* + * Optional field class base. + * + * Specific properties over `Fc`: + * + * • Selector field location of instances. + * • Optional field of instances. + */ +template +class OptionalFc : public Fc, public UserMixinsT::OptionalFc +{ +protected: + explicit OptionalFc(const FcType type, typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::OptionalFc mixin, typename Fc::UP&& fc, + FieldLoc&& selFieldLoc, OptAttrs&& attrs) : + Fc {type, std::move(fcMixin), 1, std::move(attrs)}, + UserMixinsT::OptionalFc {std::move(mixin)}, _mSelFieldLoc {std::move(selFieldLoc)}, + _mFc {std::move(fc)} + { + } + +public: + /* + * Selector field location of instances of this field class. + */ + const FieldLoc& selFieldLoc() const noexcept + { + return _mSelFieldLoc; + } + + /* + * Sets the selector field location of instances of this field class + * to `loc`. + */ + void selFieldLoc(FieldLoc loc) noexcept + { + _mSelFieldLoc = std::move(loc); + } + + /* + * Moves the selector field location of instances of this field + * class to the caller. + */ + FieldLoc takeSelFieldLoc() noexcept + { + return std::move(_mSelFieldLoc); + } + + /* + * Class of the optional field of instances of this field class. + */ + const Fc& fc() const noexcept + { + return *_mFc; + } + + /* + * Class of the optional field of instances of this field class. + */ + Fc& fc() noexcept + { + return *_mFc; + } + + /* + * Sets the class of the optional field of instances of this field + * class. + */ + void fc(typename Fc::UP fc) noexcept + { + _mFc = std::move(fc); + } + + /* + * Moves the class of the optional field of instances of this field + * class to the caller. + */ + typename Fc::UP takeFc() noexcept + { + return std::move(_mFc); + } + +private: + /* Selector field location of instances of this field class */ + FieldLoc _mSelFieldLoc; + + /* Class of the optional field of instances of this field class */ + typename Fc::UP _mFc; +}; + +/* + * Class of optional fields with a boolean selector. + */ +template +class OptionalWithBoolSelFc final : + public OptionalFc, + public UserMixinsT::OptionalWithBoolSelFc +{ +public: + /* Selector value type */ + using SelVal = bool; + + explicit OptionalWithBoolSelFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::OptionalFc optionalFcMixin, + typename UserMixinsT::OptionalWithBoolSelFc mixin, + typename Fc::UP fc, + FieldLoc selFieldLoc, + OptAttrs attrs = OptAttrs {}) : + OptionalFc {FcType::OptionalWithBoolSel, std::move(fcMixin), + std::move(optionalFcMixin), std::move(fc), + std::move(selFieldLoc), std::move(attrs)}, + UserMixinsT::OptionalWithBoolSelFc(std::move(mixin)) + { + } + + /* + * Returns whether or not an instance of this field class is enabled + * by the selector value `selVal`. + */ + bool isEnabledBySelVal(const bool selVal) const noexcept + { + return selVal; + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, this->fc().clone(), + this->selFieldLoc(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Base class of optional fields with an integer selector. + * + * `IntRangeSetT` is the integer selector range set type. + * + * Specific property over `OptionalFc`: + * + * • Selector field ranges which enable an instance. + */ +template +class OptionalWithIntSelFc : + public OptionalFc, + public UserMixinsT::OptionalWithIntSelFc +{ +public: + /* Integer selector range set type */ + using SelFieldRanges = IntRangeSetT; + + /* Selector value type */ + using SelVal = typename IntRangeSetT::Val; + +protected: + explicit OptionalWithIntSelFc(const FcType type, typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::OptionalFc optionalFcMixin, + typename UserMixinsT::OptionalWithIntSelFc mixin, + typename Fc::UP&& fc, + FieldLoc&& selFieldLoc, + IntRangeSetT&& selFieldRanges, OptAttrs&& attrs) : + OptionalFc {type, std::move(fcMixin), std::move(optionalFcMixin), + std::move(fc), std::move(selFieldLoc), std::move(attrs)}, + UserMixinsT::OptionalWithIntSelFc(std::move(mixin)), + _mSelFieldRanges {std::move(selFieldRanges)} + { + } + +public: + /* + * Integer selector field ranges which enable an instance of this + * field class. + */ + const IntRangeSetT& selFieldRanges() const noexcept + { + return _mSelFieldRanges; + } + + /* + * Returns whether or not an instance of this field class is + * enabled by the selector value `selVal`. + */ + bool isEnabledBySelVal(const SelVal selVal) const noexcept + { + return _mSelFieldRanges.contains(selVal); + } + +private: + /* Integer selector field ranges */ + IntRangeSetT _mSelFieldRanges; +}; + +/* + * Class of optional fields with an unsigned integer selector. + */ +template +class OptionalWithUIntSelFc final : + public OptionalWithIntSelFc, + public UserMixinsT::OptionalWithUIntSelFc +{ +public: + explicit OptionalWithUIntSelFc( + typename UserMixinsT::Fc fcMixin, typename UserMixinsT::OptionalFc optionalFcMixin, + typename UserMixinsT::OptionalWithIntSelFc optionalWithIntSelFcMixin, + typename UserMixinsT::OptionalWithUIntSelFc mixin, typename Fc::UP fc, + FieldLoc selFieldLoc, UIntRangeSet selFieldRanges, + OptAttrs attrs = OptAttrs {}) : + OptionalWithIntSelFc {FcType::OptionalWithUIntSel, + std::move(fcMixin), + std::move(optionalFcMixin), + std::move(optionalWithIntSelFcMixin), + std::move(fc), + std::move(selFieldLoc), + std::move(selFieldRanges), + std::move(attrs)}, + UserMixinsT::OptionalWithUIntSelFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, *this, + this->fc().clone(), this->selFieldLoc(), + this->selFieldRanges(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Class of optional fields with a signed integer selector. + */ +template +class OptionalWithSIntSelFc final : + public OptionalWithIntSelFc, + public UserMixinsT::OptionalWithSIntSelFc +{ +public: + explicit OptionalWithSIntSelFc( + typename UserMixinsT::Fc fcMixin, typename UserMixinsT::OptionalFc optionalFcMixin, + typename UserMixinsT::OptionalWithIntSelFc optionalWithIntSelFcMixin, + typename UserMixinsT::OptionalWithSIntSelFc mixin, typename Fc::UP fc, + FieldLoc selFieldLoc, SIntRangeSet selFieldRanges, + OptAttrs attrs = OptAttrs {}) : + OptionalWithIntSelFc {FcType::OptionalWithSIntSel, + std::move(fcMixin), + std::move(optionalFcMixin), + std::move(optionalWithIntSelFcMixin), + std::move(fc), + std::move(selFieldLoc), + std::move(selFieldRanges), + std::move(attrs)}, + UserMixinsT::OptionalWithSIntSelFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, *this, + this->fc().clone(), this->selFieldLoc(), + this->selFieldRanges(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Variant field class option. + * + * `IntRangeSetT` is the integer selector range set type. + */ +template +class VariantFcOpt final : public internal::WithAttrsMixin, public UserMixinsT::VariantFcOpt +{ +public: + /* Integer selector range set type */ + using SelFieldRanges = IntRangeSetT; + + /* Selector value type */ + using SelVal = typename IntRangeSetT::Val; + + explicit VariantFcOpt(typename UserMixinsT::VariantFcOpt mixin, typename Fc::UP fc, + IntRangeSetT selFieldRanges, bt2s::optional name, + OptAttrs attrs = OptAttrs {}) : + internal::WithAttrsMixin {std::move(attrs)}, + UserMixinsT::VariantFcOpt(std::move(mixin)), _mName {std::move(name)}, _mFc {std::move(fc)}, + _mSelFieldRanges {std::move(selFieldRanges)} + { + BT_ASSERT(_mFc); + } + + /* + * Builds a variant field class option from `other`, cloning its + * field class. + */ + VariantFcOpt(const VariantFcOpt& other) : + internal::WithAttrsMixin {other.attrs()}, UserMixinsT::VariantFcOpt(other), + _mName {other.name()}, _mFc {other.fc().clone()}, _mSelFieldRanges {other.selFieldRanges()} + { + } + + /* + * Name of this variant field class option. + */ + const bt2s::optional& name() const noexcept + { + return _mName; + } + + /* + * Moves the name of this variant field class option to the caller. + */ + typename bt2s::optional takeName() noexcept + { + return std::move(_mName); + } + + /* + * Field class of this variant field class option. + */ + const Fc& fc() const noexcept + { + return *_mFc; + } + + /* + * Name of this variant field class option. + */ + Fc& fc() noexcept + { + return *_mFc; + } + + /* + * Moves the field class of this variant field class option to the + * caller. + */ + typename Fc::UP takeFc() noexcept + { + return std::move(_mFc); + } + + /* + * Sets the field class of this variant field class option. + */ + void fc(typename Fc::UP fc) noexcept + { + _mFc = std::move(fc); + } + + /* + * Integer selector field ranges which select this variant field + * class option. + */ + const IntRangeSetT& selFieldRanges() const noexcept + { + return _mSelFieldRanges; + } + + /* + * Moves the attributes of this variant field class option to + * the caller. + */ + OptAttrs takeAttrs() noexcept + { + return this->_takeAttrs(); + } + +private: + bt2s::optional _mName; + typename Fc::UP _mFc; + IntRangeSetT _mSelFieldRanges; +}; + +/* + * Variant field class base. + * + * `IntRangeSetT` is the integer selector range set type. + * + * Specific properties over `Fc`: + * + * • Selector field location of instances. + * • Options. + */ +template +class VariantFc : public Fc, public UserMixinsT::VariantFc +{ +public: + /* Option type */ + using Opt = VariantFcOpt; + + /* Type of options */ + using Opts = std::vector; + + /* Integer selector range set type */ + using SelFieldRanges = typename Opt::SelFieldRanges; + + /* Selector value type */ + using SelVal = typename Opt::SelVal; + +protected: + explicit VariantFc(const FcType type, typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::VariantFc mixin, Opts&& opts, + FieldLoc&& selFieldLoc, OptAttrs&& attrs) : + Fc {type, std::move(fcMixin), 1, std::move(attrs)}, + UserMixinsT::VariantFc {std::move(mixin)}, _mOpts {std::move(opts)}, + _mSelFieldLoc {std::move(selFieldLoc)} + { + } + +public: + /* + * Selector field location of instances of this field class. + */ + const FieldLoc& selFieldLoc() const noexcept + { + return _mSelFieldLoc; + } + + /* + * Sets the selector field location of instances of this field class + * to `loc`. + */ + void selFieldLoc(FieldLoc loc) noexcept + { + _mSelFieldLoc = std::move(loc); + } + + /* + * Moves the selector field location of instances of this field + * class to the caller. + */ + FieldLoc takeSelFieldLoc() noexcept + { + return std::move(_mSelFieldLoc); + } + + /* + * Options of this field class. + */ + const Opts& opts() const noexcept + { + return _mOpts; + } + + /* + * Options of this field class. + */ + Opts& opts() noexcept + { + return _mOpts; + } + + typename Opts::const_reference operator[](const typename Opts::size_type index) const noexcept + { + return _mOpts[index]; + } + + typename Opts::reference operator[](const typename Opts::size_type index) noexcept + { + return _mOpts[index]; + } + + const typename Opts::value_type *operator[](const std::string& name) const noexcept + { + return this->_optByName(*this, name); + } + + typename Opts::value_type *operator[](const std::string& name) noexcept + { + return this->_optByName(*this, name); + } + + typename Opts::size_type size() const noexcept + { + return _mOpts.size(); + } + + typename Opts::const_iterator begin() const noexcept + { + return _mOpts.begin(); + } + + typename Opts::iterator begin() noexcept + { + return _mOpts.begin(); + } + + typename Opts::const_iterator end() const noexcept + { + return _mOpts.end(); + } + + typename Opts::iterator end() noexcept + { + return _mOpts.end(); + } + + /* + * Returns the option of this field class which the selector value + * `selVal` selects, or `nullptr` if none. + */ + typename Opts::const_iterator findOptBySelVal(const SelVal selVal) const noexcept + { + return std::find_if(_mOpts.begin(), _mOpts.end(), [selVal](const Opt& opt) { + return opt.selFieldRanges().contains(selVal); + }); + } + +private: + template + static ValT *_optByName(VarFcT& varFc, const std::string& name) noexcept + { + for (auto& opt : varFc._mOpts) { + if (opt.name() && *opt.name() == name) { + return &opt; + } + } + + return nullptr; + } + + /* Options of this field class */ + Opts _mOpts; + + /* Selector field location of instances of this field class */ + FieldLoc _mSelFieldLoc; +}; + +/* + * Class of variant fields with an unsigned integer selector. + */ +template +class VariantWithUIntSelFc final : + public VariantFc, + public UserMixinsT::VariantWithUIntSelFc +{ +public: + explicit VariantWithUIntSelFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::VariantFc variantFcMixin, + typename UserMixinsT::VariantWithUIntSelFc mixin, + typename VariantFc::Opts opts, + FieldLoc selFieldLoc, OptAttrs attrs = OptAttrs {}) : + VariantFc {FcType::VariantWithUIntSel, std::move(fcMixin), + std::move(variantFcMixin), std::move(opts), + std::move(selFieldLoc), std::move(attrs)}, + UserMixinsT::VariantWithUIntSelFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, this->opts(), + this->selFieldLoc(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +/* + * Class of variant fields with a signed integer selector. + */ +template +class VariantWithSIntSelFc final : + public VariantFc, + public UserMixinsT::VariantWithSIntSelFc +{ +public: + explicit VariantWithSIntSelFc(typename UserMixinsT::Fc fcMixin, + typename UserMixinsT::VariantFc variantFcMixin, + typename UserMixinsT::VariantWithSIntSelFc mixin, + typename VariantFc::Opts opts, + FieldLoc selFieldLoc, OptAttrs attrs = OptAttrs {}) : + VariantFc {FcType::VariantWithSIntSel, std::move(fcMixin), + std::move(variantFcMixin), std::move(opts), + std::move(selFieldLoc), std::move(attrs)}, + UserMixinsT::VariantWithSIntSelFc(std::move(mixin)) + { + } + + typename Fc::UP clone() const override + { + return bt2s::make_unique(*this, *this, *this, this->opts(), + this->selFieldLoc(), this->attrs()); + } + + void accept(FcVisitor& visitor) override + { + visitor.visit(*this); + } + + void accept(ConstFcVisitor& visitor) const override + { + visitor.visit(*this); + } +}; + +template +FixedLenBitArrayFc& Fc::asFixedLenBitArray() noexcept +{ + BT_ASSERT_DBG(this->isFixedLenBitArray()); + return static_cast&>(*this); +} + +template +const FixedLenBitArrayFc& Fc::asFixedLenBitArray() const noexcept +{ + BT_ASSERT_DBG(this->isFixedLenBitArray()); + return static_cast&>(*this); +} + +template +FixedLenBitMapFc& Fc::asFixedLenBitMap() noexcept +{ + BT_ASSERT_DBG(this->isFixedLenBitMap()); + return static_cast&>(*this); +} + +template +const FixedLenBitMapFc& Fc::asFixedLenBitMap() const noexcept +{ + BT_ASSERT_DBG(this->isFixedLenBitMap()); + return static_cast&>(*this); +} + +template +FixedLenBoolFc& Fc::asFixedLenBool() noexcept +{ + BT_ASSERT_DBG(this->isFixedLenBool()); + return static_cast&>(*this); +} + +template +const FixedLenBoolFc& Fc::asFixedLenBool() const noexcept +{ + BT_ASSERT_DBG(this->isFixedLenBool()); + return static_cast&>(*this); +} + +template +FixedLenFloatFc& Fc::asFixedLenFloat() noexcept +{ + BT_ASSERT_DBG(this->isFixedLenFloat()); + return static_cast&>(*this); +} + +template +const FixedLenFloatFc& Fc::asFixedLenFloat() const noexcept +{ + BT_ASSERT_DBG(this->isFixedLenFloat()); + return static_cast&>(*this); +} + +template +FixedLenIntFc& Fc::asFixedLenInt() noexcept +{ + BT_ASSERT_DBG(this->isFixedLenInt()); + return static_cast&>(*this); +} + +template +const FixedLenIntFc& Fc::asFixedLenInt() const noexcept +{ + BT_ASSERT_DBG(this->isFixedLenInt()); + return static_cast&>(*this); +} + +template +FixedLenSIntFc& Fc::asFixedLenSInt() noexcept +{ + BT_ASSERT_DBG(this->isFixedLenSInt()); + return static_cast&>(*this); +} + +template +const FixedLenSIntFc& Fc::asFixedLenSInt() const noexcept +{ + BT_ASSERT_DBG(this->isFixedLenSInt()); + return static_cast&>(*this); +} + +template +FixedLenUIntFc& Fc::asFixedLenUInt() noexcept +{ + BT_ASSERT_DBG(this->isFixedLenUInt()); + return static_cast&>(*this); +} + +template +const FixedLenUIntFc& Fc::asFixedLenUInt() const noexcept +{ + BT_ASSERT_DBG(this->isFixedLenUInt()); + return static_cast&>(*this); +} + +template +VarLenIntFc& Fc::asVarLenInt() noexcept +{ + BT_ASSERT_DBG(this->isVarLenInt()); + return static_cast&>(*this); +} + +template +const VarLenIntFc& Fc::asVarLenInt() const noexcept +{ + BT_ASSERT_DBG(this->isVarLenInt()); + return static_cast&>(*this); +} + +template +VarLenSIntFc& Fc::asVarLenSInt() noexcept +{ + BT_ASSERT_DBG(this->isVarLenSInt()); + return static_cast&>(*this); +} + +template +const VarLenSIntFc& Fc::asVarLenSInt() const noexcept +{ + BT_ASSERT_DBG(this->isVarLenSInt()); + return static_cast&>(*this); +} + +template +VarLenUIntFc& Fc::asVarLenUInt() noexcept +{ + BT_ASSERT_DBG(this->isVarLenUInt()); + return static_cast&>(*this); +} + +template +const VarLenUIntFc& Fc::asVarLenUInt() const noexcept +{ + BT_ASSERT_DBG(this->isVarLenUInt()); + return static_cast&>(*this); +} + +template +NullTerminatedStrFc& Fc::asNullTerminatedStr() noexcept +{ + BT_ASSERT_DBG(this->isNullTerminatedStr()); + return static_cast&>(*this); +} + +template +const NullTerminatedStrFc& Fc::asNullTerminatedStr() const noexcept +{ + BT_ASSERT_DBG(this->isNullTerminatedStr()); + return static_cast&>(*this); +} + +template +NonNullTerminatedStrFc& Fc::asNonNullTerminatedStr() noexcept +{ + BT_ASSERT_DBG(this->isNonNullTerminatedStr()); + return static_cast&>(*this); +} + +template +const NonNullTerminatedStrFc& Fc::asNonNullTerminatedStr() const noexcept +{ + BT_ASSERT_DBG(this->isNonNullTerminatedStr()); + return static_cast&>(*this); +} + +template +StrFc& Fc::asStr() noexcept +{ + BT_ASSERT_DBG(this->isStr()); + return static_cast&>(*this); +} + +template +const StrFc& Fc::asStr() const noexcept +{ + BT_ASSERT_DBG(this->isStr()); + return static_cast&>(*this); +} + +template +StaticLenStrFc& Fc::asStaticLenStr() noexcept +{ + BT_ASSERT_DBG(this->isStaticLenStr()); + return static_cast&>(*this); +} + +template +const StaticLenStrFc& Fc::asStaticLenStr() const noexcept +{ + BT_ASSERT_DBG(this->isStaticLenStr()); + return static_cast&>(*this); +} + +template +DynLenStrFc& Fc::asDynLenStr() noexcept +{ + BT_ASSERT_DBG(this->isDynLenStr()); + return static_cast&>(*this); +} + +template +const DynLenStrFc& Fc::asDynLenStr() const noexcept +{ + BT_ASSERT_DBG(this->isDynLenStr()); + return static_cast&>(*this); +} + +template +BlobFc& Fc::asBlob() noexcept +{ + BT_ASSERT_DBG(this->isBlob()); + return static_cast&>(*this); +} + +template +const BlobFc& Fc::asBlob() const noexcept +{ + BT_ASSERT_DBG(this->isBlob()); + return static_cast&>(*this); +} + +template +StaticLenBlobFc& Fc::asStaticLenBlob() noexcept +{ + BT_ASSERT_DBG(this->isStaticLenBlob()); + return static_cast&>(*this); +} + +template +const StaticLenBlobFc& Fc::asStaticLenBlob() const noexcept +{ + BT_ASSERT_DBG(this->isStaticLenBlob()); + return static_cast&>(*this); +} + +template +DynLenBlobFc& Fc::asDynLenBlob() noexcept +{ + BT_ASSERT_DBG(this->isDynLenBlob()); + return static_cast&>(*this); +} + +template +const DynLenBlobFc& Fc::asDynLenBlob() const noexcept +{ + BT_ASSERT_DBG(this->isDynLenBlob()); + return static_cast&>(*this); +} + +template +ArrayFc& Fc::asArray() noexcept +{ + BT_ASSERT_DBG(this->isArray()); + return static_cast&>(*this); +} + +template +const ArrayFc& Fc::asArray() const noexcept +{ + BT_ASSERT_DBG(this->isArray()); + return static_cast&>(*this); +} + +template +StaticLenArrayFc& Fc::asStaticLenArray() noexcept +{ + BT_ASSERT_DBG(this->isStaticLenArray()); + return static_cast&>(*this); +} + +template +const StaticLenArrayFc& Fc::asStaticLenArray() const noexcept +{ + BT_ASSERT_DBG(this->isStaticLenArray()); + return static_cast&>(*this); +} + +template +DynLenArrayFc& Fc::asDynLenArray() noexcept +{ + BT_ASSERT_DBG(this->isDynLenArray()); + return static_cast&>(*this); +} + +template +const DynLenArrayFc& Fc::asDynLenArray() const noexcept +{ + BT_ASSERT_DBG(this->isDynLenArray()); + return static_cast&>(*this); +} + +template +StructFc& Fc::asStruct() noexcept +{ + BT_ASSERT_DBG(this->isStruct()); + return static_cast&>(*this); +} + +template +const StructFc& Fc::asStruct() const noexcept +{ + BT_ASSERT_DBG(this->isStruct()); + return static_cast&>(*this); +} + +template +OptionalFc& Fc::asOptional() noexcept +{ + BT_ASSERT_DBG(this->isOptional()); + return static_cast&>(*this); +} + +template +const OptionalFc& Fc::asOptional() const noexcept +{ + BT_ASSERT_DBG(this->isOptional()); + return static_cast&>(*this); +} + +template +OptionalWithBoolSelFc& Fc::asOptionalWithBoolSel() noexcept +{ + BT_ASSERT_DBG(this->isOptionalWithBoolSel()); + return static_cast&>(*this); +} + +template +const OptionalWithBoolSelFc& Fc::asOptionalWithBoolSel() const noexcept +{ + BT_ASSERT_DBG(this->isOptionalWithBoolSel()); + return static_cast&>(*this); +} + +template +OptionalWithUIntSelFc& Fc::asOptionalWithUIntSel() noexcept +{ + BT_ASSERT_DBG(this->isOptionalWithUIntSel()); + return static_cast&>(*this); +} + +template +const OptionalWithUIntSelFc& Fc::asOptionalWithUIntSel() const noexcept +{ + BT_ASSERT_DBG(this->isOptionalWithUIntSel()); + return static_cast&>(*this); +} + +template +OptionalWithSIntSelFc& Fc::asOptionalWithSIntSel() noexcept +{ + BT_ASSERT_DBG(this->isOptionalWithSIntSel()); + return static_cast&>(*this); +} + +template +const OptionalWithSIntSelFc& Fc::asOptionalWithSIntSel() const noexcept +{ + BT_ASSERT_DBG(this->isOptionalWithSIntSel()); + return static_cast&>(*this); +} + +template +VariantWithUIntSelFc& Fc::asVariantWithUIntSel() noexcept +{ + BT_ASSERT_DBG(this->isVariantWithUIntSel()); + return static_cast&>(*this); +} + +template +const VariantWithUIntSelFc& Fc::asVariantWithUIntSel() const noexcept +{ + BT_ASSERT_DBG(this->isVariantWithUIntSel()); + return static_cast&>(*this); +} + +template +VariantWithSIntSelFc& Fc::asVariantWithSIntSel() noexcept +{ + BT_ASSERT_DBG(this->isVariantWithSIntSel()); + return static_cast&>(*this); +} + +template +const VariantWithSIntSelFc& Fc::asVariantWithSIntSel() const noexcept +{ + BT_ASSERT_DBG(this->isVariantWithSIntSel()); + return static_cast&>(*this); +} + +/* + * Clock offset (seconds and cycles). + */ +class ClkOffset final +{ +public: + explicit ClkOffset(const long long seconds = 0, const unsigned long long cycles = 0) noexcept : + _mSeconds {seconds}, _mCycles {cycles} + { + } + + /* + * Seconds part of this clock offset offset. + */ + long long seconds() const noexcept + { + return _mSeconds; + } + + /* + * Cycles part of this clock offset offset. + */ + unsigned long long cycles() const noexcept + { + return _mCycles; + } + +private: + /* Seconds part of this clock offset offset */ + long long _mSeconds; + + /* Cycles part of this clock offset offset */ + unsigned long long _mCycles; +}; + +/* + * Clock origin (namespace, name, and unique ID). + */ +class ClkOrigin final +{ +public: + /* + * Builds a clock origin having the (optional) namespace `ns`, the + * name `name`, and the unique ID `uid`. + */ + explicit ClkOrigin(bt2s::optional ns, std::string name, std::string uid) : + _mNs {std::move(ns)}, _mName {std::move(name)}, _mUid {std::move(uid)} + { + } + + /* + * Builds a Unix epoch clock origin. + */ + explicit ClkOrigin() : ClkOrigin {_unixEpochNs, _unixEpochName, _unixEpochUid} + { + } + + /* + * Namespace. + */ + const bt2s::optional& ns() const noexcept + { + return _mNs; + } + + /* + * Name. + */ + const std::string& name() const noexcept + { + return _mName; + } + + /* + * Unique ID. + */ + const std::string& uid() const noexcept + { + return _mUid; + } + + /* + * Returns whether or not this clock origin is the Unix epoch. + */ + bool isUnixEpoch() const noexcept + { + return _mNs == _unixEpochNs && _mName == _unixEpochName && _mUid == _unixEpochUid; + } + +private: + /* Internal Unix epoch origin namespace, name, and unique ID */ + static const char * const _unixEpochNs; + static const char * const _unixEpochName; + static const char * const _unixEpochUid; + + /* Namespace */ + bt2s::optional _mNs; + + /* Name */ + std::string _mName; + + /* Unique ID */ + std::string _mUid; +}; + +/* + * Clock class. + */ +template +class ClkCls final : + public internal::WithAttrsMixin, + public internal::WithLibCls, + public UserMixinsT::ClkCls +{ +public: + /* Shared pointer to a clock class */ + using SP = std::shared_ptr; + + explicit ClkCls(typename UserMixinsT::ClkCls mixin, std::string id, + const unsigned long long freq, bt2s::optional ns = bt2s::nullopt, + bt2s::optional name = bt2s::nullopt, + bt2s::optional uid = bt2s::nullopt, + const ClkOffset& offsetFromOrigin = ClkOffset {}, + bt2s::optional origin = ClkOrigin {}, + bt2s::optional descr = bt2s::nullopt, + bt2s::optional precision = bt2s::nullopt, + bt2s::optional accuracy = bt2s::nullopt, + OptAttrs attrs = OptAttrs {}) : + internal::WithAttrsMixin {std::move(attrs)}, + UserMixinsT::ClkCls {std::move(mixin)}, _mId {std::move(id)}, _mNs {std::move(ns)}, + _mName {std::move(name)}, _mUid {std::move(uid)}, _mFreq {freq}, + _mOffsetFromOrigin {offsetFromOrigin}, _mOrigin {std::move(origin)}, + _mDescr {std::move(descr)}, _mPrecision {std::move(precision)}, + _mAccuracy {std::move(accuracy)} + { + BT_ASSERT(_mFreq > 0); + BT_ASSERT(_mOffsetFromOrigin.cycles() < _mFreq); + } + + /* + * Unique ID of this clock class within its trace class. + */ + const std::string& id() const noexcept + { + return _mId; + } + + /* + * Namespace of instances of this clock class. + */ + const bt2s::optional& ns() const noexcept + { + return _mNs; + } + + /* + * Name of instances of this clock class. + */ + const bt2s::optional& name() const noexcept + { + return _mName; + } + + /* + * UID of instances of this clock class. + */ + const bt2s::optional& uid() const noexcept + { + return _mUid; + } + + /* + * Frequency (Hz) of instances of this clock class. + */ + unsigned long long freq() const noexcept + { + return _mFreq; + } + + /* + * Offset from origin of instances of this clock class. + */ + const ClkOffset& offsetFromOrigin() const noexcept + { + return _mOffsetFromOrigin; + } + + /* + * Sets the offset from origin of instances of this clock class. + */ + void offsetFromOrigin(const ClkOffset& offsetFromOrigin) noexcept + { + _mOffsetFromOrigin = offsetFromOrigin; + } + + /* + * Origin of instances of this clock class. + */ + const bt2s::optional& origin() const noexcept + { + return _mOrigin; + } + + /* + * Sets the origin of instances of this clock class. + */ + void origin(bt2s::optional origin) noexcept + { + _mOrigin = std::move(origin); + } + + /* + * Description of instances of this clock class. + */ + const bt2s::optional& descr() const noexcept + { + return _mDescr; + } + + /* + * Precision (cycles) of instances of this clock class. + */ + const bt2s::optional& precision() const noexcept + { + return _mPrecision; + } + + /* + * Accuracy (cycles) of instances of this clock class. + */ + const bt2s::optional& accuracy() const noexcept + { + return _mAccuracy; + } + +private: + /* Unique ID of this clock class within its trace class */ + std::string _mId; + + /* Namespace of instances of this clock class */ + bt2s::optional _mNs; + + /* Name of instances of this clock class */ + bt2s::optional _mName; + + /* UID of instances of this clock class */ + bt2s::optional _mUid; + + /* Frequency (Hz) of instances of this clock class */ + unsigned long long _mFreq; + + /* Offset from origin of instances of this clock class */ + ClkOffset _mOffsetFromOrigin; + + /* Origin of instances of this clock class */ + bt2s::optional _mOrigin; + + /* Description of instances of this clock class */ + bt2s::optional _mDescr; + + /* Precision (cycles) of instances of this clock class */ + bt2s::optional _mPrecision; + + /* Accuracy (cycles) of instances of this clock class */ + bt2s::optional _mAccuracy; +}; + +/* + * Event record class. + */ +template +class EventRecordCls final : + public internal::WithAttrsMixin, + public internal::WithLibCls, + public UserMixinsT::EventRecordCls +{ +public: + /* Unique pointer to an event record class */ + using UP = std::unique_ptr; + + explicit EventRecordCls(typename UserMixinsT::EventRecordCls mixin, const unsigned long long id, + bt2s::optional ns = bt2s::nullopt, + bt2s::optional name = bt2s::nullopt, + bt2s::optional uid = bt2s::nullopt, + typename StructFc::UP specCtxFc = nullptr, + typename StructFc::UP payloadFc = nullptr, + OptAttrs attrs = OptAttrs {}) : + internal::WithAttrsMixin {std::move(attrs)}, + UserMixinsT::EventRecordCls(std::move(mixin)), _mId {id}, _mNs {std::move(ns)}, + _mName {std::move(name)}, _mUid {std::move(uid)}, _mSpecCtxFc {std::move(specCtxFc)}, + _mPayloadFc {std::move(payloadFc)} + { + } + + /* + * ID of this event record class. + */ + unsigned long long id() const noexcept + { + return _mId; + } + + /* + * Namespace of instances of this event record class. + */ + const bt2s::optional& ns() const noexcept + { + return _mNs; + } + + /* + * Name of instances of this event record class. + */ + const bt2s::optional& name() const noexcept + { + return _mName; + } + + /* + * UID of instances of this event record class. + */ + const bt2s::optional& uid() const noexcept + { + return _mUid; + } + + /* + * Class of the specific context field of instances of this event + * record class. + */ + const StructFc *specCtxFc() const noexcept + { + return static_cast *>(_mSpecCtxFc.get()); + } + + /* + * Class of the specific context field of instances of this event + * record class. + */ + StructFc *specCtxFc() noexcept + { + return static_cast *>(_mSpecCtxFc.get()); + } + + /* + * Class of the payload field of instances of this event record + * class. + */ + const StructFc *payloadFc() const noexcept + { + return static_cast *>(_mPayloadFc.get()); + } + + /* + * Class of the payload field of instances of this event record + * class. + */ + StructFc *payloadFc() noexcept + { + return static_cast *>(_mPayloadFc.get()); + } + +private: + /* ID of this event record class */ + unsigned long long _mId; + + /* Namespace of instances of this event record class */ + bt2s::optional _mNs; + + /* Name of instances of this event record class */ + bt2s::optional _mName; + + /* UID of instances of this event record class */ + bt2s::optional _mUid; + + /* + * Class of the specific context field of instances of this event + * record class. + */ + typename StructFc::UP _mSpecCtxFc; + + /* + * Class of the payload field of instances of this event record + * class. + */ + typename StructFc::UP _mPayloadFc; +}; + +namespace internal { + +/* + * Less-than functor working on numeric IDs of unique pointers to + * `ObjT`. + */ +template +struct ObjUpIdLt final +{ + bool operator()(const typename ObjT::UP& objA, const typename ObjT::UP& objB) const noexcept + { + return objA->id() < objB->id(); + } +}; + +} /* namespace internal */ + +/* + * Data stream class. + */ +template +class DataStreamCls final : + public internal::WithAttrsMixin, + public internal::WithLibCls, + public UserMixinsT::DataStreamCls +{ +public: + /* Unique pointer to a data stream class */ + using UP = std::unique_ptr; + + /* Event record class set */ + using EventRecordClsSet = std::set::UP, + internal::ObjUpIdLt>>; + + explicit DataStreamCls(typename UserMixinsT::DataStreamCls mixin, const unsigned long long id, + bt2s::optional ns = bt2s::nullopt, + bt2s::optional name = bt2s::nullopt, + bt2s::optional uid = bt2s::nullopt, + typename StructFc::UP pktCtxFc = nullptr, + typename StructFc::UP eventRecordHeaderFc = nullptr, + typename StructFc::UP commonEventRecordCtxFc = nullptr, + typename ClkCls::SP defClkCls = nullptr, + OptAttrs attrs = OptAttrs {}) : + internal::WithAttrsMixin {std::move(attrs)}, + UserMixinsT::DataStreamCls(std::move(mixin)), _mId {id}, _mNs {std::move(ns)}, + _mName {std::move(name)}, _mUid {std::move(uid)}, _mPktCtxFc {std::move(pktCtxFc)}, + _mEventRecordHeaderFc {std::move(eventRecordHeaderFc)}, + _mCommonEventRecordCtxFc {std::move(commonEventRecordCtxFc)}, + _mDefClkCls {std::move(defClkCls)} + { + } + + /* + * ID of this data stream class. + */ + unsigned long long id() const noexcept + { + return _mId; + } + + /* + * Namespace of instances of this data stream class. + */ + const bt2s::optional& ns() const noexcept + { + return _mNs; + } + + /* + * Name of instances of this data stream class. + */ + const bt2s::optional& name() const noexcept + { + return _mName; + } + + /* + * UID of instances of this data stream class. + */ + const bt2s::optional& uid() const noexcept + { + return _mUid; + } + + /* + * Class of the packet context field of instances of this data + * stream class. + */ + const StructFc *pktCtxFc() const noexcept + { + return static_cast *>(_mPktCtxFc.get()); + } + + /* + * Class of the context field of packets which are part of instances + * of this data stream class. + */ + StructFc *pktCtxFc() noexcept + { + return static_cast *>(_mPktCtxFc.get()); + } + + /* + * Class of the context field of packets which are part of instances + * of this data stream class. + */ + const StructFc *eventRecordHeaderFc() const noexcept + { + return static_cast *>(_mEventRecordHeaderFc.get()); + } + + /* + * Class of the header field of event records which are part of + * instances of this data stream class. + */ + StructFc *eventRecordHeaderFc() noexcept + { + return static_cast *>(_mEventRecordHeaderFc.get()); + } + + /* + * Class of the header field of event records which are part of + * instances of this data stream class. + */ + const StructFc *commonEventRecordCtxFc() const noexcept + { + return static_cast *>(_mCommonEventRecordCtxFc.get()); + } + + /* + * Class of the common context field of event records which are part + * of instances of this data stream class. + */ + StructFc *commonEventRecordCtxFc() noexcept + { + return static_cast *>(_mCommonEventRecordCtxFc.get()); + } + + /* + * Class of the common context field of event records which are part + * of instances of this data stream class. + */ + const ClkCls *defClkCls() const noexcept + { + return _mDefClkCls.get(); + } + + /* + * Class of the default clock of instances of this data stream + * class. + */ + ClkCls *defClkCls() noexcept + { + return _mDefClkCls.get(); + } + + /* + * Event record classes of this data stream class. + */ + const EventRecordClsSet& eventRecordClasses() const noexcept + { + return _mEventRecordClasses; + } + + /* + * Adds the event record class `eventRecordCls` to the set of event + * record classes of this data stream class. + */ + void addEventRecordCls(typename EventRecordCls::UP eventRecordCls) + { + BT_ASSERT_DBG(eventRecordCls); + _mEventRecordClsIdMap[eventRecordCls->id()] = eventRecordCls.get(); + _mEventRecordClasses.emplace(std::move(eventRecordCls)); + } + + const EventRecordCls *operator[](const unsigned long long id) const noexcept + { + return this->_eventRecordClsById>(*this, id); + } + + EventRecordCls *operator[](const unsigned long long id) noexcept + { + return this->_eventRecordClsById>(*this, id); + } + + typename EventRecordClsSet::size_type size() const noexcept + { + return _mEventRecordClasses.size(); + } + + typename EventRecordClsSet::const_iterator begin() const noexcept + { + return _mEventRecordClasses.begin(); + } + + typename EventRecordClsSet::iterator begin() noexcept + { + return _mEventRecordClasses.begin(); + } + + typename EventRecordClsSet::const_iterator end() const noexcept + { + return _mEventRecordClasses.end(); + } + + typename EventRecordClsSet::iterator end() noexcept + { + return _mEventRecordClasses.end(); + } + +private: + using _EventRecordClsByIdMap = + std::unordered_map *>; + + template + static ValT *_eventRecordClsById(DataStreamClsT& dataStreamCls, + const unsigned long long id) noexcept + { + const auto it = dataStreamCls._mEventRecordClsIdMap.find(id); + + if (it == dataStreamCls._mEventRecordClsIdMap.end()) { + return nullptr; + } + + return it->second; + } + + /* ID of this data stream class */ + unsigned long long _mId; + + /* Event record classes of this data stream class */ + EventRecordClsSet _mEventRecordClasses; + + /* Map of event record class ID to event record class */ + _EventRecordClsByIdMap _mEventRecordClsIdMap; + + /* Namespace of instances of this data stream class */ + bt2s::optional _mNs; + + /* Name of instances of this data stream class */ + bt2s::optional _mName; + + /* UID of instances of this data stream class */ + bt2s::optional _mUid; + + /* + * Class of the context field of packets which are part of instances + * of this data stream class. + */ + typename Fc::UP _mPktCtxFc; + + /* + * Class of the header field of event records which are part of + * instances of this data stream class. + */ + typename Fc::UP _mEventRecordHeaderFc; + + /* + * Class of the common context field of event records which are part + * of instances of this data stream class. + */ + typename Fc::UP _mCommonEventRecordCtxFc; + + /* + * Class of the default clock of instances of this data stream + * class. + */ + typename ClkCls::SP _mDefClkCls; +}; + +/* + * Trace class. + */ +template +class TraceCls final : + public internal::WithAttrsMixin, + public internal::WithLibCls, + public UserMixinsT::TraceCls +{ +public: + /* Data stream class set */ + using DataStreamClsSet = std::set::UP, + internal::ObjUpIdLt>>; + + explicit TraceCls(typename UserMixinsT::TraceCls mixin, + bt2s::optional ns = bt2s::nullopt, + bt2s::optional name = bt2s::nullopt, + bt2s::optional uid = bt2s::nullopt, + bt2::ConstMapValue::Shared env = bt2::ConstMapValue::Shared {}, + typename Fc::UP pktHeaderFc = nullptr, + OptAttrs attrs = OptAttrs {}) : + internal::WithAttrsMixin {std::move(attrs)}, + UserMixinsT::TraceCls {std::move(mixin)}, _mNs {std::move(ns)}, _mName {std::move(name)}, + _mUid {std::move(uid)}, _mEnv {std::move(env)}, _mPktHeaderFc {std::move(pktHeaderFc)} + { + BT_ASSERT(!_mPktHeaderFc || _mPktHeaderFc->isStruct()); + } + + /* + * Namespace of instances of this trace class. + */ + const bt2s::optional& ns() const noexcept + { + return _mNs; + } + + /* + * Name of instances of this trace class. + */ + const bt2s::optional& name() const noexcept + { + return _mName; + } + + /* + * UID of instances of this trace class. + */ + const bt2s::optional& uid() const noexcept + { + return _mUid; + } + + /* + * Environment of instances of this trace class. + */ + const bt2::ConstMapValue::Shared& env() const noexcept + { + return _mEnv; + } + + /* + * Class of the header field of packets which are part of instances + * of this data stream class. + */ + const StructFc *pktHeaderFc() const noexcept + { + return static_cast *>(_mPktHeaderFc.get()); + } + + /* + * Class of the header field of packets which are part of instances + * of this data stream class. + */ + StructFc *pktHeaderFc() noexcept + { + return static_cast *>(_mPktHeaderFc.get()); + } + + /* + * Data stream classes of this trace class. + */ + const DataStreamClsSet& dataStreamClasses() const noexcept + { + return _mDataStreamClasses; + } + + /* + * Adds the data stream class `dataStreamCls` to the set of data + * stream classes of this trace class. + */ + void addDataStreamCls(typename DataStreamCls::UP dataStreamCls) + { + BT_ASSERT_DBG(dataStreamCls); + _mDataStreamClsIdMap[dataStreamCls->id()] = dataStreamCls.get(); + _mDataStreamClasses.emplace(std::move(dataStreamCls)); + } + + const DataStreamCls *operator[](const unsigned long long id) const noexcept + { + return this->_dataStreamClsById>(*this, id); + } + + DataStreamCls *operator[](const unsigned long long id) noexcept + { + return this->_dataStreamClsById>(*this, id); + } + + typename DataStreamClsSet::size_type size() const noexcept + { + return _mDataStreamClasses.size(); + } + + typename DataStreamClsSet::const_iterator begin() const noexcept + { + return _mDataStreamClasses.begin(); + } + + typename DataStreamClsSet::iterator begin() noexcept + { + return _mDataStreamClasses.begin(); + } + + typename DataStreamClsSet::const_iterator end() const noexcept + { + return _mDataStreamClasses.end(); + } + + typename DataStreamClsSet::iterator end() noexcept + { + return _mDataStreamClasses.end(); + } + +private: + using _DataStreamClsByIdMap = + std::unordered_map *>; + + template + static ValT *_dataStreamClsById(TraceClsT& traceCls, const unsigned long long id) noexcept + { + const auto it = traceCls._mDataStreamClsIdMap.find(id); + + if (it == traceCls._mDataStreamClsIdMap.end()) { + return nullptr; + } + + return it->second; + } + + /* Data stream classes of this trace class */ + DataStreamClsSet _mDataStreamClasses; + + /* Map of data stream class ID to data stream class */ + _DataStreamClsByIdMap _mDataStreamClsIdMap; + + /* Namespace of instances of this trace class */ + bt2s::optional _mNs; + + /* Name of instances of this trace class */ + bt2s::optional _mName; + + /* UID of instances of this trace class */ + bt2s::optional _mUid; + + /* Environment of instances of this trace class */ + bt2::ConstMapValue::Shared _mEnv; + + /* + * Class of the header field of packets which are part of instances + * of this data stream class. + */ + typename Fc::UP _mPktHeaderFc; +}; + +/* + * Default user mixins. + */ +struct DefUserMixins +{ + struct FieldLoc + { + }; + + struct Fc + { + }; + + struct FixedLenBitArrayFc + { + }; + + struct FixedLenBitMapFc + { + }; + + struct FixedLenBoolFc + { + }; + + struct FixedLenIntFc + { + }; + + struct FixedLenUIntFc + { + }; + + struct VarLenIntFc + { + }; + + struct VarLenUIntFc + { + }; + + struct StaticLenStrFc + { + }; + + struct DynLenStrFc + { + }; + + struct StaticLenBlobFc + { + }; + + struct DynLenBlobFc + { + }; + + struct StaticLenArrayFc + { + }; + + struct DynLenArrayFc + { + }; + + struct StructFieldMemberCls + { + }; + + struct StructFc + { + }; + + struct OptionalFc + { + }; + + struct OptionalWithBoolSelFc + { + }; + + struct OptionalWithIntSelFc + { + }; + + struct OptionalWithUIntSelFc + { + }; + + struct OptionalWithSIntSelFc + { + }; + + struct VariantFcOpt + { + }; + + struct VariantFc + { + }; + + struct VariantWithUIntSelFc + { + }; + + struct VariantWithSIntSelFc + { + }; + + struct ClkCls + { + }; + + struct EventRecordCls + { + }; + + struct DataStreamCls + { + }; + + struct TraceCls + { + }; +}; + +} /* namespace ir */ +} /* namespace ctf */ + +#endif /* BABELTRACE_PLUGINS_CTF_COMMON_METADATA_CTF_IR_HPP */ -- 2.34.1