]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | #pragma once |
2 | ||
3 | #include <optional> | |
4 | #include <string> | |
5 | #include <utility> | |
6 | ||
7 | namespace ceph::perf_counters { | |
8 | ||
9 | /// A key/value pair representing a perf counter label | |
10 | using label_pair = std::pair<std::string_view, std::string_view>; | |
11 | ||
12 | ||
13 | /// \brief Construct a key for a perf counter and set of labels. | |
14 | /// | |
15 | /// Returns a string of the form "counter_name\0key1\0val1\0key2\0val2\0", | |
16 | /// where label pairs are sorted by key with duplicates removed. | |
17 | /// | |
18 | /// This string representation avoids extra memory allocations associated | |
19 | /// with map<string, string>. It also supports the hashing and comparison | |
20 | /// operators required for use as a key in unordered and ordered containers. | |
21 | /// | |
22 | /// Example: | |
23 | /// \code | |
24 | /// std::string key = key_create("counter_name", { | |
25 | /// {"key1", "val1"}, {"key2", "val2"} | |
26 | /// }); | |
27 | /// \endcode | |
28 | template <std::size_t Count> | |
29 | std::string key_create(std::string_view counter_name, | |
30 | label_pair (&&labels)[Count]); | |
31 | ||
32 | /// \brief Construct a key for a perf counter without labels. | |
33 | /// \overload | |
34 | std::string key_create(std::string_view counter_name); | |
35 | ||
36 | /// \brief Insert additional labels into an existing key. | |
37 | /// | |
38 | /// This returns a new string without modifying the input. The returned | |
39 | /// string has labels in sorted order and no duplicate keys. | |
40 | template <std::size_t Count> | |
41 | std::string key_insert(std::string_view key, | |
42 | label_pair (&&labels)[Count]); | |
43 | ||
44 | /// \brief Return the counter name for a given key. | |
45 | std::string_view key_name(std::string_view key); | |
46 | ||
47 | ||
48 | /// A forward iterator over label_pairs encoded in a key | |
49 | class label_iterator { | |
50 | public: | |
51 | using base_iterator = const char*; | |
52 | using difference_type = std::ptrdiff_t; | |
53 | using value_type = label_pair; | |
54 | using pointer = const value_type*; | |
55 | using reference = const value_type&; | |
56 | ||
57 | label_iterator() = default; | |
58 | label_iterator(base_iterator begin, base_iterator end); | |
59 | ||
60 | label_iterator& operator++(); | |
61 | label_iterator operator++(int); | |
62 | ||
63 | reference operator*() const { return state->label; } | |
64 | pointer operator->() const { return &state->label; } | |
65 | ||
66 | auto operator<=>(const label_iterator& rhs) const = default; | |
67 | ||
68 | private: | |
69 | struct iterator_state { | |
70 | base_iterator pos; // end of current label | |
71 | base_iterator end; // end of buffer | |
72 | label_pair label; // current label | |
73 | ||
74 | auto operator<=>(const iterator_state& rhs) const = default; | |
75 | }; | |
76 | // an empty state represents a past-the-end iterator | |
77 | std::optional<iterator_state> state; | |
78 | ||
79 | // find the next two delimiters and construct the label string views | |
80 | static void advance(std::optional<iterator_state>& s); | |
81 | ||
82 | // try to parse the first label pair | |
83 | static auto make_state(base_iterator begin, base_iterator end) | |
84 | -> std::optional<iterator_state>; | |
85 | }; | |
86 | ||
87 | /// A sorted range of label_pairs | |
88 | class label_range { | |
89 | std::string_view buffer; | |
90 | public: | |
91 | using iterator = label_iterator; | |
92 | using const_iterator = label_iterator; | |
93 | ||
94 | label_range(std::string_view buffer) : buffer(buffer) {} | |
95 | ||
96 | const_iterator begin() const { return {buffer.begin(), buffer.end()}; } | |
97 | const_iterator cbegin() const { return {buffer.begin(), buffer.end()}; } | |
98 | ||
99 | const_iterator end() const { return {}; } | |
100 | const_iterator cend() const { return {}; } | |
101 | }; | |
102 | ||
103 | /// \brief Return the sorted range of label_pairs for a given key. | |
104 | /// | |
105 | /// Example: | |
106 | /// \code | |
107 | /// for (label_pair label : key_labels(key)) { | |
108 | /// std::cout << label.first << ":" << label.second << std::endl; | |
109 | /// } | |
110 | /// \endcode | |
111 | label_range key_labels(std::string_view key); | |
112 | ||
113 | ||
114 | namespace detail { | |
115 | ||
116 | std::string create(std::string_view counter_name, | |
117 | label_pair* begin, label_pair* end); | |
118 | ||
119 | std::string insert(const char* begin1, const char* end1, | |
120 | label_pair* begin2, label_pair* end2); | |
121 | ||
122 | } // namespace detail | |
123 | ||
124 | template <std::size_t Count> | |
125 | std::string key_create(std::string_view counter_name, | |
126 | label_pair (&&labels)[Count]) | |
127 | { | |
128 | return detail::create(counter_name, std::begin(labels), std::end(labels)); | |
129 | } | |
130 | ||
131 | template <std::size_t Count> | |
132 | std::string key_insert(std::string_view key, | |
133 | label_pair (&&labels)[Count]) | |
134 | { | |
135 | return detail::insert(key.begin(), key.end(), | |
136 | std::begin(labels), std::end(labels)); | |
137 | } | |
138 | ||
139 | } // namespace ceph::perf_counters |