blob: a8611572987b6c96721686f14cc63833e0f446d9 [file] [log] [blame]
reed9d93c2e2014-10-08 05:17:12 -07001/*
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 SkCachedData_DEFINED
9#define SkCachedData_DEFINED
10
mtklein1b249332015-07-07 12:21:21 -070011#include "SkMutex.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkTypes.h"
reed9d93c2e2014-10-08 05:17:12 -070013
14class SkDiscardableMemory;
15
16class SkCachedData : ::SkNoncopyable {
17public:
18 SkCachedData(void* mallocData, size_t size);
19 SkCachedData(size_t size, SkDiscardableMemory*);
20 virtual ~SkCachedData();
21
22 size_t size() const { return fSize; }
23 const void* data() const { return fData; }
24
25 void* writable_data() { return fData; }
26
27 void ref() const { this->internalRef(false); }
28 void unref() const { this->internalUnref(false); }
29
30 int testing_only_getRefCnt() const { return fRefCnt; }
31 bool testing_only_isLocked() const { return fIsLocked; }
32 bool testing_only_isInCache() const { return fInCache; }
33
34protected:
35 // called when fData changes. could be NULL.
36 virtual void onDataChange(void* oldData, void* newData) {}
37
38private:
39 SkMutex fMutex; // could use a pool of these...
40
41 enum StorageType {
42 kDiscardableMemory_StorageType,
43 kMalloc_StorageType
44 };
45
46 union {
47 SkDiscardableMemory* fDM;
48 void* fMalloc;
49 } fStorage;
50 void* fData;
51 size_t fSize;
52 int fRefCnt; // low-bit means we're owned by the cache
53 StorageType fStorageType;
54 bool fInCache;
55 bool fIsLocked;
56
57 void internalRef(bool fromCache) const;
58 void internalUnref(bool fromCache) const;
59
60 void inMutexRef(bool fromCache);
61 bool inMutexUnref(bool fromCache); // returns true if we should delete "this"
62 void inMutexLock();
63 void inMutexUnlock();
64
65 // called whenever our fData might change (lock or unlock)
66 void setData(void* newData) {
67 if (newData != fData) {
68 // notify our subclasses of the change
69 this->onDataChange(fData, newData);
70 fData = newData;
71 }
72 }
73
74 class AutoMutexWritable;
75
76public:
77#ifdef SK_DEBUG
78 void validate() const;
79#else
80 void validate() const {}
81#endif
mtklein1b249332015-07-07 12:21:21 -070082
reed9d93c2e2014-10-08 05:17:12 -070083 /*
84 * Attaching a data to to a SkResourceCache (only one at a time) enables the data to be
85 * unlocked when the cache is the only owner, thus freeing it to be purged (assuming the
86 * data is backed by a SkDiscardableMemory).
87 *
88 * When attached, it also automatically attempts to "lock" the data when the first client
89 * ref's the data (typically from a find(key, visitor) call).
90 *
91 * Thus the data will always be "locked" when a non-cache has a ref on it (whether or not
92 * the lock succeeded to recover the memory -- check data() to see if it is NULL).
93 */
94
95 /*
96 * Call when adding this instance to a SkResourceCache::Rec subclass
97 * (typically in the Rec's constructor).
98 */
99 void attachToCacheAndRef() const { this->internalRef(true); }
100
101 /*
102 * Call when removing this instance from a SkResourceCache::Rec subclass
103 * (typically in the Rec's destructor).
104 */
105 void detachFromCacheAndUnref() const { this->internalUnref(true); }
106};
107
108#endif