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 { |
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 in src will be ordered after elements in this set. |
52 */ | 58 */ |
53 int mergeInto(const SkTSet<T>& src) { | 59 int mergeInto(const SkTSet<T>& src) { |
ducky
2013/07/16 01:03:10
So this is now a O(n^2) algorithm (src loop, then
| |
54 SkASSERT(fArray); | 60 SkASSERT(fSetArray); |
61 SkASSERT(fOrderedArray); | |
55 int duplicates = 0; | 62 int duplicates = 0; |
56 | 63 |
57 SkTDArray<T>* fArrayNew = new SkTDArray<T>(); | 64 for (int i = 0; i < src.count(); ++i) { |
58 fArrayNew->setReserve(count() + src.count()); | 65 if (!add((*src.fOrderedArray)[i])) { |
59 int i = 0; | |
60 int j = 0; | |
61 | |
62 while (i < count() && j < src.count()) { | |
63 if ((*fArray)[i] < (*src.fArray)[j]) { | |
64 fArrayNew->push((*fArray)[i]); | |
65 i++; | |
66 } else if ((*fArray)[i] > (*src.fArray)[j]) { | |
67 fArrayNew->push((*src.fArray)[j]); | |
68 j++; | |
69 } else { | |
70 duplicates++; | 66 duplicates++; |
71 j++; // Skip one of the duplicates. | |
72 } | 67 } |
73 } | 68 } |
74 | 69 |
75 while (i < count()) { | |
76 fArrayNew->push((*fArray)[i]); | |
77 i++; | |
78 } | |
79 | |
80 while (j < src.count()) { | |
81 fArrayNew->push((*src.fArray)[j]); | |
82 j++; | |
83 } | |
84 SkDELETE(fArray); | |
85 fArray = fArrayNew; | |
86 fArrayNew = NULL; | |
87 | |
88 #ifdef SK_DEBUG | 70 #ifdef SK_DEBUG |
89 validate(); | 71 validate(); |
90 #endif | 72 #endif |
91 return duplicates; | 73 return duplicates; |
92 } | 74 } |
93 | 75 |
94 /** Adds a new element into set and returns true if the element is already | 76 /** Adds a new element into set and returns false if the element is already |
95 * in this set. | 77 * in this set. |
96 */ | 78 */ |
97 bool add(const T& elem) { | 79 bool add(const T& elem) { |
98 SkASSERT(fArray); | 80 SkASSERT(fSetArray); |
81 SkASSERT(fOrderedArray); | |
99 | 82 |
100 int pos = 0; | 83 int pos = 0; |
101 int i = find(elem, &pos); | 84 int i = find(elem, &pos); |
102 if (i >= 0) { | 85 if (i >= 0) { |
103 return false; | 86 return false; |
104 } | 87 } |
105 *fArray->insert(pos) = elem; | 88 *fSetArray->insert(pos) = elem; |
89 fOrderedArray->push(elem); | |
106 #ifdef SK_DEBUG | 90 #ifdef SK_DEBUG |
107 validate(); | 91 validate(); |
108 #endif | 92 #endif |
109 return true; | 93 return true; |
110 } | 94 } |
111 | 95 |
112 /** Returns true if this set is empty. | 96 /** Returns true if this set is empty. |
113 */ | 97 */ |
114 bool isEmpty() const { | 98 bool isEmpty() const { |
115 SkASSERT(fArray); | 99 SkASSERT(fOrderedArray); |
116 return fArray->isEmpty(); | 100 return fOrderedArray->isEmpty(); |
117 } | 101 } |
118 | 102 |
119 /** Return the number of elements in the set. | 103 /** Return the number of elements in the set. |
120 */ | 104 */ |
121 int count() const { | 105 int count() const { |
122 SkASSERT(fArray); | 106 SkASSERT(fOrderedArray); |
123 return fArray->count(); | 107 return fOrderedArray->count(); |
124 } | 108 } |
125 | 109 |
126 /** Return the number of bytes in the set: count * sizeof(T). | 110 /** Return the number of bytes in the set: count * sizeof(T). |
127 */ | 111 */ |
128 size_t bytes() const { | 112 size_t bytes() const { |
129 SkASSERT(fArray); | 113 SkASSERT(fOrderedArray); |
130 return fArray->bytes(); | 114 return fOrderedArray->bytes(); |
131 } | 115 } |
132 | 116 |
133 /** Return the beginning of a set iterator. | 117 /** Return the beginning of a set iterator. |
134 * Elements in the iterator will be sorted ascending. | 118 * Elements in the iterator will be sorted ascending. |
135 */ | 119 */ |
136 const T* begin() const { | 120 const T* begin() const { |
137 SkASSERT(fArray); | 121 SkASSERT(fOrderedArray); |
138 return fArray->begin(); | 122 return fOrderedArray->begin(); |
139 } | 123 } |
140 | 124 |
141 /** Return the end of a set iterator. | 125 /** Return the end of a set iterator. |
142 */ | 126 */ |
143 const T* end() const { | 127 const T* end() const { |
144 SkASSERT(fArray); | 128 SkASSERT(fOrderedArray); |
145 return fArray->end(); | 129 return fOrderedArray->end(); |
146 } | 130 } |
147 | 131 |
148 const T& operator[](int index) const { | 132 const T& operator[](int index) const { |
149 SkASSERT(fArray); | 133 SkASSERT(fOrderedArray); |
150 return (*fArray)[index]; | 134 return (*fOrderedArray)[index]; |
151 } | 135 } |
152 | 136 |
153 /** Resets the set (deletes memory and initiates an empty set). | 137 /** Resets the set (deletes memory and initiates an empty set). |
154 */ | 138 */ |
155 void reset() { | 139 void reset() { |
156 SkASSERT(fArray); | 140 SkASSERT(fSetArray); |
157 fArray->reset(); | 141 SkASSERT(fOrderedArray); |
142 fSetArray->reset(); | |
143 fOrderedArray->reset(); | |
158 } | 144 } |
159 | 145 |
160 /** Rewinds the set (preserves memory and initiates an empty set). | 146 /** Rewinds the set (preserves memory and initiates an empty set). |
161 */ | 147 */ |
162 void rewind() { | 148 void rewind() { |
163 SkASSERT(fArray); | 149 SkASSERT(fSetArray); |
164 fArray->rewind(); | 150 SkASSERT(fOrderedArray); |
151 fSetArray->rewind(); | |
152 fOrderedArray->rewind(); | |
165 } | 153 } |
166 | 154 |
167 /** Reserves memory for the set. | 155 /** Reserves memory for the set. |
168 */ | 156 */ |
169 void setReserve(size_t reserve) { | 157 void setReserve(size_t reserve) { |
170 SkASSERT(fArray); | 158 SkASSERT(fSetArray); |
171 fArray->setReserve(reserve); | 159 SkASSERT(fOrderedArray); |
172 } | 160 fSetArray->setReserve(reserve); |
173 | 161 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 } | 162 } |
213 | 163 |
214 /** Returns true if the array contains this element. | 164 /** Returns true if the array contains this element. |
215 */ | 165 */ |
216 bool contains(const T& elem) const { | 166 bool contains(const T& elem) const { |
217 SkASSERT(fArray); | 167 SkASSERT(fSetArray); |
218 return (this->find(elem) >= 0); | 168 return (this->find(elem) >= 0); |
219 } | 169 } |
220 | 170 |
221 /** Copies internal array to destination. | 171 /** Copies internal array to destination. |
222 */ | 172 */ |
223 void copy(T* dst) const { | 173 void copy(T* dst) const { |
224 SkASSERT(fArray); | 174 SkASSERT(fOrderedArray); |
225 fArray->copyRange(0, fArray->count(), dst); | 175 fOrderedArray->copyRange(0, fOrderedArray->count(), dst); |
226 } | 176 } |
227 | 177 |
228 /** Returns a const reference to the internal vector. | 178 /** Returns a const reference to the internal vector. |
229 */ | 179 */ |
230 const SkTDArray<T>& toArray() { | 180 const SkTDArray<T>& toArray() { |
231 SkASSERT(fArray); | 181 SkASSERT(fOrderedArray); |
232 return *fArray; | 182 return *fOrderedArray; |
233 } | 183 } |
234 | 184 |
235 /** Unref all elements in the set. | 185 /** Unref all elements in the set. |
236 */ | 186 */ |
237 void unrefAll() { | 187 void unrefAll() { |
238 SkASSERT(fArray); | 188 SkASSERT(fOrderedArray); |
239 fArray->unrefAll(); | 189 fOrderedArray->unrefAll(); |
240 } | 190 } |
241 | 191 |
242 /** safeUnref all elements in the set. | 192 /** safeUnref all elements in the set. |
243 */ | 193 */ |
244 void safeUnrefAll() { | 194 void safeUnrefAll() { |
245 SkASSERT(fArray); | 195 SkASSERT(fOrderedArray); |
246 fArray->safeUnrefAll(); | 196 fOrderedArray->safeUnrefAll(); |
247 } | 197 } |
248 | 198 |
249 #ifdef SK_DEBUG | 199 #ifdef SK_DEBUG |
250 void validate() const { | 200 void validate() const { |
251 SkASSERT(fArray); | 201 SkASSERT(fSetArray); |
252 fArray->validate(); | 202 SkASSERT(fOrderedArray); |
253 SkASSERT(isSorted() && !hasDuplicates()); | 203 fSetArray->validate(); |
204 fOrderedArray->validate(); | |
205 SkASSERT(isSorted() && !hasDuplicates() && arraysConsistent()); | |
254 } | 206 } |
255 | 207 |
256 bool hasDuplicates() const { | 208 bool hasDuplicates() const { |
257 for (int i = 0; i < fArray->count() - 1; ++i) { | 209 for (int i = 0; i < fSetArray->count() - 1; ++i) { |
258 if ((*fArray)[i] == (*fArray)[i + 1]) { | 210 if ((*fSetArray)[i] == (*fSetArray)[i + 1]) { |
259 return true; | 211 return true; |
260 } | 212 } |
261 } | 213 } |
262 return false; | 214 return false; |
263 } | 215 } |
264 | 216 |
265 bool isSorted() const { | 217 bool isSorted() const { |
266 for (int i = 0; i < fArray->count() - 1; ++i) { | 218 for (int i = 0; i < fSetArray->count() - 1; ++i) { |
267 // Use only < operator | 219 // Use only < operator |
268 if (!((*fArray)[i] < (*fArray)[i + 1])) { | 220 if (!((*fSetArray)[i] < (*fSetArray)[i + 1])) { |
269 return false; | 221 return false; |
270 } | 222 } |
271 } | 223 } |
272 return true; | 224 return true; |
273 } | 225 } |
226 | |
227 /** Checks if fSetArray is consistent with fOrderedArray | |
228 */ | |
229 bool arraysConsistent() const { | |
230 SkASSERT(fSetArray->count() == fOrderedArray->count()); | |
231 for (int i = 0; i < fOrderedArray->count(); ++i) { | |
232 if (!contains((*fOrderedArray)[i])) { | |
233 return false; | |
234 } | |
235 } | |
236 // Checking fSetArray -> fOrderedArray should also be done, but | |
237 // the O(n^2)ness makes some GMs unacceptably slow. | |
238 | |
239 return true; | |
240 } | |
274 #endif | 241 #endif |
275 | 242 |
276 private: | 243 private: |
277 SkTDArray<T>* fArray; | 244 SkTDArray<T>* fSetArray; // Sorted by pointer address for fast |
245 // lookup. | |
246 SkTDArray<T>* fOrderedArray; // Sorted by insertion order for | |
247 // deterministic output. | |
248 | |
249 /** Returns the index in fSetArray where an element was found. | |
250 * Returns -1 if the element was not found, and it fills *posToInsertSorted | |
251 * with the index of the place where elem should be inserted to preserve the | |
252 * internal array sorted. | |
253 * If element was found, *posToInsertSorted is undefined. | |
254 */ | |
255 int find(const T& elem, int* posToInsertSorted = NULL) const { | |
256 SkASSERT(fSetArray); | |
257 | |
258 if (fSetArray->count() == 0) { | |
259 if (posToInsertSorted) { | |
260 *posToInsertSorted = 0; | |
261 } | |
262 return -1; | |
263 } | |
264 int iMin = 0; | |
265 int iMax = fSetArray->count(); | |
266 | |
267 while (iMin < iMax - 1) { | |
268 int iMid = (iMin + iMax) / 2; | |
269 if (elem < (*fSetArray)[iMid]) { | |
270 iMax = iMid; | |
271 } else { | |
272 iMin = iMid; | |
273 } | |
274 } | |
275 if (elem == (*fSetArray)[iMin]) { | |
276 return iMin; | |
277 } | |
278 if (posToInsertSorted) { | |
279 if (elem < (*fSetArray)[iMin]) { | |
280 *posToInsertSorted = iMin; | |
281 } else { | |
282 *posToInsertSorted = iMin + 1; | |
283 } | |
284 } | |
285 | |
286 return -1; | |
287 } | |
278 }; | 288 }; |
279 | 289 |
280 #endif | 290 #endif |
OLD | NEW |