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