blob: 4d2d7f7ed321946ccbeaa58bcad676c6eae20c3f [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkTDArray_DEFINED
18#define SkTDArray_DEFINED
19
20#include "SkTypes.h"
21
22template <typename T> class SkTDArray {
23public:
24 SkTDArray() {
25 fReserve = fCount = 0;
26 fArray = NULL;
27#ifdef SK_DEBUG
28 fData = NULL;
29#endif
30 }
31 SkTDArray(const T src[], size_t count) {
32 SkASSERT(src || count == 0);
33
34 fReserve = fCount = 0;
35 fArray = NULL;
36#ifdef SK_DEBUG
37 fData = NULL;
38#endif
39 if (count) {
40 fArray = (T*)sk_malloc_throw(count * sizeof(T));
41#ifdef SK_DEBUG
42 fData = (ArrayT*)fArray;
43#endif
44 memcpy(fArray, src, sizeof(T) * count);
45 fReserve = fCount = count;
46 }
47 }
48 SkTDArray(const SkTDArray<T>& src) {
49 fReserve = fCount = 0;
50 fArray = NULL;
51#ifdef SK_DEBUG
52 fData = NULL;
53#endif
54 SkTDArray<T> tmp(src.fArray, src.fCount);
55 this->swap(tmp);
56 }
57 ~SkTDArray() {
58 sk_free(fArray);
59 }
60
61 SkTDArray<T>& operator=(const SkTDArray<T>& src) {
62 if (this != &src) {
63 if (src.fCount > fReserve) {
64 SkTDArray<T> tmp(src.fArray, src.fCount);
65 this->swap(tmp);
66 } else {
67 memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
68 fCount = src.fCount;
69 }
70 }
71 return *this;
72 }
73
74 friend int operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
75 return a.fCount == b.fCount &&
76 (a.fCount == 0 ||
77 !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
78 }
79
80 void swap(SkTDArray<T>& other) {
81 SkTSwap(fArray, other.fArray);
82#ifdef SK_DEBUG
83 SkTSwap(fData, other.fData);
84#endif
85 SkTSwap(fReserve, other.fReserve);
86 SkTSwap(fCount, other.fCount);
87 }
88
89 bool isEmpty() const { return fCount == 0; }
90 int count() const { return fCount; }
91 T* begin() const { return fArray; }
92 T* end() const { return fArray ? fArray + fCount : NULL; }
93 T& operator[](int index) const {
94 SkASSERT((unsigned)index < fCount);
95 return fArray[index];
96 }
97
98 void reset() {
99 if (fArray) {
100 sk_free(fArray);
101 fArray = NULL;
102#ifdef SK_DEBUG
103 fData = NULL;
104#endif
105 fReserve = fCount = 0;
106 } else {
107 SkASSERT(fReserve == 0 && fCount == 0);
108 }
109 }
110
111 void rewind() {
112 // same as setCount(0)
113 fCount = 0;
114 }
115
116 void setCount(size_t count) {
117 if (count > fReserve) {
118 this->growBy(count - fCount);
119 } else {
120 fCount = count;
121 }
122 }
123
124 void setReserve(size_t reserve) {
125 if (reserve > fReserve) {
126 SkASSERT(reserve > fCount);
127 size_t count = fCount;
128 this->growBy(reserve - fCount);
129 fCount = count;
130 }
131 }
132
133 T* prepend() {
134 this->growBy(1);
135 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
136 return fArray;
137 }
138
139 T* append() {
140 return this->append(1, NULL);
141 }
142 T* append(size_t count, const T* src = NULL) {
143 unsigned oldCount = fCount;
144 if (count) {
145 SkASSERT(src == NULL || fArray == NULL ||
146 src + count <= fArray || fArray + oldCount <= src);
147
148 this->growBy(count);
149 if (src) {
150 memcpy(fArray + oldCount, src, sizeof(T) * count);
151 }
152 }
153 return fArray + oldCount;
154 }
155
156 T* appendClear() {
157 T* result = this->append();
158 *result = 0;
159 return result;
160 }
161
162 T* insert(size_t index) {
163 return this->insert(index, 1, NULL);
164 }
165 T* insert(size_t index, size_t count, const T* src = NULL) {
166 SkASSERT(count);
167 SkASSERT(index <= fCount);
168 int oldCount = fCount;
169 this->growBy(count);
170 T* dst = fArray + index;
171 memmove(dst + count, dst, sizeof(T) * (oldCount - index));
172 if (src) {
173 memcpy(dst, src, sizeof(T) * count);
174 }
175 return dst;
176 }
177
178 void remove(size_t index, size_t count = 1) {
179 SkASSERT(index + count <= fCount);
180 fCount = fCount - count;
181 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
182 }
183
184 void removeShuffle(size_t index) {
185 SkASSERT(index < fCount);
186 unsigned newCount = fCount - 1;
187 fCount = newCount;
188 if (index != newCount) {
189 memcpy(fArray + index, fArray + newCount, sizeof(T));
190 }
191 }
192
193 int find(const T& elem) const {
194 const T* iter = fArray;
195 const T* stop = fArray + fCount;
196
197 for (; iter < stop; iter++) {
198 if (*iter == elem) {
199 return (int) (iter - fArray);
200 }
201 }
202 return -1;
203 }
204
205 int rfind(const T& elem) const {
206 const T* iter = fArray + fCount;
207 const T* stop = fArray;
208
209 while (iter > stop) {
210 if (*--iter == elem) {
211 return iter - stop;
212 }
213 }
214 return -1;
215 }
216
217 // routines to treat the array like a stack
218 T* push() { return this->append(); }
219 void push(const T& elem) { *this->append() = elem; }
220 const T& top() const { return (*this)[fCount - 1]; }
221 T& top() { return (*this)[fCount - 1]; }
222 void pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; }
223 void pop() { --fCount; }
224
225 void deleteAll() {
226 T* iter = fArray;
227 T* stop = fArray + fCount;
228 while (iter < stop) {
229 delete (*iter);
230 iter += 1;
231 }
232 this->reset();
233 }
234
235 void freeAll() {
236 T* iter = fArray;
237 T* stop = fArray + fCount;
238 while (iter < stop) {
239 sk_free(*iter);
240 iter += 1;
241 }
242 this->reset();
243 }
244
245 void unrefAll() {
246 T* iter = fArray;
247 T* stop = fArray + fCount;
248 while (iter < stop) {
249 (*iter)->unref();
250 iter += 1;
251 }
252 this->reset();
253 }
254
255#ifdef SK_DEBUG
256 void validate() const {
257 SkASSERT((fReserve == 0 && fArray == NULL) ||
258 (fReserve > 0 && fArray != NULL));
259 SkASSERT(fCount <= fReserve);
260 SkASSERT(fData == (ArrayT*)fArray);
261 }
262#endif
263
264private:
265#ifdef SK_DEBUG
266 enum {
267 kDebugArraySize = 16
268 };
269 typedef T ArrayT[kDebugArraySize];
270 ArrayT* fData;
271#endif
272 T* fArray;
273 size_t fReserve, fCount;
274
275 void growBy(size_t extra) {
276 SkASSERT(extra);
277
278 if (fCount + extra > fReserve) {
279 size_t size = fCount + extra + 4;
280 size += size >> 2;
281
282 fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T));
283#ifdef SK_DEBUG
284 fData = (ArrayT*)fArray;
285#endif
286 fReserve = size;
287 }
288 fCount += extra;
289 }
290};
291
292#endif
293