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