blob: 683528b61e6adecc670eb1183738efa8901f574b [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#ifndef GrBinHashKey_DEFINED
18#define GrBinHashKey_DEFINED
19
20#include "GrTypes.h"
21
22/**
23 * Abstract base class that presents the building interface of GrBinHashKey.
24 * This base class allows builder methods to not know the exact template
25 * parameters of GrBinHashKey
26 */
27class GrBinHashKeyBuilder {
28public:
29 GrBinHashKeyBuilder() {}
30 virtual ~GrBinHashKeyBuilder() {}
31 virtual void keyData(const uint8_t *dataToAdd, size_t len) = 0;
32};
33
34/**
35 * Hash function class than can take a data stream of indeterminate length.
36 * It also has the ability to recieve data in several chunks (steamed). The
37 * hash function used is Adler-32.
38 *
39 * Keys are built in two passes the first pass builds the key until the
40 * allocated storage for the key runs out, raw data accumulation stops, but
41 * the calculation of the 32-bit hash value and total key length continue.
42 * The second pass is only necessary if storage ran-out during the first pass.
43 * If that is the case, the heap storage portion of the key will be
44 * re-allocated so that the entire key can be stored in the second pass.
45 *
46 * Code for building a key:
47 *
48 * GrBinHashKey<MyEntryStruct, MyStackSize> MyKey;
49 * while( MyKey->doPass() )
50 * {
51 * MyObject->buildKey(&MyKey); //invoke a builder method
52 * }
53 *
54 * All the builder method needs to do is make calls to the keyData method to
55 * append binary data to the key.
56 */
57template<typename Entry, size_t StackSize>
58class GrBinHashKey : public GrBinHashKeyBuilder {
59public:
60 GrBinHashKey()
61 : fA(1)
62 , fB(0)
63 , fLength(0)
64 , fHeapData(NULL)
65 , fPhysicalSize(StackSize)
66 , fUseHeap(false)
67 , fPass(0)
68#if GR_DEBUG
69 , fIsValid(true)
70#endif
71 {}
72
73private:
74 // Illegal: must choose explicitly between copyAndTakeOwnership
75 // and deepCopyFrom.
76 // Not inheriting GrNoncopyable, because it causes very obscure compiler
77 // errors with template classes, which are hard to trace back to the use
78 // of assignment.
79 GrBinHashKey(const GrBinHashKey<Entry, StackSize>&) {}
80 GrBinHashKey<Entry, StackSize>& operator=(const GrBinHashKey<Entry,
81 StackSize>&) {
82 return this;
83 }
84
85public:
86 void copyAndTakeOwnership(GrBinHashKey<Entry, StackSize>& key) {
87 memcpy(this, &key, sizeof(*this));
88 GrAssert(key.fIsValid);
89 if (fUseHeap) {
90 key.fHeapData = NULL; // ownership transfer
91 }
92 // Consistency Checking
93 // To avoid the overhead of copying or ref-counting the dynamically
94 // allocated portion of the key, we use ownership transfer
95 // Key usability is only tracked in debug builds.
96 GR_DEBUGCODE(key.fIsValid = false;)
97 }
98
99 void deepCopyFrom(const GrBinHashKey<Entry, StackSize>& key) {
100 GrAssert(key.fIsValid);
101 memcpy(this, &key, sizeof(key));
102 if (fUseHeap) {
103 fHeapData = reinterpret_cast<uint8_t*>(
104 GrMalloc(sizeof(uint8_t) * fPhysicalSize));
105 memcpy(fHeapData, key.fHeapData, fLength);
106 }
107 }
108
109 virtual ~GrBinHashKey() {
110 if (fUseHeap) {
111 GrFree(fHeapData);
112 }
113 }
114
115 bool doPass() {
116 GrAssert(fIsValid);
117 if (0 == fPass) {
118 fPass++;
119 return true;
120 }
121 if (1 == fPass) {
122 bool passNeeded = false;
123 if (fLength > fPhysicalSize) {
124 // If the first pass ran out of space the we need to
125 // re-allocate and perform a second pass
126 GrFree(fHeapData);
127 fHeapData = reinterpret_cast<uint8_t*>(
128 GrMalloc(sizeof(uint8_t) * fLength));
129 fPhysicalSize = fLength;
130 fUseHeap = true;
131 passNeeded = true;
132 fLength = 0;
133 }
134 fPass++;
135 return passNeeded;
136 }
137 return false;
138 }
139
140 void keyData(const uint8_t *dataToAdd, size_t len) {
141 GrAssert(fIsValid);
142 GrAssert(fPass);
143 if (fUseHeap) {
144 GrAssert(fHeapData);
145 GrAssert(fLength + len <= fPhysicalSize);
146 memcpy(&fHeapData[fLength], dataToAdd, len );
147 } else {
148 if (fLength + len <= StackSize) {
149 memcpy(&fStackData[fLength], dataToAdd, len);
150 } else {
151 GrAssert(1 == fPass);
152 }
153 }
154
155 fLength += len;
156
157 if (1 == fPass) {
158 // update the 32-bit hash
159 while (len) {
160 fA = (fA + *dataToAdd) % kBigPrime;
161 fB = (fB + fA) % kBigPrime;
162 dataToAdd++;
163 len--;
164 }
165 }
166 }
167
168 int compare(const GrBinHashKey<Entry, StackSize>& key) const {
169 GrAssert(fIsValid);
170 if (fLength == key.fLength) {
171 GrAssert(fUseHeap == key.fUseHeap);
172 if(fUseHeap) {
173 return memcmp(fHeapData, key.fHeapData, fLength);
174 } else {
175 return memcmp(fStackData, key.fStackData, fLength);
176 }
177 }
178
179 return (fLength - key.fLength);
180 }
181
182 static bool
183 EQ(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
184 GrAssert(key.fIsValid);
185 return 0 == entry.compare(key);
186 }
187
188 static bool
189 LT(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
190 GrAssert(key.fIsValid);
191 return entry.compare(key) < 0;
192 }
193
194 uint32_t getHash() const {
195 GrAssert(fIsValid);
196 return (fB << 16) | fA;
197 }
198
199private:
200 // For computing the Adler-32 hash
201 enum Constants {
202 kBigPrime = 65521 // largest prime smaller than 2^16
203 };
204 uint32_t fA;
205 uint32_t fB;
206
207 // For accumulating the variable length binary key
208 size_t fLength; // length of data accumulated so far
209 uint8_t fStackData[StackSize]; //Buffer for key storage
210 uint8_t* fHeapData; //Dynamically allocated extended key storage
211 size_t fPhysicalSize; //Total size available for key storage
212 bool fUseHeap; //Using a dynamically allocated key storage
213 int fPass; //Key generation pass counter
214
215#if GR_DEBUG
216public:
217 bool fIsValid;
218#endif
219};
220
221#endif