273 lines
7.2 KiB
C++
273 lines
7.2 KiB
C++
// 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/shared_ptr.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())
|
|
: 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)
|
|
{
|
|
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 { return key_.get(); }
|
|
|
|
// Gets the value associated with this entry.
|
|
nostd::string_view GetValue() const { return value_.get(); }
|
|
|
|
// Sets the value for this entry. This overrides the previous value.
|
|
void SetValue(nostd::string_view value) { 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)
|
|
: num_entries_(0), max_num_entries_(size), entries_(new Entry[size])
|
|
{}
|
|
|
|
// Create Empty Key-Value list
|
|
KeyValueProperties() : 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)
|
|
: 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)
|
|
{
|
|
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
|
|
{
|
|
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
|
|
{
|
|
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 |