context.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include <cstring>
  5. #include <utility>
  6. #include "opentelemetry/context/context_value.h"
  7. #include "opentelemetry/nostd/shared_ptr.h"
  8. #include "opentelemetry/nostd/string_view.h"
  9. #include "opentelemetry/nostd/variant.h"
  10. #include "opentelemetry/version.h"
  11. OPENTELEMETRY_BEGIN_NAMESPACE
  12. namespace context
  13. {
  14. // The context class provides a context identifier. Is built as a linked list
  15. // of DataList nodes and each context holds a shared_ptr to a place within
  16. // the list that determines which keys and values it has access to. All that
  17. // come before and none that come after.
  18. class Context
  19. {
  20. public:
  21. Context() = default;
  22. // Creates a context object from a map of keys and identifiers, this will
  23. // hold a shared_ptr to the head of the DataList linked list
  24. template <class T>
  25. Context(const T &keys_and_values) noexcept
  26. : head_{nostd::shared_ptr<DataList>{new DataList(keys_and_values)}}
  27. {}
  28. // Creates a context object from a key and value, this will
  29. // hold a shared_ptr to the head of the DataList linked list
  30. Context(nostd::string_view key, ContextValue value) noexcept
  31. : head_{nostd::shared_ptr<DataList>{new DataList(key, value)}}
  32. {}
  33. // Accepts a new iterable and then returns a new context that
  34. // contains the new key and value data. It attaches the
  35. // exisiting list to the end of the new list.
  36. template <class T>
  37. Context SetValues(T &values) noexcept
  38. {
  39. Context context = Context(values);
  40. nostd::shared_ptr<DataList> last = context.head_;
  41. while (last->next_ != nullptr)
  42. {
  43. last = last->next_;
  44. }
  45. last->next_ = head_;
  46. return context;
  47. }
  48. // Accepts a new iterable and then returns a new context that
  49. // contains the new key and value data. It attaches the
  50. // exisiting list to the end of the new list.
  51. Context SetValue(nostd::string_view key, ContextValue value) noexcept
  52. {
  53. Context context = Context(key, value);
  54. context.head_->next_ = head_;
  55. return context;
  56. }
  57. // Returns the value associated with the passed in key.
  58. context::ContextValue GetValue(const nostd::string_view key) const noexcept
  59. {
  60. for (DataList *data = head_.get(); data != nullptr; data = data->next_.get())
  61. {
  62. if (key.size() == data->key_length_)
  63. {
  64. if (std::memcmp(key.data(), data->key_, data->key_length_) == 0)
  65. {
  66. return data->value_;
  67. }
  68. }
  69. }
  70. return ContextValue{};
  71. }
  72. // Checks for key and returns true if found
  73. bool HasKey(const nostd::string_view key) const noexcept
  74. {
  75. return !nostd::holds_alternative<nostd::monostate>(GetValue(key));
  76. }
  77. bool operator==(const Context &other) const noexcept { return (head_ == other.head_); }
  78. private:
  79. // A linked list to contain the keys and values of this context node
  80. struct DataList
  81. {
  82. char *key_ = nullptr;
  83. nostd::shared_ptr<DataList> next_{nullptr};
  84. size_t key_length_ = 0UL;
  85. ContextValue value_;
  86. DataList() = default;
  87. // Builds a data list off of a key and value iterable and returns the head
  88. template <class T>
  89. DataList(const T &keys_and_vals)
  90. {
  91. bool first = true;
  92. auto *node = this;
  93. for (auto &iter : keys_and_vals)
  94. {
  95. if (first)
  96. {
  97. *node = DataList(iter.first, iter.second);
  98. first = false;
  99. }
  100. else
  101. {
  102. node->next_ = nostd::shared_ptr<DataList>(new DataList(iter.first, iter.second));
  103. node = node->next_.get();
  104. }
  105. }
  106. }
  107. // Builds a data list with just a key and value, so it will just be the head
  108. // and returns that head.
  109. DataList(nostd::string_view key, const ContextValue &value)
  110. {
  111. key_ = new char[key.size()];
  112. key_length_ = key.size();
  113. std::memcpy(key_, key.data(), key.size() * sizeof(char));
  114. next_ = nostd::shared_ptr<DataList>{nullptr};
  115. value_ = value;
  116. }
  117. DataList(const DataList &other)
  118. : key_(new char[other.key_length_]),
  119. next_(other.next_),
  120. key_length_(other.key_length_),
  121. value_(other.value_)
  122. {
  123. std::memcpy(key_, other.key_, other.key_length_ * sizeof(char));
  124. }
  125. DataList &operator=(DataList &&other) noexcept
  126. {
  127. key_length_ = other.key_length_;
  128. value_ = std::move(other.value_);
  129. next_ = std::move(other.next_);
  130. key_ = other.key_;
  131. other.key_ = nullptr;
  132. return *this;
  133. }
  134. ~DataList()
  135. {
  136. if (key_ != nullptr)
  137. {
  138. delete[] key_;
  139. }
  140. }
  141. };
  142. // Head of the list which holds the keys and values of this context
  143. nostd::shared_ptr<DataList> head_;
  144. };
  145. } // namespace context
  146. OPENTELEMETRY_END_NAMESPACE