1 /*
2 * Copyright 2006 The Android Open Source Project
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 SkTDArray_DEFINED
9 #define SkTDArray_DEFINED
10
11 #include "include/private/base/SkAPI.h"
12 #include "include/private/base/SkAssert.h"
13 #include "include/private/base/SkDebug.h"
14 #include "include/private/base/SkTo.h"
15
16 #include <algorithm>
17 #include <cstddef>
18 #include <initializer_list>
19
20 class SK_SPI SkTDStorage {
21 public:
22 explicit SkTDStorage(int sizeOfT);
23 SkTDStorage(const void* src, int size, int sizeOfT);
24
25 // Copy
26 SkTDStorage(const SkTDStorage& that);
27 SkTDStorage& operator= (const SkTDStorage& that);
28
29 // Move
30 SkTDStorage(SkTDStorage&& that);
31 SkTDStorage& operator= (SkTDStorage&& that);
32
33 ~SkTDStorage();
34
35 void reset();
36 void swap(SkTDStorage& that);
37
38 // Size routines
empty()39 bool empty() const { return fSize == 0; }
clear()40 void clear() { fSize = 0; }
size()41 int size() const { return fSize; }
42 void resize(int newSize);
size_bytes()43 size_t size_bytes() const { return this->bytes(fSize); }
44
45 // Capacity routines
capacity()46 int capacity() const { return fCapacity; }
47 void reserve(int newCapacity);
48 void shrink_to_fit();
49
data()50 void* data() { return fStorage; }
data()51 const void* data() const { return fStorage; }
52
53 // Deletion routines
54 void erase(int index, int count);
55 // Removes the entry at 'index' and replaces it with the last array element
56 void removeShuffle(int index);
57
58 // Insertion routines
59 void* prepend();
60
61 void append();
62 void append(int count);
63 void* append(const void* src, int count);
64
65 void* insert(int index);
66 void* insert(int index, int count, const void* src);
67
pop_back()68 void pop_back() {
69 SkASSERT(fSize > 0);
70 fSize--;
71 }
72
73 friend bool operator==(const SkTDStorage& a, const SkTDStorage& b);
74 friend bool operator!=(const SkTDStorage& a, const SkTDStorage& b) {
75 return !(a == b);
76 }
77
78 private:
bytes(int n)79 size_t bytes(int n) const { return SkToSizeT(n * fSizeOfT); }
address(int n)80 void* address(int n) { return fStorage + this->bytes(n); }
81
82 // Adds delta to fSize. Crash if outside [0, INT_MAX]
83 int calculateSizeOrDie(int delta);
84
85 // Move the tail of the array defined by the indexes tailStart and tailEnd to dstIndex. The
86 // elements at dstIndex are overwritten by the tail.
87 void moveTail(int dstIndex, int tailStart, int tailEnd);
88
89 // Copy src into the array at dstIndex.
90 void copySrc(int dstIndex, const void* src, int count);
91
92 const int fSizeOfT;
93 std::byte* fStorage{nullptr};
94 int fCapacity{0}; // size of the allocation in fArray (#elements)
95 int fSize{0}; // logical number of elements (fSize <= fCapacity)
96 };
97
swap(SkTDStorage & a,SkTDStorage & b)98 static inline void swap(SkTDStorage& a, SkTDStorage& b) {
99 a.swap(b);
100 }
101
102 // SkTDArray<T> implements a std::vector-like array for raw data-only objects that do not require
103 // construction or destruction. The constructor and destructor for T will not be called; T objects
104 // will always be moved via raw memcpy. Newly created T objects will contain uninitialized memory.
105 template <typename T> class SkTDArray {
106 public:
SkTDArray()107 SkTDArray() : fStorage{sizeof(T)} {}
SkTDArray(const T src[],int count)108 SkTDArray(const T src[], int count) : fStorage{src, count, sizeof(T)} { }
SkTDArray(const std::initializer_list<T> & list)109 SkTDArray(const std::initializer_list<T>& list) : SkTDArray(list.begin(), list.size()) {}
110
111 // Copy
SkTDArray(const SkTDArray<T> & src)112 SkTDArray(const SkTDArray<T>& src) : SkTDArray(src.data(), src.size()) {}
113 SkTDArray<T>& operator=(const SkTDArray<T>& src) {
114 fStorage = src.fStorage;
115 return *this;
116 }
117
118 // Move
SkTDArray(SkTDArray<T> && src)119 SkTDArray(SkTDArray<T>&& src) : fStorage{std::move(src.fStorage)} {}
120 SkTDArray<T>& operator=(SkTDArray<T>&& src) {
121 fStorage = std::move(src.fStorage);
122 return *this;
123 }
124
125 friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
126 return a.fStorage == b.fStorage;
127 }
128 friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) { return !(a == b); }
129
swap(SkTDArray<T> & that)130 void swap(SkTDArray<T>& that) {
131 using std::swap;
132 swap(fStorage, that.fStorage);
133 }
134
empty()135 bool empty() const { return fStorage.empty(); }
136
137 // Return the number of elements in the array
size()138 int size() const { return fStorage.size(); }
139
140 // Return the total number of elements allocated.
141 // Note: capacity() - size() gives you the number of elements you can add without causing an
142 // allocation.
capacity()143 int capacity() const { return fStorage.capacity(); }
144
145 // return the number of bytes in the array: count * sizeof(T)
size_bytes()146 size_t size_bytes() const { return fStorage.size_bytes(); }
147
data()148 T* data() { return static_cast<T*>(fStorage.data()); }
data()149 const T* data() const { return static_cast<const T*>(fStorage.data()); }
begin()150 T* begin() { return this->data(); }
begin()151 const T* begin() const { return this->data(); }
end()152 T* end() { return this->data() + this->size(); }
end()153 const T* end() const { return this->data() + this->size(); }
154
155 T& operator[](int index) {
156 return this->data()[sk_collection_check_bounds(index, this->size())];
157 }
158 const T& operator[](int index) const {
159 return this->data()[sk_collection_check_bounds(index, this->size())];
160 }
161
back()162 const T& back() const {
163 sk_collection_not_empty(this->empty());
164 return this->data()[this->size() - 1];
165 }
back()166 T& back() {
167 sk_collection_not_empty(this->empty());
168 return this->data()[this->size() - 1];
169 }
170
reset()171 void reset() {
172 fStorage.reset();
173 }
174
clear()175 void clear() {
176 fStorage.clear();
177 }
178
179 // Sets the number of elements in the array.
180 // If the array does not have space for count elements, it will increase
181 // the storage allocated to some amount greater than that required.
182 // It will never shrink the storage.
resize(int count)183 void resize(int count) {
184 fStorage.resize(count);
185 }
186
reserve(int n)187 void reserve(int n) {
188 fStorage.reserve(n);
189 }
190
append()191 T* append() {
192 fStorage.append();
193 return this->end() - 1;
194 }
append(int count)195 T* append(int count) {
196 fStorage.append(count);
197 return this->end() - count;
198 }
append(int count,const T * src)199 T* append(int count, const T* src) {
200 return static_cast<T*>(fStorage.append(src, count));
201 }
202
insert(int index)203 T* insert(int index) {
204 return static_cast<T*>(fStorage.insert(index));
205 }
206 T* insert(int index, int count, const T* src = nullptr) {
207 return static_cast<T*>(fStorage.insert(index, count, src));
208 }
209
210 void remove(int index, int count = 1) {
211 fStorage.erase(index, count);
212 }
213
removeShuffle(int index)214 void removeShuffle(int index) {
215 fStorage.removeShuffle(index);
216 }
217
218 // routines to treat the array like a stack
push_back(const T & v)219 void push_back(const T& v) {
220 this->append();
221 this->back() = v;
222 }
pop_back()223 void pop_back() { fStorage.pop_back(); }
224
shrink_to_fit()225 void shrink_to_fit() {
226 fStorage.shrink_to_fit();
227 }
228
229 private:
230 SkTDStorage fStorage;
231 };
232
swap(SkTDArray<T> & a,SkTDArray<T> & b)233 template <typename T> static inline void swap(SkTDArray<T>& a, SkTDArray<T>& b) { a.swap(b); }
234
235 #endif
236