Home | History | Annotate | Download | only in include
      1 /*
      2     Copyright 2010 Google Inc.
      3 
      4     Licensed under the Apache License, Version 2.0 (the "License");
      5     you may not use this file except in compliance with the License.
      6     You may obtain a copy of the License at
      7 
      8          http://www.apache.org/licenses/LICENSE-2.0
      9 
     10     Unless required by applicable law or agreed to in writing, software
     11     distributed under the License is distributed on an "AS IS" BASIS,
     12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13     See the License for the specific language governing permissions and
     14     limitations under the License.
     15  */
     16 
     17 
     18 #ifndef GrAllocator_DEFINED
     19 #define GrAllocator_DEFINED
     20 
     21 #include "GrConfig.h"
     22 #include "GrTArray.h"
     23 
     24 class GrAllocator {
     25 public:
     26     virtual ~GrAllocator() {
     27         reset();
     28     }
     29 
     30     /**
     31      * Create an allocator
     32      *
     33      * @param   itemSize        the size of each item to allocate
     34      * @param   itemsPerBlock   the number of items to allocate at once
     35      * @param   initialBlock    optional memory to use for the first block.
     36      *                          Must be at least itemSize*itemsPerBlock sized.
     37      *                          Caller is responsible for freeing this memory.
     38      */
     39     GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
     40             fBlocks(fBlockInitialStorage, NUM_INIT_BLOCK_PTRS),
     41             fItemSize(itemSize),
     42             fItemsPerBlock(itemsPerBlock),
     43             fOwnFirstBlock(NULL == initialBlock),
     44             fCount(0) {
     45         GrAssert(itemsPerBlock > 0);
     46         fBlockSize = fItemSize * fItemsPerBlock;
     47         fBlocks.push_back() = initialBlock;
     48         GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
     49     }
     50 
     51     /**
     52      * Adds an item and returns pointer to it.
     53      *
     54      * @return pointer to the added item.
     55      */
     56     void* push_back() {
     57         int indexInBlock = fCount % fItemsPerBlock;
     58         // we always have at least one block
     59         if (0 == indexInBlock) {
     60             if (0 != fCount) {
     61                 fBlocks.push_back() = GrMalloc(fBlockSize);
     62             } else if (fOwnFirstBlock) {
     63                 fBlocks[0] = GrMalloc(fBlockSize);
     64             }
     65         }
     66         void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
     67                     fItemSize * indexInBlock;
     68         ++fCount;
     69         return ret;
     70     }
     71 
     72     /**
     73      * removes all added items
     74      */
     75     void reset() {
     76         int blockCount = GrMax((unsigned)1,
     77                                GrUIDivRoundUp(fCount, fItemsPerBlock));
     78         for (int i = 1; i < blockCount; ++i) {
     79             GrFree(fBlocks[i]);
     80         }
     81         if (fOwnFirstBlock) {
     82             GrFree(fBlocks[0]);
     83             fBlocks[0] = NULL;
     84         }
     85         fBlocks.pop_back_n(blockCount-1);
     86         fCount = 0;
     87     }
     88 
     89     /**
     90      * count of items
     91      */
     92     int count() const {
     93         return fCount;
     94     }
     95 
     96     /**
     97      * is the count 0
     98      */
     99     bool empty() const { return fCount == 0; }
    100 
    101     /**
    102      * access last item, only call if count() != 0
    103      */
    104     void* back() {
    105         GrAssert(fCount);
    106         return (*this)[fCount-1];
    107     }
    108 
    109     /**
    110      * access last item, only call if count() != 0
    111      */
    112     const void* back() const {
    113         GrAssert(fCount);
    114         return (*this)[fCount-1];
    115     }
    116 
    117     /**
    118      * access item by index.
    119      */
    120     void* operator[] (int i) {
    121         GrAssert(i >= 0 && i < fCount);
    122         return (char*)fBlocks[i / fItemsPerBlock] +
    123                fItemSize * (i % fItemsPerBlock);
    124     }
    125 
    126     /**
    127      * access item by index.
    128      */
    129     const void* operator[] (int i) const {
    130         GrAssert(i >= 0 && i < fCount);
    131         return (const char*)fBlocks[i / fItemsPerBlock] +
    132                fItemSize * (i % fItemsPerBlock);
    133     }
    134 
    135 private:
    136     static const int NUM_INIT_BLOCK_PTRS = 8;
    137 
    138     GrTArray<void*> fBlocks;
    139     size_t          fBlockSize;
    140     char            fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)];
    141     size_t          fItemSize;
    142     int             fItemsPerBlock;
    143     bool            fOwnFirstBlock;
    144     int             fCount;
    145 };
    146 
    147 template <typename T>
    148 class GrTAllocator {
    149 private:
    150     GrAllocator fAllocator;
    151 
    152 public:
    153     virtual ~GrTAllocator() {};
    154 
    155     /**
    156      * Create an allocator
    157      *
    158      * @param   itemsPerBlock   the number of items to allocate at once
    159      * @param   initialBlock    optional memory to use for the first block.
    160      *                          Must be at least size(T)*itemsPerBlock sized.
    161      *                          Caller is responsible for freeing this memory.
    162      */
    163     GrTAllocator(int itemsPerBlock, void* initialBlock)
    164         : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {}
    165 
    166     /**
    167      * Create an allocator using a GrAlignedTAlloc as the initial block.
    168      *
    169      * @param   initialBlock    specifies the storage for the initial block
    170      *                          and the size of subsequent blocks.
    171      */
    172     template <int N>
    173     GrTAllocator(GrAlignedSTStorage<N,T>* initialBlock)
    174         : fAllocator(sizeof(T), N, initialBlock->get()) {}
    175 
    176     /**
    177      * Adds an item and returns it.
    178      *
    179      * @return the added item.
    180      */
    181     T& push_back() {
    182         void* item = fAllocator.push_back();
    183         GrAssert(NULL != item);
    184         new (item) T;
    185         return *(T*)item;
    186     }
    187 
    188     /**
    189      * removes all added items
    190      */
    191     void reset() {
    192         int c = fAllocator.count();
    193         for (int i = 0; i < c; ++i) {
    194             ((T*)fAllocator[i])->~T();
    195         }
    196         fAllocator.reset();
    197     }
    198 
    199     /**
    200      * count of items
    201      */
    202     int count() const {
    203         return fAllocator.count();
    204     }
    205 
    206     /**
    207      * is the count 0
    208      */
    209     bool empty() const { return fAllocator.empty(); }
    210 
    211     /**
    212      * access last item, only call if count() != 0
    213      */
    214     T& back() {
    215         return *(T*)fAllocator.back();
    216     }
    217 
    218     /**
    219      * access last item, only call if count() != 0
    220      */
    221     const T& back() const {
    222         return *(const T*)fAllocator.back();
    223     }
    224 
    225     /**
    226      * access item by index.
    227      */
    228     T& operator[] (int i) {
    229         return *(T*)(fAllocator[i]);
    230     }
    231 
    232     /**
    233      * access item by index.
    234      */
    235     const T& operator[] (int i) const {
    236         return *(const T*)(fAllocator[i]);
    237     }
    238 };
    239 
    240 #endif
    241