OLD | NEW |
| (Empty) |
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 | |
OLD | NEW |