xref: /aosp_15_r20/external/skia/include/private/base/SkTDArray.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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