| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 | // 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_NAMESPACEnamespace common{// Constructor parameter for KeyValueStringTokenizerstruct KeyValueStringTokenizerOptions{  char member_separator     = ',';  char key_value_separator  = '=';  bool ignore_empty_members = true;};// Tokenizer for key-value headersclass 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 typeclass KeyValueProperties{  // Class to store key-value pairs of string typespublic:  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 commonOPENTELEMETRY_END_NAMESPACE
 |