Make SkDeque::back faster & inline

http://codereview.appspot.com/6462073/



git-svn-id: http://skia.googlecode.com/svn/trunk@5149 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2012-08-17 13:53:05 +00:00
parent 1b3ce47c7b
commit 63ae1cfb10
3 changed files with 93 additions and 70 deletions

View File

@ -12,6 +12,17 @@
#include "SkTypes.h"
/*
* The deque class works by blindly creating memory space of a specified element
* size. It manages the memory as a doubly linked list of blocks each of which
* can contain multiple elements. Pushes and pops add/remove blocks from the
* beginning/end of the list as necessary while each block tracks the used
* portion of its memory.
* One behavior to be aware of is that the pops do not immediately remove an
* empty block from the beginning/end of the list (Presumably so push/pop pairs
* on the block boundaries don't cause thrashing). This can result in the first/
* last element not residing in the first/last block.
*/
class SK_API SkDeque : SkNoncopyable {
public:
/**
@ -26,8 +37,8 @@ public:
int count() const { return fCount; }
size_t elemSize() const { return fElemSize; }
const void* front() const;
const void* back() const;
const void* front() const { return fFront; }
const void* back() const { return fBack; }
void* front() {
return (void*)((const SkDeque*)this)->front();
@ -37,6 +48,10 @@ public:
return (void*)((const SkDeque*)this)->back();
}
/**
* push_front and push_back return a pointer to the memory space
* for the new element
*/
void* push_front();
void* push_back();
@ -100,8 +115,11 @@ private:
// allow unit test to call numBlocksAllocated
friend class DequeUnitTestHelper;
Block* fFront;
Block* fBack;
void* fFront;
void* fBack;
Block* fFrontBlock;
Block* fBackBlock;
size_t fElemSize;
void* fInitialStorage;
int fCount; // number of elements in the deque

View File

@ -565,6 +565,7 @@ void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
int32_t genID = GetNextGenID();
// Use reverse iterator instead of back because Rect path may need previous
SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart);
Rec* rec = (Rec*) iter.prev();
@ -647,10 +648,9 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
}
void SkClipStack::clipEmpty() {
SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart);
Rec* rec = (Rec*) iter.prev();
Rec* rec = (Rec*) fDeque.back();
if (rec && rec->canBeIntersectedInPlace(fSaveCount, SkRegion::kIntersect_Op)) {
switch (rec->fState) {
case Rec::kEmpty_State:

View File

@ -32,6 +32,7 @@ SkDeque::SkDeque(size_t elemSize, int allocCount)
, fCount(0)
, fAllocCount(allocCount) {
SkASSERT(allocCount >= 1);
fFrontBlock = fBackBlock = NULL;
fFront = fBack = NULL;
}
@ -44,16 +45,17 @@ SkDeque::SkDeque(size_t elemSize, void* storage, size_t storageSize, int allocCo
SkASSERT(allocCount >= 1);
if (storageSize >= sizeof(Block) + elemSize) {
fFront = (Block*)storage;
fFront->init(storageSize);
fFrontBlock = (Block*)storage;
fFrontBlock->init(storageSize);
} else {
fFront = NULL;
fFrontBlock = NULL;
}
fBack = fFront;
fBackBlock = fFrontBlock;
fFront = fBack = NULL;
}
SkDeque::~SkDeque() {
Block* head = fFront;
Block* head = fFrontBlock;
Block* initialHead = (Block*)fInitialStorage;
while (head) {
@ -65,47 +67,15 @@ SkDeque::~SkDeque() {
}
}
const void* SkDeque::front() const {
Block* 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 {
Block* 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 = this->allocateBlock(fAllocCount);
fBack = fFront; // update our linklist
if (NULL == fFrontBlock) {
fFrontBlock = this->allocateBlock(fAllocCount);
fBackBlock = fFrontBlock; // update our linklist
}
Block* first = fFront;
Block* first = fFrontBlock;
char* begin;
if (NULL == first->fBegin) {
@ -117,26 +87,35 @@ void* SkDeque::push_front() {
if (begin < first->start()) { // no more room in this chunk
// should we alloc more as we accumulate more elements?
first = this->allocateBlock(fAllocCount);
first->fNext = fFront;
fFront->fPrev = first;
fFront = first;
first->fNext = fFrontBlock;
fFrontBlock->fPrev = first;
fFrontBlock = first;
goto INIT_CHUNK;
}
}
first->fBegin = begin;
if (NULL == fFront) {
SkASSERT(NULL == fBack);
fFront = fBack = begin;
} else {
SkASSERT(NULL != fBack);
fFront = begin;
}
return begin;
}
void* SkDeque::push_back() {
fCount += 1;
if (NULL == fBack) {
fBack = this->allocateBlock(fAllocCount);
fFront = fBack; // update our linklist
if (NULL == fBackBlock) {
fBackBlock = this->allocateBlock(fAllocCount);
fFrontBlock = fBackBlock; // update our linklist
}
Block* last = fBack;
Block* last = fBackBlock;
char* end;
if (NULL == last->fBegin) {
@ -148,40 +127,58 @@ void* SkDeque::push_back() {
if (end > last->fStop) { // no more room in this chunk
// should we alloc more as we accumulate more elements?
last = this->allocateBlock(fAllocCount);
last->fPrev = fBack;
fBack->fNext = last;
fBack = last;
last->fPrev = fBackBlock;
fBackBlock->fNext = last;
fBackBlock = last;
goto INIT_CHUNK;
}
}
last->fEnd = end;
return end - fElemSize;
end -= fElemSize;
if (NULL == fBack) {
SkASSERT(NULL == fFront);
fFront = fBack = end;
} else {
SkASSERT(NULL != fFront);
fBack = end;
}
return end;
}
void SkDeque::pop_front() {
SkASSERT(fCount > 0);
fCount -= 1;
Block* first = fFront;
Block* first = fFrontBlock;
SkASSERT(first != NULL);
if (first->fBegin == NULL) { // we were marked empty from before
first = first->fNext;
first->fPrev = NULL;
this->freeBlock(fFront);
fFront = first;
this->freeBlock(fFrontBlock);
fFrontBlock = first;
SkASSERT(first != NULL); // else we popped too far
}
char* begin = first->fBegin + fElemSize;
SkASSERT(begin <= first->fEnd);
if (begin < fFront->fEnd) {
if (begin < fFrontBlock->fEnd) {
first->fBegin = begin;
SkASSERT(NULL != first->fBegin);
fFront = first->fBegin;
} else {
first->fBegin = first->fEnd = NULL; // mark as empty
if (NULL == first->fNext) {
fFront = fBack = NULL;
} else {
SkASSERT(NULL != first->fNext->fBegin);
fFront = first->fNext->fBegin;
}
}
}
@ -189,15 +186,15 @@ void SkDeque::pop_back() {
SkASSERT(fCount > 0);
fCount -= 1;
Block* last = fBack;
Block* last = fBackBlock;
SkASSERT(last != NULL);
if (last->fEnd == NULL) { // we were marked empty from before
last = last->fPrev;
last->fNext = NULL;
this->freeBlock(fBack);
fBack = last;
this->freeBlock(fBackBlock);
fBackBlock = last;
SkASSERT(last != NULL); // else we popped too far
}
@ -206,15 +203,23 @@ void SkDeque::pop_back() {
if (end > last->fBegin) {
last->fEnd = end;
SkASSERT(NULL != last->fEnd);
fBack = last->fEnd - fElemSize;
} else {
last->fBegin = last->fEnd = NULL; // mark as empty
if (NULL == last->fPrev) {
fFront = fBack = NULL;
} else {
SkASSERT(NULL != last->fPrev->fEnd);
fBack = last->fPrev->fEnd - fElemSize;
}
}
}
int SkDeque::numBlocksAllocated() const {
int numBlocks = 0;
for (const Block* temp = fFront; temp; temp = temp->fNext) {
for (const Block* temp = fFrontBlock; temp; temp = temp->fNext) {
++numBlocks;
}
@ -287,14 +292,14 @@ void SkDeque::Iter::reset(const SkDeque& d, IterStart startLoc) {
if (kFront_IterStart == startLoc) {
// initialize the iterator to start at the front
fCurBlock = d.fFront;
fCurBlock = d.fFrontBlock;
while (NULL != fCurBlock && NULL == fCurBlock->fBegin) {
fCurBlock = fCurBlock->fNext;
}
fPos = fCurBlock ? fCurBlock->fBegin : NULL;
} else {
// initialize the iterator to start at the back
fCurBlock = d.fBack;
fCurBlock = d.fBackBlock;
while (NULL != fCurBlock && NULL == fCurBlock->fEnd) {
fCurBlock = fCurBlock->fPrev;
}