gfx/skia/trunk/include/core/SkTArray.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial