1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 // std::span is a stand-in for C++20's std::span. Do NOT include this header 16 // directly; instead, include it as <span>. 17 // 18 // A span is a non-owning array view class. It refers to an external array by 19 // storing a pointer and length. Unlike std::array, the size does not have to be 20 // a template parameter, so this class can be used to without stating its size. 21 // 22 // This file a modified version of base::span from Chromium: 23 // https://chromium.googlesource.com/chromium/src/+/d93ae920e4309682deb9352a4637cfc2941c1d1f/base/containers/span.h 24 // 25 // In order to minimize changes from the original, this file does NOT fully 26 // adhere to Pigweed's style guide. 27 // 28 // A few changes were made to the Chromium version of span. These include: 29 // - Use std::data and std::size instead of base::* versions. 30 // - Rename base namespace to std. 31 // - Rename internal namespace to pw_span_internal. 32 // - Remove uses of checked_iterators.h and CHECK. 33 // - Replace make_span functions with C++17 class template deduction guides. 34 // - Use std::byte instead of uint8_t for compatibility with std::span. 35 // 36 #pragma once 37 38 #ifndef __cpp_lib_span 39 #define __cpp_lib_span 202002L 40 41 #include <algorithm> 42 #include <array> 43 #include <cstddef> 44 #include <iterator> 45 #include <limits> 46 #include <type_traits> 47 #include <utility> 48 49 #include "pw_polyfill/language_feature_macros.h" 50 #include "pw_polyfill/standard_library/namespace.h" 51 52 // Pigweed: Disable the asserts from Chromium for now. 53 #define _PW_SPAN_ASSERT(arg) 54 55 _PW_POLYFILL_BEGIN_NAMESPACE_STD 56 57 // [views.constants] 58 constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max(); 59 60 template <typename T, size_t Extent = dynamic_extent> 61 class span; 62 63 namespace pw_span_internal { 64 65 template <typename T> 66 struct ExtentImpl : std::integral_constant<size_t, dynamic_extent> {}; 67 68 template <typename T, size_t N> 69 struct ExtentImpl<T[N]> : std::integral_constant<size_t, N> {}; 70 71 template <typename T, size_t N> 72 struct ExtentImpl<std::array<T, N>> : std::integral_constant<size_t, N> {}; 73 74 template <typename T, size_t N> 75 struct ExtentImpl<std::span<T, N>> : std::integral_constant<size_t, N> {}; 76 77 template <typename T> 78 using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>; 79 80 template <typename T> 81 struct IsSpanImpl : std::false_type {}; 82 83 template <typename T, size_t Extent> 84 struct IsSpanImpl<span<T, Extent>> : std::true_type {}; 85 86 template <typename T> 87 using IsSpan = IsSpanImpl<std::decay_t<T>>; 88 89 template <typename T> 90 struct IsStdArrayImpl : std::false_type {}; 91 92 template <typename T, size_t N> 93 struct IsStdArrayImpl<std::array<T, N>> : std::true_type {}; 94 95 template <typename T> 96 using IsStdArray = IsStdArrayImpl<std::decay_t<T>>; 97 98 template <typename T> 99 using IsCArray = std::is_array<std::remove_reference_t<T>>; 100 101 template <typename From, typename To> 102 using IsLegalDataConversion = std::is_convertible<From (*)[], To (*)[]>; 103 104 template <typename Container, typename T> 105 using ContainerHasConvertibleData = IsLegalDataConversion< 106 std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>, 107 T>; 108 109 template <typename Container> 110 using ContainerHasIntegralSize = 111 std::is_integral<decltype(std::size(std::declval<Container>()))>; 112 113 template <typename From, size_t FromExtent, typename To, size_t ToExtent> 114 using EnableIfLegalSpanConversion = 115 std::enable_if_t<(ToExtent == dynamic_extent || ToExtent == FromExtent) && 116 IsLegalDataConversion<From, To>::value>; 117 118 // SFINAE check if Array can be converted to a span<T>. 119 template <typename Array, typename T, size_t Extent> 120 using EnableIfSpanCompatibleArray = 121 std::enable_if_t<(Extent == dynamic_extent || 122 Extent == pw_span_internal::Extent<Array>::value) && 123 ContainerHasConvertibleData<Array, T>::value>; 124 125 // SFINAE check if Container can be converted to a span<T>. 126 template <typename Container, typename T> 127 using IsSpanCompatibleContainer = 128 std::conditional_t<!IsSpan<Container>::value && 129 !IsStdArray<Container>::value && 130 !IsCArray<Container>::value && 131 ContainerHasConvertibleData<Container, T>::value && 132 ContainerHasIntegralSize<Container>::value, 133 std::true_type, 134 std::false_type>; 135 136 template <typename Container, typename T> 137 using EnableIfSpanCompatibleContainer = 138 std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value>; 139 140 template <typename Container, typename T, size_t Extent> 141 using EnableIfSpanCompatibleContainerAndSpanIsDynamic = 142 std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value && 143 Extent == dynamic_extent>; 144 145 // A helper template for storing the size of a span. Spans with static extents 146 // don't require additional storage, since the extent itself is specified in the 147 // template parameter. 148 template <size_t Extent> 149 class ExtentStorage { 150 public: 151 constexpr explicit ExtentStorage(size_t /* size */) noexcept {} 152 constexpr size_t size() const noexcept { return Extent; } 153 }; 154 155 // Specialization of ExtentStorage for dynamic extents, which do require 156 // explicit storage for the size. 157 template <> 158 struct ExtentStorage<dynamic_extent> { 159 constexpr explicit ExtentStorage(size_t size) noexcept : size_(size) {} 160 constexpr size_t size() const noexcept { return size_; } 161 162 private: 163 size_t size_; 164 }; 165 166 } // namespace pw_span_internal 167 168 // A span is a value type that represents an array of elements of type T. Since 169 // it only consists of a pointer to memory with an associated size, it is very 170 // light-weight. It is cheap to construct, copy, move and use spans, so that 171 // users are encouraged to use it as a pass-by-value parameter. A span does not 172 // own the underlying memory, so care must be taken to ensure that a span does 173 // not outlive the backing store. 174 // 175 // span is somewhat analogous to StringPiece, but with arbitrary element types, 176 // allowing mutation if T is non-const. 177 // 178 // span is implicitly convertible from C++ arrays, as well as most [1] 179 // container-like types that provide a data() and size() method (such as 180 // std::vector<T>). A mutable span<T> can also be implicitly converted to an 181 // immutable span<const T>. 182 // 183 // Consider using a span for functions that take a data pointer and size 184 // parameter: it allows the function to still act on an array-like type, while 185 // allowing the caller code to be a bit more concise. 186 // 187 // For read-only data access pass a span<const T>: the caller can supply either 188 // a span<const T> or a span<T>, while the callee will have a read-only view. 189 // For read-write access a mutable span<T> is required. 190 // 191 // Without span: 192 // Read-Only: 193 // // std::string HexEncode(const uint8_t* data, size_t size); 194 // std::vector<uint8_t> data_buffer = GenerateData(); 195 // std::string r = HexEncode(data_buffer.data(), data_buffer.size()); 196 // 197 // Mutable: 198 // // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...); 199 // char str_buffer[100]; 200 // SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14); 201 // 202 // With span: 203 // Read-Only: 204 // // std::string HexEncode(std::span<const uint8_t> data); 205 // std::vector<uint8_t> data_buffer = GenerateData(); 206 // std::string r = HexEncode(data_buffer); 207 // 208 // Mutable: 209 // // ssize_t SafeSNPrintf(std::span<char>, const char* fmt, Args...); 210 // char str_buffer[100]; 211 // SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14); 212 // 213 // Spans with "const" and pointers 214 // ------------------------------- 215 // 216 // Const and pointers can get confusing. Here are vectors of pointers and their 217 // corresponding spans: 218 // 219 // const std::vector<int*> => std::span<int* const> 220 // std::vector<const int*> => std::span<const int*> 221 // const std::vector<const int*> => std::span<const int* const> 222 // 223 // Differences from the C++20 draft 224 // -------------------------------- 225 // 226 // http://eel.is/c++draft/views contains the latest C++20 draft of std::span. 227 // Chromium tries to follow the draft as close as possible. Differences between 228 // the draft and the implementation are documented in subsections below. 229 // 230 // Differences from [span.cons]: 231 // - Constructing a static span (i.e. Extent != dynamic_extent) from a dynamic 232 // sized container (e.g. std::vector) requires an explicit conversion (in the 233 // C++20 draft this is simply UB) 234 // 235 // Furthermore, all constructors and methods are marked noexcept due to the lack 236 // of exceptions in Chromium. 237 238 // [span], class template span 239 template <typename T, size_t Extent> 240 class span : public pw_span_internal::ExtentStorage<Extent> { 241 private: 242 using ExtentStorage = pw_span_internal::ExtentStorage<Extent>; 243 244 public: 245 using element_type = T; 246 using value_type = std::remove_cv_t<T>; 247 using size_type = size_t; 248 using difference_type = ptrdiff_t; 249 using pointer = T*; 250 using reference = T&; 251 using iterator = T*; 252 using reverse_iterator = std::reverse_iterator<iterator>; 253 static constexpr size_t extent = Extent; 254 255 // [span.cons], span constructors, copy, assignment, and destructor 256 constexpr span() noexcept : ExtentStorage(0), data_(nullptr) { 257 static_assert(Extent == dynamic_extent || Extent == 0, "Invalid Extent"); 258 } 259 260 constexpr span(T* data, size_t size) noexcept 261 : ExtentStorage(size), data_(data) { 262 _PW_SPAN_ASSERT(Extent == dynamic_extent || Extent == size); 263 } 264 265 // Artificially templatized to break ambiguity for span(ptr, 0). 266 template <typename = void> 267 constexpr span(T* begin, T* end) noexcept : span(begin, end - begin) { 268 // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. 269 _PW_SPAN_ASSERT(begin <= end); 270 } 271 272 template < 273 size_t N, 274 typename = 275 pw_span_internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>> 276 constexpr span(T (&array)[N]) noexcept : span(std::data(array), N) {} 277 278 template <typename U, 279 size_t N, 280 typename = pw_span_internal:: 281 EnableIfSpanCompatibleArray<std::array<U, N>&, T, Extent>> 282 constexpr span(std::array<U, N>& array) noexcept 283 : span(std::data(array), N) {} 284 285 template <typename U, 286 size_t N, 287 typename = pw_span_internal:: 288 EnableIfSpanCompatibleArray<const std::array<U, N>&, T, Extent>> 289 constexpr span(const std::array<U, N>& array) noexcept 290 : span(std::data(array), N) {} 291 292 // Conversion from a container that has compatible std::data() and integral 293 // std::size(). 294 template <typename Container, 295 typename = pw_span_internal:: 296 EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&, 297 T, 298 Extent>> 299 constexpr span(Container& container) noexcept 300 : span(std::data(container), std::size(container)) {} 301 302 template < 303 typename Container, 304 typename = pw_span_internal:: 305 EnableIfSpanCompatibleContainerAndSpanIsDynamic<const Container&, 306 T, 307 Extent>> 308 constexpr span(const Container& container) noexcept 309 : span(std::data(container), std::size(container)) {} 310 311 constexpr span(const span& other) noexcept = default; 312 313 // Conversions from spans of compatible types and extents: this allows a 314 // span<T> to be seamlessly used as a span<const T>, but not the other way 315 // around. If extent is not dynamic, OtherExtent has to be equal to Extent. 316 template <typename U, 317 size_t OtherExtent, 318 typename = pw_span_internal:: 319 EnableIfLegalSpanConversion<U, OtherExtent, T, Extent>> 320 constexpr span(const span<U, OtherExtent>& other) 321 : span(other.data(), other.size()) {} 322 323 constexpr span& operator=(const span& other) noexcept = default; 324 ~span() noexcept = default; 325 326 // [span.sub], span subviews 327 template <size_t Count> 328 constexpr span<T, Count> first() const noexcept { 329 static_assert(Count <= Extent, "Count must not exceed Extent"); 330 _PW_SPAN_ASSERT(Extent != dynamic_extent || Count <= size()); 331 return {data(), Count}; 332 } 333 334 template <size_t Count> 335 constexpr span<T, Count> last() const noexcept { 336 static_assert(Count <= Extent, "Count must not exceed Extent"); 337 _PW_SPAN_ASSERT(Extent != dynamic_extent || Count <= size()); 338 return {data() + (size() - Count), Count}; 339 } 340 341 template <size_t Offset, size_t Count = dynamic_extent> 342 constexpr span<T, 343 (Count != dynamic_extent 344 ? Count 345 : (Extent != dynamic_extent ? Extent - Offset 346 : dynamic_extent))> 347 subspan() const noexcept { 348 static_assert(Offset <= Extent, "Offset must not exceed Extent"); 349 static_assert(Count == dynamic_extent || Count <= Extent - Offset, 350 "Count must not exceed Extent - Offset"); 351 _PW_SPAN_ASSERT(Extent != dynamic_extent || Offset <= size()); 352 _PW_SPAN_ASSERT(Extent != dynamic_extent || Count == dynamic_extent || 353 Count <= size() - Offset); 354 return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset}; 355 } 356 357 constexpr span<T, dynamic_extent> first(size_t count) const noexcept { 358 // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. 359 _PW_SPAN_ASSERT(count <= size()); 360 return {data(), count}; 361 } 362 363 constexpr span<T, dynamic_extent> last(size_t count) const noexcept { 364 // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. 365 _PW_SPAN_ASSERT(count <= size()); 366 return {data() + (size() - count), count}; 367 } 368 369 constexpr span<T, dynamic_extent> subspan( 370 size_t offset, size_t count = dynamic_extent) const noexcept { 371 // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. 372 _PW_SPAN_ASSERT(offset <= size()); 373 _PW_SPAN_ASSERT(count == dynamic_extent || count <= size() - offset); 374 return {data() + offset, count != dynamic_extent ? count : size() - offset}; 375 } 376 377 // [span.obs], span observers 378 constexpr size_t size() const noexcept { return ExtentStorage::size(); } 379 constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); } 380 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } 381 382 // [span.elem], span element access 383 constexpr T& operator[](size_t idx) const noexcept { 384 // Note: CHECK_LT is not constexpr, hence regular CHECK must be used. 385 _PW_SPAN_ASSERT(idx < size()); 386 return *(data() + idx); 387 } 388 389 constexpr T& front() const noexcept { 390 static_assert(Extent == dynamic_extent || Extent > 0, 391 "Extent must not be 0"); 392 _PW_SPAN_ASSERT(Extent != dynamic_extent || !empty()); 393 return *data(); 394 } 395 396 constexpr T& back() const noexcept { 397 static_assert(Extent == dynamic_extent || Extent > 0, 398 "Extent must not be 0"); 399 _PW_SPAN_ASSERT(Extent != dynamic_extent || !empty()); 400 return *(data() + size() - 1); 401 } 402 403 constexpr T* data() const noexcept { return data_; } 404 405 // [span.iter], span iterator support 406 constexpr iterator begin() const noexcept { return data_; } 407 constexpr iterator end() const noexcept { return data_ + size(); } 408 409 constexpr reverse_iterator rbegin() const noexcept { 410 return reverse_iterator(end()); 411 } 412 constexpr reverse_iterator rend() const noexcept { 413 return reverse_iterator(begin()); 414 } 415 416 private: 417 T* data_; 418 }; 419 420 // span<T, Extent>::extent can not be declared inline prior to C++17, hence this 421 // definition is required. 422 // template <class T, size_t Extent> 423 // constexpr size_t span<T, Extent>::extent; 424 425 // [span.objectrep], views of object representation 426 template <typename T, size_t X> 427 span<const std::byte, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)> 428 as_bytes(span<T, X> s) noexcept { 429 return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()}; 430 } 431 432 template <typename T, 433 size_t X, 434 typename = std::enable_if_t<!std::is_const<T>::value>> 435 span<std::byte, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)> 436 as_writable_bytes(span<T, X> s) noexcept { 437 return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()}; 438 } 439 440 // Type-deducing helpers for constructing a span. 441 // Pigweed: Instead of a make_span function, provide the deduction guides 442 // specified in the C++20 standard. 443 #ifdef __cpp_deduction_guides 444 445 template <class T, std::size_t N> 446 span(T (&)[N]) -> span<T, N>; 447 448 template <class T, std::size_t N> 449 span(std::array<T, N>&) -> span<T, N>; 450 451 template <class T, std::size_t N> 452 span(const std::array<T, N>&) -> span<const T, N>; 453 454 namespace pw_span_internal { 455 456 // Containers can be mutable or const and have mutable or const members. Check 457 // the type of the accessed elements to determine which type of span should be 458 // created (e.g. span<char> or span<const char>). 459 template <typename T> 460 using ValueType = std::remove_reference_t<decltype(std::declval<T>()[0])>; 461 462 } // namespace pw_span_internal 463 464 // This diverges a little from the standard, which uses std::ranges. 465 template <class Container> 466 span(Container&) -> span<pw_span_internal::ValueType<Container>>; 467 468 template <class Container> 469 span(const Container&) -> span<pw_span_internal::ValueType<const Container>>; 470 471 #endif // __cpp_deduction_guides 472 473 _PW_POLYFILL_END_NAMESPACE_STD 474 475 #undef _PW_SPAN_ASSERT 476 #endif // __cpp_lib_span 477