/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkDeque.h" #define INIT_ELEM_COUNT 1 // should we let the caller set this? struct SkDeque::Head { Head* fNext; Head* fPrev; char* fBegin; // start of used section in this chunk char* fEnd; // end of used section in this chunk char* fStop; // end of the allocated chunk char* start() { return (char*)(this + 1); } const char* start() const { return (const char*)(this + 1); } void init(size_t size) { fNext = fPrev = NULL; fBegin = fEnd = NULL; fStop = (char*)this + size; } }; SkDeque::SkDeque(size_t elemSize) : fElemSize(elemSize), fInitialStorage(NULL), fCount(0) { fFront = fBack = NULL; } SkDeque::SkDeque(size_t elemSize, void* storage, size_t storageSize) : fElemSize(elemSize), fInitialStorage(storage), fCount(0) { SkASSERT(storageSize == 0 || storage != NULL); if (storageSize >= sizeof(Head) + elemSize) { fFront = (Head*)storage; fFront->init(storageSize); } else { fFront = NULL; } fBack = fFront; } SkDeque::~SkDeque() { Head* head = fFront; Head* initialHead = (Head*)fInitialStorage; while (head) { Head* next = head->fNext; if (head != initialHead) { sk_free(head); } head = next; } } const void* SkDeque::front() const { Head* front = fFront; if (NULL == front) { return NULL; } if (NULL == front->fBegin) { front = front->fNext; if (NULL == front) { return NULL; } } SkASSERT(front->fBegin); return front->fBegin; } const void* SkDeque::back() const { Head* back = fBack; if (NULL == back) { return NULL; } if (NULL == back->fEnd) { // marked as deleted back = back->fPrev; if (NULL == back) { return NULL; } } SkASSERT(back->fEnd); return back->fEnd - fElemSize; } void* SkDeque::push_front() { fCount += 1; if (NULL == fFront) { fFront = (Head*)sk_malloc_throw(sizeof(Head) + INIT_ELEM_COUNT * fElemSize); fFront->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize); fBack = fFront; // update our linklist } Head* first = fFront; char* begin; if (NULL == first->fBegin) { INIT_CHUNK: first->fEnd = first->fStop; begin = first->fStop - fElemSize; } else { begin = first->fBegin - fElemSize; if (begin < first->start()) { // no more room in this chunk // should we alloc more as we accumulate more elements? size_t size = sizeof(Head) + INIT_ELEM_COUNT * fElemSize; first = (Head*)sk_malloc_throw(size); first->init(size); first->fNext = fFront; fFront->fPrev = first; fFront = first; goto INIT_CHUNK; } } first->fBegin = begin; return begin; } void* SkDeque::push_back() { fCount += 1; if (NULL == fBack) { fBack = (Head*)sk_malloc_throw(sizeof(Head) + INIT_ELEM_COUNT * fElemSize); fBack->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize); fFront = fBack; // update our linklist } Head* last = fBack; char* end; if (NULL == last->fBegin) { INIT_CHUNK: last->fBegin = last->start(); end = last->fBegin + fElemSize; } else { end = last->fEnd + fElemSize; if (end > last->fStop) { // no more room in this chunk // should we alloc more as we accumulate more elements? size_t size = sizeof(Head) + INIT_ELEM_COUNT * fElemSize; last = (Head*)sk_malloc_throw(size); last->init(size); last->fPrev = fBack; fBack->fNext = last; fBack = last; goto INIT_CHUNK; } } last->fEnd = end; return end - fElemSize; } void SkDeque::pop_front() { SkASSERT(fCount > 0); fCount -= 1; Head* first = fFront; SkASSERT(first != NULL); if (first->fBegin == NULL) { // we were marked empty from before first = first->fNext; first->fPrev = NULL; sk_free(fFront); fFront = first; SkASSERT(first != NULL); // else we popped too far } char* begin = first->fBegin + fElemSize; SkASSERT(begin <= first->fEnd); if (begin < fFront->fEnd) { first->fBegin = begin; } else { first->fBegin = first->fEnd = NULL; // mark as empty } } void SkDeque::pop_back() { SkASSERT(fCount > 0); fCount -= 1; Head* last = fBack; SkASSERT(last != NULL); if (last->fEnd == NULL) { // we were marked empty from before last = last->fPrev; last->fNext = NULL; sk_free(fBack); fBack = last; SkASSERT(last != NULL); // else we popped too far } char* end = last->fEnd - fElemSize; SkASSERT(end >= last->fBegin); if (end > last->fBegin) { last->fEnd = end; } else { last->fBegin = last->fEnd = NULL; // mark as empty } } /////////////////////////////////////////////////////////////////////////////// SkDeque::F2BIter::F2BIter() : fHead(NULL), fPos(NULL), fElemSize(0) {} SkDeque::F2BIter::F2BIter(const SkDeque& d) { this->reset(d); } void* SkDeque::F2BIter::next() { char* pos = fPos; if (pos) { // if we were valid, try to move to the next setting char* next = pos + fElemSize; SkASSERT(next <= fHead->fEnd); if (next == fHead->fEnd) { // exhausted this chunk, move to next do { fHead = fHead->fNext; } while (fHead != NULL && fHead->fBegin == NULL); next = fHead ? fHead->fBegin : NULL; } fPos = next; } return pos; } void SkDeque::F2BIter::reset(const SkDeque& d) { fElemSize = d.fElemSize; fHead = d.fFront; while (fHead != NULL && fHead->fBegin == NULL) { fHead = fHead->fNext; } fPos = fHead ? fHead->fBegin : NULL; }