Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Side by Side Diff: include/core/SkTArray.h

Issue 1702073002: Move SkTArray to include/private. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix kilobench. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/core/SkString.h ('k') | include/core/SkTextBlob.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2011 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
8 #ifndef SkTArray_DEFINED
9 #define SkTArray_DEFINED
10
11 #include "../private/SkTLogic.h"
12 #include "../private/SkTemplates.h"
13 #include "SkTypes.h"
14
15 #include <new>
16 #include <utility>
17
18 /** When MEM_COPY is true T will be bit copied when moved.
19 When MEM_COPY is false, T will be copy constructed / destructed.
20 In all cases T will be default-initialized on allocation,
21 and its destructor will be called from this object's destructor.
22 */
23 template <typename T, bool MEM_COPY = false> class SkTArray {
24 public:
25 /**
26 * Creates an empty array with no initial storage
27 */
28 SkTArray() {
29 fCount = 0;
30 fReserveCount = gMIN_ALLOC_COUNT;
31 fAllocCount = 0;
32 fMemArray = NULL;
33 fPreAllocMemArray = NULL;
34 }
35
36 /**
37 * Creates an empty array that will preallocate space for reserveCount
38 * elements.
39 */
40 explicit SkTArray(int reserveCount) {
41 this->init(NULL, 0, NULL, reserveCount);
42 }
43
44 /**
45 * Copies one array to another. The new array will be heap allocated.
46 */
47 explicit SkTArray(const SkTArray& array) {
48 this->init(array.fItemArray, array.fCount, NULL, 0);
49 }
50
51 /**
52 * Creates a SkTArray by copying contents of a standard C array. The new
53 * array will be heap allocated. Be careful not to use this constructor
54 * when you really want the (void*, int) version.
55 */
56 SkTArray(const T* array, int count) {
57 this->init(array, count, NULL, 0);
58 }
59
60 /**
61 * assign copy of array to this
62 */
63 SkTArray& operator =(const SkTArray& array) {
64 for (int i = 0; i < fCount; ++i) {
65 fItemArray[i].~T();
66 }
67 fCount = 0;
68 this->checkRealloc((int)array.count());
69 fCount = array.count();
70 this->copy(static_cast<const T*>(array.fMemArray));
71 return *this;
72 }
73
74 ~SkTArray() {
75 for (int i = 0; i < fCount; ++i) {
76 fItemArray[i].~T();
77 }
78 if (fMemArray != fPreAllocMemArray) {
79 sk_free(fMemArray);
80 }
81 }
82
83 /**
84 * Resets to count() == 0
85 */
86 void reset() { this->pop_back_n(fCount); }
87
88 /**
89 * Resets to count() = n newly constructed T objects.
90 */
91 void reset(int n) {
92 SkASSERT(n >= 0);
93 for (int i = 0; i < fCount; ++i) {
94 fItemArray[i].~T();
95 }
96 // set fCount to 0 before calling checkRealloc so that no copy cons. are called.
97 fCount = 0;
98 this->checkRealloc(n);
99 fCount = n;
100 for (int i = 0; i < fCount; ++i) {
101 new (fItemArray + i) T;
102 }
103 }
104
105 /**
106 * Resets to a copy of a C array.
107 */
108 void reset(const T* array, int count) {
109 for (int i = 0; i < fCount; ++i) {
110 fItemArray[i].~T();
111 }
112 int delta = count - fCount;
113 this->checkRealloc(delta);
114 fCount = count;
115 this->copy(array);
116 }
117
118 void removeShuffle(int n) {
119 SkASSERT(n < fCount);
120 int newCount = fCount - 1;
121 fCount = newCount;
122 fItemArray[n].~T();
123 if (n != newCount) {
124 this->move(n, newCount);
125 }
126 }
127
128 /**
129 * Number of elements in the array.
130 */
131 int count() const { return fCount; }
132
133 /**
134 * Is the array empty.
135 */
136 bool empty() const { return !fCount; }
137
138 /**
139 * Adds 1 new default-initialized T value and returns it by reference. Note
140 * the reference only remains valid until the next call that adds or removes
141 * elements.
142 */
143 T& push_back() {
144 T* newT = reinterpret_cast<T*>(this->push_back_raw(1));
145 new (newT) T;
146 return *newT;
147 }
148
149 /**
150 * Version of above that uses a copy constructor to initialize the new item
151 */
152 T& push_back(const T& t) {
153 T* newT = reinterpret_cast<T*>(this->push_back_raw(1));
154 new (newT) T(t);
155 return *newT;
156 }
157
158 /**
159 * Construct a new T at the back of this array.
160 */
161 template<class... Args> T& emplace_back(Args&&... args) {
162 T* newT = reinterpret_cast<T*>(this->push_back_raw(1));
163 return *new (newT) T(std::forward<Args>(args)...);
164 }
165
166 /**
167 * Allocates n more default-initialized T values, and returns the address of
168 * the start of that new range. Note: this address is only valid until the
169 * next API call made on the array that might add or remove elements.
170 */
171 T* push_back_n(int n) {
172 SkASSERT(n >= 0);
173 T* newTs = reinterpret_cast<T*>(this->push_back_raw(n));
174 for (int i = 0; i < n; ++i) {
175 new (newTs + i) T;
176 }
177 return newTs;
178 }
179
180 /**
181 * Version of above that uses a copy constructor to initialize all n items
182 * to the same T.
183 */
184 T* push_back_n(int n, const T& t) {
185 SkASSERT(n >= 0);
186 T* newTs = reinterpret_cast<T*>(this->push_back_raw(n));
187 for (int i = 0; i < n; ++i) {
188 new (newTs[i]) T(t);
189 }
190 return newTs;
191 }
192
193 /**
194 * Version of above that uses a copy constructor to initialize the n items
195 * to separate T values.
196 */
197 T* push_back_n(int n, const T t[]) {
198 SkASSERT(n >= 0);
199 this->checkRealloc(n);
200 for (int i = 0; i < n; ++i) {
201 new (fItemArray + fCount + i) T(t[i]);
202 }
203 fCount += n;
204 return fItemArray + fCount - n;
205 }
206
207 /**
208 * Removes the last element. Not safe to call when count() == 0.
209 */
210 void pop_back() {
211 SkASSERT(fCount > 0);
212 --fCount;
213 fItemArray[fCount].~T();
214 this->checkRealloc(0);
215 }
216
217 /**
218 * Removes the last n elements. Not safe to call when count() < n.
219 */
220 void pop_back_n(int n) {
221 SkASSERT(n >= 0);
222 SkASSERT(fCount >= n);
223 fCount -= n;
224 for (int i = 0; i < n; ++i) {
225 fItemArray[fCount + i].~T();
226 }
227 this->checkRealloc(0);
228 }
229
230 /**
231 * Pushes or pops from the back to resize. Pushes will be default
232 * initialized.
233 */
234 void resize_back(int newCount) {
235 SkASSERT(newCount >= 0);
236
237 if (newCount > fCount) {
238 this->push_back_n(newCount - fCount);
239 } else if (newCount < fCount) {
240 this->pop_back_n(fCount - newCount);
241 }
242 }
243
244 /** Swaps the contents of this array with that array. Does a pointer swap if possible,
245 otherwise copies the T values. */
246 void swap(SkTArray* that) {
247 if (this == that) {
248 return;
249 }
250 if (this->fPreAllocMemArray != this->fItemArray &&
251 that->fPreAllocMemArray != that->fItemArray) {
252 // If neither is using a preallocated array then just swap.
253 SkTSwap(fItemArray, that->fItemArray);
254 SkTSwap(fCount, that->fCount);
255 SkTSwap(fAllocCount, that->fAllocCount);
256 } else {
257 // This could be more optimal...
258 SkTArray copy(*that);
259 *that = *this;
260 *this = copy;
261 }
262 }
263
264 T* begin() {
265 return fItemArray;
266 }
267 const T* begin() const {
268 return fItemArray;
269 }
270 T* end() {
271 return fItemArray ? fItemArray + fCount : NULL;
272 }
273 const T* end() const {
274 return fItemArray ? fItemArray + fCount : NULL;
275 }
276
277 /**
278 * Get the i^th element.
279 */
280 T& operator[] (int i) {
281 SkASSERT(i < fCount);
282 SkASSERT(i >= 0);
283 return fItemArray[i];
284 }
285
286 const T& operator[] (int i) const {
287 SkASSERT(i < fCount);
288 SkASSERT(i >= 0);
289 return fItemArray[i];
290 }
291
292 /**
293 * equivalent to operator[](0)
294 */
295 T& front() { SkASSERT(fCount > 0); return fItemArray[0];}
296
297 const T& front() const { SkASSERT(fCount > 0); return fItemArray[0];}
298
299 /**
300 * equivalent to operator[](count() - 1)
301 */
302 T& back() { SkASSERT(fCount); return fItemArray[fCount - 1];}
303
304 const T& back() const { SkASSERT(fCount > 0); return fItemArray[fCount - 1]; }
305
306 /**
307 * equivalent to operator[](count()-1-i)
308 */
309 T& fromBack(int i) {
310 SkASSERT(i >= 0);
311 SkASSERT(i < fCount);
312 return fItemArray[fCount - i - 1];
313 }
314
315 const T& fromBack(int i) const {
316 SkASSERT(i >= 0);
317 SkASSERT(i < fCount);
318 return fItemArray[fCount - i - 1];
319 }
320
321 bool operator==(const SkTArray<T, MEM_COPY>& right) const {
322 int leftCount = this->count();
323 if (leftCount != right.count()) {
324 return false;
325 }
326 for (int index = 0; index < leftCount; ++index) {
327 if (fItemArray[index] != right.fItemArray[index]) {
328 return false;
329 }
330 }
331 return true;
332 }
333
334 bool operator!=(const SkTArray<T, MEM_COPY>& right) const {
335 return !(*this == right);
336 }
337
338 protected:
339 /**
340 * Creates an empty array that will use the passed storage block until it
341 * is insufficiently large to hold the entire array.
342 */
343 template <int N>
344 SkTArray(SkAlignedSTStorage<N,T>* storage) {
345 this->init(NULL, 0, storage->get(), N);
346 }
347
348 /**
349 * Copy another array, using preallocated storage if preAllocCount >=
350 * array.count(). Otherwise storage will only be used when array shrinks
351 * to fit.
352 */
353 template <int N>
354 SkTArray(const SkTArray& array, SkAlignedSTStorage<N,T>* storage) {
355 this->init(array.fItemArray, array.fCount, storage->get(), N);
356 }
357
358 /**
359 * Copy a C array, using preallocated storage if preAllocCount >=
360 * count. Otherwise storage will only be used when array shrinks
361 * to fit.
362 */
363 template <int N>
364 SkTArray(const T* array, int count, SkAlignedSTStorage<N,T>* storage) {
365 this->init(array, count, storage->get(), N);
366 }
367
368 void init(const T* array, int count,
369 void* preAllocStorage, int preAllocOrReserveCount) {
370 SkASSERT(count >= 0);
371 SkASSERT(preAllocOrReserveCount >= 0);
372 fCount = count;
373 fReserveCount = (preAllocOrReserveCount > 0) ?
374 preAllocOrReserveCount :
375 gMIN_ALLOC_COUNT;
376 fPreAllocMemArray = preAllocStorage;
377 if (fReserveCount >= fCount &&
378 preAllocStorage) {
379 fAllocCount = fReserveCount;
380 fMemArray = preAllocStorage;
381 } else {
382 fAllocCount = SkMax32(fCount, fReserveCount);
383 fMemArray = sk_malloc_throw(fAllocCount * sizeof(T));
384 }
385
386 this->copy(array);
387 }
388
389 private:
390 /** In the following move and copy methods, 'dst' is assumed to be uninitial ized raw storage.
391 * In the following move methods, 'src' is destroyed leaving behind uniniti alized raw storage.
392 */
393 template <bool E = MEM_COPY> SK_WHEN(E, void) copy(const T* src) {
394 sk_careful_memcpy(fMemArray, src, fCount * sizeof(T));
395 }
396 template <bool E = MEM_COPY> SK_WHEN(E, void) move(int dst, int src) {
397 memcpy(&fItemArray[dst], &fItemArray[src], sizeof(T));
398 }
399 template <bool E = MEM_COPY> SK_WHEN(E, void) move(char* dst) {
400 sk_careful_memcpy(dst, fMemArray, fCount * sizeof(T));
401 }
402
403 template <bool E = MEM_COPY> SK_WHEN(!E, void) copy(const T* src) {
404 for (int i = 0; i < fCount; ++i) {
405 new (fItemArray + i) T(src[i]);
406 }
407 }
408 template <bool E = MEM_COPY> SK_WHEN(!E, void) move(int dst, int src) {
409 new (&fItemArray[dst]) T(std::move(fItemArray[src]));
410 fItemArray[src].~T();
411 }
412 template <bool E = MEM_COPY> SK_WHEN(!E, void) move(char* dst) {
413 for (int i = 0; i < fCount; ++i) {
414 new (dst + sizeof(T) * i) T(std::move(fItemArray[i]));
415 fItemArray[i].~T();
416 }
417 }
418
419 static const int gMIN_ALLOC_COUNT = 8;
420
421 // Helper function that makes space for n objects, adjusts the count, but do es not initialize
422 // the new objects.
423 void* push_back_raw(int n) {
424 this->checkRealloc(n);
425 void* ptr = fItemArray + fCount;
426 fCount += n;
427 return ptr;
428 }
429
430 inline void checkRealloc(int delta) {
431 SkASSERT(fCount >= 0);
432 SkASSERT(fAllocCount >= 0);
433
434 SkASSERT(-delta <= fCount);
435
436 int newCount = fCount + delta;
437 int newAllocCount = fAllocCount;
438
439 if (newCount > fAllocCount || newCount < (fAllocCount / 3)) {
440 // whether we're growing or shrinking, we leave at least 50% extra s pace for future
441 // growth (clamped to the reserve count).
442 newAllocCount = SkMax32(newCount + ((newCount + 1) >> 1), fReserveCo unt);
443 }
444 if (newAllocCount != fAllocCount) {
445
446 fAllocCount = newAllocCount;
447 char* newMemArray;
448
449 if (fAllocCount == fReserveCount && fPreAllocMemArray) {
450 newMemArray = (char*) fPreAllocMemArray;
451 } else {
452 newMemArray = (char*) sk_malloc_throw(fAllocCount*sizeof(T));
453 }
454
455 this->move(newMemArray);
456
457 if (fMemArray != fPreAllocMemArray) {
458 sk_free(fMemArray);
459 }
460 fMemArray = newMemArray;
461 }
462 }
463
464 int fReserveCount;
465 int fCount;
466 int fAllocCount;
467 void* fPreAllocMemArray;
468 union {
469 T* fItemArray;
470 void* fMemArray;
471 };
472 };
473
474 /**
475 * Subclass of SkTArray that contains a preallocated memory block for the array.
476 */
477 template <int N, typename T, bool MEM_COPY = false>
478 class SkSTArray : public SkTArray<T, MEM_COPY> {
479 private:
480 typedef SkTArray<T, MEM_COPY> INHERITED;
481
482 public:
483 SkSTArray() : INHERITED(&fStorage) {
484 }
485
486 SkSTArray(const SkSTArray& array)
487 : INHERITED(array, &fStorage) {
488 }
489
490 explicit SkSTArray(const INHERITED& array)
491 : INHERITED(array, &fStorage) {
492 }
493
494 explicit SkSTArray(int reserveCount)
495 : INHERITED(reserveCount) {
496 }
497
498 SkSTArray(const T* array, int count)
499 : INHERITED(array, count, &fStorage) {
500 }
501
502 SkSTArray& operator= (const SkSTArray& array) {
503 return *this = *(const INHERITED*)&array;
504 }
505
506 SkSTArray& operator= (const INHERITED& array) {
507 INHERITED::operator=(array);
508 return *this;
509 }
510
511 private:
512 SkAlignedSTStorage<N,T> fStorage;
513 };
514
515 #endif
OLDNEW
« no previous file with comments | « include/core/SkString.h ('k') | include/core/SkTextBlob.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698