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