clang-tidy: add Chrome-inspired checks
[lttng-tools.git] / src / bin / lttng-sessiond / field.hpp
CommitLineData
0220be14
JG
1/*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8#ifndef LTTNG_FIELD_H
9#define LTTNG_FIELD_H
10
6e01cdc6 11#include <common/format.hpp>
b6bbb1d6 12#include <common/make-unique.hpp>
6e01cdc6
JG
13
14#include <vendor/optional.hpp>
15
45110cdd 16#include <algorithm>
0220be14
JG
17#include <memory>
18#include <string>
19#include <type_traits>
20#include <vector>
21
0220be14
JG
22namespace lttng {
23namespace sessiond {
24namespace trace {
25
26class field_visitor;
27class type_visitor;
28
24ed18f2
JG
29enum class byte_order {
30 BIG_ENDIAN_,
31 LITTLE_ENDIAN_,
32};
33
eda1aa02
JG
34class field_location {
35public:
36 enum class root {
37 PACKET_HEADER,
38 PACKET_CONTEXT,
39 EVENT_RECORD_HEADER,
40 EVENT_RECORD_COMMON_CONTEXT,
41 EVENT_RECORD_SPECIFIC_CONTEXT,
42 EVENT_RECORD_PAYLOAD,
43 };
44
45 using elements = std::vector<std::string>;
46
47 field_location(root lookup_root, elements elements);
48 bool operator==(const field_location& other) const noexcept;
49
50 const root root_;
51 const elements elements_;
52};
53
0220be14
JG
54/*
55 * Field, and the various field types, represents fields as exposed by the
56 * LTTng tracers. These classes do not attempt to describe the complete spectrum of the CTF
57 * specification.
58 */
59
60class type {
61public:
62 using cuptr = std::unique_ptr<const type>;
63
64 static byte_order reverse_byte_order(byte_order byte_order) noexcept;
65
66 bool operator==(const type& other) const noexcept;
67 bool operator!=(const type& other) const noexcept;
68 virtual ~type();
b6bbb1d6
JG
69
70 /* Obtain an independent copy of `type`. */
71 virtual type::cuptr copy() const = 0;
72
0220be14
JG
73 virtual void accept(type_visitor& visitor) const = 0;
74
75 const unsigned int alignment;
76
77protected:
cd9adb8b 78 explicit type(unsigned int alignment);
0220be14
JG
79
80private:
81 virtual bool _is_equal(const type& rhs) const noexcept = 0;
82};
83
84class field {
85public:
45110cdd 86 using uptr = std::unique_ptr<field>;
0220be14
JG
87 using cuptr = std::unique_ptr<const field>;
88
89 field(std::string name, type::cuptr type);
90 void accept(field_visitor& visitor) const;
91 bool operator==(const field& other) const noexcept;
92
45110cdd
JG
93 const type& get_type() const;
94 type::cuptr move_type() noexcept;
95
0220be14 96 const std::string name;
45110cdd
JG
97
98private:
99 type::cuptr _type;
0220be14
JG
100};
101
102class integer_type : public type {
103public:
104 enum class signedness {
105 SIGNED,
106 UNSIGNED,
107 };
108
109 enum class base {
110 BINARY = 2,
111 OCTAL = 8,
112 DECIMAL = 10,
113 HEXADECIMAL = 16,
114 };
115
e7360180
JG
116 enum class role {
117 DEFAULT_CLOCK_TIMESTAMP,
118 /* Packet header field class specific roles. */
119 DATA_STREAM_CLASS_ID,
120 DATA_STREAM_ID,
121 PACKET_MAGIC_NUMBER,
122 /* Packet context field class specific roles. */
123 DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT,
124 PACKET_CONTENT_LENGTH,
125 PACKET_END_DEFAULT_CLOCK_TIMESTAMP,
126 PACKET_SEQUENCE_NUMBER,
127 PACKET_TOTAL_LENGTH,
128 /* Event record field class roles. */
129 EVENT_RECORD_CLASS_ID,
130 };
131
132 using roles = std::vector<role>;
133
0220be14
JG
134 integer_type(unsigned int alignment,
135 byte_order byte_order,
136 unsigned int size,
137 signedness signedness,
e7360180
JG
138 base base,
139 roles roles = {});
0220be14 140
cd9adb8b 141 type::cuptr copy() const override;
b6bbb1d6 142
cd9adb8b 143 void accept(type_visitor& visitor) const override;
0220be14
JG
144
145 const enum byte_order byte_order;
146 const unsigned int size;
65cd3c0c
JG
147 /*
148 * signedness and base are suffixed with '_' to work-around a bug in older
149 * GCCs (before 6) that do not recognize hidden/shadowed enumeration as valid
150 * nested-name-specifiers.
151 */
152 const signedness signedness_;
153 const base base_;
e7360180 154 const roles roles_;
0220be14
JG
155
156protected:
cd9adb8b 157 bool _is_equal(const type& other) const noexcept override;
0220be14
JG
158};
159
160class floating_point_type : public type {
161public:
162 floating_point_type(unsigned int alignment,
163 byte_order byte_order,
164 unsigned int exponent_digits,
165 unsigned int mantissa_digits);
166
cd9adb8b 167 type::cuptr copy() const final;
b6bbb1d6 168
cd9adb8b 169 void accept(type_visitor& visitor) const final;
0220be14
JG
170
171 const enum byte_order byte_order;
172 const unsigned int exponent_digits;
173 const unsigned int mantissa_digits;
174
175private:
cd9adb8b 176 bool _is_equal(const type& other) const noexcept final;
0220be14
JG
177};
178
179class enumeration_type : public integer_type {
180protected:
181 enumeration_type(unsigned int alignment,
182 enum byte_order byte_order,
183 unsigned int size,
184 enum signedness signedness,
e7360180
JG
185 enum base base,
186 integer_type::roles roles = {});
0220be14 187
cd9adb8b 188 void accept(type_visitor& visitor) const override = 0;
0220be14
JG
189};
190
191namespace details {
192template <class MappingIntegerType>
193class enumeration_mapping_range {
194public:
195 using range_integer_t = MappingIntegerType;
196
197 enumeration_mapping_range(MappingIntegerType in_begin, MappingIntegerType in_end) :
198 begin{in_begin}, end{in_end}
199 {
200 }
201
202 const range_integer_t begin, end;
203};
204
205template <class MappingIntegerType>
206bool operator==(const enumeration_mapping_range<MappingIntegerType>& lhs,
207 const enumeration_mapping_range<MappingIntegerType>& rhs) noexcept
208{
209 return lhs.begin == rhs.begin && lhs.end == rhs.end;
210}
211
212template <class MappingIntegerType>
213class enumeration_mapping {
214public:
215 using range_t = enumeration_mapping_range<MappingIntegerType>;
216
45110cdd 217 enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = default;
cd9adb8b
JG
218 enumeration_mapping(const enumeration_mapping<MappingIntegerType>&& other) noexcept :
219 name{ std::move(other.name) }, range{ other.range }
0220be14
JG
220 {
221 }
222
da9dd521 223 enumeration_mapping(std::string in_name, MappingIntegerType value) : name{std::move(in_name)}, range{value, value}
0220be14
JG
224 {
225 }
226
227 enumeration_mapping(std::string in_name, range_t in_range) : name{std::move(in_name)}, range{in_range}
228 {
229 }
230
231 const std::string name;
da9dd521
JG
232 /*
233 * Only one range per mapping is supported for the moment as
234 * the tracers (and CTF 1.8) can't express multiple ranges per
235 * mapping, which is allowed by CTF 2.
236 */
237 const range_t range;
0220be14
JG
238};
239
240template <class MappingIntegerType>
241bool operator==(const enumeration_mapping<MappingIntegerType>& lhs,
242 const enumeration_mapping<MappingIntegerType>& rhs) noexcept
243{
244 return lhs.name == rhs.name && lhs.range == rhs.range;
245}
246} /* namespace details */
247
b6bbb1d6 248template <typename MappingIntegerType>
0220be14
JG
249class typed_enumeration_type : public enumeration_type {
250public:
251 using mapping = details::enumeration_mapping<MappingIntegerType>;
252 using mappings = std::vector<mapping>;
253
254 static_assert(std::is_integral<MappingIntegerType>::value &&
255 sizeof(MappingIntegerType) == 8,
256 "MappingIntegerType must be either int64_t or uint64_t");
257
258 typed_enumeration_type(unsigned int in_alignment,
259 enum byte_order in_byte_order,
260 unsigned int in_size,
0220be14 261 enum base in_base,
e7360180
JG
262 const std::shared_ptr<const mappings>& in_mappings,
263 integer_type::roles in_roles = {}) :
0220be14
JG
264 enumeration_type(in_alignment,
265 in_byte_order,
266 in_size,
e7360180
JG
267 std::is_signed<MappingIntegerType>::value ?
268 integer_type::signedness::SIGNED :
269 integer_type::signedness::UNSIGNED,
270 in_base,
271 std::move(in_roles)),
da9dd521 272 mappings_{std::move(in_mappings)}
0220be14
JG
273 {
274 }
275
cd9adb8b 276 type::cuptr copy() const override
b6bbb1d6
JG
277 {
278 return lttng::make_unique<typed_enumeration_type<MappingIntegerType>>(
279 alignment, byte_order, size, base_, mappings_, roles_);
280 }
281
cd9adb8b 282 void accept(type_visitor& visitor) const final;
0220be14 283
da9dd521 284 const std::shared_ptr<const mappings> mappings_;
0220be14
JG
285
286private:
cd9adb8b 287 bool _is_equal(const type& base_other) const noexcept final
0220be14
JG
288 {
289 const auto& other = static_cast<const typed_enumeration_type<MappingIntegerType>&>(
290 base_other);
291
da9dd521 292 return integer_type::_is_equal(base_other) && *this->mappings_ == *other.mappings_;
0220be14
JG
293 }
294};
295
296/* Aliases for all allowed enumeration mapping types. */
297using signed_enumeration_type = typed_enumeration_type<int64_t>;
298using unsigned_enumeration_type = typed_enumeration_type<uint64_t>;
299
300class array_type : public type {
301public:
302 array_type(unsigned int alignment, type::cuptr element_type);
303
d7bfb9b0 304 const type::cuptr element_type;
0220be14
JG
305
306protected:
cd9adb8b 307 bool _is_equal(const type& base_other) const noexcept override;
0220be14
JG
308};
309
310class static_length_array_type : public array_type {
311public:
312 static_length_array_type(unsigned int alignment,
313 type::cuptr element_type,
314 uint64_t in_length);
315
cd9adb8b 316 type::cuptr copy() const final;
b6bbb1d6 317
cd9adb8b 318 void accept(type_visitor& visitor) const final;
0220be14
JG
319
320 const uint64_t length;
321
322private:
cd9adb8b 323 bool _is_equal(const type& base_other) const noexcept final;
0220be14
JG
324};
325
326class dynamic_length_array_type : public array_type {
327public:
328 dynamic_length_array_type(unsigned int alignment,
329 type::cuptr element_type,
eda1aa02 330 field_location length_field_location);
0220be14 331
cd9adb8b 332 type::cuptr copy() const final;
b6bbb1d6 333
cd9adb8b 334 void accept(type_visitor& visitor) const final;
0220be14 335
eda1aa02 336 const field_location length_field_location;
0220be14
JG
337
338private:
cd9adb8b 339 bool _is_equal(const type& base_other) const noexcept final;
0220be14
JG
340};
341
e7360180
JG
342class static_length_blob_type : public type {
343public:
344 enum class role {
345 /* Packet header field class specific role. */
da9dd521 346 METADATA_STREAM_UUID,
e7360180
JG
347 };
348
349 using roles = std::vector<role>;
350
351 static_length_blob_type(unsigned int alignment, uint64_t in_length_bytes, roles roles = {});
352
cd9adb8b 353 type::cuptr copy() const final;
b6bbb1d6 354
cd9adb8b 355 void accept(type_visitor& visitor) const final;
e7360180
JG
356
357 const uint64_t length_bytes;
358 const roles roles_;
359
360private:
cd9adb8b 361 bool _is_equal(const type& base_other) const noexcept final;
e7360180
JG
362};
363
364class dynamic_length_blob_type : public type {
365public:
eda1aa02 366 dynamic_length_blob_type(unsigned int alignment, field_location length_field_location);
e7360180 367
cd9adb8b 368 type::cuptr copy() const final;
b6bbb1d6 369
cd9adb8b 370 void accept(type_visitor& visitor) const final;
e7360180 371
eda1aa02 372 const field_location length_field_location;
e7360180
JG
373
374private:
cd9adb8b 375 bool _is_equal(const type& base_other) const noexcept final;
e7360180
JG
376};
377
0220be14
JG
378class string_type : public type {
379public:
380 enum class encoding {
381 ASCII,
382 UTF8,
383 };
384
385 string_type(unsigned int alignment, enum encoding encoding);
386
65cd3c0c
JG
387 /*
388 * encoding is suffixed with '_' to work-around a bug in older
389 * GCCs (before 6) that do not recognize hidden/shadowed enumeration as valid
390 * nested-name-specifiers.
391 */
392 const encoding encoding_;
0220be14
JG
393
394protected:
cd9adb8b 395 bool _is_equal(const type& base_other) const noexcept override;
0220be14
JG
396};
397
398class static_length_string_type : public string_type {
399public:
400 static_length_string_type(
401 unsigned int alignment, enum encoding in_encoding, uint64_t length);
b6bbb1d6 402
cd9adb8b 403 type::cuptr copy() const final;
b6bbb1d6 404
cd9adb8b 405 void accept(type_visitor& visitor) const final;
0220be14
JG
406
407 const uint64_t length;
408
409private:
cd9adb8b 410 bool _is_equal(const type& base_other) const noexcept final;
0220be14
JG
411};
412
413class dynamic_length_string_type : public string_type {
414public:
415 dynamic_length_string_type(unsigned int alignment,
416 enum encoding in_encoding,
eda1aa02 417 field_location length_field_location);
b6bbb1d6 418
cd9adb8b 419 type::cuptr copy() const final;
b6bbb1d6 420
cd9adb8b 421 void accept(type_visitor& visitor) const final;
0220be14 422
eda1aa02 423 const field_location length_field_location;
0220be14
JG
424
425private:
cd9adb8b 426 bool _is_equal(const type& base_other) const noexcept final;
0220be14
JG
427};
428
429class null_terminated_string_type : public string_type {
430public:
431 null_terminated_string_type(unsigned int alignment, enum encoding in_encoding);
b6bbb1d6 432
cd9adb8b 433 type::cuptr copy() const final;
b6bbb1d6 434
cd9adb8b 435 void accept(type_visitor& visitor) const final;
0220be14
JG
436};
437
438class structure_type : public type {
439public:
440 using fields = std::vector<field::cuptr>;
441
442 structure_type(unsigned int alignment, fields in_fields);
443
cd9adb8b 444 type::cuptr copy() const final;
b6bbb1d6 445
cd9adb8b 446 void accept(type_visitor& visitor) const final;
0220be14 447
da9dd521 448 const fields fields_;
0220be14
JG
449
450private:
cd9adb8b 451 bool _is_equal(const type& base_other) const noexcept final;
0220be14
JG
452};
453
b6bbb1d6 454template <typename MappingIntegerType>
0220be14 455class variant_type : public type {
45110cdd
JG
456 static_assert(std::is_same<MappingIntegerType,
457 unsigned_enumeration_type::mapping::range_t::
458 range_integer_t>::value ||
459 std::is_same<MappingIntegerType,
460 signed_enumeration_type::mapping::range_t::
461 range_integer_t>::value,
462 "Variant mapping integer type must be one of those allowed by typed_enumeration_type");
0220be14 463
45110cdd
JG
464public:
465 using choice = std::pair<const details::enumeration_mapping<MappingIntegerType>, type::cuptr>;
466 using choices = std::vector<choice>;
467
468 variant_type(unsigned int in_alignment,
469 field_location in_selector_field_location,
470 choices in_choices) :
471 type(in_alignment),
472 selector_field_location{std::move(in_selector_field_location)},
da9dd521 473 choices_{std::move(in_choices)}
45110cdd
JG
474 {
475 }
0220be14 476
cd9adb8b 477 type::cuptr copy() const final
b6bbb1d6
JG
478 {
479 choices copy_of_choices;
480
481 copy_of_choices.reserve(choices_.size());
482 for (const auto& current_choice : choices_) {
483 copy_of_choices.emplace_back(
484 current_choice.first, current_choice.second->copy());
485 }
486
487 return lttng::make_unique<variant_type<MappingIntegerType>>(
488 alignment, selector_field_location, std::move(copy_of_choices));
489 }
490
cd9adb8b 491 void accept(type_visitor& visitor) const final;
0220be14 492
eda1aa02 493 const field_location selector_field_location;
da9dd521 494 const choices choices_;
0220be14
JG
495
496private:
45110cdd
JG
497 static bool _choices_are_equal(const choices& a, const choices& b)
498 {
499 if (a.size() != b.size()) {
500 return false;
501 }
502
503 return true;
504
505 return std::equal(a.cbegin(), a.cend(), b.cbegin(),
506 [](const choice& choice_a, const choice& choice_b) {
507 return choice_a.first == choice_b.first &&
508 *choice_a.second == *choice_b.second;
509 });
510 }
511
cd9adb8b 512 bool _is_equal(const type& base_other) const noexcept final
45110cdd
JG
513 {
514 const auto& other = static_cast<decltype(*this)&>(base_other);
515
516 return selector_field_location == other.selector_field_location &&
da9dd521 517 _choices_are_equal(choices_, other.choices_);
45110cdd 518 }
0220be14
JG
519};
520
521class field_visitor {
522public:
523 virtual ~field_visitor() = default;
524 virtual void visit(const field& field) = 0;
525
526protected:
527 field_visitor() = default;
528};
529
530class type_visitor {
531public:
532 virtual ~type_visitor() = default;
533 virtual void visit(const integer_type& type) = 0;
534 virtual void visit(const floating_point_type& type) = 0;
535 virtual void visit(const signed_enumeration_type& type) = 0;
536 virtual void visit(const unsigned_enumeration_type& type) = 0;
537 virtual void visit(const static_length_array_type& type) = 0;
538 virtual void visit(const dynamic_length_array_type& type) = 0;
e7360180
JG
539 virtual void visit(const static_length_blob_type& type) = 0;
540 virtual void visit(const dynamic_length_blob_type& type) = 0;
0220be14
JG
541 virtual void visit(const null_terminated_string_type& type) = 0;
542 virtual void visit(const static_length_string_type& type) = 0;
543 virtual void visit(const dynamic_length_string_type& type) = 0;
544 virtual void visit(const structure_type& type) = 0;
45110cdd
JG
545 virtual void visit(const variant_type<signed_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
546 virtual void visit(const variant_type<unsigned_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
0220be14
JG
547
548protected:
549 type_visitor() = default;
550};
551
552} /* namespace trace */
553} /* namespace sessiond */
554} /* namespace lttng */
555
6e01cdc6 556/*
b6bbb1d6
JG
557 * Field formatters for libfmt.
558 *
6e01cdc6
JG
559 * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace,
560 * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480.
561 */
562namespace fmt {
563template <>
564struct formatter<lttng::sessiond::trace::field_location> : formatter<std::string> {
565 template <typename FormatCtx>
566 typename FormatCtx::iterator format(
567 const lttng::sessiond::trace::field_location& location, FormatCtx& ctx)
568 {
569 std::string location_str{"["};
570
571 switch (location.root_) {
572 case lttng::sessiond::trace::field_location::root::PACKET_HEADER:
573 location_str += "\"packet-header\"";
574 break;
575 case lttng::sessiond::trace::field_location::root::PACKET_CONTEXT:
576 location_str += "\"packet-context\"";
577 break;
578 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_HEADER:
579 location_str += "\"event-record-header\"";
580 break;
581 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_COMMON_CONTEXT:
582 location_str += "\"event-record-common-context\"";
583 break;
584 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_SPECIFIC_CONTEXT:
585 location_str += "\"event-record-specific-context\"";
586 break;
587 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_PAYLOAD:
588 location_str += "\"event-record-payload\"";
589 break;
590 }
591
592 for (const auto &name : location.elements_) {
593 location_str += ", \"" + name + "\"";
594 }
595
596 location_str += "]";
597 return format_to(ctx.out(), location_str);
598 }
599};
b6bbb1d6
JG
600
601namespace details {
602template <typename MappingIntegerType>
603::std::string format_mapping_range(typename lttng::sessiond::trace::typed_enumeration_type<
604 MappingIntegerType>::mapping::range_t range)
605{
606 if (range.begin == range.end) {
607 return ::fmt::format("[{}]", range.begin);
608 } else {
609 return ::fmt::format("[{}, {}]", range.begin, range.end);
610 }
611}
612} /* namespace details */
613
614template <>
615struct formatter<typename lttng::sessiond::trace::signed_enumeration_type::mapping::range_t>
616 : formatter<std::string> {
617 template <typename FormatCtx>
618 typename FormatCtx::iterator
619 format(typename lttng::sessiond::trace::signed_enumeration_type::mapping::range_t range,
620 FormatCtx& ctx)
621 {
622 return format_to(ctx.out(),
623 details::format_mapping_range<
624 lttng::sessiond::trace::signed_enumeration_type::
625 mapping::range_t::range_integer_t>(
626 range));
627 }
628};
629
630template <>
631struct formatter<typename lttng::sessiond::trace::unsigned_enumeration_type::mapping::range_t>
632 : formatter<std::string> {
633 template <typename FormatCtx>
634 typename FormatCtx::iterator
635 format(typename lttng::sessiond::trace::unsigned_enumeration_type::mapping::range_t range,
636 FormatCtx& ctx)
637 {
638 return format_to(ctx.out(),
639 details::format_mapping_range<
640 lttng::sessiond::trace::unsigned_enumeration_type::
641 mapping::range_t::range_integer_t>(
642 range));
643 }
644};
645
6e01cdc6
JG
646} /* namespace fmt */
647
0220be14 648#endif /* LTTNG_FIELD_H */
This page took 0.053078 seconds and 4 git commands to generate.