kv_properties.h 7.2 KB

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