Home | History | Annotate | Download | only in core
      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:
     17     SkTDArray() {
     18         fReserve = fCount = 0;
     19         fArray = NULL;
     20 #ifdef SK_DEBUG
     21         fData = NULL;
     22 #endif
     23     }
     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     }
     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     }
     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     friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) {
     73         return !(a == b);
     74     }
     75 
     76     void swap(SkTDArray<T>& other) {
     77         SkTSwap(fArray, other.fArray);
     78 #ifdef SK_DEBUG
     79         SkTSwap(fData, other.fData);
     80 #endif
     81         SkTSwap(fReserve, other.fReserve);
     82         SkTSwap(fCount, other.fCount);
     83     }
     84 
     85     /** Return a ptr to the array of data, to be freed with sk_free. This also
     86         resets the SkTDArray to be empty.
     87      */
     88     T* detach() {
     89         T* array = fArray;
     90         fArray = NULL;
     91         fReserve = fCount = 0;
     92         SkDEBUGCODE(fData = NULL;)
     93         return array;
     94     }
     95 
     96     bool isEmpty() const { return fCount == 0; }
     97 
     98     /**
     99      *  Return the number of elements in the array
    100      */
    101     int count() const { return (int)fCount; }
    102 
    103     /**
    104      *  return the number of bytes in the array: count * sizeof(T)
    105      */
    106     size_t bytes() const { return fCount * sizeof(T); }
    107 
    108     T*  begin() { return fArray; }
    109     const T*  begin() const { return fArray; }
    110     T*  end() { return fArray ? fArray + fCount : NULL; }
    111     const T*  end() const { return fArray ? fArray + fCount : NULL; }
    112 
    113     T&  operator[](int index) {
    114         SkASSERT((unsigned)index < fCount);
    115         return fArray[index];
    116     }
    117     const T&  operator[](int index) const {
    118         SkASSERT((unsigned)index < fCount);
    119         return fArray[index];
    120     }
    121 
    122     T&  getAt(int index)  {
    123         return (*this)[index];
    124     }
    125     const T&  getAt(int index) const {
    126         return (*this)[index];
    127     }
    128 
    129     void reset() {
    130         if (fArray) {
    131             sk_free(fArray);
    132             fArray = NULL;
    133 #ifdef SK_DEBUG
    134             fData = NULL;
    135 #endif
    136             fReserve = fCount = 0;
    137         } else {
    138             SkASSERT(fReserve == 0 && fCount == 0);
    139         }
    140     }
    141 
    142     void rewind() {
    143         // same as setCount(0)
    144         fCount = 0;
    145     }
    146 
    147     void setCount(size_t count) {
    148         if (count > fReserve) {
    149             this->growBy(count - fCount);
    150         } else {
    151             fCount = count;
    152         }
    153     }
    154 
    155     void setReserve(size_t reserve) {
    156         if (reserve > fReserve) {
    157             SkASSERT(reserve > fCount);
    158             size_t count = fCount;
    159             this->growBy(reserve - fCount);
    160             fCount = count;
    161         }
    162     }
    163 
    164     T* prepend() {
    165         this->growBy(1);
    166         memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
    167         return fArray;
    168     }
    169 
    170     T* append() {
    171         return this->append(1, NULL);
    172     }
    173     T* append(size_t count, const T* src = NULL) {
    174         size_t oldCount = fCount;
    175         if (count)  {
    176             SkASSERT(src == NULL || fArray == NULL ||
    177                     src + count <= fArray || fArray + oldCount <= src);
    178 
    179             this->growBy(count);
    180             if (src) {
    181                 memcpy(fArray + oldCount, src, sizeof(T) * count);
    182             }
    183         }
    184         return fArray + oldCount;
    185     }
    186 
    187     T* appendClear() {
    188         T* result = this->append();
    189         *result = 0;
    190         return result;
    191     }
    192 
    193     T* insert(size_t index) {
    194         return this->insert(index, 1, NULL);
    195     }
    196     T* insert(size_t index, size_t count, const T* src = NULL) {
    197         SkASSERT(count);
    198         SkASSERT(index <= fCount);
    199         size_t oldCount = fCount;
    200         this->growBy(count);
    201         T* dst = fArray + index;
    202         memmove(dst + count, dst, sizeof(T) * (oldCount - index));
    203         if (src) {
    204             memcpy(dst, src, sizeof(T) * count);
    205         }
    206         return dst;
    207     }
    208 
    209     void remove(size_t index, size_t count = 1) {
    210         SkASSERT(index + count <= fCount);
    211         fCount = fCount - count;
    212         memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
    213     }
    214 
    215     void removeShuffle(size_t index) {
    216         SkASSERT(index < fCount);
    217         size_t newCount = fCount - 1;
    218         fCount = newCount;
    219         if (index != newCount) {
    220             memcpy(fArray + index, fArray + newCount, sizeof(T));
    221         }
    222     }
    223 
    224     int find(const T& elem) const {
    225         const T* iter = fArray;
    226         const T* stop = fArray + fCount;
    227 
    228         for (; iter < stop; iter++) {
    229             if (*iter == elem) {
    230                 return (int) (iter - fArray);
    231             }
    232         }
    233         return -1;
    234     }
    235 
    236     int rfind(const T& elem) const {
    237         const T* iter = fArray + fCount;
    238         const T* stop = fArray;
    239 
    240         while (iter > stop) {
    241             if (*--iter == elem) {
    242                 return iter - stop;
    243             }
    244         }
    245         return -1;
    246     }
    247 
    248     /**
    249      * Returns true iff the array contains this element.
    250      */
    251     bool contains(const T& elem) const {
    252         return (this->find(elem) >= 0);
    253     }
    254 
    255     /**
    256      * Copies up to max elements into dst. The number of items copied is
    257      * capped by count - index. The actual number copied is returned.
    258      */
    259     int copyRange(T* dst, size_t index, int max) const {
    260         SkASSERT(max >= 0);
    261         SkASSERT(!max || dst);
    262         if (index >= fCount) {
    263             return 0;
    264         }
    265         int count = SkMin32(max, fCount - index);
    266         memcpy(dst, fArray + index, sizeof(T) * count);
    267         return count;
    268     }
    269 
    270     void copy(T* dst) const {
    271         this->copyRange(dst, 0, fCount);
    272     }
    273 
    274     // routines to treat the array like a stack
    275     T*          push() { return this->append(); }
    276     void        push(const T& elem) { *this->append() = elem; }
    277     const T&    top() const { return (*this)[fCount - 1]; }
    278     T&          top() { return (*this)[fCount - 1]; }
    279     void        pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; }
    280     void        pop() { --fCount; }
    281 
    282     void deleteAll() {
    283         T*  iter = fArray;
    284         T*  stop = fArray + fCount;
    285         while (iter < stop) {
    286             SkDELETE (*iter);
    287             iter += 1;
    288         }
    289         this->reset();
    290     }
    291 
    292     void freeAll() {
    293         T*  iter = fArray;
    294         T*  stop = fArray + fCount;
    295         while (iter < stop) {
    296             sk_free(*iter);
    297             iter += 1;
    298         }
    299         this->reset();
    300     }
    301 
    302     void unrefAll() {
    303         T*  iter = fArray;
    304         T*  stop = fArray + fCount;
    305         while (iter < stop) {
    306             (*iter)->unref();
    307             iter += 1;
    308         }
    309         this->reset();
    310     }
    311 
    312     void safeUnrefAll() {
    313         T*  iter = fArray;
    314         T*  stop = fArray + fCount;
    315         while (iter < stop) {
    316             SkSafeUnref(*iter);
    317             iter += 1;
    318         }
    319         this->reset();
    320     }
    321 
    322     void visitAll(void visitor(T&)) {
    323         T* stop = this->end();
    324         for (T* curr = this->begin(); curr < stop; curr++) {
    325             if (*curr) {
    326                 visitor(*curr);
    327             }
    328         }
    329     }
    330 
    331 #ifdef SK_DEBUG
    332     void validate() const {
    333         SkASSERT((fReserve == 0 && fArray == NULL) ||
    334                  (fReserve > 0 && fArray != NULL));
    335         SkASSERT(fCount <= fReserve);
    336         SkASSERT(fData == (ArrayT*)fArray);
    337     }
    338 #endif
    339 
    340 private:
    341 #ifdef SK_DEBUG
    342     enum {
    343         kDebugArraySize = 16
    344     };
    345     typedef T ArrayT[kDebugArraySize];
    346     ArrayT* fData;
    347 #endif
    348     T*      fArray;
    349     size_t  fReserve, fCount;
    350 
    351     void growBy(size_t extra) {
    352         SkASSERT(extra);
    353 
    354         if (fCount + extra > fReserve) {
    355             size_t size = fCount + extra + 4;
    356             size += size >> 2;
    357 
    358             fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T));
    359 #ifdef SK_DEBUG
    360             fData = (ArrayT*)fArray;
    361 #endif
    362             fReserve = size;
    363         }
    364         fCount += extra;
    365     }
    366 };
    367 
    368 #endif
    369