You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
7.2 KiB
272 lines
7.2 KiB
// Copyright The OpenTelemetry Authors |
|
// SPDX-License-Identifier: Apache-2.0 |
|
|
|
#pragma once |
|
|
|
#include "opentelemetry/common/key_value_iterable_view.h" |
|
#include "opentelemetry/common/string_util.h" |
|
#include "opentelemetry/nostd/function_ref.h" |
|
#include "opentelemetry/nostd/string_view.h" |
|
#include "opentelemetry/nostd/unique_ptr.h" |
|
#include "opentelemetry/version.h" |
|
|
|
#include <cstring> |
|
#include <string> |
|
#include <type_traits> |
|
|
|
OPENTELEMETRY_BEGIN_NAMESPACE |
|
namespace common |
|
{ |
|
|
|
// Constructor parameter for KeyValueStringTokenizer |
|
struct KeyValueStringTokenizerOptions |
|
{ |
|
char member_separator = ','; |
|
char key_value_separator = '='; |
|
bool ignore_empty_members = true; |
|
}; |
|
|
|
// Tokenizer for key-value headers |
|
class KeyValueStringTokenizer |
|
{ |
|
public: |
|
KeyValueStringTokenizer( |
|
nostd::string_view str, |
|
const KeyValueStringTokenizerOptions &opts = KeyValueStringTokenizerOptions()) noexcept |
|
: str_(str), opts_(opts), index_(0) |
|
{} |
|
|
|
static nostd::string_view GetDefaultKeyOrValue() |
|
{ |
|
static std::string default_str = ""; |
|
return default_str; |
|
} |
|
|
|
// Returns next key value in the string header |
|
// @param valid_kv : if the found kv pair is valid or not |
|
// @param key : key in kv pair |
|
// @param key : value in kv pair |
|
// @returns true if next kv pair was found, false otherwise. |
|
bool next(bool &valid_kv, nostd::string_view &key, nostd::string_view &value) noexcept |
|
{ |
|
valid_kv = true; |
|
while (index_ < str_.size()) |
|
{ |
|
bool is_empty_pair = false; |
|
size_t end = str_.find(opts_.member_separator, index_); |
|
if (end == std::string::npos) |
|
{ |
|
end = str_.size() - 1; |
|
} |
|
else if (end == index_) // empty pair. do not update end |
|
{ |
|
is_empty_pair = true; |
|
} |
|
else |
|
{ |
|
end--; |
|
} |
|
|
|
auto list_member = StringUtil::Trim(str_, index_, end); |
|
if (list_member.size() == 0 || is_empty_pair) |
|
{ |
|
// empty list member |
|
index_ = end + 2 - is_empty_pair; |
|
if (opts_.ignore_empty_members) |
|
{ |
|
continue; |
|
} |
|
|
|
valid_kv = true; |
|
key = GetDefaultKeyOrValue(); |
|
value = GetDefaultKeyOrValue(); |
|
return true; |
|
} |
|
|
|
auto key_end_pos = list_member.find(opts_.key_value_separator); |
|
if (key_end_pos == std::string::npos) |
|
{ |
|
// invalid member |
|
valid_kv = false; |
|
} |
|
else |
|
{ |
|
key = list_member.substr(0, key_end_pos); |
|
value = list_member.substr(key_end_pos + 1); |
|
} |
|
|
|
index_ = end + 2; |
|
|
|
return true; |
|
} |
|
|
|
// no more entries remaining |
|
return false; |
|
} |
|
|
|
// Returns total number of tokens in header string |
|
size_t NumTokens() const noexcept |
|
{ |
|
size_t cnt = 0, begin = 0; |
|
while (begin < str_.size()) |
|
{ |
|
++cnt; |
|
size_t end = str_.find(opts_.member_separator, begin); |
|
if (end == std::string::npos) |
|
{ |
|
break; |
|
} |
|
|
|
begin = end + 1; |
|
} |
|
|
|
return cnt; |
|
} |
|
|
|
// Resets the iterator |
|
void reset() noexcept { index_ = 0; } |
|
|
|
private: |
|
nostd::string_view str_; |
|
KeyValueStringTokenizerOptions opts_; |
|
size_t index_; |
|
}; |
|
|
|
// Class to store fixed size array of key-value pairs of string type |
|
class KeyValueProperties |
|
{ |
|
// Class to store key-value pairs of string types |
|
public: |
|
class Entry |
|
{ |
|
public: |
|
Entry() : key_(nullptr), value_(nullptr) {} |
|
|
|
// Copy constructor |
|
Entry(const Entry ©) |
|
{ |
|
key_ = CopyStringToPointer(copy.key_.get()); |
|
value_ = CopyStringToPointer(copy.value_.get()); |
|
} |
|
|
|
// Copy assignment operator |
|
Entry &operator=(Entry &other) |
|
{ |
|
key_ = CopyStringToPointer(other.key_.get()); |
|
value_ = CopyStringToPointer(other.value_.get()); |
|
return *this; |
|
} |
|
|
|
// Move contructor and assignment operator |
|
Entry(Entry &&other) = default; |
|
Entry &operator=(Entry &&other) = default; |
|
|
|
// Creates an Entry for a given key-value pair. |
|
Entry(nostd::string_view key, nostd::string_view value) |
|
{ |
|
key_ = CopyStringToPointer(key); |
|
value_ = CopyStringToPointer(value); |
|
} |
|
|
|
// Gets the key associated with this entry. |
|
nostd::string_view GetKey() const noexcept { return key_.get(); } |
|
|
|
// Gets the value associated with this entry. |
|
nostd::string_view GetValue() const noexcept { return value_.get(); } |
|
|
|
// Sets the value for this entry. This overrides the previous value. |
|
void SetValue(nostd::string_view value) noexcept { value_ = CopyStringToPointer(value); } |
|
|
|
private: |
|
// Store key and value as raw char pointers to avoid using std::string. |
|
nostd::unique_ptr<const char[]> key_; |
|
nostd::unique_ptr<const char[]> value_; |
|
|
|
// Copies string into a buffer and returns a unique_ptr to the buffer. |
|
// This is a workaround for the fact that memcpy doesn't accept a const destination. |
|
nostd::unique_ptr<const char[]> CopyStringToPointer(nostd::string_view str) |
|
{ |
|
char *temp = new char[str.size() + 1]; |
|
memcpy(temp, str.data(), str.size()); |
|
temp[str.size()] = '\0'; |
|
return nostd::unique_ptr<const char[]>(temp); |
|
} |
|
}; |
|
|
|
// Maintain the number of entries in entries_. |
|
size_t num_entries_; |
|
|
|
// Max size of allocated array |
|
size_t max_num_entries_; |
|
|
|
// Store entries in a C-style array to avoid using std::array or std::vector. |
|
nostd::unique_ptr<Entry[]> entries_; |
|
|
|
public: |
|
// Create Key-value list of given size |
|
// @param size : Size of list. |
|
KeyValueProperties(size_t size) noexcept |
|
: num_entries_(0), max_num_entries_(size), entries_(new Entry[size]) |
|
{} |
|
|
|
// Create Empty Key-Value list |
|
KeyValueProperties() noexcept : num_entries_(0), max_num_entries_(0), entries_(nullptr) {} |
|
|
|
template <class T, class = typename std::enable_if<detail::is_key_value_iterable<T>::value>::type> |
|
KeyValueProperties(const T &keys_and_values) noexcept |
|
: num_entries_(0), |
|
max_num_entries_(keys_and_values.size()), |
|
entries_(new Entry[max_num_entries_]) |
|
{ |
|
for (auto &e : keys_and_values) |
|
{ |
|
Entry entry(e.first, e.second); |
|
(entries_.get())[num_entries_++] = std::move(entry); |
|
} |
|
} |
|
|
|
// Adds new kv pair into kv properties |
|
void AddEntry(nostd::string_view key, nostd::string_view value) noexcept |
|
{ |
|
if (num_entries_ < max_num_entries_) |
|
{ |
|
Entry entry(key, value); |
|
(entries_.get())[num_entries_++] = std::move(entry); |
|
} |
|
} |
|
|
|
// Returns all kv pair entries |
|
bool GetAllEntries( |
|
nostd::function_ref<bool(nostd::string_view, nostd::string_view)> callback) const noexcept |
|
{ |
|
for (size_t i = 0; i < num_entries_; i++) |
|
{ |
|
auto &entry = (entries_.get())[i]; |
|
if (!callback(entry.GetKey(), entry.GetValue())) |
|
{ |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
// Return value for key if exists, return false otherwise |
|
bool GetValue(nostd::string_view key, std::string &value) const noexcept |
|
{ |
|
for (size_t i = 0; i < num_entries_; i++) |
|
{ |
|
auto &entry = (entries_.get())[i]; |
|
if (entry.GetKey() == key) |
|
{ |
|
const auto &entry_value = entry.GetValue(); |
|
value = std::string(entry_value.data(), entry_value.size()); |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
size_t Size() const noexcept { return num_entries_; } |
|
}; |
|
} // namespace common |
|
OPENTELEMETRY_END_NAMESPACE
|
|
|