1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #ifndef SkTDArray_DEFINED 11 #define SkTDArray_DEFINED 12 13 #include "SkTypes.h" 14 15 template <typename T> class SK_API SkTDArray { 16 public: SkTDArray()17 SkTDArray() { 18 fReserve = fCount = 0; 19 fArray = NULL; 20 #ifdef SK_DEBUG 21 fData = NULL; 22 #endif 23 } SkTDArray(const T src[],size_t count)24 SkTDArray(const T src[], size_t count) { 25 SkASSERT(src || count == 0); 26 27 fReserve = fCount = 0; 28 fArray = NULL; 29 #ifdef SK_DEBUG 30 fData = NULL; 31 #endif 32 if (count) { 33 fArray = (T*)sk_malloc_throw(count * sizeof(T)); 34 #ifdef SK_DEBUG 35 fData = (ArrayT*)fArray; 36 #endif 37 memcpy(fArray, src, sizeof(T) * count); 38 fReserve = fCount = count; 39 } 40 } SkTDArray(const SkTDArray<T> & src)41 SkTDArray(const SkTDArray<T>& src) { 42 fReserve = fCount = 0; 43 fArray = NULL; 44 #ifdef SK_DEBUG 45 fData = NULL; 46 #endif 47 SkTDArray<T> tmp(src.fArray, src.fCount); 48 this->swap(tmp); 49 } ~SkTDArray()50 ~SkTDArray() { 51 sk_free(fArray); 52 } 53 54 SkTDArray<T>& operator=(const SkTDArray<T>& src) { 55 if (this != &src) { 56 if (src.fCount > fReserve) { 57 SkTDArray<T> tmp(src.fArray, src.fCount); 58 this->swap(tmp); 59 } else { 60 memcpy(fArray, src.fArray, sizeof(T) * src.fCount); 61 fCount = src.fCount; 62 } 63 } 64 return *this; 65 } 66 67 friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) { 68 return a.fCount == b.fCount && 69 (a.fCount == 0 || 70 !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T))); 71 } 72 swap(SkTDArray<T> & other)73 void swap(SkTDArray<T>& other) { 74 SkTSwap(fArray, other.fArray); 75 #ifdef SK_DEBUG 76 SkTSwap(fData, other.fData); 77 #endif 78 SkTSwap(fReserve, other.fReserve); 79 SkTSwap(fCount, other.fCount); 80 } 81 82 /** Return a ptr to the array of data, to be freed with sk_free. This also 83 resets the SkTDArray to be empty. 84 */ detach()85 T* detach() { 86 T* array = fArray; 87 fArray = NULL; 88 fReserve = fCount = 0; 89 SkDEBUGCODE(fData = NULL;) 90 return array; 91 } 92 isEmpty()93 bool isEmpty() const { return fCount == 0; } 94 95 /** 96 * Return the number of elements in the array 97 */ count()98 int count() const { return (int)fCount; } 99 100 /** 101 * return the number of bytes in the array: count * sizeof(T) 102 */ bytes()103 size_t bytes() const { return fCount * sizeof(T); } 104 begin()105 T* begin() const { return fArray; } end()106 T* end() const { return fArray ? fArray + fCount : NULL; } 107 T& operator[](int index) const { 108 SkASSERT((unsigned)index < fCount); 109 return fArray[index]; 110 } 111 getAt(int index)112 T& getAt(int index) const { 113 return (*this)[index]; 114 } 115 reset()116 void reset() { 117 if (fArray) { 118 sk_free(fArray); 119 fArray = NULL; 120 #ifdef SK_DEBUG 121 fData = NULL; 122 #endif 123 fReserve = fCount = 0; 124 } else { 125 SkASSERT(fReserve == 0 && fCount == 0); 126 } 127 } 128 rewind()129 void rewind() { 130 // same as setCount(0) 131 fCount = 0; 132 } 133 setCount(size_t count)134 void setCount(size_t count) { 135 if (count > fReserve) { 136 this->growBy(count - fCount); 137 } else { 138 fCount = count; 139 } 140 } 141 setReserve(size_t reserve)142 void setReserve(size_t reserve) { 143 if (reserve > fReserve) { 144 SkASSERT(reserve > fCount); 145 size_t count = fCount; 146 this->growBy(reserve - fCount); 147 fCount = count; 148 } 149 } 150 prepend()151 T* prepend() { 152 this->growBy(1); 153 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T)); 154 return fArray; 155 } 156 append()157 T* append() { 158 return this->append(1, NULL); 159 } 160 T* append(size_t count, const T* src = NULL) { 161 size_t oldCount = fCount; 162 if (count) { 163 SkASSERT(src == NULL || fArray == NULL || 164 src + count <= fArray || fArray + oldCount <= src); 165 166 this->growBy(count); 167 if (src) { 168 memcpy(fArray + oldCount, src, sizeof(T) * count); 169 } 170 } 171 return fArray + oldCount; 172 } 173 appendClear()174 T* appendClear() { 175 T* result = this->append(); 176 *result = 0; 177 return result; 178 } 179 insert(size_t index)180 T* insert(size_t index) { 181 return this->insert(index, 1, NULL); 182 } 183 T* insert(size_t index, size_t count, const T* src = NULL) { 184 SkASSERT(count); 185 SkASSERT(index <= fCount); 186 size_t oldCount = fCount; 187 this->growBy(count); 188 T* dst = fArray + index; 189 memmove(dst + count, dst, sizeof(T) * (oldCount - index)); 190 if (src) { 191 memcpy(dst, src, sizeof(T) * count); 192 } 193 return dst; 194 } 195 196 void remove(size_t index, size_t count = 1) { 197 SkASSERT(index + count <= fCount); 198 fCount = fCount - count; 199 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index)); 200 } 201 removeShuffle(size_t index)202 void removeShuffle(size_t index) { 203 SkASSERT(index < fCount); 204 size_t newCount = fCount - 1; 205 fCount = newCount; 206 if (index != newCount) { 207 memcpy(fArray + index, fArray + newCount, sizeof(T)); 208 } 209 } 210 find(const T & elem)211 int find(const T& elem) const { 212 const T* iter = fArray; 213 const T* stop = fArray + fCount; 214 215 for (; iter < stop; iter++) { 216 if (*iter == elem) { 217 return (int) (iter - fArray); 218 } 219 } 220 return -1; 221 } 222 rfind(const T & elem)223 int rfind(const T& elem) const { 224 const T* iter = fArray + fCount; 225 const T* stop = fArray; 226 227 while (iter > stop) { 228 if (*--iter == elem) { 229 return iter - stop; 230 } 231 } 232 return -1; 233 } 234 235 /** 236 * Returns true iff the array contains this element. 237 */ contains(const T & elem)238 bool contains(const T& elem) const { 239 return (this->find(elem) >= 0); 240 } 241 242 /** 243 * Copies up to max elements into dst. The number of items copied is 244 * capped by count - index. The actual number copied is returned. 245 */ copyRange(T * dst,size_t index,int max)246 int copyRange(T* dst, size_t index, int max) const { 247 SkASSERT(max >= 0); 248 SkASSERT(!max || dst); 249 if (index >= fCount) { 250 return 0; 251 } 252 int count = SkMin32(max, fCount - index); 253 memcpy(dst, fArray + index, sizeof(T) * count); 254 return count; 255 } 256 copy(T * dst)257 void copy(T* dst) const { 258 this->copyRange(0, fCount, dst); 259 } 260 261 // routines to treat the array like a stack push()262 T* push() { return this->append(); } push(const T & elem)263 void push(const T& elem) { *this->append() = elem; } top()264 const T& top() const { return (*this)[fCount - 1]; } top()265 T& top() { return (*this)[fCount - 1]; } pop(T * elem)266 void pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; } pop()267 void pop() { --fCount; } 268 deleteAll()269 void deleteAll() { 270 T* iter = fArray; 271 T* stop = fArray + fCount; 272 while (iter < stop) { 273 SkDELETE (*iter); 274 iter += 1; 275 } 276 this->reset(); 277 } 278 freeAll()279 void freeAll() { 280 T* iter = fArray; 281 T* stop = fArray + fCount; 282 while (iter < stop) { 283 sk_free(*iter); 284 iter += 1; 285 } 286 this->reset(); 287 } 288 unrefAll()289 void unrefAll() { 290 T* iter = fArray; 291 T* stop = fArray + fCount; 292 while (iter < stop) { 293 (*iter)->unref(); 294 iter += 1; 295 } 296 this->reset(); 297 } 298 safeUnrefAll()299 void safeUnrefAll() { 300 T* iter = fArray; 301 T* stop = fArray + fCount; 302 while (iter < stop) { 303 SkSafeUnref(*iter); 304 iter += 1; 305 } 306 this->reset(); 307 } 308 visitAll(void visitor (T &))309 void visitAll(void visitor(T&)) const { 310 T* stop = this->end(); 311 for (T* curr = this->begin(); curr < stop; curr++) { 312 if (*curr) { 313 visitor(*curr); 314 } 315 } 316 } 317 318 #ifdef SK_DEBUG validate()319 void validate() const { 320 SkASSERT((fReserve == 0 && fArray == NULL) || 321 (fReserve > 0 && fArray != NULL)); 322 SkASSERT(fCount <= fReserve); 323 SkASSERT(fData == (ArrayT*)fArray); 324 } 325 #endif 326 327 private: 328 #ifdef SK_DEBUG 329 enum { 330 kDebugArraySize = 16 331 }; 332 typedef T ArrayT[kDebugArraySize]; 333 ArrayT* fData; 334 #endif 335 T* fArray; 336 size_t fReserve, fCount; 337 growBy(size_t extra)338 void growBy(size_t extra) { 339 SkASSERT(extra); 340 341 if (fCount + extra > fReserve) { 342 size_t size = fCount + extra + 4; 343 size += size >> 2; 344 345 fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T)); 346 #ifdef SK_DEBUG 347 fData = (ArrayT*)fArray; 348 #endif 349 fReserve = size; 350 } 351 fCount += extra; 352 } 353 }; 354 355 #endif 356