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