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