lst::field::field(std::string in_name, lst::type::cuptr in_type) :
name{std::move(in_name)}, _type{std::move(in_type)}
{
+ if (!_type) {
+ LTTNG_THROW_ERROR(fmt::format("Invalid type used to create field: field name = `{}`", name));
+ }
}
void lst::field::accept(lst::field_visitor& visitor) const
return name == other.name && *_type == *other._type;
}
+lst::type::cuptr lst::field::move_type() noexcept
+{
+ return std::move(_type);
+}
+
+const lst::type &lst::field::get_type() const
+{
+ if (_type) {
+ return *_type;
+ } else {
+ LTTNG_THROW_ERROR(fmt::format("Invalid attempt to access field type after transfer: field name = `{}`", name));
+ }
+}
+
lst::integer_type::integer_type(unsigned int in_alignment,
enum lst::byte_order in_byte_order,
unsigned int in_size,
} /* namespace sessiond */
} /* namespace lttng */
+template <>
+void lst::variant_type<lst::signed_enumeration_type::mapping::range_t::range_integer_t>::accept(
+ lst::type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+template <>
+void lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::accept(
+ lst::type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
lst::array_type::array_type(unsigned int in_alignment, type::cuptr in_element_type) :
type(in_alignment), element_type{std::move(in_element_type)}
{
{
visitor.visit(*this);
}
-
-lst::variant_type::variant_type(unsigned int in_alignment,
- field_location in_selector_field_location,
- choices in_choices) :
- type(in_alignment),
- selector_field_location{std::move(in_selector_field_location)},
- _choices
-{std::move(in_choices)}
-{
-}
-
-bool lst::variant_type::_is_equal(const type& base_other) const noexcept
-{
- const auto &other = static_cast<decltype(*this)&>(base_other);
-
- return this->selector_field_location == other.selector_field_location &&
- fields_are_equal(this->_choices
-, other._choices
-);
-}
-
-void lst::variant_type::accept(type_visitor& visitor) const
-{
- visitor.visit(*this);
-}
#include <vendor/optional.hpp>
+#include <algorithm>
#include <memory>
#include <string>
#include <type_traits>
class field {
public:
+ using uptr = std::unique_ptr<field>;
using cuptr = std::unique_ptr<const field>;
field(std::string name, type::cuptr type);
void accept(field_visitor& visitor) const;
bool operator==(const field& other) const noexcept;
+ const type& get_type() const;
+ type::cuptr move_type() noexcept;
+
const std::string name;
- const type::cuptr _type;
+
+private:
+ type::cuptr _type;
};
class integer_type : public type {
public:
using range_t = enumeration_mapping_range<MappingIntegerType>;
- enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = delete;
+ enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = default;
enumeration_mapping(const enumeration_mapping<MappingIntegerType>&& other) :
name{std::move(other.name)}, range{other.range}
{
virtual bool _is_equal(const type& base_other) const noexcept override final;
};
+template <class MappingIntegerType>
class variant_type : public type {
-public:
- using choices = std::vector<field::cuptr>;
+ static_assert(std::is_same<MappingIntegerType,
+ unsigned_enumeration_type::mapping::range_t::
+ range_integer_t>::value ||
+ std::is_same<MappingIntegerType,
+ signed_enumeration_type::mapping::range_t::
+ range_integer_t>::value,
+ "Variant mapping integer type must be one of those allowed by typed_enumeration_type");
- variant_type(unsigned int alignment,
- field_location selector_field_location,
- choices in_choices);
+public:
+ using choice = std::pair<const details::enumeration_mapping<MappingIntegerType>, type::cuptr>;
+ using choices = std::vector<choice>;
+
+ variant_type(unsigned int in_alignment,
+ field_location in_selector_field_location,
+ choices in_choices) :
+ type(in_alignment),
+ selector_field_location{std::move(in_selector_field_location)},
+ _choices{std::move(in_choices)}
+ {
+ }
virtual void accept(type_visitor& visitor) const override final;
const field_location selector_field_location;
const choices _choices;
-;
private:
- virtual bool _is_equal(const type& base_other) const noexcept override final;
+ static bool _choices_are_equal(const choices& a, const choices& b)
+ {
+ if (a.size() != b.size()) {
+ return false;
+ }
+
+ return true;
+
+ return std::equal(a.cbegin(), a.cend(), b.cbegin(),
+ [](const choice& choice_a, const choice& choice_b) {
+ return choice_a.first == choice_b.first &&
+ *choice_a.second == *choice_b.second;
+ });
+ }
+
+ virtual bool _is_equal(const type& base_other) const noexcept override final
+ {
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return selector_field_location == other.selector_field_location &&
+ _choices_are_equal(_choices, other._choices);
+ }
};
class field_visitor {
virtual void visit(const static_length_string_type& type) = 0;
virtual void visit(const dynamic_length_string_type& type) = 0;
virtual void visit(const structure_type& type) = 0;
- virtual void visit(const variant_type& type) = 0;
+ virtual void visit(const variant_type<signed_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
+ virtual void visit(const variant_type<unsigned_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
protected:
type_visitor() = default;
_current_field_name.push(_bypass_identifier_escape ?
field.name : escape_tsdl_identifier(field.name));
- field._type->accept(*this);
+ field.get_type().accept(*this);
_description += " ";
_description += _current_field_name.top();
_current_field_name.pop();
_description += "}";
}
- virtual void visit(const lst::variant_type& type) override final
+ template <class MappingIntegerType>
+ void visit_variant(const lst::variant_type<MappingIntegerType>& type)
{
if (type.alignment != 0) {
LTTNG_ASSERT(_current_field_name.size() > 0);
_bypass_identifier_escape = true;
for (const auto& field : type._choices) {
_description.resize(_description.size() + _indentation_level, '\t');
- field->accept(*this);
- _description += fmt::format("\n", field->name);
+ field.second->accept(*this);
+ _description += fmt::format(" {};\n", field.first.name);
}
_bypass_identifier_escape = previous_bypass_identifier_escape;
_description += "}";
}
+ virtual void visit(const lst::variant_type<lst::signed_enumeration_type::mapping::range_t::range_integer_t>& type) override final
+ {
+ visit_variant(type);
+ }
+
+ virtual void visit(const lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>& type) override final
+ {
+ visit_variant(type);
+ }
+
lst::type::cuptr create_character_type(enum lst::string_type::encoding encoding)
{
_current_integer_encoding_override = encoding;
};
/* Used to publish fields on which a field being decoded has an implicit dependency. */
-using publish_field_fn = std::function<void(lst::field::cuptr)>;
+using publish_field_fn = std::function<void(lst::field::uptr)>;
/* Look-up field from a field location. */
using lookup_field_fn = std::function<const lst::field &(const lst::field_location &)>;
/* Validate existence of length field (throws if not found). */
const auto &length_field = lookup_field(length_field_location);
const auto *integer_selector_field =
- dynamic_cast<const lst::integer_type *>(length_field._type.get());
+ dynamic_cast<const lst::integer_type *>(&length_field.get_type());
if (!integer_selector_field) {
LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from sequence: expected integer or enumeration");
}
return lttng::make_unique<lst::structure_type>(alignment, lst::structure_type::fields());
}
+template <class VariantSelectorMappingIntegerType>
+typename lst::variant_type<VariantSelectorMappingIntegerType>::choices create_typed_variant_choices(
+ const lttng_ust_ctl_field *current,
+ const lttng_ust_ctl_field *end,
+ const session_attributes& session_attributes,
+ const lttng_ust_ctl_field **next_ust_ctl_field,
+ lookup_field_fn lookup_field,
+ lst::field_location::root lookup_root,
+ lst::field_location::elements& current_field_location_elements,
+ unsigned int choice_count,
+ const lst::field& selector_field)
+{
+ typename lst::variant_type<VariantSelectorMappingIntegerType>::choices choices;
+ const auto& typed_enumeration = static_cast<
+ const lst::typed_enumeration_type<VariantSelectorMappingIntegerType>&>(
+ selector_field.get_type());
+
+ for (unsigned int i = 0; i < choice_count; i++) {
+ create_field_from_ust_ctl_fields(
+ current, end, session_attributes, next_ust_ctl_field,
+ [&choices, typed_enumeration, &selector_field](
+ lst::field::uptr field) {
+ /*
+ * Find the enumeration mapping that matches the
+ * field's name.
+ */
+ const auto mapping_it = std::find_if(
+ typed_enumeration._mappings->begin(),
+ typed_enumeration._mappings->end(),
+ [&field](const typename std::remove_reference<
+ decltype(typed_enumeration)>::type::
+ mapping& mapping) {
+ return mapping.name == field->name;
+ });
+
+ if (mapping_it == typed_enumeration._mappings->end()) {
+ LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
+ "Invalid variant choice: `{}` does not match any mapping in `{}` enumeration",
+ field->name, selector_field.name));
+ }
+
+ choices.emplace_back(*mapping_it, field->move_type());
+ },
+ lookup_field, lookup_root, current_field_location_elements);
+
+ current = *next_ust_ctl_field;
+ }
+
+ return choices;
+}
+
lst::type::cuptr create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
const lttng_ust_ctl_field *end,
const session_attributes& session_attributes,
/* Validate existence of selector field (throws if not found). */
const auto &selector_field = lookup_field(selector_field_location);
- const auto *integer_selector_field = dynamic_cast<const lst::integer_type *>(selector_field._type.get());
- if (!integer_selector_field) {
- LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from variant: expected integer or enumeration");
+ const auto *enumeration_selector_type =
+ dynamic_cast<const lst::enumeration_type *>(&selector_field.get_type());
+ if (!enumeration_selector_type) {
+ LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from variant: expected enumeration");
}
+ const bool selector_is_signed = enumeration_selector_type->signedness_ ==
+ lst::integer_type::signedness::SIGNED;
+
/* Choices follow. next_ust_ctl_field is updated as needed. */
- lst::variant_type::choices choices;
- for (unsigned int i = 0; i < choice_count; i++) {
- create_field_from_ust_ctl_fields(
- current, end, session_attributes, next_ust_ctl_field,
- [&choices](lst::field::cuptr field) {
- choices.emplace_back(std::move(field));
- },
- lookup_field,
- lookup_root, current_field_location_elements);
+ if (selector_is_signed) {
+ lst::variant_type<lst::signed_enumeration_type::mapping::range_t::range_integer_t>::
+ choices choices = create_typed_variant_choices<int64_t>(current,
+ end, session_attributes, next_ust_ctl_field,
+ lookup_field, lookup_root,
+ current_field_location_elements, choice_count,
+ selector_field);
+
+ return lttng::make_unique<lst::variant_type<int64_t>>(
+ alignment, std::move(selector_field_location), std::move(choices));
+ } else {
+ lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
+ choices choices = create_typed_variant_choices<uint64_t>(current,
+ end, session_attributes, next_ust_ctl_field,
+ lookup_field, lookup_root,
+ current_field_location_elements, choice_count,
+ selector_field);
- current = *next_ust_ctl_field;
+ return lttng::make_unique<lst::variant_type<uint64_t>>(
+ alignment, std::move(selector_field_location), std::move(choices));
}
-
- return lttng::make_unique<lst::variant_type>(
- alignment, std::move(selector_field_location), std::move(choices));
}
lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
if (header_type == lst::stream_class::header_type::COMPACT) {
auto enum_mappings = std::make_shared<lst::unsigned_enumeration_type::mappings>();
+ lst::unsigned_enumeration_type::mapping compact_mapping{
+ "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30)};
+ lst::unsigned_enumeration_type::mapping extended_mapping{"extended"};
- enum_mappings->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30));
- enum_mappings->emplace_back("extended");
+ enum_mappings->emplace_back(compact_mapping);
+ enum_mappings->emplace_back(extended_mapping);
lst::type::cuptr choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(1,
trace_abi.byte_order, 5, lst::integer_type::base::DECIMAL,
std::initializer_list<lst::integer_type::role>(
{lst::integer_type::role::EVENT_RECORD_CLASS_ID}));
- lst::variant_type::choices variant_choices;
+ lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
+ choices variant_choices;
lst::structure_type::fields compact_fields;
compact_fields.emplace_back(lttng::make_unique<lst::field>("timestamp",
role>({lst::integer_type::role::
DEFAULT_CLOCK_TIMESTAMP}))));
- lst::type::cuptr compact = lttng::make_unique<lst::structure_type>(
+ auto compact_type = lttng::make_unique<lst::structure_type>(
0, std::move(compact_fields));
- variant_choices.emplace_back(lttng::make_unique<lst::field>("compact", std::move(compact)));
+ variant_choices.emplace_back(std::move(compact_mapping), std::move(compact_type));
lst::structure_type::fields extended_fields;
extended_fields.emplace_back(lttng::make_unique<lst::field>("id",
role>({lst::integer_type::role::
DEFAULT_CLOCK_TIMESTAMP}))));
- lst::type::cuptr extended = lttng::make_unique<lst::structure_type>(0, std::move(extended_fields));
- variant_choices.emplace_back(lttng::make_unique<lst::field>("extended", std::move(extended)));
+ lst::type::cuptr extended_type = lttng::make_unique<lst::structure_type>(0, std::move(extended_fields));
+ variant_choices.emplace_back(std::move(extended_mapping), std::move(extended_type));
- lst::type::cuptr variant = lttng::make_unique<lst::variant_type>(0,
+ auto variant = lttng::make_unique<lst::variant_type<
+ lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
+ 0,
lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER,
{"id"}),
std::move(variant_choices));
lttng::make_unique<lst::field>("v", std::move(variant)));
} else {
auto enum_mappings = std::make_shared<lst::unsigned_enumeration_type::mappings>();
+ lst::unsigned_enumeration_type::mapping compact_mapping{"compact",
+ lst::unsigned_enumeration_type::mapping::range_t(0, 65534)};
+ lst::unsigned_enumeration_type::mapping extended_mapping{"extended"};
+ enum_mappings->emplace_back(compact_mapping);
+ enum_mappings->emplace_back(extended_mapping);
- enum_mappings->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 65534));
- enum_mappings->emplace_back("extended");
-
- lst::type::cuptr choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(
+ auto choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(
trace_abi.uint16_t_alignment, trace_abi.byte_order, 16,
lst::integer_type::base::DECIMAL, std::move(enum_mappings),
std::initializer_list<lst::integer_type::role>(
{lst::integer_type::role::EVENT_RECORD_CLASS_ID}));
- lst::variant_type::choices variant_choices;
+ lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
+ choices variant_choices;
lst::structure_type::fields compact_fields;
compact_fields.emplace_back(lttng::make_unique<lst::field>("timestamp",
role>({lst::integer_type::role::
DEFAULT_CLOCK_TIMESTAMP}))));
- lst::type::cuptr compact = lttng::make_unique<lst::structure_type>(
+ lst::type::cuptr compact_type = lttng::make_unique<lst::structure_type>(
0, std::move(compact_fields));
- variant_choices.emplace_back(
- lttng::make_unique<lst::field>("compact", std::move(compact)));
+ variant_choices.emplace_back(std::move(compact_mapping), std::move(compact_type));
lst::structure_type::fields extended_fields;
extended_fields.emplace_back(lttng::make_unique<lst::field>("id",
role>({lst::integer_type::role::
DEFAULT_CLOCK_TIMESTAMP}))));
- lst::type::cuptr extended = lttng::make_unique<lst::structure_type>(0, std::move(extended_fields));
- variant_choices.emplace_back(lttng::make_unique<lst::field>("extended", std::move(extended)));
+ auto extended_type = lttng::make_unique<lst::structure_type>(
+ 0, std::move(extended_fields));
+ variant_choices.emplace_back(std::move(extended_mapping), std::move(extended_type));
- lst::type::cuptr variant = lttng::make_unique<lst::variant_type>(0,
+ auto variant = lttng::make_unique<lst::variant_type<
+ lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
+ 0,
lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER,
{"id"}),
std::move(variant_choices));
- event_header_fields.emplace_back(lttng::make_unique<lst::field>("id", std::move(choice_enum)));
+ event_header_fields.emplace_back(
+ lttng::make_unique<lst::field>("id", std::move(choice_enum)));
event_header_fields.emplace_back(
lttng::make_unique<lst::field>("v", std::move(variant)));
}