Index: src/core/SkCachedData.h |
diff --git a/src/core/SkCachedData.h b/src/core/SkCachedData.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..886ca3e7e44cdbec055bf01b731cfe69ded96002 |
--- /dev/null |
+++ b/src/core/SkCachedData.h |
@@ -0,0 +1,107 @@ |
+/* |
+ * 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 SkCachedData_DEFINED |
+#define SkCachedData_DEFINED |
+ |
+#include "SkThread.h" |
+ |
+class SkDiscardableMemory; |
+ |
+class SkCachedData : ::SkNoncopyable { |
+public: |
+ SkCachedData(void* mallocData, size_t size); |
+ SkCachedData(size_t size, SkDiscardableMemory*); |
+ virtual ~SkCachedData(); |
+ |
+ size_t size() const { return fSize; } |
+ const void* data() const { return fData; } |
+ |
+ void* writable_data() { return fData; } |
+ |
+ void ref() const { this->internalRef(false); } |
+ void unref() const { this->internalUnref(false); } |
+ |
+ int testing_only_getRefCnt() const { return fRefCnt; } |
+ bool testing_only_isLocked() const { return fIsLocked; } |
+ bool testing_only_isInCache() const { return fInCache; } |
+ |
+protected: |
+ // called when fData changes. could be NULL. |
+ virtual void onDataChange(void* oldData, void* newData) {} |
+ |
+private: |
+ SkMutex fMutex; // could use a pool of these... |
+ |
+ enum StorageType { |
+ kDiscardableMemory_StorageType, |
+ kMalloc_StorageType |
+ }; |
+ |
+ union { |
+ SkDiscardableMemory* fDM; |
+ void* fMalloc; |
+ } fStorage; |
+ void* fData; |
+ size_t fSize; |
+ int fRefCnt; // low-bit means we're owned by the cache |
+ StorageType fStorageType; |
+ bool fInCache; |
+ bool fIsLocked; |
+ |
+ void internalRef(bool fromCache) const; |
+ void internalUnref(bool fromCache) const; |
+ |
+ void inMutexRef(bool fromCache); |
+ bool inMutexUnref(bool fromCache); // returns true if we should delete "this" |
+ void inMutexLock(); |
+ void inMutexUnlock(); |
+ |
+ // called whenever our fData might change (lock or unlock) |
+ void setData(void* newData) { |
+ if (newData != fData) { |
+ // notify our subclasses of the change |
+ this->onDataChange(fData, newData); |
+ fData = newData; |
+ } |
+ } |
+ |
+ class AutoMutexWritable; |
+ |
+public: |
+#ifdef SK_DEBUG |
+ void validate() const; |
+#else |
+ void validate() const {} |
+#endif |
+ |
+ /* |
+ * Attaching a data to to a SkResourceCache (only one at a time) enables the data to be |
+ * unlocked when the cache is the only owner, thus freeing it to be purged (assuming the |
+ * data is backed by a SkDiscardableMemory). |
+ * |
+ * When attached, it also automatically attempts to "lock" the data when the first client |
+ * ref's the data (typically from a find(key, visitor) call). |
+ * |
+ * Thus the data will always be "locked" when a non-cache has a ref on it (whether or not |
+ * the lock succeeded to recover the memory -- check data() to see if it is NULL). |
+ */ |
+ |
+ /* |
+ * Call when adding this instance to a SkResourceCache::Rec subclass |
+ * (typically in the Rec's constructor). |
+ */ |
+ void attachToCacheAndRef() const { this->internalRef(true); } |
+ |
+ /* |
+ * Call when removing this instance from a SkResourceCache::Rec subclass |
+ * (typically in the Rec's destructor). |
+ */ |
+ void detachFromCacheAndUnref() const { this->internalUnref(true); } |
+}; |
+ |
+#endif |