OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 SkTHash_DEFINED | 8 #ifndef SkTHash_DEFINED |
9 #define SkTHash_DEFINED | 9 #define SkTHash_DEFINED |
10 | 10 |
(...skipping 30 matching lines...) Expand all Loading... |
41 // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!
!!!! | 41 // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!
!!!! |
42 // set(), find() and foreach() all allow mutable access to table entries. | 42 // set(), find() and foreach() all allow mutable access to table entries. |
43 // If you change an entry so that it no longer has the same key, all hell | 43 // If you change an entry so that it no longer has the same key, all hell |
44 // will break loose. Do not do that! | 44 // will break loose. Do not do that! |
45 // | 45 // |
46 // Please prefer to use SkTHashMap or SkTHashSet, which do not have this dan
ger. | 46 // Please prefer to use SkTHashMap or SkTHashSet, which do not have this dan
ger. |
47 | 47 |
48 // The pointers returned by set() and find() are valid only until the next c
all to set(). | 48 // The pointers returned by set() and find() are valid only until the next c
all to set(). |
49 // The pointers you receive in foreach() are only valid for its duration. | 49 // The pointers you receive in foreach() are only valid for its duration. |
50 | 50 |
51 // Copy val into the hash table, returning a pointer to the copy now in the
table. | 51 // Move val into the hash table, returning a pointer to the copy now in the
table. |
52 // If there already is an entry in the table with the same key, we overwrite
it. | 52 // If there already is an entry in the table with the same key, we overwrite
it. |
53 T* set(const T& val) { | 53 T* set(T val) { |
54 if (4 * (fCount+fRemoved) >= 3 * fCapacity) { | 54 if (4 * (fCount+fRemoved) >= 3 * fCapacity) { |
55 this->resize(fCapacity > 0 ? fCapacity * 2 : 4); | 55 this->resize(fCapacity > 0 ? fCapacity * 2 : 4); |
56 } | 56 } |
57 return this->uncheckedSet(val); | 57 return this->uncheckedSet(std::move(val)); |
58 } | 58 } |
59 | 59 |
| 60 |
60 // If there is an entry in the table with this key, return a pointer to it.
If not, NULL. | 61 // If there is an entry in the table with this key, return a pointer to it.
If not, NULL. |
61 T* find(const K& key) const { | 62 T* find(const K& key) const { |
62 uint32_t hash = Hash(key); | 63 uint32_t hash = Hash(key); |
63 int index = hash & (fCapacity-1); | 64 int index = hash & (fCapacity-1); |
64 for (int n = 0; n < fCapacity; n++) { | 65 for (int n = 0; n < fCapacity; n++) { |
65 Slot& s = fSlots[index]; | 66 Slot& s = fSlots[index]; |
66 if (s.empty()) { | 67 if (s.empty()) { |
67 return NULL; | 68 return NULL; |
68 } | 69 } |
69 if (!s.removed() && hash == s.hash && key == Traits::GetKey(s.val))
{ | 70 if (!s.removed() && hash == s.hash && key == Traits::GetKey(s.val))
{ |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 template <typename Fn> // f(T) or f(const T&) | 110 template <typename Fn> // f(T) or f(const T&) |
110 void foreach(Fn&& fn) const { | 111 void foreach(Fn&& fn) const { |
111 for (int i = 0; i < fCapacity; i++) { | 112 for (int i = 0; i < fCapacity; i++) { |
112 if (!fSlots[i].empty() && !fSlots[i].removed()) { | 113 if (!fSlots[i].empty() && !fSlots[i].removed()) { |
113 fn(fSlots[i].val); | 114 fn(fSlots[i].val); |
114 } | 115 } |
115 } | 116 } |
116 } | 117 } |
117 | 118 |
118 private: | 119 private: |
119 T* uncheckedSet(const T& val) { | 120 T* uncheckedSet(T val) { |
120 const K& key = Traits::GetKey(val); | 121 const K& key = Traits::GetKey(val); |
121 uint32_t hash = Hash(key); | 122 uint32_t hash = Hash(key); |
122 int index = hash & (fCapacity-1); | 123 int index = hash & (fCapacity-1); |
123 for (int n = 0; n < fCapacity; n++) { | 124 for (int n = 0; n < fCapacity; n++) { |
124 Slot& s = fSlots[index]; | 125 Slot& s = fSlots[index]; |
125 if (s.empty() || s.removed()) { | 126 if (s.empty() || s.removed()) { |
126 // New entry. | 127 // New entry. |
127 if (s.removed()) { | 128 if (s.removed()) { |
128 fRemoved--; | 129 fRemoved--; |
129 } | 130 } |
130 s.val = val; | 131 s.val = std::move(val); |
131 s.hash = hash; | 132 s.hash = hash; |
132 fCount++; | 133 fCount++; |
133 return &s.val; | 134 return &s.val; |
134 } | 135 } |
135 if (hash == s.hash && key == Traits::GetKey(s.val)) { | 136 if (hash == s.hash && key == Traits::GetKey(s.val)) { |
136 // Overwrite previous entry. | 137 // Overwrite previous entry. |
137 // Note: this triggers extra copies when adding the same value r
epeatedly. | 138 // Note: this triggers extra copies when adding the same value r
epeatedly. |
138 s.val = val; | 139 s.val = std::move(val); |
139 return &s.val; | 140 return &s.val; |
140 } | 141 } |
141 index = this->next(index, n); | 142 index = this->next(index, n); |
142 } | 143 } |
143 SkASSERT(false); | 144 SkASSERT(false); |
144 return NULL; | 145 return NULL; |
145 } | 146 } |
146 | 147 |
147 void resize(int capacity) { | 148 void resize(int capacity) { |
148 int oldCapacity = fCapacity; | 149 int oldCapacity = fCapacity; |
149 SkDEBUGCODE(int oldCount = fCount); | 150 SkDEBUGCODE(int oldCount = fCount); |
150 | 151 |
151 fCount = fRemoved = 0; | 152 fCount = fRemoved = 0; |
152 fCapacity = capacity; | 153 fCapacity = capacity; |
153 SkAutoTArray<Slot> oldSlots(capacity); | 154 SkAutoTArray<Slot> oldSlots(capacity); |
154 oldSlots.swap(fSlots); | 155 oldSlots.swap(fSlots); |
155 | 156 |
156 for (int i = 0; i < oldCapacity; i++) { | 157 for (int i = 0; i < oldCapacity; i++) { |
157 const Slot& s = oldSlots[i]; | 158 const Slot& s = oldSlots[i]; |
158 if (!s.empty() && !s.removed()) { | 159 if (!s.empty() && !s.removed()) { |
159 this->uncheckedSet(s.val); | 160 this->uncheckedSet(std::move(s.val)); |
160 } | 161 } |
161 } | 162 } |
162 SkASSERT(fCount == oldCount); | 163 SkASSERT(fCount == oldCount); |
163 } | 164 } |
164 | 165 |
165 int next(int index, int n) const { | 166 int next(int index, int n) const { |
166 // A valid strategy explores all slots in [0, fCapacity) as n walks from
0 to fCapacity-1. | 167 // A valid strategy explores all slots in [0, fCapacity) as n walks from
0 to fCapacity-1. |
167 // Both of these strategies are valid: | 168 // Both of these strategies are valid: |
168 //return (index + 0 + 1) & (fCapacity-1); // Linear probing. | 169 //return (index + 0 + 1) & (fCapacity-1); // Linear probing. |
169 return (index + n + 1) & (fCapacity-1); // Quadratic probing. | 170 return (index + n + 1) & (fCapacity-1); // Quadratic probing. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 // How many key/value pairs are in the table? | 203 // How many key/value pairs are in the table? |
203 int count() const { return fTable.count(); } | 204 int count() const { return fTable.count(); } |
204 | 205 |
205 // Approximately how many bytes of memory do we use beyond sizeof(*this)? | 206 // Approximately how many bytes of memory do we use beyond sizeof(*this)? |
206 size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } | 207 size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } |
207 | 208 |
208 // N.B. The pointers returned by set() and find() are valid only until the n
ext call to set(). | 209 // N.B. The pointers returned by set() and find() are valid only until the n
ext call to set(). |
209 | 210 |
210 // Set key to val in the table, replacing any previous value with the same k
ey. | 211 // Set key to val in the table, replacing any previous value with the same k
ey. |
211 // We copy both key and val, and return a pointer to the value copy now in t
he table. | 212 // We copy both key and val, and return a pointer to the value copy now in t
he table. |
212 V* set(const K& key, const V& val) { | 213 V* set(const K& key, V val) { |
213 Pair in = { key, val }; | 214 Pair* out = fTable.set(Pair{ key, std::move(val) }); |
214 Pair* out = fTable.set(in); | |
215 return &out->val; | 215 return &out->val; |
216 } | 216 } |
217 | 217 |
218 // If there is key/value entry in the table with this key, return a pointer
to the value. | 218 // If there is key/value entry in the table with this key, return a pointer
to the value. |
219 // If not, return NULL. | 219 // If not, return NULL. |
220 V* find(const K& key) const { | 220 V* find(const K& key) const { |
221 if (Pair* p = fTable.find(key)) { | 221 if (Pair* p = fTable.find(key)) { |
222 return &p->val; | 222 return &p->val; |
223 } | 223 } |
224 return NULL; | 224 return NULL; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 | 292 |
293 private: | 293 private: |
294 struct Traits { | 294 struct Traits { |
295 static const T& GetKey(const T& item) { return item; } | 295 static const T& GetKey(const T& item) { return item; } |
296 static uint32_t Hash(const T& item) { return HashT()(item); } | 296 static uint32_t Hash(const T& item) { return HashT()(item); } |
297 }; | 297 }; |
298 SkTHashTable<T, T, Traits> fTable; | 298 SkTHashTable<T, T, Traits> fTable; |
299 }; | 299 }; |
300 | 300 |
301 #endif//SkTHash_DEFINED | 301 #endif//SkTHash_DEFINED |
OLD | NEW |