Chromium Code Reviews| 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 { |
|
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 |
| OLD | NEW |