]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // Copyright The OpenTelemetry Authors |
2 | // SPDX-License-Identifier: Apache-2.0 | |
3 | ||
4 | #pragma once | |
5 | ||
6 | #include "opentelemetry/common/key_value_iterable_view.h" | |
7 | #include "opentelemetry/common/string_util.h" | |
8 | #include "opentelemetry/nostd/function_ref.h" | |
9 | #include "opentelemetry/nostd/shared_ptr.h" | |
10 | #include "opentelemetry/nostd/string_view.h" | |
11 | #include "opentelemetry/nostd/unique_ptr.h" | |
12 | #include "opentelemetry/version.h" | |
13 | ||
14 | #include <cstring> | |
15 | #include <string> | |
16 | #include <type_traits> | |
17 | ||
18 | OPENTELEMETRY_BEGIN_NAMESPACE | |
19 | namespace common | |
20 | { | |
21 | ||
22 | // Constructor parameter for KeyValueStringTokenizer | |
23 | struct KeyValueStringTokenizerOptions | |
24 | { | |
25 | char member_separator = ','; | |
26 | char key_value_separator = '='; | |
27 | bool ignore_empty_members = true; | |
28 | }; | |
29 | ||
30 | // Tokenizer for key-value headers | |
31 | class KeyValueStringTokenizer | |
32 | { | |
33 | public: | |
34 | KeyValueStringTokenizer( | |
35 | nostd::string_view str, | |
36 | const KeyValueStringTokenizerOptions &opts = KeyValueStringTokenizerOptions()) noexcept | |
37 | : str_(str), opts_(opts), index_(0) | |
38 | {} | |
39 | ||
40 | static nostd::string_view GetDefaultKeyOrValue() | |
41 | { | |
42 | static std::string default_str = ""; | |
43 | return default_str; | |
44 | } | |
45 | ||
46 | // Returns next key value in the string header | |
47 | // @param valid_kv : if the found kv pair is valid or not | |
48 | // @param key : key in kv pair | |
49 | // @param key : value in kv pair | |
50 | // @returns true if next kv pair was found, false otherwise. | |
51 | bool next(bool &valid_kv, nostd::string_view &key, nostd::string_view &value) noexcept | |
52 | { | |
53 | valid_kv = true; | |
54 | while (index_ < str_.size()) | |
55 | { | |
56 | bool is_empty_pair = false; | |
57 | size_t end = str_.find(opts_.member_separator, index_); | |
58 | if (end == std::string::npos) | |
59 | { | |
60 | end = str_.size() - 1; | |
61 | } | |
62 | else if (end == index_) // empty pair. do not update end | |
63 | { | |
64 | is_empty_pair = true; | |
65 | } | |
66 | else | |
67 | { | |
68 | end--; | |
69 | } | |
70 | ||
71 | auto list_member = StringUtil::Trim(str_, index_, end); | |
72 | if (list_member.size() == 0 || is_empty_pair) | |
73 | { | |
74 | // empty list member | |
75 | index_ = end + 2 - is_empty_pair; | |
76 | if (opts_.ignore_empty_members) | |
77 | { | |
78 | continue; | |
79 | } | |
80 | ||
81 | valid_kv = true; | |
82 | key = GetDefaultKeyOrValue(); | |
83 | value = GetDefaultKeyOrValue(); | |
84 | return true; | |
85 | } | |
86 | ||
87 | auto key_end_pos = list_member.find(opts_.key_value_separator); | |
88 | if (key_end_pos == std::string::npos) | |
89 | { | |
90 | // invalid member | |
91 | valid_kv = false; | |
92 | } | |
93 | else | |
94 | { | |
95 | key = list_member.substr(0, key_end_pos); | |
96 | value = list_member.substr(key_end_pos + 1); | |
97 | } | |
98 | ||
99 | index_ = end + 2; | |
100 | ||
101 | return true; | |
102 | } | |
103 | ||
104 | // no more entries remaining | |
105 | return false; | |
106 | } | |
107 | ||
108 | // Returns total number of tokens in header string | |
109 | size_t NumTokens() const noexcept | |
110 | { | |
111 | size_t cnt = 0, begin = 0; | |
112 | while (begin < str_.size()) | |
113 | { | |
114 | ++cnt; | |
115 | size_t end = str_.find(opts_.member_separator, begin); | |
116 | if (end == std::string::npos) | |
117 | { | |
118 | break; | |
119 | } | |
120 | ||
121 | begin = end + 1; | |
122 | } | |
123 | ||
124 | return cnt; | |
125 | } | |
126 | ||
127 | // Resets the iterator | |
128 | void reset() noexcept { index_ = 0; } | |
129 | ||
130 | private: | |
131 | nostd::string_view str_; | |
132 | KeyValueStringTokenizerOptions opts_; | |
133 | size_t index_; | |
134 | }; | |
135 | ||
136 | // Class to store fixed size array of key-value pairs of string type | |
137 | class KeyValueProperties | |
138 | { | |
139 | // Class to store key-value pairs of string types | |
140 | public: | |
141 | class Entry | |
142 | { | |
143 | public: | |
144 | Entry() : key_(nullptr), value_(nullptr) {} | |
145 | ||
146 | // Copy constructor | |
147 | Entry(const Entry ©) | |
148 | { | |
149 | key_ = CopyStringToPointer(copy.key_.get()); | |
150 | value_ = CopyStringToPointer(copy.value_.get()); | |
151 | } | |
152 | ||
153 | // Copy assignment operator | |
154 | Entry &operator=(Entry &other) | |
155 | { | |
156 | key_ = CopyStringToPointer(other.key_.get()); | |
157 | value_ = CopyStringToPointer(other.value_.get()); | |
158 | return *this; | |
159 | } | |
160 | ||
161 | // Move contructor and assignment operator | |
162 | Entry(Entry &&other) = default; | |
163 | Entry &operator=(Entry &&other) = default; | |
164 | ||
165 | // Creates an Entry for a given key-value pair. | |
166 | Entry(nostd::string_view key, nostd::string_view value) | |
167 | { | |
168 | key_ = CopyStringToPointer(key); | |
169 | value_ = CopyStringToPointer(value); | |
170 | } | |
171 | ||
172 | // Gets the key associated with this entry. | |
173 | nostd::string_view GetKey() const noexcept { return key_.get(); } | |
174 | ||
175 | // Gets the value associated with this entry. | |
176 | nostd::string_view GetValue() const noexcept { return value_.get(); } | |
177 | ||
178 | // Sets the value for this entry. This overrides the previous value. | |
179 | void SetValue(nostd::string_view value) noexcept { value_ = CopyStringToPointer(value); } | |
180 | ||
181 | private: | |
182 | // Store key and value as raw char pointers to avoid using std::string. | |
183 | nostd::unique_ptr<const char[]> key_; | |
184 | nostd::unique_ptr<const char[]> value_; | |
185 | ||
186 | // Copies string into a buffer and returns a unique_ptr to the buffer. | |
187 | // This is a workaround for the fact that memcpy doesn't accept a const destination. | |
188 | nostd::unique_ptr<const char[]> CopyStringToPointer(nostd::string_view str) | |
189 | { | |
190 | char *temp = new char[str.size() + 1]; | |
191 | memcpy(temp, str.data(), str.size()); | |
192 | temp[str.size()] = '\0'; | |
193 | return nostd::unique_ptr<const char[]>(temp); | |
194 | } | |
195 | }; | |
196 | ||
197 | // Maintain the number of entries in entries_. | |
198 | size_t num_entries_; | |
199 | ||
200 | // Max size of allocated array | |
201 | size_t max_num_entries_; | |
202 | ||
203 | // Store entries in a C-style array to avoid using std::array or std::vector. | |
204 | nostd::unique_ptr<Entry[]> entries_; | |
205 | ||
206 | public: | |
207 | // Create Key-value list of given size | |
208 | // @param size : Size of list. | |
209 | KeyValueProperties(size_t size) noexcept | |
210 | : num_entries_(0), max_num_entries_(size), entries_(new Entry[size]) | |
211 | {} | |
212 | ||
213 | // Create Empty Key-Value list | |
214 | KeyValueProperties() noexcept : num_entries_(0), max_num_entries_(0), entries_(nullptr) {} | |
215 | ||
216 | template <class T, class = typename std::enable_if<detail::is_key_value_iterable<T>::value>::type> | |
217 | KeyValueProperties(const T &keys_and_values) noexcept | |
218 | : num_entries_(0), | |
219 | max_num_entries_(keys_and_values.size()), | |
220 | entries_(new Entry[max_num_entries_]) | |
221 | { | |
222 | for (auto &e : keys_and_values) | |
223 | { | |
224 | Entry entry(e.first, e.second); | |
225 | (entries_.get())[num_entries_++] = std::move(entry); | |
226 | } | |
227 | } | |
228 | ||
229 | // Adds new kv pair into kv properties | |
230 | void AddEntry(nostd::string_view key, nostd::string_view value) noexcept | |
231 | { | |
232 | if (num_entries_ < max_num_entries_) | |
233 | { | |
234 | Entry entry(key, value); | |
235 | (entries_.get())[num_entries_++] = std::move(entry); | |
236 | } | |
237 | } | |
238 | ||
239 | // Returns all kv pair entries | |
240 | bool GetAllEntries( | |
241 | nostd::function_ref<bool(nostd::string_view, nostd::string_view)> callback) const noexcept | |
242 | { | |
243 | for (size_t i = 0; i < num_entries_; i++) | |
244 | { | |
245 | auto &entry = (entries_.get())[i]; | |
246 | if (!callback(entry.GetKey(), entry.GetValue())) | |
247 | { | |
248 | return false; | |
249 | } | |
250 | } | |
251 | return true; | |
252 | } | |
253 | ||
254 | // Return value for key if exists, return false otherwise | |
255 | bool GetValue(nostd::string_view key, std::string &value) const noexcept | |
256 | { | |
257 | for (size_t i = 0; i < num_entries_; i++) | |
258 | { | |
259 | auto &entry = (entries_.get())[i]; | |
260 | if (entry.GetKey() == key) | |
261 | { | |
262 | const auto &entry_value = entry.GetValue(); | |
263 | value = std::string(entry_value.data(), entry_value.size()); | |
264 | return true; | |
265 | } | |
266 | } | |
267 | return false; | |
268 | } | |
269 | ||
270 | size_t Size() const noexcept { return num_entries_; } | |
271 | }; | |
272 | } // namespace common | |
273 | OPENTELEMETRY_END_NAMESPACE |