OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 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 SkTSet_DEFINED | 8 #ifndef SkTSet_DEFINED |
9 #define SkTSet_DEFINED | 9 #define SkTSet_DEFINED |
10 | 10 |
11 #include "SkTDArray.h" | 11 #include "SkTDArray.h" |
12 #include "SkTypes.h" | 12 #include "SkTypes.h" |
13 | 13 |
14 /** \class SkTSet<T> | 14 /** \class SkTSet<T> |
15 | 15 |
16 The SkTSet template class defines a set. | 16 The SkTSet template class defines a set. Elements are additionally |
17 guaranteed to be sorted by their insertion order. | |
17 Main operations supported now are: add, merge, find and contains. | 18 Main operations supported now are: add, merge, find and contains. |
18 | 19 |
19 TSet<T> is mutable. | 20 TSet<T> is mutable. |
20 */ | 21 */ |
21 | 22 |
22 // TODO: Add remove, intersect and difference operations. | 23 // TODO: Add remove, intersect and difference operations. |
23 // TODO: Add bench tests. | 24 // TODO: Add bench tests. |
24 template <typename T> class SkTSet { | 25 template <typename T> class SkTSet { |
vandebo (ex-Chrome)
2013/07/17 15:30:43
Should this be renamed to SkTOrderedSet now?
ducky
2013/07/17 19:32:21
Renaming this class would require a lot of changes
| |
25 public: | 26 public: |
26 SkTSet() { | 27 SkTSet() { |
27 fArray = SkNEW(SkTDArray<T>); | 28 fSetArray = SkNEW(SkTDArray<T>); |
29 fOrderedArray = SkNEW(SkTDArray<T>); | |
28 } | 30 } |
29 | 31 |
30 ~SkTSet() { | 32 ~SkTSet() { |
31 SkASSERT(fArray); | 33 SkASSERT(fSetArray); |
32 SkDELETE(fArray); | 34 SkDELETE(fSetArray); |
35 SkASSERT(fOrderedArray); | |
36 SkDELETE(fOrderedArray); | |
33 } | 37 } |
34 | 38 |
35 SkTSet(const SkTSet<T>& src) { | 39 SkTSet(const SkTSet<T>& src) { |
36 this->fArray = SkNEW_ARGS(SkTDArray<T>, (*src.fArray)); | 40 this->fSetArray = SkNEW_ARGS(SkTDArray<T>, (*src.fSetArray)); |
41 this->fOrderedArray = SkNEW_ARGS(SkTDArray<T>, (*src.fOrderedArray)); | |
37 #ifdef SK_DEBUG | 42 #ifdef SK_DEBUG |
38 validate(); | 43 validate(); |
39 #endif | 44 #endif |
40 } | 45 } |
41 | 46 |
42 SkTSet<T>& operator=(const SkTSet<T>& src) { | 47 SkTSet<T>& operator=(const SkTSet<T>& src) { |
43 *this->fArray = *src.fArray; | 48 *this->fSetArray = *src.fSetArray; |
49 *this->fOrderedArray = *src.fOrderedArray; | |
44 #ifdef SK_DEBUG | 50 #ifdef SK_DEBUG |
45 validate(); | 51 validate(); |
46 #endif | 52 #endif |
47 return *this; | 53 return *this; |
48 } | 54 } |
49 | 55 |
50 /** Merges src elements into this, and returns the number of duplicates | 56 /** Merges src elements into this, and returns the number of duplicates |
51 * found. | 57 * found. Elements from src will retain their ordering and will be ordered |
52 */ | 58 * after the elements currently in this set. |
59 * | |
60 * Implementation note: this uses a 2-stage merge to obtain O(n log n) time. | |
61 * The first stage goes through src.fOrderedArray, checking if | |
62 * this->contains() is false before adding to this.fOrderedArray. | |
63 * The second stage does a standard sorted list merge on the fSetArrays. | |
64 */ | |
53 int mergeInto(const SkTSet<T>& src) { | 65 int mergeInto(const SkTSet<T>& src) { |
54 SkASSERT(fArray); | 66 SkASSERT(fSetArray); |
67 SkASSERT(fOrderedArray); | |
68 | |
69 // Do fOrderedArray merge. | |
70 for (int i = 0; i < src.count(); ++i) { | |
71 if (!contains((*src.fOrderedArray)[i])) { | |
72 fOrderedArray->push((*src.fOrderedArray)[i]); | |
73 } | |
74 } | |
75 | |
76 // Do fSetArray merge. | |
55 int duplicates = 0; | 77 int duplicates = 0; |
56 | 78 |
57 SkTDArray<T>* fArrayNew = new SkTDArray<T>(); | 79 SkTDArray<T>* fArrayNew = new SkTDArray<T>(); |
58 fArrayNew->setReserve(count() + src.count()); | 80 fArrayNew->setReserve(fOrderedArray->count()); |
59 int i = 0; | 81 int i = 0; |
60 int j = 0; | 82 int j = 0; |
61 | 83 |
62 while (i < count() && j < src.count()) { | 84 while (i < fSetArray->count() && j < src.count()) { |
63 if ((*fArray)[i] < (*src.fArray)[j]) { | 85 if ((*fSetArray)[i] < (*src.fSetArray)[j]) { |
64 fArrayNew->push((*fArray)[i]); | 86 fArrayNew->push((*fSetArray)[i]); |
65 i++; | 87 i++; |
66 } else if ((*fArray)[i] > (*src.fArray)[j]) { | 88 } else if ((*fSetArray)[i] > (*src.fSetArray)[j]) { |
67 fArrayNew->push((*src.fArray)[j]); | 89 fArrayNew->push((*src.fSetArray)[j]); |
68 j++; | 90 j++; |
69 } else { | 91 } else { |
70 duplicates++; | 92 duplicates++; |
71 j++; // Skip one of the duplicates. | 93 j++; // Skip one of the duplicates. |
72 } | 94 } |
73 } | 95 } |
74 | 96 |
75 while (i < count()) { | 97 while (i < fSetArray->count()) { |
76 fArrayNew->push((*fArray)[i]); | 98 fArrayNew->push((*fSetArray)[i]); |
77 i++; | 99 i++; |
78 } | 100 } |
79 | 101 |
80 while (j < src.count()) { | 102 while (j < src.count()) { |
81 fArrayNew->push((*src.fArray)[j]); | 103 fArrayNew->push((*src.fSetArray)[j]); |
82 j++; | 104 j++; |
83 } | 105 } |
84 SkDELETE(fArray); | 106 SkDELETE(fSetArray); |
85 fArray = fArrayNew; | 107 fSetArray = fArrayNew; |
86 fArrayNew = NULL; | 108 fArrayNew = NULL; |
87 | 109 |
88 #ifdef SK_DEBUG | 110 #ifdef SK_DEBUG |
89 validate(); | 111 validate(); |
90 #endif | 112 #endif |
91 return duplicates; | 113 return duplicates; |
92 } | 114 } |
93 | 115 |
94 /** Adds a new element into set and returns true if the element is already | 116 /** Adds a new element into set and returns false if the element is already |
95 * in this set. | 117 * in this set. |
96 */ | 118 */ |
97 bool add(const T& elem) { | 119 bool add(const T& elem) { |
98 SkASSERT(fArray); | 120 SkASSERT(fSetArray); |
121 SkASSERT(fOrderedArray); | |
99 | 122 |
100 int pos = 0; | 123 int pos = 0; |
101 int i = find(elem, &pos); | 124 int i = find(elem, &pos); |
102 if (i >= 0) { | 125 if (i >= 0) { |
103 return false; | 126 return false; |
104 } | 127 } |
105 *fArray->insert(pos) = elem; | 128 *fSetArray->insert(pos) = elem; |
129 fOrderedArray->push(elem); | |
106 #ifdef SK_DEBUG | 130 #ifdef SK_DEBUG |
107 validate(); | 131 validate(); |
108 #endif | 132 #endif |
109 return true; | 133 return true; |
110 } | 134 } |
111 | 135 |
112 /** Returns true if this set is empty. | 136 /** Returns true if this set is empty. |
113 */ | 137 */ |
114 bool isEmpty() const { | 138 bool isEmpty() const { |
115 SkASSERT(fArray); | 139 SkASSERT(fOrderedArray); |
edisonn
2013/07/17 12:32:09
assert fSetArray is empty too
ducky
2013/07/17 19:32:21
Done.
| |
116 return fArray->isEmpty(); | 140 return fOrderedArray->isEmpty(); |
117 } | 141 } |
118 | 142 |
119 /** Return the number of elements in the set. | 143 /** Return the number of elements in the set. |
120 */ | 144 */ |
121 int count() const { | 145 int count() const { |
122 SkASSERT(fArray); | 146 SkASSERT(fOrderedArray); |
edisonn
2013/07/17 12:32:09
assert both array have the same number of elements
ducky
2013/07/17 19:32:21
Done.
| |
123 return fArray->count(); | 147 return fOrderedArray->count(); |
124 } | 148 } |
125 | 149 |
126 /** Return the number of bytes in the set: count * sizeof(T). | 150 /** Return the number of bytes in the set: count * sizeof(T). |
127 */ | 151 */ |
128 size_t bytes() const { | 152 size_t bytes() const { |
129 SkASSERT(fArray); | 153 SkASSERT(fOrderedArray); |
edisonn
2013/07/17 12:32:09
I think we should report the number of total bytes
ducky
2013/07/17 19:32:21
Should we? According to the function comments, it
| |
130 return fArray->bytes(); | 154 return fOrderedArray->bytes(); |
131 } | 155 } |
132 | 156 |
133 /** Return the beginning of a set iterator. | 157 /** Return the beginning of a set iterator. |
134 * Elements in the iterator will be sorted ascending. | 158 * Elements in the iterator will be sorted ascending. |
135 */ | 159 */ |
136 const T* begin() const { | 160 const T* begin() const { |
137 SkASSERT(fArray); | 161 SkASSERT(fOrderedArray); |
138 return fArray->begin(); | 162 return fOrderedArray->begin(); |
139 } | 163 } |
140 | 164 |
141 /** Return the end of a set iterator. | 165 /** Return the end of a set iterator. |
142 */ | 166 */ |
143 const T* end() const { | 167 const T* end() const { |
144 SkASSERT(fArray); | 168 SkASSERT(fOrderedArray); |
145 return fArray->end(); | 169 return fOrderedArray->end(); |
146 } | 170 } |
147 | 171 |
148 const T& operator[](int index) const { | 172 const T& operator[](int index) const { |
149 SkASSERT(fArray); | 173 SkASSERT(fOrderedArray); |
150 return (*fArray)[index]; | 174 return (*fOrderedArray)[index]; |
151 } | 175 } |
152 | 176 |
153 /** Resets the set (deletes memory and initiates an empty set). | 177 /** Resets the set (deletes memory and initiates an empty set). |
154 */ | 178 */ |
155 void reset() { | 179 void reset() { |
156 SkASSERT(fArray); | 180 SkASSERT(fSetArray); |
157 fArray->reset(); | 181 SkASSERT(fOrderedArray); |
182 fSetArray->reset(); | |
183 fOrderedArray->reset(); | |
158 } | 184 } |
159 | 185 |
160 /** Rewinds the set (preserves memory and initiates an empty set). | 186 /** Rewinds the set (preserves memory and initiates an empty set). |
161 */ | 187 */ |
162 void rewind() { | 188 void rewind() { |
163 SkASSERT(fArray); | 189 SkASSERT(fSetArray); |
164 fArray->rewind(); | 190 SkASSERT(fOrderedArray); |
191 fSetArray->rewind(); | |
192 fOrderedArray->rewind(); | |
165 } | 193 } |
166 | 194 |
167 /** Reserves memory for the set. | 195 /** Reserves memory for the set. |
168 */ | 196 */ |
169 void setReserve(size_t reserve) { | 197 void setReserve(size_t reserve) { |
170 SkASSERT(fArray); | 198 SkASSERT(fSetArray); |
171 fArray->setReserve(reserve); | 199 SkASSERT(fOrderedArray); |
172 } | 200 fSetArray->setReserve(reserve); |
173 | 201 fOrderedArray->setReserve(reserve); |
174 /** Returns the index where an element was found. | |
175 * Returns -1 if the element was not found, and it fills *posToInsertSorted | |
176 * with the index of the place where elem should be inserted to preserve the | |
177 * internal array sorted. | |
178 * If element was found, *posToInsertSorted is undefined. | |
179 */ | |
180 int find(const T& elem, int* posToInsertSorted = NULL) const { | |
181 SkASSERT(fArray); | |
182 | |
183 if (fArray->count() == 0) { | |
184 if (posToInsertSorted) { | |
185 *posToInsertSorted = 0; | |
186 } | |
187 return -1; | |
188 } | |
189 int iMin = 0; | |
190 int iMax = fArray->count(); | |
191 | |
192 while (iMin < iMax - 1) { | |
193 int iMid = (iMin + iMax) / 2; | |
194 if (elem < (*fArray)[iMid]) { | |
195 iMax = iMid; | |
196 } else { | |
197 iMin = iMid; | |
198 } | |
199 } | |
200 if (elem == (*fArray)[iMin]) { | |
201 return iMin; | |
202 } | |
203 if (posToInsertSorted) { | |
204 if (elem < (*fArray)[iMin]) { | |
205 *posToInsertSorted = iMin; | |
206 } else { | |
207 *posToInsertSorted = iMin + 1; | |
208 } | |
209 } | |
210 | |
211 return -1; | |
212 } | 202 } |
213 | 203 |
214 /** Returns true if the array contains this element. | 204 /** Returns true if the array contains this element. |
215 */ | 205 */ |
216 bool contains(const T& elem) const { | 206 bool contains(const T& elem) const { |
217 SkASSERT(fArray); | 207 SkASSERT(fSetArray); |
218 return (this->find(elem) >= 0); | 208 return (this->find(elem) >= 0); |
219 } | 209 } |
220 | 210 |
221 /** Copies internal array to destination. | 211 /** Copies internal array to destination. |
222 */ | 212 */ |
223 void copy(T* dst) const { | 213 void copy(T* dst) const { |
224 SkASSERT(fArray); | 214 SkASSERT(fOrderedArray); |
225 fArray->copyRange(0, fArray->count(), dst); | 215 fOrderedArray->copyRange(0, fOrderedArray->count(), dst); |
226 } | 216 } |
227 | 217 |
228 /** Returns a const reference to the internal vector. | 218 /** Returns a const reference to the internal vector. |
229 */ | 219 */ |
230 const SkTDArray<T>& toArray() { | 220 const SkTDArray<T>& toArray() { |
231 SkASSERT(fArray); | 221 SkASSERT(fOrderedArray); |
232 return *fArray; | 222 return *fOrderedArray; |
233 } | 223 } |
234 | 224 |
235 /** Unref all elements in the set. | 225 /** Unref all elements in the set. |
236 */ | 226 */ |
237 void unrefAll() { | 227 void unrefAll() { |
238 SkASSERT(fArray); | 228 SkASSERT(fSetArray); |
239 fArray->unrefAll(); | 229 SkASSERT(fOrderedArray); |
230 fOrderedArray->unrefAll(); | |
231 fSetArray->reset(); | |
edisonn
2013/07/17 12:32:09
I don't think we should reset fSetArray. We just c
ducky
2013/07/17 19:32:21
This was a tricky one. I looked into SkTDArray.h,
| |
240 } | 232 } |
241 | 233 |
242 /** safeUnref all elements in the set. | 234 /** safeUnref all elements in the set. |
243 */ | 235 */ |
244 void safeUnrefAll() { | 236 void safeUnrefAll() { |
245 SkASSERT(fArray); | 237 SkASSERT(fSetArray); |
246 fArray->safeUnrefAll(); | 238 SkASSERT(fOrderedArray); |
239 fOrderedArray->safeUnrefAll(); | |
240 fSetArray->reset(); | |
edisonn
2013/07/17 12:32:09
I don't think we should reset fSetArray. We just s
ducky
2013/07/17 19:32:21
See above comment - SkTDArray::safeUnrefAll does a
| |
247 } | 241 } |
248 | 242 |
249 #ifdef SK_DEBUG | 243 #ifdef SK_DEBUG |
250 void validate() const { | 244 void validate() const { |
251 SkASSERT(fArray); | 245 SkASSERT(fSetArray); |
252 fArray->validate(); | 246 SkASSERT(fOrderedArray); |
253 SkASSERT(isSorted() && !hasDuplicates()); | 247 fSetArray->validate(); |
248 fOrderedArray->validate(); | |
249 SkASSERT(isSorted() && !hasDuplicates() && arraysConsistent()); | |
254 } | 250 } |
255 | 251 |
256 bool hasDuplicates() const { | 252 bool hasDuplicates() const { |
257 for (int i = 0; i < fArray->count() - 1; ++i) { | 253 for (int i = 0; i < fSetArray->count() - 1; ++i) { |
258 if ((*fArray)[i] == (*fArray)[i + 1]) { | 254 if ((*fSetArray)[i] == (*fSetArray)[i + 1]) { |
259 return true; | 255 return true; |
260 } | 256 } |
261 } | 257 } |
262 return false; | 258 return false; |
263 } | 259 } |
264 | 260 |
265 bool isSorted() const { | 261 bool isSorted() const { |
266 for (int i = 0; i < fArray->count() - 1; ++i) { | 262 for (int i = 0; i < fSetArray->count() - 1; ++i) { |
267 // Use only < operator | 263 // Use only < operator |
268 if (!((*fArray)[i] < (*fArray)[i + 1])) { | 264 if (!((*fSetArray)[i] < (*fSetArray)[i + 1])) { |
269 return false; | 265 return false; |
270 } | 266 } |
271 } | 267 } |
272 return true; | 268 return true; |
273 } | 269 } |
270 | |
271 /** Checks if fSetArray is consistent with fOrderedArray | |
272 */ | |
273 bool arraysConsistent() const { | |
274 SkASSERT(fSetArray->count() == fOrderedArray->count()); | |
275 for (int i = 0; i < fOrderedArray->count(); ++i) { | |
276 if (!contains((*fOrderedArray)[i])) { | |
277 return false; | |
278 } | |
279 } | |
280 // Checking fSetArray -> fOrderedArray should also be done, but | |
vandebo (ex-Chrome)
2013/07/17 15:30:43
What about sorting fSetArray into a temporary copy
ducky
2013/07/17 19:32:21
Done.
| |
281 // the O(n^2)ness makes some GMs unacceptably slow. | |
282 | |
283 return true; | |
284 } | |
274 #endif | 285 #endif |
275 | 286 |
276 private: | 287 private: |
277 SkTDArray<T>* fArray; | 288 SkTDArray<T>* fSetArray; // Sorted by pointer address for fast |
289 // lookup. | |
290 SkTDArray<T>* fOrderedArray; // Sorted by insertion order for | |
291 // deterministic output. | |
292 | |
293 /** Returns the index in fSetArray where an element was found. | |
294 * Returns -1 if the element was not found, and it fills *posToInsertSorted | |
295 * with the index of the place where elem should be inserted to preserve the | |
296 * internal array sorted. | |
297 * If element was found, *posToInsertSorted is undefined. | |
298 */ | |
299 int find(const T& elem, int* posToInsertSorted = NULL) const { | |
300 SkASSERT(fSetArray); | |
301 | |
302 if (fSetArray->count() == 0) { | |
303 if (posToInsertSorted) { | |
304 *posToInsertSorted = 0; | |
305 } | |
306 return -1; | |
307 } | |
308 int iMin = 0; | |
309 int iMax = fSetArray->count(); | |
310 | |
311 while (iMin < iMax - 1) { | |
312 int iMid = (iMin + iMax) / 2; | |
313 if (elem < (*fSetArray)[iMid]) { | |
314 iMax = iMid; | |
315 } else { | |
316 iMin = iMid; | |
317 } | |
318 } | |
319 if (elem == (*fSetArray)[iMin]) { | |
320 return iMin; | |
321 } | |
322 if (posToInsertSorted) { | |
323 if (elem < (*fSetArray)[iMin]) { | |
324 *posToInsertSorted = iMin; | |
325 } else { | |
326 *posToInsertSorted = iMin + 1; | |
327 } | |
328 } | |
329 | |
330 return -1; | |
331 } | |
278 }; | 332 }; |
279 | 333 |
280 #endif | 334 #endif |
OLD | NEW |