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