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 "SkDynamicAnnotations.h" 35 #include "SkThreadPriv.h" 36 37 namespace Private { 38 39 // This has no constructor and must be zero-initialized (the macro above does this). 40 template <typename F, F (*Choose)()> 41 class SkLazyFnPtr { 42 public: 43 F get() { 44 // First, try reading to see if it's already set. 45 F fn = (F)SK_ANNOTATE_UNPROTECTED_READ(fPtr); 46 if (fn != NULL) { 47 return fn; 48 } 49 50 // We think it's not already set. 51 fn = Choose(); 52 53 // No particular memory barriers needed; we're not guarding anything but the pointer itself. 54 F prev = (F)sk_atomic_cas(&fPtr, NULL, (void*)fn); 55 56 // If prev != NULL, someone snuck in and set fPtr concurrently. 57 // If prev == NULL, we did write fn to fPtr. 58 return prev != NULL ? prev : fn; 59 } 60 61 private: 62 void* fPtr; 63 }; 64 65 } // namespace Private 66 67 #endif//SkLazyFnPtr_DEFINED 68