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