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