1 /* 2 * Copyright 2014 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 SkLazyFnPtr_DEFINED 9 #define SkLazyFnPtr_DEFINED 10 11 /** Declare a lazily-chosen static function pointer of type F. 12 * 13 * Example usage: 14 * 15 * typedef int (*FooImpl)(int, int); 16 * 17 * static FooImpl choose_foo() { return ... }; 18 * 19 * int Foo(int a, int b) { 20 * SK_DECLARE_STATIC_LAZY_FN_PTR(FooImpl, foo, choose_foo); 21 * return foo.get()(a, b); 22 * } 23 * 24 * You can think of SK_DECLARE_STATIC_LAZY_FN_PTR as a cheaper specialization of SkOnce. 25 * There is no mutex, and in the fast path, no memory barriers are issued. 26 * 27 * This must be used in a global or function scope, not as a class member. 28 */ 29 #define SK_DECLARE_STATIC_LAZY_FN_PTR(F, name, Choose) static Private::SkLazyFnPtr<F, Choose> name 30 31 32 // Everything below here is private implementation details. Don't touch, don't even look. 33 34 #include "SkAtomics.h" 35 36 namespace Private { 37 38 // This has no constructor and must be zero-initialized (the macro above does this). 39 template <typename F, F (*Choose)()> 40 class SkLazyFnPtr { 41 public: get()42 F get() { 43 // First, try reading to see if it's already set. 44 F fn = (F)sk_atomic_load(&fPtr, sk_memory_order_relaxed); 45 if (fn != NULL) { 46 return fn; 47 } 48 49 // We think it's not already set. 50 fn = Choose(); 51 52 // No particular memory barriers needed; we're not guarding anything but the pointer itself. 53 F prev = (F)sk_atomic_cas(&fPtr, NULL, (void*)fn); 54 55 // If prev != NULL, someone snuck in and set fPtr concurrently. 56 // If prev == NULL, we did write fn to fPtr. 57 return prev != NULL ? prev : fn; 58 } 59 60 private: 61 void* fPtr; 62 }; 63 64 } // namespace Private 65 66 #endif//SkLazyFnPtr_DEFINED 67