Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: src/core/SkTDynamicHash.h

Issue 22571010: SkTDynamicHash: support remove() without needing Deleted(). (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/DynamicHashTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #ifndef SkTDynamicHash_DEFINED 8 #ifndef SkTDynamicHash_DEFINED
9 #define SkTDynamicHash_DEFINED 9 #define SkTDynamicHash_DEFINED
10 10
(...skipping 16 matching lines...) Expand all
27 sk_free(fArray); 27 sk_free(fArray);
28 } 28 }
29 29
30 int count() const { return fCount; } 30 int count() const { return fCount; }
31 31
32 // Return the entry with this key if we have it, otherwise NULL. 32 // Return the entry with this key if we have it, otherwise NULL.
33 T* find(const Key& key) const { 33 T* find(const Key& key) const {
34 int index = this->firstIndex(key); 34 int index = this->firstIndex(key);
35 for (int round = 0; round < fCapacity; round++) { 35 for (int round = 0; round < fCapacity; round++) {
36 T* candidate = fArray[index]; 36 T* candidate = fArray[index];
37 if (candidate == Empty()) { 37 if (candidate == NULL) {
reed1 2013/08/07 18:10:32 nit: NULL == candidate
38 return NULL; 38 return NULL;
39 } 39 } else if(Equal(*candidate, key)) {
40 if (candidate != Deleted() && Equal(*candidate, key)) {
41 return candidate; 40 return candidate;
42 } 41 }
43 index = this->nextIndex(index, round); 42 index = this->nextIndex(index, round);
44 } 43 }
45 SkASSERT(!"find: should be unreachable"); 44 SkASSERT(!"find: should be unreachable");
46 return NULL; 45 return NULL;
47 } 46 }
48 47
49 // Add an entry with this key. 48 // Add an entry with this key.
50 void add(T* newEntry) { 49 void add(T* newEntry) {
51 this->maybeGrow(); 50 this->maybeGrow();
52 51
53 const Key& key = GetKey(*newEntry); 52 const Key& key = GetKey(*newEntry);
54 int index = this->firstIndex(key); 53 int index = this->firstIndex(key);
55 for (int round = 0; round < fCapacity; round++) { 54 for (int round = 0; round < fCapacity; round++) {
56 T* candidate = fArray[index]; 55 T* candidate = fArray[index];
57 if (candidate == Empty() || candidate == Deleted()) { 56 if (candidate == NULL) {
reed1 2013/08/07 18:10:32 see prev. nit
58 fArray[index] = newEntry; 57 fArray[index] = newEntry;
59 fCount++; 58 fCount++;
60 return; 59 return;
61 } 60 } else if (Equal(*candidate, key)) {
62 if (Equal(*candidate, key)) {
63 fArray[index] = newEntry; 61 fArray[index] = newEntry;
64 return; 62 return;
65 } 63 }
66 index = this->nextIndex(index, round); 64 index = this->nextIndex(index, round);
67 } 65 }
68 SkASSERT(!"add: should be unreachable"); 66 SkASSERT(!"add: should be unreachable");
69 } 67 }
70 68
71 // Remove entry with this key, if we have it. 69 // Remove entry with this key, if we have it.
72 void remove(const Key& key) { 70 void remove(const Key& key) {
73 this->innerRemove(key); 71 this->innerRemove(key);
74 this->maybeShrink(); 72 this->maybeShrink();
75 } 73 }
76 74
77 protected: 75 protected:
78 // These methods are used by tests only. 76 // These methods are used by tests only.
79 77
80 int capacity() const { return fCapacity; } 78 int capacity() const { return fCapacity; }
81 79
82 // How many collisions do we go through before finding where this entry shou ld be inserted? 80 // How many collisions do we go through before finding where this entry shou ld be inserted?
83 int countCollisions(const Key& key) const { 81 int countCollisions(const Key& key) const {
84 int index = this->firstIndex(key); 82 int index = this->firstIndex(key);
85 for (int round = 0; round < fCapacity; round++) { 83 for (int round = 0; round < fCapacity; round++) {
86 const T* candidate = fArray[index]; 84 const T* candidate = fArray[index];
87 if (candidate == Empty() || candidate == Deleted() || Equal(*candida te, key)) { 85 if (candidate == NULL || Equal(*candidate, key)) {
reed1 2013/08/07 18:10:32 again with the nits
88 return round; 86 return round;
89 } 87 }
90 index = this->nextIndex(index, round); 88 index = this->nextIndex(index, round);
91 } 89 }
92 SkASSERT(!"countCollisions: should be unreachable"); 90 SkASSERT(!"countCollisions: should be unreachable");
93 return -1; 91 return -1;
94 } 92 }
95 93
96 private: 94 private:
97 // We have two special values to indicate an empty or deleted entry.
98 static const T* Empty() { return reinterpret_cast<const T*>(0); } // i.e. NULL
99 static const T* Deleted() { return reinterpret_cast<const T*>(1); } // Also an invalid pointer.
100
101 static T** AllocArray(int capacity) { 95 static T** AllocArray(int capacity) {
102 T** array = (T**)sk_malloc_throw(sizeof(T*) * capacity); 96 T** array = (T**)sk_malloc_throw(sizeof(T*) * capacity);
103 sk_bzero(array, sizeof(T*) * capacity); // All cells == Empty(). 97 sk_bzero(array, sizeof(T*) * capacity); // All cells == NULL.
104 return array; 98 return array;
105 } 99 }
106 100
107 void innerRemove(const Key& key) { 101 void innerRemove(const Key& key) {
108 int index = this->firstIndex(key); 102 int index = this->firstIndex(key);
109 for (int round = 0; round < fCapacity; round++) { 103 for (int round = 0; round < fCapacity; round++) {
110 const T* candidate = fArray[index]; 104 const T* candidate = fArray[index];
111 if (candidate == Empty()) { 105 if (candidate == NULL) {
reed1 2013/08/07 18:10:32 not again?
112 return; 106 return;
113 } 107 } else if (Equal(*candidate, key)) {
114 if (candidate != Deleted() && Equal(*candidate, key)) { 108 // To delete an entry we find the last non-empty entry in this c ollision chain, move
115 fArray[index] = const_cast<T*>(Deleted()); 109 // it up here, then clear out that last entry. This way there's never an empty slot
110 // in the middle of a collision chain.
111 int last = index;
112 while (fArray[nextIndex(last, round)] != NULL) {
113 last = nextIndex(last, round);
114 round++;
115 }
116 // Note how this works even if index == last.
117 fArray[index] = fArray[last];
118 fArray[last] = NULL;
116 fCount--; 119 fCount--;
117 return; 120 return;
118 } 121 }
119 index = this->nextIndex(index, round); 122 index = this->nextIndex(index, round);
120 } 123 }
121 SkASSERT(!"innerRemove: should be unreachable"); 124 SkASSERT(!"innerRemove: should be unreachable");
122 } 125 }
123 126
124 void maybeGrow() { 127 void maybeGrow() {
125 if (fCount < fCapacity / 2) { 128 if (fCount < fCapacity / 2) {
126 return; 129 return;
127 } 130 }
128 131
129 SkDEBUGCODE(int oldCount = fCount;) 132 SkDEBUGCODE(int oldCount = fCount;)
130 int oldCapacity = fCapacity; 133 int oldCapacity = fCapacity;
131 T** oldArray = fArray; 134 T** oldArray = fArray;
132 135
133 fCount = 0; 136 fCount = 0;
134 fCapacity *= 2; 137 fCapacity *= 2;
135 fArray = AllocArray(fCapacity); 138 fArray = AllocArray(fCapacity);
136 139
137 for (int i = 0; i < oldCapacity; i++) { 140 for (int i = 0; i < oldCapacity; i++) {
138 T* entry = oldArray[i]; 141 T* entry = oldArray[i];
139 if (entry != Empty() && entry != Deleted()) { 142 if (entry != NULL) {
140 this->add(entry); 143 this->add(entry);
141 } 144 }
142 } 145 }
143 SkASSERT(oldCount == fCount); 146 SkASSERT(oldCount == fCount);
144 147
145 sk_free(oldArray); 148 sk_free(oldArray);
146 } 149 }
147 150
148 void maybeShrink() { 151 void maybeShrink() {
149 // TODO 152 // TODO
150 } 153 }
151 154
152 // fCapacity is always a power of 2, so this masks the correct low bits to i ndex into our hash. 155 // fCapacity is always a power of 2, so this masks the correct low bits to i ndex into our hash.
153 uint32_t hashMask() const { return fCapacity - 1; } 156 uint32_t hashMask() const { return fCapacity - 1; }
154 157
155 int firstIndex(const Key& key) const { 158 int firstIndex(const Key& key) const {
156 return Hash(key) & this->hashMask(); 159 return Hash(key) & this->hashMask();
157 } 160 }
158 161
159 // Given index at round N, what is the index to check at N+1? round should start at 0. 162 // Given index at round N, what is the index to check at N+1? round should start at 0.
160 int nextIndex(int index, int round) const { 163 int nextIndex(int index, int round) const {
161 // This will search a power-of-two array fully without repeating an inde x. 164 // This will search a power-of-two array fully without repeating an inde x.
162 return (index + round + 1) & this->hashMask(); 165 return (index + round + 1) & this->hashMask();
163 } 166 }
164 167
165 int fCount; // Number of non-empty, non-deleted entries in fArray. 168 int fCount; // Number of non-NULL entries in fArray.
166 int fCapacity; // Number of entries in fArray. Always a power of 2. 169 int fCapacity; // Number of entries in fArray. Always a power of 2.
167 T** fArray; 170 T** fArray;
168 }; 171 };
169 172
170 #endif 173 #endif
OLDNEW
« no previous file with comments | « no previous file | tests/DynamicHashTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698