1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/core/SkTLazy.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,192 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 + 1.14 +#ifndef SkTLazy_DEFINED 1.15 +#define SkTLazy_DEFINED 1.16 + 1.17 +#include "SkTypes.h" 1.18 +#include <new> 1.19 + 1.20 +template <typename T> class SkTLazy; 1.21 +template <typename T> void* operator new(size_t, SkTLazy<T>* lazy); 1.22 + 1.23 +/** 1.24 + * Efficient way to defer allocating/initializing a class until it is needed 1.25 + * (if ever). 1.26 + */ 1.27 +template <typename T> class SkTLazy { 1.28 +public: 1.29 + SkTLazy() : fPtr(NULL) {} 1.30 + 1.31 + explicit SkTLazy(const T* src) : fPtr(NULL) { 1.32 + if (src) { 1.33 + fPtr = new (fStorage) T(*src); 1.34 + } 1.35 + } 1.36 + 1.37 + SkTLazy(const SkTLazy<T>& src) : fPtr(NULL) { 1.38 + if (src.isValid()) { 1.39 + fPtr = new (fStorage) T(*src->get()); 1.40 + } else { 1.41 + fPtr = NULL; 1.42 + } 1.43 + } 1.44 + 1.45 + ~SkTLazy() { 1.46 + if (this->isValid()) { 1.47 + fPtr->~T(); 1.48 + } 1.49 + } 1.50 + 1.51 + /** 1.52 + * Return a pointer to a default-initialized instance of the class. If a 1.53 + * previous instance had been initialized (either from init() or set()) it 1.54 + * will first be destroyed, so that a freshly initialized instance is 1.55 + * always returned. 1.56 + */ 1.57 + T* init() { 1.58 + if (this->isValid()) { 1.59 + fPtr->~T(); 1.60 + } 1.61 + fPtr = new (SkTCast<T*>(fStorage)) T; 1.62 + return fPtr; 1.63 + } 1.64 + 1.65 + /** 1.66 + * Copy src into this, and return a pointer to a copy of it. Note this 1.67 + * will always return the same pointer, so if it is called on a lazy that 1.68 + * has already been initialized, then this will copy over the previous 1.69 + * contents. 1.70 + */ 1.71 + T* set(const T& src) { 1.72 + if (this->isValid()) { 1.73 + *fPtr = src; 1.74 + } else { 1.75 + fPtr = new (SkTCast<T*>(fStorage)) T(src); 1.76 + } 1.77 + return fPtr; 1.78 + } 1.79 + 1.80 + /** 1.81 + * Destroy the lazy object (if it was created via init() or set()) 1.82 + */ 1.83 + void reset() { 1.84 + if (this->isValid()) { 1.85 + fPtr->~T(); 1.86 + fPtr = NULL; 1.87 + } 1.88 + } 1.89 + 1.90 + /** 1.91 + * Returns true if a valid object has been initialized in the SkTLazy, 1.92 + * false otherwise. 1.93 + */ 1.94 + bool isValid() const { return NULL != fPtr; } 1.95 + 1.96 + /** 1.97 + * Returns the object. This version should only be called when the caller 1.98 + * knows that the object has been initialized. 1.99 + */ 1.100 + T* get() const { SkASSERT(this->isValid()); return fPtr; } 1.101 + 1.102 + /** 1.103 + * Like above but doesn't assert if object isn't initialized (in which case 1.104 + * NULL is returned). 1.105 + */ 1.106 + T* getMaybeNull() const { return fPtr; } 1.107 + 1.108 +private: 1.109 + friend void* operator new<T>(size_t, SkTLazy* lazy); 1.110 + 1.111 + T* fPtr; // NULL or fStorage 1.112 + char fStorage[sizeof(T)]; 1.113 +}; 1.114 + 1.115 +// Use the below macro (SkNEW_IN_TLAZY) rather than calling this directly 1.116 +template <typename T> void* operator new(size_t, SkTLazy<T>* lazy) { 1.117 + SkASSERT(!lazy->isValid()); 1.118 + lazy->fPtr = reinterpret_cast<T*>(lazy->fStorage); 1.119 + return lazy->fPtr; 1.120 +} 1.121 + 1.122 +// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete 1.123 +// to match the op new silences warnings about missing op delete when a constructor throws an 1.124 +// exception. 1.125 +template <typename T> void operator delete(void*, SkTLazy<T>*) { SK_CRASH(); } 1.126 + 1.127 +// Use this to construct a T inside an SkTLazy using a non-default constructor. 1.128 +#define SkNEW_IN_TLAZY(tlazy_ptr, type_name, args) (new (tlazy_ptr) type_name args) 1.129 + 1.130 +/** 1.131 + * A helper built on top of SkTLazy to do copy-on-first-write. The object is initialized 1.132 + * with a const pointer but provides a non-const pointer accessor. The first time the 1.133 + * accessor is called (if ever) the object is cloned. 1.134 + * 1.135 + * In the following example at most one copy of constThing is made: 1.136 + * 1.137 + * SkTCopyOnFirstWrite<Thing> thing(&constThing); 1.138 + * ... 1.139 + * function_that_takes_a_const_thing_ptr(thing); // constThing is passed 1.140 + * ... 1.141 + * if (need_to_modify_thing()) { 1.142 + * thing.writable()->modifyMe(); // makes a copy of constThing 1.143 + * } 1.144 + * ... 1.145 + * x = thing->readSomething(); 1.146 + * ... 1.147 + * if (need_to_modify_thing_now()) { 1.148 + * thing.writable()->changeMe(); // makes a copy of constThing if we didn't call modifyMe() 1.149 + * } 1.150 + * 1.151 + * consume_a_thing(thing); // could be constThing or a modified copy. 1.152 + */ 1.153 +template <typename T> 1.154 +class SkTCopyOnFirstWrite { 1.155 +public: 1.156 + SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {} 1.157 + 1.158 + // Constructor for delayed initialization. 1.159 + SkTCopyOnFirstWrite() : fObj(NULL) {} 1.160 + 1.161 + // Should only be called once, and only if the default constructor was used. 1.162 + void init(const T& initial) { 1.163 + SkASSERT(NULL == fObj); 1.164 + SkASSERT(!fLazy.isValid()); 1.165 + fObj = &initial; 1.166 + } 1.167 + 1.168 + /** 1.169 + * Returns a writable T*. The first time this is called the initial object is cloned. 1.170 + */ 1.171 + T* writable() { 1.172 + SkASSERT(NULL != fObj); 1.173 + if (!fLazy.isValid()) { 1.174 + fLazy.set(*fObj); 1.175 + fObj = fLazy.get(); 1.176 + } 1.177 + return const_cast<T*>(fObj); 1.178 + } 1.179 + 1.180 + /** 1.181 + * Operators for treating this as though it were a const pointer. 1.182 + */ 1.183 + 1.184 + const T *operator->() const { return fObj; } 1.185 + 1.186 + operator const T*() const { return fObj; } 1.187 + 1.188 + const T& operator *() const { return *fObj; } 1.189 + 1.190 +private: 1.191 + const T* fObj; 1.192 + SkTLazy<T> fLazy; 1.193 +}; 1.194 + 1.195 +#endif