blob: 1d2e81434e3d2053eca794d086fec9c74827b5f5 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 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 * Maintain an expanding set of unique pointer values.
18 */
19#include "Dalvik.h"
20
21/*
22 * Sorted, expanding list of pointers.
23 */
24struct PointerSet {
25 u2 alloc;
26 u2 count;
27 const void** list;
28};
29
30/*
31 * Verify that the set is in sorted order.
32 */
Carl Shapiroe3c01da2010-05-20 22:54:18 -070033#ifndef NDEBUG
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080034static bool verifySorted(PointerSet* pSet)
35{
36 const void* last = NULL;
37 int i;
38
39 for (i = 0; i < pSet->count; i++) {
40 const void* cur = pSet->list[i];
41 if (cur < last)
42 return false;
43 last = cur;
44 }
45
46 return true;
47}
Carl Shapiroe3c01da2010-05-20 22:54:18 -070048#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080049
50/*
51 * Allocate a new PointerSet.
52 *
53 * Returns NULL on failure.
54 */
55PointerSet* dvmPointerSetAlloc(int initialSize)
56{
57 PointerSet* pSet = calloc(1, sizeof(PointerSet));
58 if (pSet != NULL) {
59 if (initialSize > 0) {
60 pSet->list = malloc(sizeof(const void*) * initialSize);
61 if (pSet->list == NULL) {
62 free(pSet);
63 return NULL;
64 }
65 pSet->alloc = initialSize;
66 }
67 }
68
69 return pSet;
70}
71
72/*
73 * Free up a PointerSet.
74 */
75void dvmPointerSetFree(PointerSet* pSet)
76{
77 if (pSet == NULL)
78 return;
79
80 if (pSet->list != NULL) {
81 free(pSet->list);
82 pSet->list = NULL;
83 }
84 free(pSet);
85}
86
87/*
88 * Clear the contents of a pointer set.
89 */
90void dvmPointerSetClear(PointerSet* pSet)
91{
92 pSet->count = 0;
93}
94
95/*
96 * Get the number of pointers currently stored in the list.
97 */
98int dvmPointerSetGetCount(const PointerSet* pSet)
99{
100 return pSet->count;
101}
102
103/*
104 * Get the Nth entry from the list.
105 */
106const void* dvmPointerSetGetEntry(const PointerSet* pSet, int i)
107{
108 return pSet->list[i];
109}
110
111/*
112 * Insert a new entry into the list. If it already exists, this returns
113 * without doing anything.
114 *
115 * Returns "true" if the value was added.
116 */
117bool dvmPointerSetAddEntry(PointerSet* pSet, const void* ptr)
118{
119 int nearby;
120
121 if (dvmPointerSetHas(pSet, ptr, &nearby))
122 return false;
123
124 /* ensure we have space to add one more */
125 if (pSet->count == pSet->alloc) {
126 /* time to expand */
127 const void** newList;
128
129 if (pSet->alloc == 0)
130 pSet->alloc = 4;
131 else
132 pSet->alloc *= 2;
133 LOGVV("expanding %p to %d\n", pSet, pSet->alloc);
134 newList = realloc(pSet->list, pSet->alloc * sizeof(const void*));
135 if (newList == NULL) {
136 LOGE("Failed expanding ptr set (alloc=%d)\n", pSet->alloc);
137 dvmAbort();
138 }
139 pSet->list = newList;
140 }
141
142 if (pSet->count == 0) {
143 /* empty list */
144 assert(nearby == 0);
145 } else {
146 /*
147 * Determine the insertion index. The binary search might have
148 * terminated "above" or "below" the value.
149 */
150 if (nearby != 0 && ptr < pSet->list[nearby-1]) {
151 //LOGD("nearby-1=%d %p, inserting %p at -1\n",
152 // nearby-1, pSet->list[nearby-1], ptr);
153 nearby--;
154 } else if (ptr < pSet->list[nearby]) {
155 //LOGD("nearby=%d %p, inserting %p at +0\n",
156 // nearby, pSet->list[nearby], ptr);
157 } else {
158 //LOGD("nearby+1=%d %p, inserting %p at +1\n",
159 // nearby+1, pSet->list[nearby+1], ptr);
160 nearby++;
161 }
162
163 /*
164 * Move existing values, if necessary.
165 */
166 if (nearby != pSet->count) {
167 /* shift up */
168 memmove(&pSet->list[nearby+1], &pSet->list[nearby],
169 (pSet->count - nearby) * sizeof(pSet->list[0]));
170 }
171 }
172
173 pSet->list[nearby] = ptr;
174 pSet->count++;
175
176 assert(verifySorted(pSet));
177 return true;
178}
179
180/*
181 * Returns "true" if the element was successfully removed.
182 */
183bool dvmPointerSetRemoveEntry(PointerSet* pSet, const void* ptr)
184{
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700185 int where;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800186
187 if (!dvmPointerSetHas(pSet, ptr, &where))
188 return false;
189
190 if (where != pSet->count-1) {
191 /* shift down */
192 memmove(&pSet->list[where], &pSet->list[where+1],
193 (pSet->count-1 - where) * sizeof(pSet->list[0]));
194 }
195
196 pSet->count--;
197 pSet->list[pSet->count] = (const void*) 0xdecadead; // debug
198 return true;
199}
200
201/*
202 * Returns the index if "ptr" appears in the list. If it doesn't appear,
203 * this returns a negative index for a nearby element.
204 */
205bool dvmPointerSetHas(const PointerSet* pSet, const void* ptr, int* pIndex)
206{
207 int hi, lo, mid;
208
209 lo = mid = 0;
210 hi = pSet->count-1;
211
212 /* array is sorted, use a binary search */
213 while (lo <= hi) {
214 mid = (lo + hi) / 2;
215 const void* listVal = pSet->list[mid];
216
217 if (ptr > listVal) {
218 lo = mid + 1;
219 } else if (ptr < listVal) {
220 hi = mid - 1;
221 } else /* listVal == ptr */ {
222 if (pIndex != NULL)
223 *pIndex = mid;
224 return true;
225 }
226 }
227
228 if (pIndex != NULL)
229 *pIndex = mid;
230 return false;
231}
232
233/*
234 * Compute the intersection of the set and the array of pointers passed in.
235 *
236 * Any pointer in "pSet" that does not appear in "ptrArray" is removed.
237 */
238void dvmPointerSetIntersect(PointerSet* pSet, const void** ptrArray, int count)
239{
240 int i, j;
241
242 for (i = 0; i < pSet->count; i++) {
243 for (j = 0; j < count; j++) {
244 if (pSet->list[i] == ptrArray[j]) {
245 /* match, keep this one */
246 break;
247 }
248 }
249
250 if (j == count) {
251 /* no match, remove entry */
252 if (i != pSet->count-1) {
253 /* shift down */
254 memmove(&pSet->list[i], &pSet->list[i+1],
255 (pSet->count-1 - i) * sizeof(pSet->list[0]));
256 }
257
258 pSet->count--;
259 pSet->list[pSet->count] = (const void*) 0xdecadead; // debug
260 i--; /* adjust loop counter */
261 }
262 }
263}
264
265/*
266 * Print the list contents to stdout. For debugging.
267 */
268void dvmPointerSetDump(const PointerSet* pSet)
269{
270 int i;
271 for (i = 0; i < pSet->count; i++)
272 printf(" %p", pSet->list[i]);
273}