string_view.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #if defined(OPENTELEMETRY_STL_VERSION)
  5. # if OPENTELEMETRY_STL_VERSION >= 2017
  6. # include "opentelemetry/std/string_view.h"
  7. # define OPENTELEMETRY_HAVE_STD_STRING_VIEW
  8. # endif
  9. #endif
  10. #if !defined(OPENTELEMETRY_HAVE_STD_STRING_VIEW)
  11. # include <algorithm>
  12. # include <cstring>
  13. # include <functional>
  14. # include <ostream>
  15. # include <stdexcept>
  16. # include <string>
  17. # include <type_traits>
  18. # include <utility>
  19. # include "opentelemetry/version.h"
  20. OPENTELEMETRY_BEGIN_NAMESPACE
  21. namespace nostd
  22. {
  23. using Traits = std::char_traits<char>;
  24. /**
  25. * Back port of std::string_view to work with pre-cpp-17 compilers.
  26. *
  27. * Note: This provides a subset of the methods available on std::string_view but
  28. * tries to be as compatible as possible with the std::string_view interface.
  29. */
  30. class string_view
  31. {
  32. public:
  33. typedef std::size_t size_type;
  34. static constexpr size_type npos = static_cast<size_type>(-1);
  35. string_view() noexcept : length_(0), data_(nullptr) {}
  36. string_view(const char *str) noexcept : length_(std::strlen(str)), data_(str) {}
  37. string_view(const std::basic_string<char> &str OPENTELEMETRY_ATTRIBUTE_LIFETIME_BOUND) noexcept
  38. : length_(str.length()), data_(str.c_str())
  39. {}
  40. string_view(const char *str, size_type len) noexcept : length_(len), data_(str) {}
  41. explicit operator std::string() const { return {data_, length_}; }
  42. const char *data() const noexcept { return data_; }
  43. bool empty() const noexcept { return length_ == 0; }
  44. size_type length() const noexcept { return length_; }
  45. size_type size() const noexcept { return length_; }
  46. const char *begin() const noexcept { return data(); }
  47. const char *end() const noexcept { return data() + length(); }
  48. const char &operator[](size_type i) { return *(data() + i); }
  49. string_view substr(size_type pos, size_type n = npos) const
  50. {
  51. if (pos > length_)
  52. {
  53. # if __EXCEPTIONS
  54. throw std::out_of_range{"opentelemetry::nostd::string_view"};
  55. # else
  56. std::terminate();
  57. # endif
  58. }
  59. n = (std::min)(n, length_ - pos);
  60. return string_view(data_ + pos, n);
  61. }
  62. int compare(string_view v) const noexcept
  63. {
  64. size_type len = (std::min)(size(), v.size());
  65. int result = Traits::compare(data(), v.data(), len);
  66. if (result == 0)
  67. result = size() == v.size() ? 0 : (size() < v.size() ? -1 : 1);
  68. return result;
  69. }
  70. int compare(size_type pos1, size_type count1, string_view v) const
  71. {
  72. return substr(pos1, count1).compare(v);
  73. }
  74. int compare(size_type pos1,
  75. size_type count1,
  76. string_view v,
  77. size_type pos2,
  78. size_type count2) const
  79. {
  80. return substr(pos1, count1).compare(v.substr(pos2, count2));
  81. }
  82. int compare(const char *s) const { return compare(string_view(s)); }
  83. int compare(size_type pos1, size_type count1, const char *s) const
  84. {
  85. return substr(pos1, count1).compare(string_view(s));
  86. }
  87. int compare(size_type pos1, size_type count1, const char *s, size_type count2) const
  88. {
  89. return substr(pos1, count1).compare(string_view(s, count2));
  90. }
  91. size_type find(char ch, size_type pos = 0) const noexcept
  92. {
  93. size_type res = npos;
  94. if (pos < length())
  95. {
  96. auto found = Traits::find(data() + pos, length() - pos, ch);
  97. if (found)
  98. {
  99. res = found - data();
  100. }
  101. }
  102. return res;
  103. }
  104. bool operator<(const string_view v) const noexcept { return compare(v) < 0; }
  105. bool operator>(const string_view v) const noexcept { return compare(v) > 0; }
  106. private:
  107. // Note: uses the same binary layout as libstdc++'s std::string_view
  108. // See
  109. // https://github.com/gcc-mirror/gcc/blob/e0c554e4da7310df83bb1dcc7b8e6c4c9c5a2a4f/libstdc%2B%2B-v3/include/std/string_view#L466-L467
  110. size_type length_;
  111. const char *data_;
  112. };
  113. inline bool operator==(string_view lhs, string_view rhs) noexcept
  114. {
  115. return lhs.length() == rhs.length() &&
  116. # if defined(_MSC_VER)
  117. # if _MSC_VER >= 1900 && _MSC_VER <= 1911
  118. // Avoid SCL error in Visual Studio 2015, VS2017 update 1 to update 4
  119. (std::memcmp(lhs.data(), rhs.data(), lhs.length()) == 0);
  120. # else
  121. std::equal(lhs.data(), lhs.data() + lhs.length(), rhs.data());
  122. # endif
  123. # else
  124. std::equal(lhs.data(), lhs.data() + lhs.length(), rhs.data());
  125. # endif
  126. }
  127. inline bool operator==(string_view lhs, const std::string &rhs) noexcept
  128. {
  129. return lhs == string_view(rhs);
  130. }
  131. inline bool operator==(const std::string &lhs, string_view rhs) noexcept
  132. {
  133. return string_view(lhs) == rhs;
  134. }
  135. inline bool operator==(string_view lhs, const char *rhs) noexcept
  136. {
  137. return lhs == string_view(rhs);
  138. }
  139. inline bool operator==(const char *lhs, string_view rhs) noexcept
  140. {
  141. return string_view(lhs) == rhs;
  142. }
  143. inline bool operator!=(string_view lhs, string_view rhs) noexcept
  144. {
  145. return !(lhs == rhs);
  146. }
  147. inline bool operator!=(string_view lhs, const std::string &rhs) noexcept
  148. {
  149. return !(lhs == rhs);
  150. }
  151. inline bool operator!=(const std::string &lhs, string_view rhs) noexcept
  152. {
  153. return !(lhs == rhs);
  154. }
  155. inline bool operator!=(string_view lhs, const char *rhs) noexcept
  156. {
  157. return !(lhs == rhs);
  158. }
  159. inline bool operator!=(const char *lhs, string_view rhs) noexcept
  160. {
  161. return !(lhs == rhs);
  162. }
  163. inline std::ostream &operator<<(std::ostream &os, string_view s)
  164. {
  165. return os.write(s.data(), static_cast<std::streamsize>(s.length()));
  166. }
  167. } // namespace nostd
  168. OPENTELEMETRY_END_NAMESPACE
  169. namespace std
  170. {
  171. template <>
  172. struct hash<OPENTELEMETRY_NAMESPACE::nostd::string_view>
  173. {
  174. std::size_t operator()(const OPENTELEMETRY_NAMESPACE::nostd::string_view &k) const
  175. {
  176. // TODO: for C++17 that has native support for std::basic_string_view it would
  177. // be more performance-efficient to provide a zero-copy hash.
  178. auto s = std::string(k.data(), k.size());
  179. return std::hash<std::string>{}(s);
  180. }
  181. };
  182. } // namespace std
  183. #endif /* OPENTELEMETRY_HAVE_STD_STRING_VIEW */