gfx/skia/trunk/include/core/SkTemplates.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 /*
michael@0 3 * Copyright 2006 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #ifndef SkTemplates_DEFINED
michael@0 11 #define SkTemplates_DEFINED
michael@0 12
michael@0 13 #include "SkTypes.h"
michael@0 14 #include <limits>
michael@0 15 #include <limits.h>
michael@0 16 #include <new>
michael@0 17
michael@0 18 /** \file SkTemplates.h
michael@0 19
michael@0 20 This file contains light-weight template classes for type-safe and exception-safe
michael@0 21 resource management.
michael@0 22 */
michael@0 23
michael@0 24 /**
michael@0 25 * Marks a local variable as known to be unused (to avoid warnings).
michael@0 26 * Note that this does *not* prevent the local variable from being optimized away.
michael@0 27 */
michael@0 28 template<typename T> inline void sk_ignore_unused_variable(const T&) { }
michael@0 29
michael@0 30 /**
michael@0 31 * SkTIsConst<T>::value is true if the type T is const.
michael@0 32 * The type T is constrained not to be an array or reference type.
michael@0 33 */
michael@0 34 template <typename T> struct SkTIsConst {
michael@0 35 static T* t;
michael@0 36 static uint16_t test(const volatile void*);
michael@0 37 static uint32_t test(volatile void *);
michael@0 38 static const bool value = (sizeof(uint16_t) == sizeof(test(t)));
michael@0 39 };
michael@0 40
michael@0 41 ///@{
michael@0 42 /** SkTConstType<T, CONST>::type will be 'const T' if CONST is true, 'T' otherwise. */
michael@0 43 template <typename T, bool CONST> struct SkTConstType {
michael@0 44 typedef T type;
michael@0 45 };
michael@0 46 template <typename T> struct SkTConstType<T, true> {
michael@0 47 typedef const T type;
michael@0 48 };
michael@0 49 ///@}
michael@0 50
michael@0 51 /**
michael@0 52 * Returns a pointer to a D which comes immediately after S[count].
michael@0 53 */
michael@0 54 template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) {
michael@0 55 return reinterpret_cast<D*>(ptr + count);
michael@0 56 }
michael@0 57
michael@0 58 /**
michael@0 59 * Returns a pointer to a D which comes byteOffset bytes after S.
michael@0 60 */
michael@0 61 template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) {
michael@0 62 // The intermediate char* has the same const-ness as D as this produces better error messages.
michael@0 63 // This relies on the fact that reinterpret_cast can add constness, but cannot remove it.
michael@0 64 return reinterpret_cast<D*>(
michael@0 65 reinterpret_cast<typename SkTConstType<char, SkTIsConst<D>::value>::type*>(ptr) + byteOffset
michael@0 66 );
michael@0 67 }
michael@0 68
michael@0 69 /** SkTSetBit<N, T>::value is a T with the Nth bit set. */
michael@0 70 template<unsigned N, typename T = uintmax_t> struct SkTSetBit {
michael@0 71 static const T value = static_cast<T>(1) << N;
michael@0 72 SK_COMPILE_ASSERT(sizeof(T)*CHAR_BIT > N, SkTSetBit_N_too_large);
michael@0 73 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, SkTSetBit_T_must_be_integer);
michael@0 74 SK_COMPILE_ASSERT(!std::numeric_limits<T>::is_signed, SkTSetBit_T_must_be_unsigned);
michael@0 75 SK_COMPILE_ASSERT(std::numeric_limits<T>::radix == 2, SkTSetBit_T_radix_must_be_2);
michael@0 76 };
michael@0 77
michael@0 78 /** \class SkAutoTCallVProc
michael@0 79
michael@0 80 Call a function when this goes out of scope. The template uses two
michael@0 81 parameters, the object, and a function that is to be called in the destructor.
michael@0 82 If detach() is called, the object reference is set to null. If the object
michael@0 83 reference is null when the destructor is called, we do not call the
michael@0 84 function.
michael@0 85 */
michael@0 86 template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable {
michael@0 87 public:
michael@0 88 SkAutoTCallVProc(T* obj): fObj(obj) {}
michael@0 89 ~SkAutoTCallVProc() { if (fObj) P(fObj); }
michael@0 90 T* detach() { T* obj = fObj; fObj = NULL; return obj; }
michael@0 91 private:
michael@0 92 T* fObj;
michael@0 93 };
michael@0 94
michael@0 95 /** \class SkAutoTCallIProc
michael@0 96
michael@0 97 Call a function when this goes out of scope. The template uses two
michael@0 98 parameters, the object, and a function that is to be called in the destructor.
michael@0 99 If detach() is called, the object reference is set to null. If the object
michael@0 100 reference is null when the destructor is called, we do not call the
michael@0 101 function.
michael@0 102 */
michael@0 103 template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable {
michael@0 104 public:
michael@0 105 SkAutoTCallIProc(T* obj): fObj(obj) {}
michael@0 106 ~SkAutoTCallIProc() { if (fObj) P(fObj); }
michael@0 107 T* detach() { T* obj = fObj; fObj = NULL; return obj; }
michael@0 108 private:
michael@0 109 T* fObj;
michael@0 110 };
michael@0 111
michael@0 112 /** \class SkAutoTDelete
michael@0 113 An SkAutoTDelete<T> is like a T*, except that the destructor of SkAutoTDelete<T>
michael@0 114 automatically deletes the pointer it holds (if any). That is, SkAutoTDelete<T>
michael@0 115 owns the T object that it points to. Like a T*, an SkAutoTDelete<T> may hold
michael@0 116 either NULL or a pointer to a T object. Also like T*, SkAutoTDelete<T> is
michael@0 117 thread-compatible, and once you dereference it, you get the threadsafety
michael@0 118 guarantees of T.
michael@0 119
michael@0 120 The size of a SkAutoTDelete is small: sizeof(SkAutoTDelete<T>) == sizeof(T*)
michael@0 121 */
michael@0 122 template <typename T> class SkAutoTDelete : SkNoncopyable {
michael@0 123 public:
michael@0 124 SkAutoTDelete(T* obj = NULL) : fObj(obj) {}
michael@0 125 ~SkAutoTDelete() { SkDELETE(fObj); }
michael@0 126
michael@0 127 T* get() const { return fObj; }
michael@0 128 T& operator*() const { SkASSERT(fObj); return *fObj; }
michael@0 129 T* operator->() const { SkASSERT(fObj); return fObj; }
michael@0 130
michael@0 131 void reset(T* obj) {
michael@0 132 if (fObj != obj) {
michael@0 133 SkDELETE(fObj);
michael@0 134 fObj = obj;
michael@0 135 }
michael@0 136 }
michael@0 137
michael@0 138 /**
michael@0 139 * Delete the owned object, setting the internal pointer to NULL.
michael@0 140 */
michael@0 141 void free() {
michael@0 142 SkDELETE(fObj);
michael@0 143 fObj = NULL;
michael@0 144 }
michael@0 145
michael@0 146 /**
michael@0 147 * Transfer ownership of the object to the caller, setting the internal
michael@0 148 * pointer to NULL. Note that this differs from get(), which also returns
michael@0 149 * the pointer, but it does not transfer ownership.
michael@0 150 */
michael@0 151 T* detach() {
michael@0 152 T* obj = fObj;
michael@0 153 fObj = NULL;
michael@0 154 return obj;
michael@0 155 }
michael@0 156
michael@0 157 void swap(SkAutoTDelete* that) {
michael@0 158 SkTSwap(fObj, that->fObj);
michael@0 159 }
michael@0 160
michael@0 161 private:
michael@0 162 T* fObj;
michael@0 163 };
michael@0 164
michael@0 165 // Calls ~T() in the destructor.
michael@0 166 template <typename T> class SkAutoTDestroy : SkNoncopyable {
michael@0 167 public:
michael@0 168 SkAutoTDestroy(T* obj = NULL) : fObj(obj) {}
michael@0 169 ~SkAutoTDestroy() {
michael@0 170 if (NULL != fObj) {
michael@0 171 fObj->~T();
michael@0 172 }
michael@0 173 }
michael@0 174
michael@0 175 T* get() const { return fObj; }
michael@0 176 T& operator*() const { SkASSERT(fObj); return *fObj; }
michael@0 177 T* operator->() const { SkASSERT(fObj); return fObj; }
michael@0 178
michael@0 179 private:
michael@0 180 T* fObj;
michael@0 181 };
michael@0 182
michael@0 183 template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
michael@0 184 public:
michael@0 185 SkAutoTDeleteArray(T array[]) : fArray(array) {}
michael@0 186 ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); }
michael@0 187
michael@0 188 T* get() const { return fArray; }
michael@0 189 void free() { SkDELETE_ARRAY(fArray); fArray = NULL; }
michael@0 190 T* detach() { T* array = fArray; fArray = NULL; return array; }
michael@0 191
michael@0 192 void reset(T array[]) {
michael@0 193 if (fArray != array) {
michael@0 194 SkDELETE_ARRAY(fArray);
michael@0 195 fArray = array;
michael@0 196 }
michael@0 197 }
michael@0 198
michael@0 199 private:
michael@0 200 T* fArray;
michael@0 201 };
michael@0 202
michael@0 203 /** Allocate an array of T elements, and free the array in the destructor
michael@0 204 */
michael@0 205 template <typename T> class SkAutoTArray : SkNoncopyable {
michael@0 206 public:
michael@0 207 SkAutoTArray() {
michael@0 208 fArray = NULL;
michael@0 209 SkDEBUGCODE(fCount = 0;)
michael@0 210 }
michael@0 211 /** Allocate count number of T elements
michael@0 212 */
michael@0 213 explicit SkAutoTArray(int count) {
michael@0 214 SkASSERT(count >= 0);
michael@0 215 fArray = NULL;
michael@0 216 if (count) {
michael@0 217 fArray = SkNEW_ARRAY(T, count);
michael@0 218 }
michael@0 219 SkDEBUGCODE(fCount = count;)
michael@0 220 }
michael@0 221
michael@0 222 /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
michael@0 223 */
michael@0 224 void reset(int count) {
michael@0 225 SkDELETE_ARRAY(fArray);
michael@0 226 SkASSERT(count >= 0);
michael@0 227 fArray = NULL;
michael@0 228 if (count) {
michael@0 229 fArray = SkNEW_ARRAY(T, count);
michael@0 230 }
michael@0 231 SkDEBUGCODE(fCount = count;)
michael@0 232 }
michael@0 233
michael@0 234 ~SkAutoTArray() {
michael@0 235 SkDELETE_ARRAY(fArray);
michael@0 236 }
michael@0 237
michael@0 238 /** Return the array of T elements. Will be NULL if count == 0
michael@0 239 */
michael@0 240 T* get() const { return fArray; }
michael@0 241
michael@0 242 /** Return the nth element in the array
michael@0 243 */
michael@0 244 T& operator[](int index) const {
michael@0 245 SkASSERT((unsigned)index < (unsigned)fCount);
michael@0 246 return fArray[index];
michael@0 247 }
michael@0 248
michael@0 249 private:
michael@0 250 T* fArray;
michael@0 251 SkDEBUGCODE(int fCount;)
michael@0 252 };
michael@0 253
michael@0 254 /** Wraps SkAutoTArray, with room for up to N elements preallocated
michael@0 255 */
michael@0 256 template <int N, typename T> class SkAutoSTArray : SkNoncopyable {
michael@0 257 public:
michael@0 258 /** Initialize with no objects */
michael@0 259 SkAutoSTArray() {
michael@0 260 fArray = NULL;
michael@0 261 fCount = 0;
michael@0 262 }
michael@0 263
michael@0 264 /** Allocate count number of T elements
michael@0 265 */
michael@0 266 SkAutoSTArray(int count) {
michael@0 267 fArray = NULL;
michael@0 268 fCount = 0;
michael@0 269 this->reset(count);
michael@0 270 }
michael@0 271
michael@0 272 ~SkAutoSTArray() {
michael@0 273 this->reset(0);
michael@0 274 }
michael@0 275
michael@0 276 /** Destroys previous objects in the array and default constructs count number of objects */
michael@0 277 void reset(int count) {
michael@0 278 T* start = fArray;
michael@0 279 T* iter = start + fCount;
michael@0 280 while (iter > start) {
michael@0 281 (--iter)->~T();
michael@0 282 }
michael@0 283
michael@0 284 if (fCount != count) {
michael@0 285 if (fCount > N) {
michael@0 286 // 'fArray' was allocated last time so free it now
michael@0 287 SkASSERT((T*) fStorage != fArray);
michael@0 288 sk_free(fArray);
michael@0 289 }
michael@0 290
michael@0 291 if (count > N) {
michael@0 292 fArray = (T*) sk_malloc_throw(count * sizeof(T));
michael@0 293 } else if (count > 0) {
michael@0 294 fArray = (T*) fStorage;
michael@0 295 } else {
michael@0 296 fArray = NULL;
michael@0 297 }
michael@0 298
michael@0 299 fCount = count;
michael@0 300 }
michael@0 301
michael@0 302 iter = fArray;
michael@0 303 T* stop = fArray + count;
michael@0 304 while (iter < stop) {
michael@0 305 SkNEW_PLACEMENT(iter++, T);
michael@0 306 }
michael@0 307 }
michael@0 308
michael@0 309 /** Return the number of T elements in the array
michael@0 310 */
michael@0 311 int count() const { return fCount; }
michael@0 312
michael@0 313 /** Return the array of T elements. Will be NULL if count == 0
michael@0 314 */
michael@0 315 T* get() const { return fArray; }
michael@0 316
michael@0 317 /** Return the nth element in the array
michael@0 318 */
michael@0 319 T& operator[](int index) const {
michael@0 320 SkASSERT(index < fCount);
michael@0 321 return fArray[index];
michael@0 322 }
michael@0 323
michael@0 324 private:
michael@0 325 int fCount;
michael@0 326 T* fArray;
michael@0 327 // since we come right after fArray, fStorage should be properly aligned
michael@0 328 char fStorage[N * sizeof(T)];
michael@0 329 };
michael@0 330
michael@0 331 /** Manages an array of T elements, freeing the array in the destructor.
michael@0 332 * Does NOT call any constructors/destructors on T (T must be POD).
michael@0 333 */
michael@0 334 template <typename T> class SkAutoTMalloc : SkNoncopyable {
michael@0 335 public:
michael@0 336 /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
michael@0 337 explicit SkAutoTMalloc(T* ptr = NULL) {
michael@0 338 fPtr = ptr;
michael@0 339 }
michael@0 340
michael@0 341 /** Allocates space for 'count' Ts. */
michael@0 342 explicit SkAutoTMalloc(size_t count) {
michael@0 343 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
michael@0 344 }
michael@0 345
michael@0 346 ~SkAutoTMalloc() {
michael@0 347 sk_free(fPtr);
michael@0 348 }
michael@0 349
michael@0 350 /** Resize the memory area pointed to by the current ptr preserving contents. */
michael@0 351 void realloc(size_t count) {
michael@0 352 fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
michael@0 353 }
michael@0 354
michael@0 355 /** Resize the memory area pointed to by the current ptr without preserving contents. */
michael@0 356 void reset(size_t count) {
michael@0 357 sk_free(fPtr);
michael@0 358 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
michael@0 359 }
michael@0 360
michael@0 361 T* get() const { return fPtr; }
michael@0 362
michael@0 363 operator T*() {
michael@0 364 return fPtr;
michael@0 365 }
michael@0 366
michael@0 367 operator const T*() const {
michael@0 368 return fPtr;
michael@0 369 }
michael@0 370
michael@0 371 T& operator[](int index) {
michael@0 372 return fPtr[index];
michael@0 373 }
michael@0 374
michael@0 375 const T& operator[](int index) const {
michael@0 376 return fPtr[index];
michael@0 377 }
michael@0 378
michael@0 379 /**
michael@0 380 * Transfer ownership of the ptr to the caller, setting the internal
michael@0 381 * pointer to NULL. Note that this differs from get(), which also returns
michael@0 382 * the pointer, but it does not transfer ownership.
michael@0 383 */
michael@0 384 T* detach() {
michael@0 385 T* ptr = fPtr;
michael@0 386 fPtr = NULL;
michael@0 387 return ptr;
michael@0 388 }
michael@0 389
michael@0 390 private:
michael@0 391 T* fPtr;
michael@0 392 };
michael@0 393
michael@0 394 template <size_t N, typename T> class SkAutoSTMalloc : SkNoncopyable {
michael@0 395 public:
michael@0 396 SkAutoSTMalloc() {
michael@0 397 fPtr = NULL;
michael@0 398 }
michael@0 399
michael@0 400 SkAutoSTMalloc(size_t count) {
michael@0 401 if (count > N) {
michael@0 402 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
michael@0 403 } else if (count) {
michael@0 404 fPtr = fTStorage;
michael@0 405 } else {
michael@0 406 fPtr = NULL;
michael@0 407 }
michael@0 408 }
michael@0 409
michael@0 410 ~SkAutoSTMalloc() {
michael@0 411 if (fPtr != fTStorage) {
michael@0 412 sk_free(fPtr);
michael@0 413 }
michael@0 414 }
michael@0 415
michael@0 416 // doesn't preserve contents
michael@0 417 T* reset(size_t count) {
michael@0 418 if (fPtr != fTStorage) {
michael@0 419 sk_free(fPtr);
michael@0 420 }
michael@0 421 if (count > N) {
michael@0 422 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
michael@0 423 } else if (count) {
michael@0 424 fPtr = fTStorage;
michael@0 425 } else {
michael@0 426 fPtr = NULL;
michael@0 427 }
michael@0 428 return fPtr;
michael@0 429 }
michael@0 430
michael@0 431 T* get() const { return fPtr; }
michael@0 432
michael@0 433 operator T*() {
michael@0 434 return fPtr;
michael@0 435 }
michael@0 436
michael@0 437 operator const T*() const {
michael@0 438 return fPtr;
michael@0 439 }
michael@0 440
michael@0 441 T& operator[](int index) {
michael@0 442 return fPtr[index];
michael@0 443 }
michael@0 444
michael@0 445 const T& operator[](int index) const {
michael@0 446 return fPtr[index];
michael@0 447 }
michael@0 448
michael@0 449 private:
michael@0 450 T* fPtr;
michael@0 451 union {
michael@0 452 uint32_t fStorage32[(N*sizeof(T) + 3) >> 2];
michael@0 453 T fTStorage[1]; // do NOT want to invoke T::T()
michael@0 454 };
michael@0 455 };
michael@0 456
michael@0 457 /**
michael@0 458 * Reserves memory that is aligned on double and pointer boundaries.
michael@0 459 * Hopefully this is sufficient for all practical purposes.
michael@0 460 */
michael@0 461 template <size_t N> class SkAlignedSStorage : SkNoncopyable {
michael@0 462 public:
michael@0 463 void* get() { return fData; }
michael@0 464 private:
michael@0 465 union {
michael@0 466 void* fPtr;
michael@0 467 double fDouble;
michael@0 468 char fData[N];
michael@0 469 };
michael@0 470 };
michael@0 471
michael@0 472 /**
michael@0 473 * Reserves memory that is aligned on double and pointer boundaries.
michael@0 474 * Hopefully this is sufficient for all practical purposes. Otherwise,
michael@0 475 * we have to do some arcane trickery to determine alignment of non-POD
michael@0 476 * types. Lifetime of the memory is the lifetime of the object.
michael@0 477 */
michael@0 478 template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
michael@0 479 public:
michael@0 480 /**
michael@0 481 * Returns void* because this object does not initialize the
michael@0 482 * memory. Use placement new for types that require a cons.
michael@0 483 */
michael@0 484 void* get() { return fStorage.get(); }
michael@0 485 private:
michael@0 486 SkAlignedSStorage<sizeof(T)*N> fStorage;
michael@0 487 };
michael@0 488
michael@0 489 #endif

mercurial