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

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

Issue 919193002: Minimize SkTHash object copying (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: relaxed same-val copy expectations Created 5 years, 10 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
« no previous file with comments | « no previous file | tests/HashTest.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 #ifndef SkTHash_DEFINED 1 #ifndef SkTHash_DEFINED
2 #define SkTHash_DEFINED 2 #define SkTHash_DEFINED
3 3
4 #include "SkTypes.h" 4 #include "SkTypes.h"
5 #include "SkTemplates.h" 5 #include "SkTemplates.h"
6 6
7 // Before trying to use SkTHashTable, look below to see if SkTHashMap or SkTHash Set works for you. 7 // Before trying to use SkTHashTable, look below to see if SkTHashMap or SkTHash Set works for you.
8 // They're easier to use, usually perform the same, and have fewer sharp edges. 8 // They're easier to use, usually perform the same, and have fewer sharp edges.
9 9
10 // T and K are treated as ordinary copyable C++ types. 10 // T and K are treated as ordinary copyable C++ types.
(...skipping 15 matching lines...) Expand all
26 // If you change an entry so that it no longer has the same key, all hell 26 // If you change an entry so that it no longer has the same key, all hell
27 // will break loose. Do not do that! 27 // will break loose. Do not do that!
28 // 28 //
29 // Please prefer to use SkTHashMap or SkTHashSet, which do not have this dan ger. 29 // Please prefer to use SkTHashMap or SkTHashSet, which do not have this dan ger.
30 30
31 // The pointers returned by set() and find() are valid only until the next c all to set(). 31 // The pointers returned by set() and find() are valid only until the next c all to set().
32 // The pointers you receive in foreach() are only valid for its duration. 32 // The pointers you receive in foreach() are only valid for its duration.
33 33
34 // Copy val into the hash table, returning a pointer to the copy now in the table. 34 // Copy val into the hash table, returning a pointer to the copy now in the table.
35 // If there already is an entry in the table with the same key, we overwrite it. 35 // If there already is an entry in the table with the same key, we overwrite it.
36 T* set(T val) { 36 T* set(const T& val) {
37 if (4 * fCount >= 3 * fCapacity) { 37 if (4 * fCount >= 3 * fCapacity) {
38 this->resize(fCapacity > 0 ? fCapacity * 2 : 4); 38 this->resize(fCapacity > 0 ? fCapacity * 2 : 4);
39 } 39 }
40 return this->uncheckedSet(val); 40 return this->uncheckedSet(val);
41 } 41 }
42 42
43 // If there is an entry in the table with this key, return a pointer to it. If not, NULL. 43 // If there is an entry in the table with this key, return a pointer to it. If not, NULL.
44 T* find(K key) const { 44 T* find(const K& key) const {
45 uint32_t hash = Hash(key); 45 uint32_t hash = Hash(key);
46 int index = hash & (fCapacity-1); 46 int index = hash & (fCapacity-1);
47 for (int n = 0; n < fCapacity; n++) { 47 for (int n = 0; n < fCapacity; n++) {
48 Slot& s = fSlots[index]; 48 Slot& s = fSlots[index];
49 if (s.empty()) { 49 if (s.empty()) {
50 return NULL; 50 return NULL;
51 } 51 }
52 if (hash == s.hash && key == Traits::GetKey(s.val)) { 52 if (hash == s.hash && key == Traits::GetKey(s.val)) {
53 return &s.val; 53 return &s.val;
54 } 54 }
55 index = this->next(index, n); 55 index = this->next(index, n);
56 } 56 }
57 SkASSERT(fCapacity == 0); 57 SkASSERT(fCapacity == 0);
58 return NULL; 58 return NULL;
59 } 59 }
60 60
61 // Call fn on every entry in the table. You may mutate the entries, but be very careful. 61 // Call fn on every entry in the table. You may mutate the entries, but be very careful.
62 template <typename Arg> 62 template <typename Arg>
63 void foreach(void(*fn)(T*, Arg), Arg arg) { 63 void foreach(void(*fn)(T*, Arg), Arg arg) {
64 for (int i = 0; i < fCapacity; i++) { 64 for (int i = 0; i < fCapacity; i++) {
65 Slot& s = fSlots[i]; 65 Slot& s = fSlots[i];
66 if (!s.empty()) { 66 if (!s.empty()) {
67 fn(&s.val, arg); 67 fn(&s.val, arg);
68 } 68 }
69 } 69 }
70 } 70 }
71 71
72 private: 72 private:
73 T* uncheckedSet(T val) { 73 T* uncheckedSet(const T& val) {
74 K key = Traits::GetKey(val); 74 const K& key = Traits::GetKey(val);
75 uint32_t hash = Hash(key); 75 uint32_t hash = Hash(key);
76 int index = hash & (fCapacity-1); 76 int index = hash & (fCapacity-1);
77 for (int n = 0; n < fCapacity; n++) { 77 for (int n = 0; n < fCapacity; n++) {
78 Slot& s = fSlots[index]; 78 Slot& s = fSlots[index];
79 if (s.empty()) { 79 if (s.empty()) {
80 // New entry. 80 // New entry.
81 s.val = val; 81 s.val = val;
82 s.hash = hash; 82 s.hash = hash;
83 fCount++; 83 fCount++;
84 return &s.val; 84 return &s.val;
85 } 85 }
86 if (hash == s.hash && key == Traits::GetKey(s.val)) { 86 if (hash == s.hash && key == Traits::GetKey(s.val)) {
87 // Overwrite previous entry. 87 // Overwrite previous entry.
88 // Note: this triggers extra copies when adding the same value r epeatedly.
88 s.val = val; 89 s.val = val;
89 return &s.val; 90 return &s.val;
90 } 91 }
91 index = this->next(index, n); 92 index = this->next(index, n);
92 } 93 }
93 SkASSERT(false); 94 SkASSERT(false);
94 return NULL; 95 return NULL;
95 } 96 }
96 97
97 void resize(int capacity) { 98 void resize(int capacity) {
(...skipping 14 matching lines...) Expand all
112 SkASSERT(fCount == oldCount); 113 SkASSERT(fCount == oldCount);
113 } 114 }
114 115
115 int next(int index, int n) const { 116 int next(int index, int n) const {
116 // A valid strategy explores all slots in [0, fCapacity) as n walks from 0 to fCapacity-1. 117 // A valid strategy explores all slots in [0, fCapacity) as n walks from 0 to fCapacity-1.
117 // Both of these strategies are valid: 118 // Both of these strategies are valid:
118 //return (index + 0 + 1) & (fCapacity-1); // Linear probing. 119 //return (index + 0 + 1) & (fCapacity-1); // Linear probing.
119 return (index + n + 1) & (fCapacity-1); // Quadratic probing. 120 return (index + n + 1) & (fCapacity-1); // Quadratic probing.
120 } 121 }
121 122
122 static uint32_t Hash(K key) { 123 static uint32_t Hash(const K& key) {
123 uint32_t hash = Traits::Hash(key); 124 uint32_t hash = Traits::Hash(key);
124 return hash == 0 ? 1 : hash; // We reserve hash == 0 to mark empty slot s. 125 return hash == 0 ? 1 : hash; // We reserve hash == 0 to mark empty slot s.
125 } 126 }
126 127
127 struct Slot { 128 struct Slot {
128 Slot() : hash(0) {} 129 Slot() : hash(0) {}
129 bool empty() const { return hash == 0; } 130 bool empty() const { return hash == 0; }
130 131
131 T val; 132 T val;
132 uint32_t hash; 133 uint32_t hash;
133 }; 134 };
134 135
135 int fCount, fCapacity; 136 int fCount, fCapacity;
136 SkAutoTArray<Slot> fSlots; 137 SkAutoTArray<Slot> fSlots;
137 }; 138 };
138 139
139 // Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for mo st use cases. 140 // Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for mo st use cases.
140 // K and V are treated as ordinary copyable C++ types, with no assumed relations hip between the two. 141 // K and V are treated as ordinary copyable C++ types, with no assumed relations hip between the two.
141 template <typename K, typename V, uint32_t(*HashK)(K)> 142 template <typename K, typename V, uint32_t(*HashK)(const K&)>
142 class SkTHashMap : SkNoncopyable { 143 class SkTHashMap : SkNoncopyable {
143 public: 144 public:
144 SkTHashMap() {} 145 SkTHashMap() {}
145 146
146 // How many key/value pairs are in the table? 147 // How many key/value pairs are in the table?
147 int count() const { return fTable.count(); } 148 int count() const { return fTable.count(); }
148 149
149 // N.B. The pointers returned by set() and find() are valid only until the n ext call to set(). 150 // N.B. The pointers returned by set() and find() are valid only until the n ext call to set().
150 151
151 // Set key to val in the table, replacing any previous value with the same k ey. 152 // Set key to val in the table, replacing any previous value with the same k ey.
152 // We copy both key and val, and return a pointer to the value copy now in t he table. 153 // We copy both key and val, and return a pointer to the value copy now in t he table.
153 V* set(K key, V val) { 154 V* set(const K& key, const V& val) {
154 Pair in = { key, val }; 155 Pair in = { key, val };
155 Pair* out = fTable.set(in); 156 Pair* out = fTable.set(in);
156 return &out->val; 157 return &out->val;
157 } 158 }
158 159
159 // If there is key/value entry in the table with this key, return a pointer to the value. 160 // If there is key/value entry in the table with this key, return a pointer to the value.
160 // If not, return NULL. 161 // If not, return NULL.
161 V* find(K key) const { 162 V* find(const K& key) const {
162 if (Pair* p = fTable.find(key)) { 163 if (Pair* p = fTable.find(key)) {
163 return &p->val; 164 return &p->val;
164 } 165 }
165 return NULL; 166 return NULL;
166 } 167 }
167 168
168 // Call fn on every key/value pair in the table. You may mutate the value b ut not the key. 169 // Call fn on every key/value pair in the table. You may mutate the value b ut not the key.
169 void foreach(void(*fn)(K, V*)) { fTable.foreach(ForEach, fn); } 170 void foreach(void(*fn)(K, V*)) { fTable.foreach(ForEach, fn); }
170 171
171 private: 172 private:
172 struct Pair { 173 struct Pair {
173 K key; 174 K key;
174 V val; 175 V val;
175 static K GetKey(Pair p) { return p.key; } 176 static const K& GetKey(const Pair& p) { return p.key; }
176 static uint32_t Hash(K key) { return HashK(key); } 177 static uint32_t Hash(const K& key) { return HashK(key); }
177 }; 178 };
178 static void ForEach(Pair* p, void (*fn)(K, V*)) { fn(p->key, &p->val); } 179 static void ForEach(Pair* p, void (*fn)(K, V*)) { fn(p->key, &p->val); }
179 180
180 SkTHashTable<Pair, K> fTable; 181 SkTHashTable<Pair, K> fTable;
181 }; 182 };
182 183
183 // A set of T. T is treated as an ordiary copyable C++ type. 184 // A set of T. T is treated as an ordiary copyable C++ type.
184 template <typename T, uint32_t(*HashT)(T)> 185 template <typename T, uint32_t(*HashT)(const T&)>
185 class SkTHashSet : SkNoncopyable { 186 class SkTHashSet : SkNoncopyable {
186 public: 187 public:
187 SkTHashSet() {} 188 SkTHashSet() {}
188 189
189 // How many items are in the set? 190 // How many items are in the set?
190 int count() const { return fTable.count(); } 191 int count() const { return fTable.count(); }
191 192
192 // Copy an item into the set. 193 // Copy an item into the set.
193 void add(T item) { fTable.set(item); } 194 void add(const T& item) { fTable.set(item); }
194 195
195 // Is this item in the set? 196 // Is this item in the set?
196 bool contains(T item) const { return SkToBool(fTable.find(item)); } 197 bool contains(const T& item) const { return SkToBool(fTable.find(item)); }
197 198
198 private: 199 private:
199 struct Traits { 200 struct Traits {
200 static T GetKey(T item) { return item; } 201 static const T& GetKey(const T& item) { return item; }
201 static uint32_t Hash(T item) { return HashT(item); } 202 static uint32_t Hash(const T& item) { return HashT(item); }
202 }; 203 };
203 SkTHashTable<T, T, Traits> fTable; 204 SkTHashTable<T, T, Traits> fTable;
204 }; 205 };
205 206
206 #endif//SkTHash_DEFINED 207 #endif//SkTHash_DEFINED
OLDNEW
« no previous file with comments | « no previous file | tests/HashTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698