blob: dd65ecbf4133dcae1525caeb66ca8b837147c90a [file] [log] [blame]
reed@google.comdc731fd2010-12-23 15:19:47 +00001/*
2 * Copyright (C) 2010 Tetrark Inc.
3 */
4
5#include "SkBitmapCache.h"
6
7struct SkBitmapCache::Entry {
8 Entry* fPrev;
9 Entry* fNext;
10
11 void* fBuffer;
12 size_t fSize;
13 SkBitmap fBitmap;
14
15 Entry(const void* buffer, size_t size, const SkBitmap& bm) : fBitmap(bm) {
16 fBuffer = sk_malloc_throw(size);
17 fSize = size;
18 memcpy(fBuffer, buffer, size);
19 }
20
21 ~Entry() { sk_free(fBuffer); }
22
23 bool equals(const void* buffer, size_t size) const {
24 return (fSize == size) && !memcmp(fBuffer, buffer, size);
25 }
26};
27
28SkBitmapCache::SkBitmapCache(int max) : fMaxEntries(max) {
29 fEntryCount = 0;
30 fHead = fTail = NULL;
31
32 this->validate();
33}
34
35SkBitmapCache::~SkBitmapCache() {
36 this->validate();
37
38 Entry* entry = fHead;
39 while (entry) {
40 Entry* next = entry->fNext;
41 delete entry;
42 entry = next;
43 }
44}
45
46SkBitmapCache::Entry* SkBitmapCache::detach(Entry* entry) const {
47 if (entry->fPrev) {
48 SkASSERT(fHead != entry);
49 entry->fPrev->fNext = entry->fNext;
50 } else {
51 SkASSERT(fHead == entry);
52 fHead = entry->fNext;
53 }
54 if (entry->fNext) {
55 SkASSERT(fTail != entry);
56 entry->fNext->fPrev = entry->fPrev;
57 } else {
58 SkASSERT(fTail == entry);
59 fTail = entry->fPrev;
60 }
61 return entry;
62}
63
64void SkBitmapCache::attachToHead(Entry* entry) const {
65 entry->fPrev = NULL;
66 entry->fNext = fHead;
67 if (fHead) {
68 fHead->fPrev = entry;
69 } else {
70 fTail = entry;
71 }
72 fHead = entry;
73}
74
75bool SkBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const {
76 AutoValidate av(this);
77
78 Entry* entry = fHead;
79 while (entry) {
80 if (entry->equals(buffer, size)) {
81 if (bm) {
82 *bm = entry->fBitmap;
83 }
84 // move to the head of our list, so we purge it last
85 this->detach(entry);
86 this->attachToHead(entry);
87 return true;
88 }
89 entry = entry->fNext;
90 }
91 return false;
92}
93
94void SkBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) {
95 AutoValidate av(this);
96
97 if (fEntryCount == fMaxEntries) {
98 if (fTail) {
99 delete this->detach(fTail);
100 }
101 }
102
103 Entry* entry = new Entry(buffer, len, bm);
104 this->attachToHead(entry);
105 fEntryCount += 1;
106}
107
108///////////////////////////////////////////////////////////////////////////////
109
110#ifdef SK_DEBUG
111
112void SkBitmapCache::validate() const {
113 SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries);
114
115 if (fEntryCount > 0) {
116 SkASSERT(NULL == fHead->fPrev);
117 SkASSERT(NULL == fTail->fNext);
118
119 if (fEntryCount == 1) {
120 SkASSERT(fHead == fTail);
121 } else {
122 SkASSERT(fHead != fTail);
123 }
124
125 Entry* entry = fHead;
126 int count = 0;
127 while (entry) {
128 count += 1;
129 entry = entry->fNext;
130 }
131 SkASSERT(count == fEntryCount);
132
133 entry = fTail;
134 while (entry) {
135 count -= 1;
136 entry = entry->fPrev;
137 }
138 SkASSERT(0 == count);
139 } else {
140 SkASSERT(NULL == fHead);
141 SkASSERT(NULL == fTail);
142 }
143}
144
145#endif
146