1d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org/*
2d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * Copyright 2014 Google Inc.
3d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org *
4d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
5d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * found in the LICENSE file.
6d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org */
7d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org
881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#ifndef SkLazyFnPtr_DEFINED
981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#define SkLazyFnPtr_DEFINED
1081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
1181496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org/** Declare a lazily-chosen static function pointer of type F.
1281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *
1381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  Example usage:
1481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *
1581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  typedef int (*FooImpl)(int, int);
1681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *
1781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  static FooImpl choose_foo() { return ... };
1881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *
1981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  int Foo(int a, int b) {
20d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org *     SK_DECLARE_STATIC_LAZY_FN_PTR(FooImpl, foo, choose_foo);
21d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org *     return foo.get()(a, b);
2281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  }
2381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *
2481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  You can think of SK_DECLARE_STATIC_LAZY_FN_PTR as a cheaper specialization of SkOnce.
2581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  There is no mutex, and in the fast path, no memory barriers are issued.
2681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *
2781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org *  This must be used in a global or function scope, not as a class member.
2881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org */
29d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org#define SK_DECLARE_STATIC_LAZY_FN_PTR(F, name, Choose) static Private::SkLazyFnPtr<F, Choose> name
3081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
3181496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
3281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org// Everything below here is private implementation details.  Don't touch, don't even look.
3381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
3481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#include "SkDynamicAnnotations.h"
3581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#include "SkThreadPriv.h"
3681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
3781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.orgnamespace Private {
3881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
39d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org// This has no constructor and must be zero-initialized (the macro above does this).
40d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgtemplate <typename F, F (*Choose)()>
41d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgclass SkLazyFnPtr {
42d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgpublic:
43d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org    F get() {
4481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        // First, try reading to see if it's already set.
4581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        F fn = (F)SK_ANNOTATE_UNPROTECTED_READ(fPtr);
4681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        if (fn != NULL) {
4781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org            return fn;
4881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        }
4981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
5081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        // We think it's not already set.
51d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org        fn = Choose();
5281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
5381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        // No particular memory barriers needed; we're not guarding anything but the pointer itself.
5481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        F prev = (F)sk_atomic_cas(&fPtr, NULL, (void*)fn);
5581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
5681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        // If prev != NULL, someone snuck in and set fPtr concurrently.
5781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        // If prev == NULL, we did write fn to fPtr.
5881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org        return prev != NULL ? prev : fn;
5981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org    }
6081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
61d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgprivate:
6281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org    void* fPtr;
6381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org};
6481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
6581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org}  // namespace Private
6681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org
6781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#endif//SkLazyFnPtr_DEFINED
68