1 /* 2 * Copyright 2015 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 SkOncePtr_DEFINED 9 #define SkOncePtr_DEFINED 10 11 #include "../private/SkAtomics.h" 12 #include "SkUniquePtr.h" 13 14 template <typename T> class SkBaseOncePtr; 15 16 // Use this to create a global static pointer that's intialized exactly once when you call get(). 17 #define SK_DECLARE_STATIC_ONCE_PTR(type, name) namespace {} static SkBaseOncePtr<type> name; 18 19 // Use this for a local or member pointer that's initialized exactly once when you call get(). 20 template <typename T, typename Delete = skstd::default_delete<T>> 21 class SkOncePtr : SkNoncopyable { 22 public: SkOncePtr()23 SkOncePtr() { sk_bzero(this, sizeof(*this)); } ~SkOncePtr()24 ~SkOncePtr() { 25 if (T* ptr = (T*)*this) { 26 Delete()(ptr); 27 } 28 } 29 30 template <typename F> get(const F & f)31 T* get(const F& f) const { 32 return fOnce.get(f); 33 } 34 35 operator T*() const { 36 return (T*)fOnce; 37 } 38 39 private: 40 SkBaseOncePtr<T> fOnce; 41 }; 42 43 // If you ask for SkOncePtr<T[]>, we'll clean up with delete[] by default. 44 template <typename T> 45 class SkOncePtr<T[]> : public SkOncePtr<T, skstd::default_delete<T[]>> {}; 46 47 /* TODO(mtklein): in next CL 48 typedef SkBaseOncePtr<void> SkOnceFlag; 49 #define SK_DECLARE_STATIC_ONCE(name) namespace {} static SkOnceFlag name 50 51 template <typename F> 52 inline void SkOnce(SkOnceFlag* once, const F& f) { 53 once->get([&]{ f(); return (void*)2; }); 54 } 55 */ 56 57 // Implementation details below here! No peeking! 58 59 template <typename T> 60 class SkBaseOncePtr { 61 public: 62 template <typename F> get(const F & f)63 T* get(const F& f) const { 64 uintptr_t state = sk_atomic_load(&fState, sk_memory_order_acquire); 65 if (state < 2) { 66 if (state == 0) { 67 // It looks like no one has tried to create our pointer yet. 68 // We try to claim that task by atomically swapping our state from '0' to '1'. 69 if (sk_atomic_compare_exchange( 70 &fState, &state, (uintptr_t)1, sk_memory_order_relaxed, sk_memory_order_relaxed)) { 71 // We've claimed it. Create our pointer and store it into fState. 72 state = (uintptr_t)f(); 73 SkASSERT(state > 1); 74 sk_atomic_store(&fState, state, sk_memory_order_release); 75 } else { 76 // Someone else claimed it. 77 // We fall through to the spin loop just below to wait for them to finish. 78 } 79 } 80 81 while (state == 1) { 82 // State '1' is our busy-but-not-done state. 83 // Some other thread has claimed the job of creating our pointer. 84 // We just need to wait for it to finish. 85 state = sk_atomic_load(&fState, sk_memory_order_acquire); 86 } 87 88 // We shouldn't be able to get here without having created our pointer. 89 SkASSERT(state > 1); 90 } 91 return (T*)state; 92 } 93 94 operator T*() const { 95 auto state = sk_atomic_load(&fState, sk_memory_order_acquire); 96 return state < 2 ? nullptr : (T*)state; 97 // TODO: If state == 1 spin until it's not? 98 } 99 100 // fState == 0 --> we have not created our ptr yet 101 // fState == 1 --> someone is in the middle of creating our ptr 102 // else --> (T*)fState is our ptr 103 mutable uintptr_t fState; 104 }; 105 106 #endif//SkOncePtr_DEFINED 107