summaryrefslogtreecommitdiffstats
path: root/skia/sgl/SkDeque.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'skia/sgl/SkDeque.cpp')
-rw-r--r--skia/sgl/SkDeque.cpp252
1 files changed, 252 insertions, 0 deletions
diff --git a/skia/sgl/SkDeque.cpp b/skia/sgl/SkDeque.cpp
new file mode 100644
index 0000000..e424817
--- /dev/null
+++ b/skia/sgl/SkDeque.cpp
@@ -0,0 +1,252 @@
+/* libs/graphics/sgl/SkDeque.cpp
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#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::Iter::Iter(const SkDeque& d) : fElemSize(d.fElemSize) {
+ fHead = d.fFront;
+ while (fHead != NULL && fHead->fBegin == NULL) {
+ fHead = fHead->fNext;
+ }
+ fPos = fHead ? fHead->fBegin : NULL;
+}
+
+void* SkDeque::Iter::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;
+}
+