• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SkTSet()28     SkTSet() {
29         fSetArray = SkNEW(SkTDArray<T>);
30         fOrderedArray = SkNEW(SkTDArray<T>);
31     }
32 
~SkTSet()33     ~SkTSet() {
34         SkASSERT(fSetArray);
35         SkDELETE(fSetArray);
36         SkASSERT(fOrderedArray);
37         SkDELETE(fOrderedArray);
38     }
39 
SkTSet(const SkTSet<T> & src)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      */
mergeInto(const SkTSet<T> & src)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     */
add(const T & elem)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     */
isEmpty()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      */
count()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      */
bytes()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      */
begin()165     const T*  begin() const {
166         SkASSERT(fOrderedArray);
167         return fOrderedArray->begin();
168     }
169 
170     /** Return the end of a set iterator.
171      */
end()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      */
reset()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      */
rewind()193     void rewind() {
194         SkASSERT(fSetArray);
195         SkASSERT(fOrderedArray);
196         fSetArray->rewind();
197         fOrderedArray->rewind();
198     }
199 
200     /** Reserves memory for the set.
201      */
setReserve(int reserve)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      */
contains(const T & elem)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      */
copy(T * dst)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      */
toArray()225     const SkTDArray<T>& toArray() {
226         SkASSERT(fOrderedArray);
227         return *fOrderedArray;
228     }
229 
230     /** Unref all elements in the set.
231      */
unrefAll()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      */
safeUnrefAll()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
validate()253     void validate() const {
254         SkASSERT(fSetArray);
255         SkASSERT(fOrderedArray);
256         fSetArray->validate();
257         fOrderedArray->validate();
258         SkASSERT(isSorted() && !hasDuplicates() && arraysConsistent());
259     }
260 
hasDuplicates()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 
isSorted()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      */
arraysConsistent()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
357