|  | /* | 
|  | * Copyright 2014 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #ifndef SkLazyFnPtr_DEFINED | 
|  | #define SkLazyFnPtr_DEFINED | 
|  |  | 
|  | /** Declare a lazily-chosen static function pointer of type F. | 
|  | * | 
|  | *  Example usage: | 
|  | * | 
|  | *  typedef int (*FooImpl)(int, int); | 
|  | * | 
|  | *  static FooImpl choose_foo() { return ... }; | 
|  | * | 
|  | *  int Foo(int a, int b) { | 
|  | *     SK_DECLARE_STATIC_LAZY_FN_PTR(FooImpl, foo, choose_foo); | 
|  | *     return foo.get()(a, b); | 
|  | *  } | 
|  | * | 
|  | *  You can think of SK_DECLARE_STATIC_LAZY_FN_PTR as a cheaper specialization of SkOnce. | 
|  | *  There is no mutex, and in the fast path, no memory barriers are issued. | 
|  | * | 
|  | *  This must be used in a global or function scope, not as a class member. | 
|  | */ | 
|  | #define SK_DECLARE_STATIC_LAZY_FN_PTR(F, name, Choose) static Private::SkLazyFnPtr<F, Choose> name | 
|  |  | 
|  |  | 
|  | // Everything below here is private implementation details.  Don't touch, don't even look. | 
|  |  | 
|  | #include "SkDynamicAnnotations.h" | 
|  | #include "SkThreadPriv.h" | 
|  |  | 
|  | namespace Private { | 
|  |  | 
|  | // This has no constructor and must be zero-initialized (the macro above does this). | 
|  | template <typename F, F (*Choose)()> | 
|  | class SkLazyFnPtr { | 
|  | public: | 
|  | F get() { | 
|  | // First, try reading to see if it's already set. | 
|  | F fn = (F)SK_ANNOTATE_UNPROTECTED_READ(fPtr); | 
|  | if (fn != NULL) { | 
|  | return fn; | 
|  | } | 
|  |  | 
|  | // We think it's not already set. | 
|  | fn = Choose(); | 
|  |  | 
|  | // No particular memory barriers needed; we're not guarding anything but the pointer itself. | 
|  | F prev = (F)sk_atomic_cas(&fPtr, NULL, (void*)fn); | 
|  |  | 
|  | // If prev != NULL, someone snuck in and set fPtr concurrently. | 
|  | // If prev == NULL, we did write fn to fPtr. | 
|  | return prev != NULL ? prev : fn; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void* fPtr; | 
|  | }; | 
|  |  | 
|  | }  // namespace Private | 
|  |  | 
|  | #endif//SkLazyFnPtr_DEFINED |