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 
     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      */
     85     T* detach() {
     86         T* array = fArray;
     87         fArray = NULL;
     88         fReserve = fCount = 0;
     89         SkDEBUGCODE(fData = NULL;)
     90         return array;
     91     }
     92 
     93     bool isEmpty() const { return fCount == 0; }
     94 
     95     /**
     96      *  Return the number of elements in the array
     97      */
     98     int count() const { return (int)fCount; }
     99 
    100     /**
    101      *  return the number of bytes in the array: count * sizeof(T)
    102      */
    103     size_t bytes() const { return fCount * sizeof(T); }
    104 
    105     T*  begin() const { return fArray; }
    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 
    112     T&  getAt(int index) const {
    113         return (*this)[index];
    114     }
    115 
    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 
    129     void rewind() {
    130         // same as setCount(0)
    131         fCount = 0;
    132     }
    133 
    134     void setCount(size_t count) {
    135         if (count > fReserve) {
    136             this->growBy(count - fCount);
    137         } else {
    138             fCount = count;
    139         }
    140     }
    141 
    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 
    151     T* prepend() {
    152         this->growBy(1);
    153         memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
    154         return fArray;
    155     }
    156 
    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 
    174     T* appendClear() {
    175         T* result = this->append();
    176         *result = 0;
    177         return result;
    178     }
    179 
    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 
    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 
    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 
    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      */
    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      */
    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 
    257     void copy(T* dst) const {
    258         this->copyRange(0, fCount, dst);
    259     }
    260 
    261     // routines to treat the array like a stack
    262     T*          push() { return this->append(); }
    263     void        push(const T& elem) { *this->append() = elem; }
    264     const T&    top() const { return (*this)[fCount - 1]; }
    265     T&          top() { return (*this)[fCount - 1]; }
    266     void        pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; }
    267     void        pop() { --fCount; }
    268 
    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 
    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 
    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 
    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 
    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
    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 
    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