Home | History | Annotate | Download | only in core
      1 /* libs/graphics/sgl/SkDeque.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include "SkDeque.h"
     19 
     20 #define INIT_ELEM_COUNT 1  // should we let the caller set this?
     21 
     22 struct SkDeque::Head {
     23     Head*   fNext;
     24     Head*   fPrev;
     25     char*   fBegin; // start of used section in this chunk
     26     char*   fEnd;   // end of used section in this chunk
     27     char*   fStop;  // end of the allocated chunk
     28 
     29     char*       start() { return (char*)(this + 1); }
     30     const char* start() const { return (const char*)(this + 1); }
     31 
     32     void init(size_t size) {
     33         fNext   = fPrev = NULL;
     34         fBegin  = fEnd = NULL;
     35         fStop   = (char*)this + size;
     36     }
     37 };
     38 
     39 SkDeque::SkDeque(size_t elemSize)
     40         : fElemSize(elemSize), fInitialStorage(NULL), fCount(0) {
     41     fFront = fBack = NULL;
     42 }
     43 
     44 SkDeque::SkDeque(size_t elemSize, void* storage, size_t storageSize)
     45         : fElemSize(elemSize), fInitialStorage(storage), fCount(0) {
     46     SkASSERT(storageSize == 0 || storage != NULL);
     47 
     48     if (storageSize >= sizeof(Head) + elemSize) {
     49         fFront = (Head*)storage;
     50         fFront->init(storageSize);
     51     } else {
     52         fFront = NULL;
     53     }
     54     fBack = fFront;
     55 }
     56 
     57 SkDeque::~SkDeque() {
     58     Head* head = fFront;
     59     Head* initialHead = (Head*)fInitialStorage;
     60 
     61     while (head) {
     62         Head* next = head->fNext;
     63         if (head != initialHead) {
     64             sk_free(head);
     65         }
     66         head = next;
     67     }
     68 }
     69 
     70 const void* SkDeque::front() const {
     71     Head* front = fFront;
     72 
     73     if (NULL == front) {
     74         return NULL;
     75     }
     76     if (NULL == front->fBegin) {
     77         front = front->fNext;
     78         if (NULL == front) {
     79             return NULL;
     80         }
     81     }
     82     SkASSERT(front->fBegin);
     83     return front->fBegin;
     84 }
     85 
     86 const void* SkDeque::back() const {
     87     Head* back = fBack;
     88 
     89     if (NULL == back) {
     90         return NULL;
     91     }
     92     if (NULL == back->fEnd) {  // marked as deleted
     93         back = back->fPrev;
     94         if (NULL == back) {
     95             return NULL;
     96         }
     97     }
     98     SkASSERT(back->fEnd);
     99     return back->fEnd - fElemSize;
    100 }
    101 
    102 void* SkDeque::push_front() {
    103     fCount += 1;
    104 
    105     if (NULL == fFront) {
    106         fFront = (Head*)sk_malloc_throw(sizeof(Head) +
    107                                         INIT_ELEM_COUNT * fElemSize);
    108         fFront->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
    109         fBack = fFront;     // update our linklist
    110     }
    111 
    112     Head*   first = fFront;
    113     char*   begin;
    114 
    115     if (NULL == first->fBegin) {
    116     INIT_CHUNK:
    117         first->fEnd = first->fStop;
    118         begin = first->fStop - fElemSize;
    119     } else {
    120         begin = first->fBegin - fElemSize;
    121         if (begin < first->start()) {    // no more room in this chunk
    122             // should we alloc more as we accumulate more elements?
    123             size_t  size = sizeof(Head) + INIT_ELEM_COUNT * fElemSize;
    124 
    125             first = (Head*)sk_malloc_throw(size);
    126             first->init(size);
    127             first->fNext = fFront;
    128             fFront->fPrev = first;
    129             fFront = first;
    130             goto INIT_CHUNK;
    131         }
    132     }
    133 
    134     first->fBegin = begin;
    135     return begin;
    136 }
    137 
    138 void* SkDeque::push_back() {
    139     fCount += 1;
    140 
    141     if (NULL == fBack) {
    142         fBack = (Head*)sk_malloc_throw(sizeof(Head) +
    143                                        INIT_ELEM_COUNT * fElemSize);
    144         fBack->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
    145         fFront = fBack; // update our linklist
    146     }
    147 
    148     Head*   last = fBack;
    149     char*   end;
    150 
    151     if (NULL == last->fBegin) {
    152     INIT_CHUNK:
    153         last->fBegin = last->start();
    154         end = last->fBegin + fElemSize;
    155     } else {
    156         end = last->fEnd + fElemSize;
    157         if (end > last->fStop) {  // no more room in this chunk
    158             // should we alloc more as we accumulate more elements?
    159             size_t  size = sizeof(Head) + INIT_ELEM_COUNT * fElemSize;
    160 
    161             last = (Head*)sk_malloc_throw(size);
    162             last->init(size);
    163             last->fPrev = fBack;
    164             fBack->fNext = last;
    165             fBack = last;
    166             goto INIT_CHUNK;
    167         }
    168     }
    169 
    170     last->fEnd = end;
    171     return end - fElemSize;
    172 }
    173 
    174 void SkDeque::pop_front() {
    175     SkASSERT(fCount > 0);
    176     fCount -= 1;
    177 
    178     Head*   first = fFront;
    179 
    180     SkASSERT(first != NULL);
    181 
    182     if (first->fBegin == NULL) {  // we were marked empty from before
    183         first = first->fNext;
    184         first->fPrev = NULL;
    185         sk_free(fFront);
    186         fFront = first;
    187         SkASSERT(first != NULL);    // else we popped too far
    188     }
    189 
    190     char* begin = first->fBegin + fElemSize;
    191     SkASSERT(begin <= first->fEnd);
    192 
    193     if (begin < fFront->fEnd) {
    194         first->fBegin = begin;
    195     } else {
    196         first->fBegin = first->fEnd = NULL;  // mark as empty
    197     }
    198 }
    199 
    200 void SkDeque::pop_back() {
    201     SkASSERT(fCount > 0);
    202     fCount -= 1;
    203 
    204     Head* last = fBack;
    205 
    206     SkASSERT(last != NULL);
    207 
    208     if (last->fEnd == NULL) {  // we were marked empty from before
    209         last = last->fPrev;
    210         last->fNext = NULL;
    211         sk_free(fBack);
    212         fBack = last;
    213         SkASSERT(last != NULL);  // else we popped too far
    214     }
    215 
    216     char* end = last->fEnd - fElemSize;
    217     SkASSERT(end >= last->fBegin);
    218 
    219     if (end > last->fBegin) {
    220         last->fEnd = end;
    221     } else {
    222         last->fBegin = last->fEnd = NULL;    // mark as empty
    223     }
    224 }
    225 
    226 ///////////////////////////////////////////////////////////////////////////////
    227 
    228 SkDeque::F2BIter::F2BIter() {
    229     fPos = NULL;
    230 }
    231 
    232 SkDeque::F2BIter::F2BIter(const SkDeque& d) {
    233     this->reset(d);
    234 }
    235 
    236 void* SkDeque::F2BIter::next() {
    237     char* pos = fPos;
    238 
    239     if (pos) {   // if we were valid, try to move to the next setting
    240         char* next = pos + fElemSize;
    241         SkASSERT(next <= fHead->fEnd);
    242         if (next == fHead->fEnd) { // exhausted this chunk, move to next
    243             do {
    244                 fHead = fHead->fNext;
    245             } while (fHead != NULL && fHead->fBegin == NULL);
    246             next = fHead ? fHead->fBegin : NULL;
    247         }
    248         fPos = next;
    249     }
    250     return pos;
    251 }
    252 
    253 void SkDeque::F2BIter::reset(const SkDeque& d) {
    254     fElemSize = d.fElemSize;
    255     fHead = d.fFront;
    256     while (fHead != NULL && fHead->fBegin == NULL) {
    257         fHead = fHead->fNext;
    258     }
    259     fPos = fHead ? fHead->fBegin : NULL;
    260 }
    261