1 /* 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 */ 24 struct PointerSet { 25 u2 alloc; 26 u2 count; 27 const void** list; 28 }; 29 30 /* 31 * Verify that the set is in sorted order. 32 */ 33 #ifndef NDEBUG 34 static 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 } 48 #endif 49 50 /* 51 * Allocate a new PointerSet. 52 * 53 * Returns NULL on failure. 54 */ 55 PointerSet* dvmPointerSetAlloc(int initialSize) 56 { 57 PointerSet* pSet = (PointerSet*)calloc(1, sizeof(PointerSet)); 58 if (pSet != NULL) { 59 if (initialSize > 0) { 60 pSet->list = (const void**)malloc(sizeof(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 */ 75 void 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 */ 90 void dvmPointerSetClear(PointerSet* pSet) 91 { 92 pSet->count = 0; 93 } 94 95 /* 96 * Get the number of pointers currently stored in the list. 97 */ 98 int dvmPointerSetGetCount(const PointerSet* pSet) 99 { 100 return pSet->count; 101 } 102 103 /* 104 * Get the Nth entry from the list. 105 */ 106 const 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 */ 117 bool 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", pSet, pSet->alloc); 134 newList = (const void**)realloc(pSet->list, pSet->alloc * sizeof(void*)); 135 if (newList == NULL) { 136 ALOGE("Failed expanding ptr set (alloc=%d)", 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 //ALOGD("nearby-1=%d %p, inserting %p at -1", 152 // nearby-1, pSet->list[nearby-1], ptr); 153 nearby--; 154 } else if (ptr < pSet->list[nearby]) { 155 //ALOGD("nearby=%d %p, inserting %p at +0", 156 // nearby, pSet->list[nearby], ptr); 157 } else { 158 //ALOGD("nearby+1=%d %p, inserting %p at +1", 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 */ 183 bool dvmPointerSetRemoveEntry(PointerSet* pSet, const void* ptr) 184 { 185 int where; 186 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 */ 205 bool 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 */ 238 void 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 */ 268 void dvmPointerSetDump(const PointerSet* pSet) 269 { 270 ALOGI("PointerSet %p", pSet); 271 int i; 272 for (i = 0; i < pSet->count; i++) 273 ALOGI(" %2d: %p", i, pSet->list[i]); 274 } 275