span.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. // Try to use either `std::span` or `gsl::span`
  5. #if defined(OPENTELEMETRY_STL_VERSION)
  6. # if OPENTELEMETRY_STL_VERSION >= 2020
  7. # include <array>
  8. # include <cstddef>
  9. # include <iterator>
  10. # include <type_traits>
  11. /**
  12. * @brief Clang 14.0.0 with libc++ do not support implicitly construct a span
  13. * for a range. We just use our fallback version.
  14. *
  15. */
  16. # if !defined(OPENTELEMETRY_OPTION_USE_STD_SPAN) && defined(_LIBCPP_VERSION)
  17. # if _LIBCPP_VERSION <= 14000
  18. # define OPENTELEMETRY_OPTION_USE_STD_SPAN 0
  19. # endif
  20. # endif
  21. # ifndef OPENTELEMETRY_OPTION_USE_STD_SPAN
  22. # define OPENTELEMETRY_OPTION_USE_STD_SPAN 1
  23. # endif
  24. # if OPENTELEMETRY_OPTION_USE_STD_SPAN
  25. # include "opentelemetry/std/span.h"
  26. # endif
  27. # endif /* OPENTELEMETRY_STL_VERSION >= 2020 */
  28. #endif /* OPENTELEMETRY_STL_VERSION */
  29. // Fallback to `nostd::span` if necessary
  30. #if !defined(OPENTELEMETRY_HAVE_SPAN)
  31. # include <array>
  32. # include <cassert>
  33. # include <cstddef>
  34. # include <exception>
  35. # include <iterator>
  36. # include <type_traits>
  37. # include "opentelemetry/nostd/utility.h"
  38. # include "opentelemetry/version.h"
  39. OPENTELEMETRY_BEGIN_NAMESPACE
  40. namespace nostd
  41. {
  42. constexpr size_t dynamic_extent = static_cast<size_t>(-1);
  43. template <class T, size_t Extent = dynamic_extent>
  44. class span;
  45. namespace detail
  46. {
  47. /**
  48. * Helper class to resolve overloaded constructors
  49. */
  50. template <class T>
  51. struct is_specialized_span_convertible : std::false_type
  52. {};
  53. template <class T, size_t N>
  54. struct is_specialized_span_convertible<std::array<T, N>> : std::true_type
  55. {};
  56. template <class T, size_t N>
  57. struct is_specialized_span_convertible<T[N]> : std::true_type
  58. {};
  59. template <class T, size_t Extent>
  60. struct is_specialized_span_convertible<span<T, Extent>> : std::true_type
  61. {};
  62. } // namespace detail
  63. /**
  64. * Back port of std::span.
  65. *
  66. * See https://en.cppreference.com/w/cpp/container/span for interface documentation.
  67. *
  68. * Note: This provides a subset of the methods available on std::span.
  69. *
  70. * Note: The std::span API specifies error cases to have undefined behavior, so this implementation
  71. * chooses to terminate or assert rather than throw exceptions.
  72. */
  73. template <class T, size_t Extent>
  74. class span
  75. {
  76. public:
  77. static constexpr size_t extent = Extent;
  78. // This arcane code is how we make default-construction result in an SFINAE error
  79. // with C++11 when Extent != 0 as specified by the std::span API.
  80. //
  81. // See https://stackoverflow.com/a/10309720/4447365
  82. template <bool B = Extent == 0, typename std::enable_if<B>::type * = nullptr>
  83. span() noexcept : data_{nullptr}
  84. {}
  85. span(T *data, size_t count) noexcept : data_{data}
  86. {
  87. if (count != Extent)
  88. {
  89. std::terminate();
  90. }
  91. }
  92. span(T *first, T *last) noexcept : data_{first}
  93. {
  94. if (std::distance(first, last) != Extent)
  95. {
  96. std::terminate();
  97. }
  98. }
  99. template <size_t N, typename std::enable_if<Extent == N>::type * = nullptr>
  100. span(T (&array)[N]) noexcept : data_{array}
  101. {}
  102. template <size_t N, typename std::enable_if<Extent == N>::type * = nullptr>
  103. span(std::array<T, N> &array) noexcept : data_{array.data()}
  104. {}
  105. template <size_t N, typename std::enable_if<Extent == N>::type * = nullptr>
  106. span(const std::array<T, N> &array) noexcept : data_{array.data()}
  107. {}
  108. template <
  109. class C,
  110. typename std::enable_if<!detail::is_specialized_span_convertible<C>::value &&
  111. std::is_convertible<typename std::remove_pointer<decltype(nostd::data(
  112. std::declval<C &>()))>::type (*)[],
  113. T (*)[]>::value &&
  114. std::is_convertible<decltype(nostd::size(std::declval<const C &>())),
  115. size_t>::value>::type * = nullptr>
  116. span(C &c) noexcept(noexcept(nostd::data(c), nostd::size(c))) : data_{nostd::data(c)}
  117. {
  118. if (nostd::size(c) != Extent)
  119. {
  120. std::terminate();
  121. }
  122. }
  123. template <
  124. class C,
  125. typename std::enable_if<!detail::is_specialized_span_convertible<C>::value &&
  126. std::is_convertible<typename std::remove_pointer<decltype(nostd::data(
  127. std::declval<const C &>()))>::type (*)[],
  128. T (*)[]>::value &&
  129. std::is_convertible<decltype(nostd::size(std::declval<const C &>())),
  130. size_t>::value>::type * = nullptr>
  131. span(const C &c) noexcept(noexcept(nostd::data(c), nostd::size(c))) : data_{nostd::data(c)}
  132. {
  133. if (nostd::size(c) != Extent)
  134. {
  135. std::terminate();
  136. }
  137. }
  138. template <class U,
  139. size_t N,
  140. typename std::enable_if<N == Extent &&
  141. std::is_convertible<U (*)[], T (*)[]>::value>::type * = nullptr>
  142. span(const span<U, N> &other) noexcept : data_{other.data()}
  143. {}
  144. span(const span &) noexcept = default;
  145. span &operator=(const span &) noexcept = default;
  146. bool empty() const noexcept { return Extent == 0; }
  147. T *data() const noexcept { return data_; }
  148. size_t size() const noexcept { return Extent; }
  149. T &operator[](size_t index) const noexcept
  150. {
  151. assert(index < Extent);
  152. return data_[index];
  153. }
  154. T *begin() const noexcept { return data_; }
  155. T *end() const noexcept { return data_ + Extent; }
  156. private:
  157. T *data_;
  158. };
  159. template <class T>
  160. class span<T, dynamic_extent>
  161. {
  162. public:
  163. static constexpr size_t extent = dynamic_extent;
  164. span() noexcept : extent_{0}, data_{nullptr} {}
  165. span(T *data, size_t count) noexcept : extent_{count}, data_{data} {}
  166. span(T *first, T *last) noexcept
  167. : extent_{static_cast<size_t>(std::distance(first, last))}, data_{first}
  168. {
  169. assert(first <= last);
  170. }
  171. template <size_t N>
  172. span(T (&array)[N]) noexcept : extent_{N}, data_{array}
  173. {}
  174. template <size_t N>
  175. span(std::array<T, N> &array) noexcept : extent_{N}, data_{array.data()}
  176. {}
  177. template <size_t N>
  178. span(const std::array<T, N> &array) noexcept : extent_{N}, data_{array.data()}
  179. {}
  180. template <
  181. class C,
  182. typename std::enable_if<!detail::is_specialized_span_convertible<C>::value &&
  183. std::is_convertible<typename std::remove_pointer<decltype(nostd::data(
  184. std::declval<C &>()))>::type (*)[],
  185. T (*)[]>::value &&
  186. std::is_convertible<decltype(nostd::size(std::declval<const C &>())),
  187. size_t>::value>::type * = nullptr>
  188. span(C &c) noexcept(noexcept(nostd::data(c), nostd::size(c)))
  189. : extent_{nostd::size(c)}, data_{nostd::data(c)}
  190. {}
  191. template <
  192. class C,
  193. typename std::enable_if<!detail::is_specialized_span_convertible<C>::value &&
  194. std::is_convertible<typename std::remove_pointer<decltype(nostd::data(
  195. std::declval<const C &>()))>::type (*)[],
  196. T (*)[]>::value &&
  197. std::is_convertible<decltype(nostd::size(std::declval<const C &>())),
  198. size_t>::value>::type * = nullptr>
  199. span(const C &c) noexcept(noexcept(nostd::data(c), nostd::size(c)))
  200. : extent_{nostd::size(c)}, data_{nostd::data(c)}
  201. {}
  202. template <class U,
  203. size_t N,
  204. typename std::enable_if<std::is_convertible<U (*)[], T (*)[]>::value>::type * = nullptr>
  205. span(const span<U, N> &other) noexcept : extent_{other.size()}, data_{other.data()}
  206. {}
  207. span(const span &) noexcept = default;
  208. span &operator=(const span &) noexcept = default;
  209. bool empty() const noexcept { return extent_ == 0; }
  210. T *data() const noexcept { return data_; }
  211. size_t size() const noexcept { return extent_; }
  212. T &operator[](size_t index) const noexcept
  213. {
  214. assert(index < extent_);
  215. return data_[index];
  216. }
  217. T *begin() const noexcept { return data_; }
  218. T *end() const noexcept { return data_ + extent_; }
  219. private:
  220. size_t extent_;
  221. T *data_;
  222. };
  223. } // namespace nostd
  224. OPENTELEMETRY_END_NAMESPACE
  225. #endif