From e9e0dea15b4d806f5da19ffa8135d4a9c62a860b Mon Sep 17 00:00:00 2001 From: mtklein Date: Tue, 21 Oct 2014 12:20:04 -0700 Subject: [PATCH] SkLazyPtr follow ups - moves test to LazyPtrTest.cpp - adds the ability to use a Create() method with an argument BUG=skia: Review URL: https://codereview.chromium.org/669783002 --- gyp/tests.gypi | 2 +- src/core/SkLazyPtr.h | 40 +++++++++++++++++--------- tests/{LazyPtr.cpp => LazyPtrTest.cpp} | 33 ++++++++++++++++++++- 3 files changed, 60 insertions(+), 15 deletions(-) rename tests/{LazyPtr.cpp => LazyPtrTest.cpp} (50%) diff --git a/gyp/tests.gypi b/gyp/tests.gypi index 422a22e2ce..827d6e3a0c 100644 --- a/gyp/tests.gypi +++ b/gyp/tests.gypi @@ -130,7 +130,7 @@ '../tests/LListTest.cpp', '../tests/LayerDrawLooperTest.cpp', '../tests/LayerRasterizerTest.cpp', - '../tests/LazyPtr.cpp', + '../tests/LazyPtrTest.cpp', '../tests/MD5Test.cpp', '../tests/MallocPixelRefTest.cpp', '../tests/MathTest.cpp', diff --git a/src/core/SkLazyPtr.h b/src/core/SkLazyPtr.h index f9508c5973..7273079252 100644 --- a/src/core/SkLazyPtr.h +++ b/src/core/SkLazyPtr.h @@ -49,10 +49,10 @@ */ #define SK_DECLARE_STATIC_LAZY_PTR(T, name, ...) \ - namespace {} static Private::SkLazyPtrBase name + namespace {} static Private::SkStaticLazyPtr name #define SK_DECLARE_STATIC_LAZY_PTR_ARRAY(T, name, N, ...) \ - namespace {} static Private::SkLazyPtrArray name + namespace {} static Private::SkStaticLazyPtrArray name // namespace {} forces these macros to only be legal in global scopes. Chrome has thread-safety // problems with them in function-local statics because it uses -fno-threadsafe-statics, and even @@ -102,7 +102,7 @@ template void sk_delete(T* ptr) { SkDELETE(ptr); } // This has no constructor and must be zero-initalized (the macro above does this). template , void (*Destroy)(T*) = sk_delete > -class SkLazyPtrBase { +class SkStaticLazyPtr { public: T* get() { // If fPtr has already been filled, we need a consume barrier when loading it. @@ -111,7 +111,7 @@ public: return ptr ? ptr : try_cas(&fPtr, Create()); } -protected: +private: void* fPtr; }; @@ -119,7 +119,7 @@ template T* sk_new_arg(int i) { return SkNEW_ARGS(T, (i)); } // This has no constructor and must be zero-initalized (the macro above does this). template , void (*Destroy)(T*) = sk_delete > -class SkLazyPtrArray { +class SkStaticLazyPtrArray { public: T* operator[](int i) { SkASSERT(i >= 0 && i < N); @@ -136,16 +136,30 @@ private: } // namespace Private // This version is suitable for use as a class member. -// It's the same as above except it has a constructor to zero itself and a destructor to clean up. -template , - void (*Destroy)(T*) = Private::sk_delete > -class SkLazyPtr : public Private::SkLazyPtrBase { +// It's much the same as above except: +// - it has a constructor to zero itself; +// - it has a destructor to clean up; +// - get() calls SkNew(T) to create the pointer; +// - get(functor) calls functor to create the pointer. +template > +class SkLazyPtr : SkNoncopyable { public: - SkLazyPtr() { INHERITED::fPtr = NULL; } - ~SkLazyPtr() { if (INHERITED::fPtr) { Destroy((T*)INHERITED::fPtr); } } + SkLazyPtr() : fPtr(NULL) {} + ~SkLazyPtr() { if (fPtr) { Destroy((T*)fPtr); } } + + T* get() { + T* ptr = (T*)sk_consume_load(&fPtr); + return ptr ? ptr : Private::try_cas(&fPtr, SkNEW(T)); + } + + template + T* get(const Create& create) { + T* ptr = (T*)sk_consume_load(&fPtr); + return ptr ? ptr : Private::try_cas(&fPtr, create()); + } + private: - typedef Private::SkLazyPtrBase INHERITED; + void* fPtr; }; diff --git a/tests/LazyPtr.cpp b/tests/LazyPtrTest.cpp similarity index 50% rename from tests/LazyPtr.cpp rename to tests/LazyPtrTest.cpp index ff235e6ed3..f719c2e0bf 100644 --- a/tests/LazyPtr.cpp +++ b/tests/LazyPtrTest.cpp @@ -2,14 +2,45 @@ #include "SkLazyPtr.h" #include "SkTaskGroup.h" +namespace { + +struct CreateIntFromFloat { + CreateIntFromFloat(float val) : fVal(val) {} + int* operator()() const { return SkNEW_ARGS(int, ((int)fVal)); } + float fVal; +}; + +// As a template argument this must have external linkage. +void custom_destroy(int* ptr) { *ptr = 99; } + +} // namespace + DEF_TEST(LazyPtr, r) { + // Basic usage: calls SkNEW(int). SkLazyPtr lazy; int* ptr = lazy.get(); - REPORTER_ASSERT(r, ptr); REPORTER_ASSERT(r, lazy.get() == ptr); + // Advanced usage: calls a functor. + SkLazyPtr lazyFunctor; + int* six = lazyFunctor.get(CreateIntFromFloat(6.4f)); + REPORTER_ASSERT(r, six); + REPORTER_ASSERT(r, 6 == *six); + + // Just makes sure this is safe. SkLazyPtr neverRead; + + // SkLazyPtr supports custom destroy methods. + { + SkLazyPtr customDestroy; + ptr = customDestroy.get(); + // custom_destroy called here. + } + REPORTER_ASSERT(r, ptr); + REPORTER_ASSERT(r, 99 == *ptr); + // Since custom_destroy didn't actually delete ptr, we do now. + SkDELETE(ptr); } namespace { -- 2.34.1