| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 | // Copyright The OpenTelemetry Authors// SPDX-License-Identifier: Apache-2.0#pragma once#include <cstring>#include <utility>#include "opentelemetry/context/context_value.h"#include "opentelemetry/nostd/shared_ptr.h"#include "opentelemetry/nostd/string_view.h"#include "opentelemetry/nostd/variant.h"#include "opentelemetry/version.h"OPENTELEMETRY_BEGIN_NAMESPACEnamespace context{// The context class provides a context identifier. Is built as a linked list// of DataList nodes and each context holds a shared_ptr to a place within// the list that determines which keys and values it has access to. All that// come before and none that come after.class Context{public:  Context() = default;  // Creates a context object from a map of keys and identifiers, this will  // hold a shared_ptr to the head of the DataList linked list  template <class T>  Context(const T &keys_and_values) noexcept      : head_{nostd::shared_ptr<DataList>{new DataList(keys_and_values)}}  {}  // Creates a context object from a key and value, this will  // hold a shared_ptr to the head of the DataList linked list  Context(nostd::string_view key, ContextValue value) noexcept      : head_{nostd::shared_ptr<DataList>{new DataList(key, value)}}  {}  // Accepts a new iterable and then returns a new context that  // contains the new key and value data. It attaches the  // exisiting list to the end of the new list.  template <class T>  Context SetValues(T &values) noexcept  {    Context context                  = Context(values);    nostd::shared_ptr<DataList> last = context.head_;    while (last->next_ != nullptr)    {      last = last->next_;    }    last->next_ = head_;    return context;  }  // Accepts a new iterable and then returns a new context that  // contains the new key and value data. It attaches the  // exisiting list to the end of the new list.  Context SetValue(nostd::string_view key, ContextValue value) noexcept  {    Context context      = Context(key, value);    context.head_->next_ = head_;    return context;  }  // Returns the value associated with the passed in key.  context::ContextValue GetValue(const nostd::string_view key) const noexcept  {    for (DataList *data = head_.get(); data != nullptr; data = data->next_.get())    {      if (key.size() == data->key_length_)      {        if (std::memcmp(key.data(), data->key_, data->key_length_) == 0)        {          return data->value_;        }      }    }    return ContextValue{};  }  // Checks for key and returns true if found  bool HasKey(const nostd::string_view key) const noexcept  {    return !nostd::holds_alternative<nostd::monostate>(GetValue(key));  }  bool operator==(const Context &other) const noexcept { return (head_ == other.head_); }private:  // A linked list to contain the keys and values of this context node  struct DataList  {    char *key_ = nullptr;    nostd::shared_ptr<DataList> next_{nullptr};    size_t key_length_ = 0UL;    ContextValue value_;    DataList() = default;    // Builds a data list off of a key and value iterable and returns the head    template <class T>    DataList(const T &keys_and_vals)    {      bool first = true;      auto *node = this;      for (auto &iter : keys_and_vals)      {        if (first)        {          *node = DataList(iter.first, iter.second);          first = false;        }        else        {          node->next_ = nostd::shared_ptr<DataList>(new DataList(iter.first, iter.second));          node        = node->next_.get();        }      }    }    // Builds a data list with just a key and value, so it will just be the head    // and returns that head.    DataList(nostd::string_view key, const ContextValue &value)    {      key_        = new char[key.size()];      key_length_ = key.size();      std::memcpy(key_, key.data(), key.size() * sizeof(char));      next_  = nostd::shared_ptr<DataList>{nullptr};      value_ = value;    }    DataList(const DataList &other)        : key_(new char[other.key_length_]),          next_(other.next_),          key_length_(other.key_length_),          value_(other.value_)    {      std::memcpy(key_, other.key_, other.key_length_ * sizeof(char));    }    DataList &operator=(DataList &&other) noexcept    {      key_length_ = other.key_length_;      value_      = std::move(other.value_);      next_       = std::move(other.next_);      key_       = other.key_;      other.key_ = nullptr;      return *this;    }    ~DataList()    {      if (key_ != nullptr)      {        delete[] key_;      }    }  };  // Head of the list which holds the keys and values of this context  nostd::shared_ptr<DataList> head_;};}  // namespace contextOPENTELEMETRY_END_NAMESPACE
 |