SkTLazy.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. #ifndef SkTLazy_DEFINED
  8. #define SkTLazy_DEFINED
  9. #include "../private/SkTemplates.h"
  10. #include "SkTypes.h"
  11. #include <new>
  12. #include <utility>
  13. /**
  14. * Efficient way to defer allocating/initializing a class until it is needed
  15. * (if ever).
  16. */
  17. template <typename T> class SkTLazy {
  18. public:
  19. SkTLazy() : fPtr(nullptr) {}
  20. explicit SkTLazy(const T* src)
  21. : fPtr(src ? new (fStorage.get()) T(*src) : nullptr) {}
  22. SkTLazy(const SkTLazy& that) : fPtr(nullptr) { *this = that; }
  23. SkTLazy(SkTLazy&& that) : fPtr(nullptr) { *this = std::move(that); }
  24. ~SkTLazy() {
  25. if (this->isValid()) {
  26. fPtr->~T();
  27. }
  28. }
  29. SkTLazy& operator=(const SkTLazy& that) {
  30. if (that.isValid()) {
  31. this->set(*that.get());
  32. } else {
  33. this->reset();
  34. }
  35. return *this;
  36. }
  37. SkTLazy& operator=(SkTLazy&& that) {
  38. if (that.isValid()) {
  39. this->set(std::move(*that.get()));
  40. } else {
  41. this->reset();
  42. }
  43. return *this;
  44. }
  45. /**
  46. * Return a pointer to an instance of the class initialized with 'args'.
  47. * If a previous instance had been initialized (either from init() or
  48. * set()) it will first be destroyed, so that a freshly initialized
  49. * instance is always returned.
  50. */
  51. template <typename... Args> T* init(Args&&... args) {
  52. if (this->isValid()) {
  53. fPtr->~T();
  54. }
  55. fPtr = new (reinterpret_cast<T*>(fStorage.get())) T(std::forward<Args>(args)...);
  56. return fPtr;
  57. }
  58. /**
  59. * Copy src into this, and return a pointer to a copy of it. Note this
  60. * will always return the same pointer, so if it is called on a lazy that
  61. * has already been initialized, then this will copy over the previous
  62. * contents.
  63. */
  64. T* set(const T& src) {
  65. if (this->isValid()) {
  66. *fPtr = src;
  67. } else {
  68. fPtr = new (reinterpret_cast<T*>(fStorage.get())) T(src);
  69. }
  70. return fPtr;
  71. }
  72. T* set(T&& src) {
  73. if (this->isValid()) {
  74. *fPtr = std::move(src);
  75. } else {
  76. fPtr = new (reinterpret_cast<T*>(fStorage.get())) T(std::move(src));
  77. }
  78. return fPtr;
  79. }
  80. /**
  81. * Destroy the lazy object (if it was created via init() or set())
  82. */
  83. void reset() {
  84. if (this->isValid()) {
  85. fPtr->~T();
  86. fPtr = nullptr;
  87. }
  88. }
  89. /**
  90. * Returns true if a valid object has been initialized in the SkTLazy,
  91. * false otherwise.
  92. */
  93. bool isValid() const { return SkToBool(fPtr); }
  94. /**
  95. * Returns the object. This version should only be called when the caller
  96. * knows that the object has been initialized.
  97. */
  98. T* get() const { SkASSERT(this->isValid()); return fPtr; }
  99. /**
  100. * Like above but doesn't assert if object isn't initialized (in which case
  101. * nullptr is returned).
  102. */
  103. T* getMaybeNull() const { return fPtr; }
  104. private:
  105. SkAlignedSTStorage<1, T> fStorage;
  106. T* fPtr; // nullptr or fStorage
  107. };
  108. /**
  109. * A helper built on top of SkTLazy to do copy-on-first-write. The object is initialized
  110. * with a const pointer but provides a non-const pointer accessor. The first time the
  111. * accessor is called (if ever) the object is cloned.
  112. *
  113. * In the following example at most one copy of constThing is made:
  114. *
  115. * SkTCopyOnFirstWrite<Thing> thing(&constThing);
  116. * ...
  117. * function_that_takes_a_const_thing_ptr(thing); // constThing is passed
  118. * ...
  119. * if (need_to_modify_thing()) {
  120. * thing.writable()->modifyMe(); // makes a copy of constThing
  121. * }
  122. * ...
  123. * x = thing->readSomething();
  124. * ...
  125. * if (need_to_modify_thing_now()) {
  126. * thing.writable()->changeMe(); // makes a copy of constThing if we didn't call modifyMe()
  127. * }
  128. *
  129. * consume_a_thing(thing); // could be constThing or a modified copy.
  130. */
  131. template <typename T>
  132. class SkTCopyOnFirstWrite {
  133. public:
  134. explicit SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {}
  135. explicit SkTCopyOnFirstWrite(const T* initial) : fObj(initial) {}
  136. // Constructor for delayed initialization.
  137. SkTCopyOnFirstWrite() : fObj(nullptr) {}
  138. SkTCopyOnFirstWrite(const SkTCopyOnFirstWrite& that) { *this = that; }
  139. SkTCopyOnFirstWrite( SkTCopyOnFirstWrite&& that) { *this = std::move(that); }
  140. SkTCopyOnFirstWrite& operator=(const SkTCopyOnFirstWrite& that) {
  141. fLazy = that.fLazy;
  142. fObj = fLazy.isValid() ? fLazy.get() : that.fObj;
  143. return *this;
  144. }
  145. SkTCopyOnFirstWrite& operator=(SkTCopyOnFirstWrite&& that) {
  146. fLazy = std::move(that.fLazy);
  147. fObj = fLazy.isValid() ? fLazy.get() : that.fObj;
  148. return *this;
  149. }
  150. // Should only be called once, and only if the default constructor was used.
  151. void init(const T& initial) {
  152. SkASSERT(nullptr == fObj);
  153. SkASSERT(!fLazy.isValid());
  154. fObj = &initial;
  155. }
  156. /**
  157. * Returns a writable T*. The first time this is called the initial object is cloned.
  158. */
  159. T* writable() {
  160. SkASSERT(fObj);
  161. if (!fLazy.isValid()) {
  162. fLazy.set(*fObj);
  163. fObj = fLazy.get();
  164. }
  165. return const_cast<T*>(fObj);
  166. }
  167. const T* get() const { return fObj; }
  168. /**
  169. * Operators for treating this as though it were a const pointer.
  170. */
  171. const T *operator->() const { return fObj; }
  172. operator const T*() const { return fObj; }
  173. const T& operator *() const { return *fObj; }
  174. private:
  175. const T* fObj;
  176. SkTLazy<T> fLazy;
  177. };
  178. #endif