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