Flutter Engine
The Flutter Engine
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
Definition: FontMgrTest.cpp:50
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)
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
bool operator==(const SkTDStorage &a, const SkTDStorage &b)
Definition: SkTDArray.cpp:211
constexpr int SkToInt(S x)
Definition: SkTo.h:29
void erase(int index, int count)
Definition: SkTDArray.cpp:141
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)
Definition: SkTDArray.cpp:154
void * insert(int index)
Definition: SkTDArray.cpp:189
void reserve(int newCapacity)
Definition: SkTDArray.cpp:92
void shrink_to_fit()
Definition: SkTDArray.cpp:127
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()
Definition: SkTDArray.cpp:167
void * prepend()
Definition: SkTDArray.cpp:163
SkTDStorage & operator=(const SkTDStorage &that)
Definition: SkTDArray.cpp:38
static bool b
struct MyStruct a[10]
static constexpr size_t kMaxCount
Definition: dart_vm.cc:287
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256