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