Home | History | Annotate | Download | only in core
      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