Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkTDArray.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google Inc.
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
9
13
14#include <climits>
15#include <cstddef>
16#include <cstdint>
17#include <cstring>
18#include <new>
19#include <utility>
20
21SkTDStorage::SkTDStorage(int sizeOfT) : fSizeOfT{sizeOfT} {}
22
23SkTDStorage::SkTDStorage(const void* src, int size, int sizeOfT)
24 : fSizeOfT{sizeOfT}
25 , fCapacity{size}
26 , fSize{size} {
27 if (size > 0) {
28 SkASSERT(src != nullptr);
29 size_t storageSize = this->bytes(size);
30 fStorage = static_cast<std::byte*>(sk_malloc_throw(storageSize));
31 memcpy(fStorage, src, storageSize);
32 }
33}
34
36 : SkTDStorage{that.fStorage, that.fSize, that.fSizeOfT} {}
37
39 if (this != &that) {
40 if (that.fSize <= fCapacity) {
41 fSize = that.fSize;
42 if (fSize > 0) {
43 memcpy(fStorage, that.data(), that.size_bytes());
44 }
45 } else {
46 *this = SkTDStorage{that.data(), that.size(), that.fSizeOfT};
47 }
48 }
49 return *this;
50}
51
53 : fSizeOfT{that.fSizeOfT}
54 , fStorage(std::exchange(that.fStorage, nullptr))
55 , fCapacity{that.fCapacity}
56 , fSize{that.fSize} {}
57
59 if (this != &that) {
60 this->~SkTDStorage();
61 new (this) SkTDStorage{std::move(that)};
62 }
63 return *this;
64}
65
67 sk_free(fStorage);
68}
69
71 const int sizeOfT = fSizeOfT;
72 this->~SkTDStorage();
73 new (this) SkTDStorage{sizeOfT};
74}
75
77 SkASSERT(fSizeOfT == that.fSizeOfT);
78 using std::swap;
79 swap(fStorage, that.fStorage);
80 swap(fCapacity, that.fCapacity);
81 swap(fSize, that.fSize);
82}
83
84void SkTDStorage::resize(int newSize) {
85 SkASSERT(newSize >= 0);
86 if (newSize > fCapacity) {
87 this->reserve(newSize);
88 }
89 fSize = newSize;
90}
91
92void SkTDStorage::reserve(int newCapacity) {
93 SkASSERT(newCapacity >= 0);
94 if (newCapacity > fCapacity) {
95 // Establish the maximum number of elements that includes a valid count for end. In the
96 // largest case end() = &fArray[INT_MAX] which is 1 after the last indexable element.
97 static constexpr int kMaxCount = INT_MAX;
98
99 // Assume that the array will max out.
100 int expandedReserve = kMaxCount;
101 if (kMaxCount - newCapacity > 4) {
102 // Add 1/4 more than we need. Add 4 to ensure this grows by at least 1. Pin to
103 // kMaxCount if no room for 1/4 growth.
104 int growth = 4 + ((newCapacity + 4) >> 2);
105 // Read this line as: if (count + growth < kMaxCount) { ... }
106 // It's rewritten to avoid signed integer overflow.
107 if (kMaxCount - newCapacity > growth) {
108 expandedReserve = newCapacity + growth;
109 }
110 }
111
112
113 // With a T size of 1, the above allocator produces the progression of 7, 15, ... Since,
114 // the sizeof max_align_t is often 16, there is no reason to allocate anything less than
115 // 16 bytes. This eliminates a realloc when pushing back bytes to an SkTDArray.
116 if (fSizeOfT == 1) {
117 // Round up to the multiple of 16.
118 expandedReserve = (expandedReserve + 15) & ~15;
119 }
120
121 fCapacity = expandedReserve;
122 size_t newStorageSize = this->bytes(fCapacity);
123 fStorage = static_cast<std::byte*>(sk_realloc_throw(fStorage, newStorageSize));
124 }
125}
126
128 if (fCapacity != fSize) {
129 fCapacity = fSize;
130 // Because calling realloc with size of 0 is implementation defined, force to a good state
131 // by freeing fStorage.
132 if (fCapacity > 0) {
133 fStorage = static_cast<std::byte*>(sk_realloc_throw(fStorage, this->bytes(fCapacity)));
134 } else {
135 sk_free(fStorage);
136 fStorage = nullptr;
137 }
138 }
139}
140
141void SkTDStorage::erase(int index, int count) {
142 SkASSERT(count >= 0);
143 SkASSERT(fSize >= count);
144 SkASSERT(0 <= index && index <= fSize);
145
146 if (count > 0) {
147 // Check that the resulting size fits in an int. This will abort if not.
148 const int newCount = this->calculateSizeOrDie(-count);
149 this->moveTail(index, index + count, fSize);
150 this->resize(newCount);
151 }
152}
153
155 SkASSERT(fSize > 0);
156 SkASSERT(0 <= index && index < fSize);
157 // Check that the new count is valid.
158 const int newCount = this->calculateSizeOrDie(-1);
159 this->moveTail(index, fSize - 1, fSize);
160 this->resize(newCount);
161}
162
164 return this->insert(/*index=*/0);
165}
166
168 if (fSize < fCapacity) {
169 fSize++;
170 } else {
171 this->insert(fSize);
172 }
173}
174
176 SkASSERT(count >= 0);
177 // Read as: if (fSize + count <= fCapacity) {...}. This is a UB safe way to avoid the add.
178 if (fCapacity - fSize >= count) {
179 fSize += count;
180 } else {
181 this->insert(fSize, count, nullptr);
182 }
183}
184
185void* SkTDStorage::append(const void* src, int count) {
186 return this->insert(fSize, count, src);
187}
188
189void* SkTDStorage::insert(int index) {
190 return this->insert(index, /*count=*/1, nullptr);
191}
192
193void* SkTDStorage::insert(int index, int count, const void* src) {
194 SkASSERT(0 <= index && index <= fSize);
195 SkASSERT(count >= 0);
196
197 if (count > 0) {
198 const int oldCount = fSize;
199 const int newCount = this->calculateSizeOrDie(count);
200 this->resize(newCount);
201 this->moveTail(index + count, index, oldCount);
202
203 if (src != nullptr) {
204 this->copySrc(index, src, count);
205 }
206 }
207
208 return this->address(index);
209}
210
211bool operator==(const SkTDStorage& a, const SkTDStorage& b) {
212 return a.size() == b.size() && (a.empty() || !memcmp(a.data(), b.data(), a.bytes(a.size())));
213}
214
215int SkTDStorage::calculateSizeOrDie(int delta) {
216 // Check that count will not go negative.
217 SkASSERT_RELEASE(-fSize <= delta);
218
219 // We take care to avoid overflow here.
220 // Because count and delta are both signed 32-bit ints, the sum of count and delta is at
221 // most 4294967294, which fits fine in uint32_t. Proof follows in assert.
222 static_assert(UINT32_MAX >= (uint32_t)INT_MAX + (uint32_t)INT_MAX);
223 uint32_t testCount = (uint32_t)fSize + (uint32_t)delta;
224 SkASSERT_RELEASE(SkTFitsIn<int>(testCount));
225 return SkToInt(testCount);
226}
227
228void SkTDStorage::moveTail(int to, int tailStart, int tailEnd) {
229 SkASSERT(0 <= to && to <= fSize);
230 SkASSERT(0 <= tailStart && tailStart <= tailEnd && tailEnd <= fSize);
231 if (to != tailStart && tailStart != tailEnd) {
232 this->copySrc(to, this->address(tailStart), tailEnd - tailStart);
233 }
234}
235
236void SkTDStorage::copySrc(int dstIndex, const void* src, int count) {
237 SkASSERT(count > 0);
238 memmove(this->address(dstIndex), src, this->bytes(count));
239}
int count
static const size_t testCount
#define SkASSERT_RELEASE(cond)
Definition SkAssert.h:100
#define SkASSERT(cond)
Definition SkAssert.h:116
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition SkMalloc.h:67
SK_API void * sk_realloc_throw(void *buffer, size_t size)
bool operator==(const SkTDStorage &a, const SkTDStorage &b)
constexpr int SkToInt(S x)
Definition SkTo.h:29
void erase(int index, int count)
void resize(int newSize)
Definition SkTDArray.cpp:84
SkTDStorage(int sizeOfT)
Definition SkTDArray.cpp:21
int size() const
Definition SkTDArray.h:41
void removeShuffle(int index)
void * insert(int index)
void reserve(int newCapacity)
Definition SkTDArray.cpp:92
void shrink_to_fit()
void * data()
Definition SkTDArray.h:50
void swap(SkTDStorage &that)
Definition SkTDArray.cpp:76
void reset()
Definition SkTDArray.cpp:70
size_t size_bytes() const
Definition SkTDArray.h:43
void append()
void * prepend()
SkTDStorage & operator=(const SkTDStorage &that)
Definition SkTDArray.cpp:38
static bool b
struct MyStruct a[10]
Definition ref_ptr.h:256