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