1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkSpan_DEFINED 9 #define SkSpan_DEFINED 10 11 #include "include/private/base/SkAssert.h" 12 #include "include/private/base/SkTo.h" 13 14 #include <cstddef> 15 #include <initializer_list> 16 #include <iterator> 17 #include <limits> 18 #include <utility> 19 20 // Having this be an export works around IWYU churn related to 21 // https://github.com/include-what-you-use/include-what-you-use/issues/1121 22 #include <type_traits> // IWYU pragma: export 23 24 // Add macro to check the lifetime of initializer_list arguments. initializer_list has a very 25 // short life span, and can only be used as a parameter, and not as a variable. 26 #if defined(__clang__) && defined(__has_cpp_attribute) && __has_cpp_attribute(clang::lifetimebound) 27 #define SK_CHECK_IL_LIFETIME [[clang::lifetimebound]] 28 #else 29 #define SK_CHECK_IL_LIFETIME 30 #endif 31 32 /** 33 * SkSpan holds a reference to contiguous data of type T along with a count. SkSpan does not own 34 * the data itself but is merely a reference, therefore you must take care with the lifetime of 35 * the underlying data. 36 * 37 * SkSpan is a count and a pointer into existing array or data type that stores its data in 38 * contiguous memory like std::vector. Any container that works with std::size() and std::data() 39 * can be used. 40 * 41 * SkSpan makes a convenient parameter for a routine to accept array like things. This allows you to 42 * write the routine without overloads for all different container types. 43 * 44 * Example: 45 * void routine(SkSpan<const int> a) { ... } 46 * 47 * std::vector v = {1, 2, 3, 4, 5}; 48 * 49 * routine(a); 50 * 51 * A word of caution when working with initializer_list, initializer_lists have a lifetime that is 52 * limited to the current statement. The following is correct and safe: 53 * 54 * Example: 55 * routine({1,2,3,4,5}); 56 * 57 * The following is undefined, and will result in erratic execution: 58 * 59 * Bad Example: 60 * initializer_list l = {1, 2, 3, 4, 5}; // The data behind l dies at the ;. 61 * routine(l); 62 */ 63 template <typename T> 64 class SkSpan { 65 public: SkSpan()66 constexpr SkSpan() : fPtr{nullptr}, fSize{0} {} 67 68 template <typename Integer, std::enable_if_t<std::is_integral_v<Integer>, bool> = true> SkSpan(T * ptr,Integer size)69 constexpr SkSpan(T* ptr, Integer size) : fPtr{ptr}, fSize{SkToSizeT(size)} { 70 SkASSERT(ptr || fSize == 0); // disallow nullptr + a nonzero size 71 SkASSERT(fSize < kMaxSize); 72 } 73 template <typename U, typename = std::enable_if_t<std::is_same_v<const U, T>>> SkSpan(const SkSpan<U> & that)74 constexpr SkSpan(const SkSpan<U>& that) : fPtr(std::data(that)), fSize(std::size(that)) {} 75 constexpr SkSpan(const SkSpan& o) = default; SkSpan(T (& a)[N])76 template<size_t N> constexpr SkSpan(T(&a)[N]) : SkSpan(a, N) { } 77 template<typename Container> SkSpan(Container & c)78 constexpr SkSpan(Container& c) : SkSpan(std::data(c), std::size(c)) { } SkSpan(std::initializer_list<T> il SK_CHECK_IL_LIFETIME)79 SkSpan(std::initializer_list<T> il SK_CHECK_IL_LIFETIME) 80 : SkSpan(std::data(il), std::size(il)) {} 81 82 constexpr SkSpan& operator=(const SkSpan& that) = default; 83 84 constexpr T& operator [] (size_t i) const { 85 SkASSERT(i < this->size()); 86 return fPtr[i]; 87 } front()88 constexpr T& front() const { return fPtr[0]; } back()89 constexpr T& back() const { return fPtr[fSize - 1]; } begin()90 constexpr T* begin() const { return fPtr; } end()91 constexpr T* end() const { return fPtr + fSize; } rbegin()92 constexpr auto rbegin() const { return std::make_reverse_iterator(this->end()); } rend()93 constexpr auto rend() const { return std::make_reverse_iterator(this->begin()); } data()94 constexpr T* data() const { return this->begin(); } size()95 constexpr size_t size() const { return fSize; } empty()96 constexpr bool empty() const { return fSize == 0; } size_bytes()97 constexpr size_t size_bytes() const { return fSize * sizeof(T); } first(size_t prefixLen)98 constexpr SkSpan<T> first(size_t prefixLen) const { 99 SkASSERT(prefixLen <= this->size()); 100 return SkSpan{fPtr, prefixLen}; 101 } last(size_t postfixLen)102 constexpr SkSpan<T> last(size_t postfixLen) const { 103 SkASSERT(postfixLen <= this->size()); 104 return SkSpan{fPtr + (this->size() - postfixLen), postfixLen}; 105 } subspan(size_t offset)106 constexpr SkSpan<T> subspan(size_t offset) const { 107 return this->subspan(offset, this->size() - offset); 108 } subspan(size_t offset,size_t count)109 constexpr SkSpan<T> subspan(size_t offset, size_t count) const { 110 SkASSERT(offset <= this->size()); 111 SkASSERT(count <= this->size() - offset); 112 return SkSpan{fPtr + offset, count}; 113 } 114 115 private: 116 static const constexpr size_t kMaxSize = std::numeric_limits<size_t>::max() / sizeof(T); 117 T* fPtr; 118 size_t fSize; 119 }; 120 121 template <typename Container> 122 SkSpan(Container&) -> 123 SkSpan<std::remove_pointer_t<decltype(std::data(std::declval<Container&>()))>>; 124 125 template <typename T> 126 SkSpan(std::initializer_list<T>) -> 127 SkSpan<std::remove_pointer_t<decltype(std::data(std::declval<std::initializer_list<T>>()))>>; 128 129 #endif // SkSpan_DEFINED 130