1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/private/SkDeque.h" 9cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_cistruct SkDeque::Block { 12cb93a386Sopenharmony_ci Block* fNext; 13cb93a386Sopenharmony_ci Block* fPrev; 14cb93a386Sopenharmony_ci char* fBegin; // start of used section in this chunk 15cb93a386Sopenharmony_ci char* fEnd; // end of used section in this chunk 16cb93a386Sopenharmony_ci char* fStop; // end of the allocated chunk 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci char* start() { return (char*)(this + 1); } 19cb93a386Sopenharmony_ci const char* start() const { return (const char*)(this + 1); } 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci void init(size_t size) { 22cb93a386Sopenharmony_ci fNext = fPrev = nullptr; 23cb93a386Sopenharmony_ci fBegin = fEnd = nullptr; 24cb93a386Sopenharmony_ci fStop = (char*)this + size; 25cb93a386Sopenharmony_ci } 26cb93a386Sopenharmony_ci}; 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciSkDeque::SkDeque(size_t elemSize, int allocCount) 29cb93a386Sopenharmony_ci : fElemSize(elemSize) 30cb93a386Sopenharmony_ci , fInitialStorage(nullptr) 31cb93a386Sopenharmony_ci , fCount(0) 32cb93a386Sopenharmony_ci , fAllocCount(allocCount) { 33cb93a386Sopenharmony_ci SkASSERT(allocCount >= 1); 34cb93a386Sopenharmony_ci fFrontBlock = fBackBlock = nullptr; 35cb93a386Sopenharmony_ci fFront = fBack = nullptr; 36cb93a386Sopenharmony_ci} 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ciSkDeque::SkDeque(size_t elemSize, void* storage, size_t storageSize, int allocCount) 39cb93a386Sopenharmony_ci : fElemSize(elemSize) 40cb93a386Sopenharmony_ci , fInitialStorage(storage) 41cb93a386Sopenharmony_ci , fCount(0) 42cb93a386Sopenharmony_ci , fAllocCount(allocCount) { 43cb93a386Sopenharmony_ci SkASSERT(storageSize == 0 || storage != nullptr); 44cb93a386Sopenharmony_ci SkASSERT(allocCount >= 1); 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci if (storageSize >= sizeof(Block) + elemSize) { 47cb93a386Sopenharmony_ci fFrontBlock = (Block*)storage; 48cb93a386Sopenharmony_ci fFrontBlock->init(storageSize); 49cb93a386Sopenharmony_ci } else { 50cb93a386Sopenharmony_ci fFrontBlock = nullptr; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci fBackBlock = fFrontBlock; 53cb93a386Sopenharmony_ci fFront = fBack = nullptr; 54cb93a386Sopenharmony_ci} 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciSkDeque::~SkDeque() { 57cb93a386Sopenharmony_ci Block* head = fFrontBlock; 58cb93a386Sopenharmony_ci Block* initialHead = (Block*)fInitialStorage; 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci while (head) { 61cb93a386Sopenharmony_ci Block* next = head->fNext; 62cb93a386Sopenharmony_ci if (head != initialHead) { 63cb93a386Sopenharmony_ci this->freeBlock(head); 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci head = next; 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci} 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_civoid* SkDeque::push_front() { 70cb93a386Sopenharmony_ci fCount += 1; 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci if (nullptr == fFrontBlock) { 73cb93a386Sopenharmony_ci fFrontBlock = this->allocateBlock(fAllocCount); 74cb93a386Sopenharmony_ci fBackBlock = fFrontBlock; // update our linklist 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci Block* first = fFrontBlock; 78cb93a386Sopenharmony_ci char* begin; 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci if (nullptr == first->fBegin) { 81cb93a386Sopenharmony_ci INIT_CHUNK: 82cb93a386Sopenharmony_ci first->fEnd = first->fStop; 83cb93a386Sopenharmony_ci begin = first->fStop - fElemSize; 84cb93a386Sopenharmony_ci } else { 85cb93a386Sopenharmony_ci begin = first->fBegin - fElemSize; 86cb93a386Sopenharmony_ci if (begin < first->start()) { // no more room in this chunk 87cb93a386Sopenharmony_ci // should we alloc more as we accumulate more elements? 88cb93a386Sopenharmony_ci first = this->allocateBlock(fAllocCount); 89cb93a386Sopenharmony_ci first->fNext = fFrontBlock; 90cb93a386Sopenharmony_ci fFrontBlock->fPrev = first; 91cb93a386Sopenharmony_ci fFrontBlock = first; 92cb93a386Sopenharmony_ci goto INIT_CHUNK; 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci first->fBegin = begin; 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci if (nullptr == fFront) { 99cb93a386Sopenharmony_ci SkASSERT(nullptr == fBack); 100cb93a386Sopenharmony_ci fFront = fBack = begin; 101cb93a386Sopenharmony_ci } else { 102cb93a386Sopenharmony_ci SkASSERT(fBack); 103cb93a386Sopenharmony_ci fFront = begin; 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci return begin; 107cb93a386Sopenharmony_ci} 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_civoid* SkDeque::push_back() { 110cb93a386Sopenharmony_ci fCount += 1; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci if (nullptr == fBackBlock) { 113cb93a386Sopenharmony_ci fBackBlock = this->allocateBlock(fAllocCount); 114cb93a386Sopenharmony_ci fFrontBlock = fBackBlock; // update our linklist 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci Block* last = fBackBlock; 118cb93a386Sopenharmony_ci char* end; 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci if (nullptr == last->fBegin) { 121cb93a386Sopenharmony_ci INIT_CHUNK: 122cb93a386Sopenharmony_ci last->fBegin = last->start(); 123cb93a386Sopenharmony_ci end = last->fBegin + fElemSize; 124cb93a386Sopenharmony_ci } else { 125cb93a386Sopenharmony_ci end = last->fEnd + fElemSize; 126cb93a386Sopenharmony_ci if (end > last->fStop) { // no more room in this chunk 127cb93a386Sopenharmony_ci // should we alloc more as we accumulate more elements? 128cb93a386Sopenharmony_ci last = this->allocateBlock(fAllocCount); 129cb93a386Sopenharmony_ci last->fPrev = fBackBlock; 130cb93a386Sopenharmony_ci fBackBlock->fNext = last; 131cb93a386Sopenharmony_ci fBackBlock = last; 132cb93a386Sopenharmony_ci goto INIT_CHUNK; 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci last->fEnd = end; 137cb93a386Sopenharmony_ci end -= fElemSize; 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci if (nullptr == fBack) { 140cb93a386Sopenharmony_ci SkASSERT(nullptr == fFront); 141cb93a386Sopenharmony_ci fFront = fBack = end; 142cb93a386Sopenharmony_ci } else { 143cb93a386Sopenharmony_ci SkASSERT(fFront); 144cb93a386Sopenharmony_ci fBack = end; 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci return end; 148cb93a386Sopenharmony_ci} 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_civoid SkDeque::pop_front() { 151cb93a386Sopenharmony_ci SkASSERT(fCount > 0); 152cb93a386Sopenharmony_ci fCount -= 1; 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ci Block* first = fFrontBlock; 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci SkASSERT(first != nullptr); 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci if (first->fBegin == nullptr) { // we were marked empty from before 159cb93a386Sopenharmony_ci first = first->fNext; 160cb93a386Sopenharmony_ci SkASSERT(first != nullptr); // else we popped too far 161cb93a386Sopenharmony_ci first->fPrev = nullptr; 162cb93a386Sopenharmony_ci this->freeBlock(fFrontBlock); 163cb93a386Sopenharmony_ci fFrontBlock = first; 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci char* begin = first->fBegin + fElemSize; 167cb93a386Sopenharmony_ci SkASSERT(begin <= first->fEnd); 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci if (begin < fFrontBlock->fEnd) { 170cb93a386Sopenharmony_ci first->fBegin = begin; 171cb93a386Sopenharmony_ci SkASSERT(first->fBegin); 172cb93a386Sopenharmony_ci fFront = first->fBegin; 173cb93a386Sopenharmony_ci } else { 174cb93a386Sopenharmony_ci first->fBegin = first->fEnd = nullptr; // mark as empty 175cb93a386Sopenharmony_ci if (nullptr == first->fNext) { 176cb93a386Sopenharmony_ci fFront = fBack = nullptr; 177cb93a386Sopenharmony_ci } else { 178cb93a386Sopenharmony_ci SkASSERT(first->fNext->fBegin); 179cb93a386Sopenharmony_ci fFront = first->fNext->fBegin; 180cb93a386Sopenharmony_ci } 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci} 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_civoid SkDeque::pop_back() { 185cb93a386Sopenharmony_ci SkASSERT(fCount > 0); 186cb93a386Sopenharmony_ci fCount -= 1; 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci Block* last = fBackBlock; 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci SkASSERT(last != nullptr); 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci if (last->fEnd == nullptr) { // we were marked empty from before 193cb93a386Sopenharmony_ci last = last->fPrev; 194cb93a386Sopenharmony_ci SkASSERT(last != nullptr); // else we popped too far 195cb93a386Sopenharmony_ci last->fNext = nullptr; 196cb93a386Sopenharmony_ci this->freeBlock(fBackBlock); 197cb93a386Sopenharmony_ci fBackBlock = last; 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci char* end = last->fEnd - fElemSize; 201cb93a386Sopenharmony_ci SkASSERT(end >= last->fBegin); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci if (end > last->fBegin) { 204cb93a386Sopenharmony_ci last->fEnd = end; 205cb93a386Sopenharmony_ci SkASSERT(last->fEnd); 206cb93a386Sopenharmony_ci fBack = last->fEnd - fElemSize; 207cb93a386Sopenharmony_ci } else { 208cb93a386Sopenharmony_ci last->fBegin = last->fEnd = nullptr; // mark as empty 209cb93a386Sopenharmony_ci if (nullptr == last->fPrev) { 210cb93a386Sopenharmony_ci fFront = fBack = nullptr; 211cb93a386Sopenharmony_ci } else { 212cb93a386Sopenharmony_ci SkASSERT(last->fPrev->fEnd); 213cb93a386Sopenharmony_ci fBack = last->fPrev->fEnd - fElemSize; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci} 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ciint SkDeque::numBlocksAllocated() const { 219cb93a386Sopenharmony_ci int numBlocks = 0; 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci for (const Block* temp = fFrontBlock; temp; temp = temp->fNext) { 222cb93a386Sopenharmony_ci ++numBlocks; 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci return numBlocks; 226cb93a386Sopenharmony_ci} 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ciSkDeque::Block* SkDeque::allocateBlock(int allocCount) { 229cb93a386Sopenharmony_ci Block* newBlock = (Block*)sk_malloc_throw(sizeof(Block) + allocCount * fElemSize); 230cb93a386Sopenharmony_ci newBlock->init(sizeof(Block) + allocCount * fElemSize); 231cb93a386Sopenharmony_ci return newBlock; 232cb93a386Sopenharmony_ci} 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_civoid SkDeque::freeBlock(Block* block) { 235cb93a386Sopenharmony_ci sk_free(block); 236cb93a386Sopenharmony_ci} 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ciSkDeque::Iter::Iter() : fCurBlock(nullptr), fPos(nullptr), fElemSize(0) {} 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ciSkDeque::Iter::Iter(const SkDeque& d, IterStart startLoc) { 243cb93a386Sopenharmony_ci this->reset(d, startLoc); 244cb93a386Sopenharmony_ci} 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci// Due to how reset and next work, next actually returns the current element 247cb93a386Sopenharmony_ci// pointed to by fPos and then updates fPos to point to the next one. 248cb93a386Sopenharmony_civoid* SkDeque::Iter::next() { 249cb93a386Sopenharmony_ci char* pos = fPos; 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci if (pos) { // if we were valid, try to move to the next setting 252cb93a386Sopenharmony_ci char* next = pos + fElemSize; 253cb93a386Sopenharmony_ci SkASSERT(next <= fCurBlock->fEnd); 254cb93a386Sopenharmony_ci if (next == fCurBlock->fEnd) { // exhausted this chunk, move to next 255cb93a386Sopenharmony_ci do { 256cb93a386Sopenharmony_ci fCurBlock = fCurBlock->fNext; 257cb93a386Sopenharmony_ci } while (fCurBlock != nullptr && fCurBlock->fBegin == nullptr); 258cb93a386Sopenharmony_ci next = fCurBlock ? fCurBlock->fBegin : nullptr; 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci fPos = next; 261cb93a386Sopenharmony_ci } 262cb93a386Sopenharmony_ci return pos; 263cb93a386Sopenharmony_ci} 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ci// Like next, prev actually returns the current element pointed to by fPos and 266cb93a386Sopenharmony_ci// then makes fPos point to the previous element. 267cb93a386Sopenharmony_civoid* SkDeque::Iter::prev() { 268cb93a386Sopenharmony_ci char* pos = fPos; 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci if (pos) { // if we were valid, try to move to the prior setting 271cb93a386Sopenharmony_ci char* prev = pos - fElemSize; 272cb93a386Sopenharmony_ci SkASSERT(prev >= fCurBlock->fBegin - fElemSize); 273cb93a386Sopenharmony_ci if (prev < fCurBlock->fBegin) { // exhausted this chunk, move to prior 274cb93a386Sopenharmony_ci do { 275cb93a386Sopenharmony_ci fCurBlock = fCurBlock->fPrev; 276cb93a386Sopenharmony_ci } while (fCurBlock != nullptr && fCurBlock->fEnd == nullptr); 277cb93a386Sopenharmony_ci prev = fCurBlock ? fCurBlock->fEnd - fElemSize : nullptr; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci fPos = prev; 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci return pos; 282cb93a386Sopenharmony_ci} 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci// reset works by skipping through the spare blocks at the start (or end) 285cb93a386Sopenharmony_ci// of the doubly linked list until a non-empty one is found. The fPos 286cb93a386Sopenharmony_ci// member is then set to the first (or last) element in the block. If 287cb93a386Sopenharmony_ci// there are no elements in the deque both fCurBlock and fPos will come 288cb93a386Sopenharmony_ci// out of this routine nullptr. 289cb93a386Sopenharmony_civoid SkDeque::Iter::reset(const SkDeque& d, IterStart startLoc) { 290cb93a386Sopenharmony_ci fElemSize = d.fElemSize; 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci if (kFront_IterStart == startLoc) { 293cb93a386Sopenharmony_ci // initialize the iterator to start at the front 294cb93a386Sopenharmony_ci fCurBlock = d.fFrontBlock; 295cb93a386Sopenharmony_ci while (fCurBlock && nullptr == fCurBlock->fBegin) { 296cb93a386Sopenharmony_ci fCurBlock = fCurBlock->fNext; 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci fPos = fCurBlock ? fCurBlock->fBegin : nullptr; 299cb93a386Sopenharmony_ci } else { 300cb93a386Sopenharmony_ci // initialize the iterator to start at the back 301cb93a386Sopenharmony_ci fCurBlock = d.fBackBlock; 302cb93a386Sopenharmony_ci while (fCurBlock && nullptr == fCurBlock->fEnd) { 303cb93a386Sopenharmony_ci fCurBlock = fCurBlock->fPrev; 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci fPos = fCurBlock ? fCurBlock->fEnd - fElemSize : nullptr; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci} 308