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