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