Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/pdf/SkTSet.h

Issue 19283005: Deterministic SkTSet and PDF Output (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: O(n log n) merge, also fixes unrefAll to clean fSetArray Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/TSetTest.cpp » ('j') | tests/TSetTest.cpp » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
OLDNEW
« no previous file with comments | « no previous file | tests/TSetTest.cpp » ('j') | tests/TSetTest.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698