span.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_CONTAINERS_SPAN_H_
  5. #define BASE_CONTAINERS_SPAN_H_
  6. #include <stddef.h>
  7. #include <algorithm>
  8. #include <array>
  9. #include <iterator>
  10. #include <limits>
  11. #include <type_traits>
  12. #include <utility>
  13. #include "base/containers/checked_iterators.h"
  14. #include "base/logging.h"
  15. #include "base/macros.h"
  16. #include "base/stl_util.h"
  17. #include "base/template_util.h"
  18. namespace base {
  19. // [views.constants]
  20. constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
  21. template <typename T, size_t Extent = dynamic_extent>
  22. class span;
  23. namespace internal {
  24. template <size_t I>
  25. using size_constant = std::integral_constant<size_t, I>;
  26. template <typename T>
  27. struct ExtentImpl : size_constant<dynamic_extent> {};
  28. template <typename T, size_t N>
  29. struct ExtentImpl<T[N]> : size_constant<N> {};
  30. template <typename T, size_t N>
  31. struct ExtentImpl<std::array<T, N>> : size_constant<N> {};
  32. template <typename T, size_t N>
  33. struct ExtentImpl<base::span<T, N>> : size_constant<N> {};
  34. template <typename T>
  35. using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>;
  36. template <typename T>
  37. struct IsSpanImpl : std::false_type {};
  38. template <typename T, size_t Extent>
  39. struct IsSpanImpl<span<T, Extent>> : std::true_type {};
  40. template <typename T>
  41. using IsNotSpan = negation<IsSpanImpl<std::decay_t<T>>>;
  42. template <typename T>
  43. struct IsStdArrayImpl : std::false_type {};
  44. template <typename T, size_t N>
  45. struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
  46. template <typename T>
  47. using IsNotStdArray = negation<IsStdArrayImpl<std::decay_t<T>>>;
  48. template <typename T>
  49. using IsNotCArray = negation<std::is_array<std::remove_reference_t<T>>>;
  50. template <typename From, typename To>
  51. using IsLegalDataConversion = std::is_convertible<From (*)[], To (*)[]>;
  52. template <typename Container, typename T>
  53. using ContainerHasConvertibleData = IsLegalDataConversion<
  54. std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>,
  55. T>;
  56. template <typename Container>
  57. using ContainerHasIntegralSize =
  58. std::is_integral<decltype(base::size(std::declval<Container>()))>;
  59. template <typename From, size_t FromExtent, typename To, size_t ToExtent>
  60. using EnableIfLegalSpanConversion =
  61. std::enable_if_t<(ToExtent == dynamic_extent || ToExtent == FromExtent) &&
  62. IsLegalDataConversion<From, To>::value>;
  63. // SFINAE check if Array can be converted to a span<T>.
  64. template <typename Array, typename T, size_t Extent>
  65. using EnableIfSpanCompatibleArray =
  66. std::enable_if_t<(Extent == dynamic_extent ||
  67. Extent == internal::Extent<Array>::value) &&
  68. ContainerHasConvertibleData<Array, T>::value>;
  69. // SFINAE check if Container can be converted to a span<T>.
  70. template <typename Container, typename T>
  71. using IsSpanCompatibleContainer =
  72. conjunction<IsNotSpan<Container>,
  73. IsNotStdArray<Container>,
  74. IsNotCArray<Container>,
  75. ContainerHasConvertibleData<Container, T>,
  76. ContainerHasIntegralSize<Container>>;
  77. template <typename Container, typename T>
  78. using EnableIfSpanCompatibleContainer =
  79. std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value>;
  80. template <typename Container, typename T, size_t Extent>
  81. using EnableIfSpanCompatibleContainerAndSpanIsDynamic =
  82. std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value &&
  83. Extent == dynamic_extent>;
  84. // A helper template for storing the size of a span. Spans with static extents
  85. // don't require additional storage, since the extent itself is specified in the
  86. // template parameter.
  87. template <size_t Extent>
  88. class ExtentStorage {
  89. public:
  90. constexpr explicit ExtentStorage(size_t size) noexcept {}
  91. constexpr size_t size() const noexcept { return Extent; }
  92. };
  93. // Specialization of ExtentStorage for dynamic extents, which do require
  94. // explicit storage for the size.
  95. template <>
  96. struct ExtentStorage<dynamic_extent> {
  97. constexpr explicit ExtentStorage(size_t size) noexcept : size_(size) {}
  98. constexpr size_t size() const noexcept { return size_; }
  99. private:
  100. size_t size_;
  101. };
  102. } // namespace internal
  103. // A span is a value type that represents an array of elements of type T. Since
  104. // it only consists of a pointer to memory with an associated size, it is very
  105. // light-weight. It is cheap to construct, copy, move and use spans, so that
  106. // users are encouraged to use it as a pass-by-value parameter. A span does not
  107. // own the underlying memory, so care must be taken to ensure that a span does
  108. // not outlive the backing store.
  109. //
  110. // span is somewhat analogous to StringPiece, but with arbitrary element types,
  111. // allowing mutation if T is non-const.
  112. //
  113. // span is implicitly convertible from C++ arrays, as well as most [1]
  114. // container-like types that provide a data() and size() method (such as
  115. // std::vector<T>). A mutable span<T> can also be implicitly converted to an
  116. // immutable span<const T>.
  117. //
  118. // Consider using a span for functions that take a data pointer and size
  119. // parameter: it allows the function to still act on an array-like type, while
  120. // allowing the caller code to be a bit more concise.
  121. //
  122. // For read-only data access pass a span<const T>: the caller can supply either
  123. // a span<const T> or a span<T>, while the callee will have a read-only view.
  124. // For read-write access a mutable span<T> is required.
  125. //
  126. // Without span:
  127. // Read-Only:
  128. // // std::string HexEncode(const uint8_t* data, size_t size);
  129. // std::vector<uint8_t> data_buffer = GenerateData();
  130. // std::string r = HexEncode(data_buffer.data(), data_buffer.size());
  131. //
  132. // Mutable:
  133. // // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
  134. // char str_buffer[100];
  135. // SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
  136. //
  137. // With span:
  138. // Read-Only:
  139. // // std::string HexEncode(base::span<const uint8_t> data);
  140. // std::vector<uint8_t> data_buffer = GenerateData();
  141. // std::string r = HexEncode(data_buffer);
  142. //
  143. // Mutable:
  144. // // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
  145. // char str_buffer[100];
  146. // SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
  147. //
  148. // Spans with "const" and pointers
  149. // -------------------------------
  150. //
  151. // Const and pointers can get confusing. Here are vectors of pointers and their
  152. // corresponding spans:
  153. //
  154. // const std::vector<int*> => base::span<int* const>
  155. // std::vector<const int*> => base::span<const int*>
  156. // const std::vector<const int*> => base::span<const int* const>
  157. //
  158. // Differences from the C++20 draft
  159. // --------------------------------
  160. //
  161. // http://eel.is/c++draft/views contains the latest C++20 draft of std::span.
  162. // Chromium tries to follow the draft as close as possible. Differences between
  163. // the draft and the implementation are documented in subsections below.
  164. //
  165. // Differences from [span.objectrep]:
  166. // - as_bytes() and as_writable_bytes() return spans of uint8_t instead of
  167. // std::byte (std::byte is a C++17 feature)
  168. //
  169. // Differences from [span.cons]:
  170. // - Constructing a static span (i.e. Extent != dynamic_extent) from a dynamic
  171. // sized container (e.g. std::vector) requires an explicit conversion (in the
  172. // C++20 draft this is simply UB)
  173. //
  174. // Differences from [span.obs]:
  175. // - empty() is marked with WARN_UNUSED_RESULT instead of [[nodiscard]]
  176. // ([[nodiscard]] is a C++17 feature)
  177. //
  178. // Furthermore, all constructors and methods are marked noexcept due to the lack
  179. // of exceptions in Chromium.
  180. //
  181. // Due to the lack of class template argument deduction guides in C++14
  182. // appropriate make_span() utility functions are provided.
  183. // [span], class template span
  184. template <typename T, size_t Extent>
  185. class span : public internal::ExtentStorage<Extent> {
  186. private:
  187. using ExtentStorage = internal::ExtentStorage<Extent>;
  188. public:
  189. using element_type = T;
  190. using value_type = std::remove_cv_t<T>;
  191. using size_type = size_t;
  192. using difference_type = ptrdiff_t;
  193. using pointer = T*;
  194. using reference = T&;
  195. using iterator = CheckedContiguousIterator<T>;
  196. // TODO(https://crbug.com/828324): Drop the const_iterator typedef once gMock
  197. // supports containers without this nested type.
  198. using const_iterator = iterator;
  199. using reverse_iterator = std::reverse_iterator<iterator>;
  200. static constexpr size_t extent = Extent;
  201. // [span.cons], span constructors, copy, assignment, and destructor
  202. constexpr span() noexcept : ExtentStorage(0), data_(nullptr) {
  203. static_assert(Extent == dynamic_extent || Extent == 0, "Invalid Extent");
  204. }
  205. constexpr span(T* data, size_t size) noexcept
  206. : ExtentStorage(size), data_(data) {
  207. CHECK(Extent == dynamic_extent || Extent == size);
  208. }
  209. // Artificially templatized to break ambiguity for span(ptr, 0).
  210. template <typename = void>
  211. constexpr span(T* begin, T* end) noexcept : span(begin, end - begin) {
  212. // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
  213. CHECK(begin <= end);
  214. }
  215. template <
  216. size_t N,
  217. typename = internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>>
  218. constexpr span(T (&array)[N]) noexcept : span(base::data(array), N) {}
  219. template <
  220. typename U,
  221. size_t N,
  222. typename =
  223. internal::EnableIfSpanCompatibleArray<std::array<U, N>&, T, Extent>>
  224. constexpr span(std::array<U, N>& array) noexcept
  225. : span(base::data(array), N) {}
  226. template <typename U,
  227. size_t N,
  228. typename = internal::
  229. EnableIfSpanCompatibleArray<const std::array<U, N>&, T, Extent>>
  230. constexpr span(const std::array<U, N>& array) noexcept
  231. : span(base::data(array), N) {}
  232. // Conversion from a container that has compatible base::data() and integral
  233. // base::size().
  234. template <
  235. typename Container,
  236. typename =
  237. internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&,
  238. T,
  239. Extent>>
  240. constexpr span(Container& container) noexcept
  241. : span(base::data(container), base::size(container)) {}
  242. template <
  243. typename Container,
  244. typename = internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<
  245. const Container&,
  246. T,
  247. Extent>>
  248. constexpr span(const Container& container) noexcept
  249. : span(base::data(container), base::size(container)) {}
  250. constexpr span(const span& other) noexcept = default;
  251. // Conversions from spans of compatible types and extents: this allows a
  252. // span<T> to be seamlessly used as a span<const T>, but not the other way
  253. // around. If extent is not dynamic, OtherExtent has to be equal to Extent.
  254. template <
  255. typename U,
  256. size_t OtherExtent,
  257. typename =
  258. internal::EnableIfLegalSpanConversion<U, OtherExtent, T, Extent>>
  259. constexpr span(const span<U, OtherExtent>& other)
  260. : span(other.data(), other.size()) {}
  261. constexpr span& operator=(const span& other) noexcept = default;
  262. ~span() noexcept = default;
  263. // [span.sub], span subviews
  264. template <size_t Count>
  265. constexpr span<T, Count> first() const noexcept {
  266. static_assert(Count <= Extent, "Count must not exceed Extent");
  267. CHECK(Extent != dynamic_extent || Count <= size());
  268. return {data(), Count};
  269. }
  270. template <size_t Count>
  271. constexpr span<T, Count> last() const noexcept {
  272. static_assert(Count <= Extent, "Count must not exceed Extent");
  273. CHECK(Extent != dynamic_extent || Count <= size());
  274. return {data() + (size() - Count), Count};
  275. }
  276. template <size_t Offset, size_t Count = dynamic_extent>
  277. constexpr span<T,
  278. (Count != dynamic_extent
  279. ? Count
  280. : (Extent != dynamic_extent ? Extent - Offset
  281. : dynamic_extent))>
  282. subspan() const noexcept {
  283. static_assert(Offset <= Extent, "Offset must not exceed Extent");
  284. static_assert(Count == dynamic_extent || Count <= Extent - Offset,
  285. "Count must not exceed Extent - Offset");
  286. CHECK(Extent != dynamic_extent || Offset <= size());
  287. CHECK(Extent != dynamic_extent || Count == dynamic_extent ||
  288. Count <= size() - Offset);
  289. return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
  290. }
  291. constexpr span<T, dynamic_extent> first(size_t count) const noexcept {
  292. // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
  293. CHECK(count <= size());
  294. return {data(), count};
  295. }
  296. constexpr span<T, dynamic_extent> last(size_t count) const noexcept {
  297. // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
  298. CHECK(count <= size());
  299. return {data() + (size() - count), count};
  300. }
  301. constexpr span<T, dynamic_extent> subspan(size_t offset,
  302. size_t count = dynamic_extent) const
  303. noexcept {
  304. // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
  305. CHECK(offset <= size());
  306. CHECK(count == dynamic_extent || count <= size() - offset);
  307. return {data() + offset, count != dynamic_extent ? count : size() - offset};
  308. }
  309. // [span.obs], span observers
  310. constexpr size_t size() const noexcept { return ExtentStorage::size(); }
  311. constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
  312. constexpr bool empty() const noexcept WARN_UNUSED_RESULT {
  313. return size() == 0;
  314. }
  315. // [span.elem], span element access
  316. constexpr T& operator[](size_t idx) const noexcept {
  317. // Note: CHECK_LT is not constexpr, hence regular CHECK must be used.
  318. CHECK(idx < size());
  319. return *(data() + idx);
  320. }
  321. constexpr T& front() const noexcept {
  322. static_assert(Extent == dynamic_extent || Extent > 0,
  323. "Extent must not be 0");
  324. CHECK(Extent != dynamic_extent || !empty());
  325. return *data();
  326. }
  327. constexpr T& back() const noexcept {
  328. static_assert(Extent == dynamic_extent || Extent > 0,
  329. "Extent must not be 0");
  330. CHECK(Extent != dynamic_extent || !empty());
  331. return *(data() + size() - 1);
  332. }
  333. constexpr T* data() const noexcept { return data_; }
  334. // [span.iter], span iterator support
  335. constexpr iterator begin() const noexcept {
  336. return iterator(data_, data_ + size());
  337. }
  338. constexpr iterator end() const noexcept {
  339. return iterator(data_, data_ + size(), data_ + size());
  340. }
  341. constexpr reverse_iterator rbegin() const noexcept {
  342. return reverse_iterator(end());
  343. }
  344. constexpr reverse_iterator rend() const noexcept {
  345. return reverse_iterator(begin());
  346. }
  347. private:
  348. T* data_;
  349. };
  350. // span<T, Extent>::extent can not be declared inline prior to C++17, hence this
  351. // definition is required.
  352. template <class T, size_t Extent>
  353. constexpr size_t span<T, Extent>::extent;
  354. // [span.objectrep], views of object representation
  355. template <typename T, size_t X>
  356. span<const uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
  357. as_bytes(span<T, X> s) noexcept {
  358. return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()};
  359. }
  360. template <typename T,
  361. size_t X,
  362. typename = std::enable_if_t<!std::is_const<T>::value>>
  363. span<uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
  364. as_writable_bytes(span<T, X> s) noexcept {
  365. return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()};
  366. }
  367. // Type-deducing helpers for constructing a span.
  368. template <int&... ExplicitArgumentBarrier, typename T>
  369. constexpr span<T> make_span(T* data, size_t size) noexcept {
  370. return {data, size};
  371. }
  372. template <int&... ExplicitArgumentBarrier, typename T>
  373. constexpr span<T> make_span(T* begin, T* end) noexcept {
  374. return {begin, end};
  375. }
  376. // make_span utility function that deduces both the span's value_type and extent
  377. // from the passed in argument.
  378. //
  379. // Usage: auto span = base::make_span(...);
  380. template <int&... ExplicitArgumentBarrier, typename Container>
  381. constexpr auto make_span(Container&& container) noexcept {
  382. using T =
  383. std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>;
  384. using Extent = internal::Extent<Container>;
  385. return span<T, Extent::value>(std::forward<Container>(container));
  386. }
  387. // make_span utility function that allows callers to explicit specify the span's
  388. // extent, the value_type is deduced automatically. This is useful when passing
  389. // a dynamically sized container to a method expecting static spans, when the
  390. // container is known to have the correct size.
  391. //
  392. // Note: This will CHECK that N indeed matches size(container).
  393. //
  394. // Usage: auto static_span = base::make_span<N>(...);
  395. template <size_t N, int&... ExplicitArgumentBarrier, typename Container>
  396. constexpr auto make_span(Container&& container) noexcept {
  397. using T =
  398. std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>;
  399. return span<T, N>(base::data(container), base::size(container));
  400. }
  401. } // namespace base
  402. #endif // BASE_CONTAINERS_SPAN_H_