summaryrefslogtreecommitdiff
path: root/vm/PointerSet.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm/PointerSet.c')
-rw-r--r--vm/PointerSet.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/vm/PointerSet.c b/vm/PointerSet.c
new file mode 100644
index 0000000..1d2e814
--- /dev/null
+++ b/vm/PointerSet.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Maintain an expanding set of unique pointer values.
+ */
+#include "Dalvik.h"
+
+/*
+ * Sorted, expanding list of pointers.
+ */
+struct PointerSet {
+ u2 alloc;
+ u2 count;
+ const void** list;
+};
+
+/*
+ * Verify that the set is in sorted order.
+ */
+#ifndef NDEBUG
+static bool verifySorted(PointerSet* pSet)
+{
+ const void* last = NULL;
+ int i;
+
+ for (i = 0; i < pSet->count; i++) {
+ const void* cur = pSet->list[i];
+ if (cur < last)
+ return false;
+ last = cur;
+ }
+
+ return true;
+}
+#endif
+
+/*
+ * Allocate a new PointerSet.
+ *
+ * Returns NULL on failure.
+ */
+PointerSet* dvmPointerSetAlloc(int initialSize)
+{
+ PointerSet* pSet = calloc(1, sizeof(PointerSet));
+ if (pSet != NULL) {
+ if (initialSize > 0) {
+ pSet->list = malloc(sizeof(const void*) * initialSize);
+ if (pSet->list == NULL) {
+ free(pSet);
+ return NULL;
+ }
+ pSet->alloc = initialSize;
+ }
+ }
+
+ return pSet;
+}
+
+/*
+ * Free up a PointerSet.
+ */
+void dvmPointerSetFree(PointerSet* pSet)
+{
+ if (pSet == NULL)
+ return;
+
+ if (pSet->list != NULL) {
+ free(pSet->list);
+ pSet->list = NULL;
+ }
+ free(pSet);
+}
+
+/*
+ * Clear the contents of a pointer set.
+ */
+void dvmPointerSetClear(PointerSet* pSet)
+{
+ pSet->count = 0;
+}
+
+/*
+ * Get the number of pointers currently stored in the list.
+ */
+int dvmPointerSetGetCount(const PointerSet* pSet)
+{
+ return pSet->count;
+}
+
+/*
+ * Get the Nth entry from the list.
+ */
+const void* dvmPointerSetGetEntry(const PointerSet* pSet, int i)
+{
+ return pSet->list[i];
+}
+
+/*
+ * Insert a new entry into the list. If it already exists, this returns
+ * without doing anything.
+ *
+ * Returns "true" if the value was added.
+ */
+bool dvmPointerSetAddEntry(PointerSet* pSet, const void* ptr)
+{
+ int nearby;
+
+ if (dvmPointerSetHas(pSet, ptr, &nearby))
+ return false;
+
+ /* ensure we have space to add one more */
+ if (pSet->count == pSet->alloc) {
+ /* time to expand */
+ const void** newList;
+
+ if (pSet->alloc == 0)
+ pSet->alloc = 4;
+ else
+ pSet->alloc *= 2;
+ LOGVV("expanding %p to %d\n", pSet, pSet->alloc);
+ newList = realloc(pSet->list, pSet->alloc * sizeof(const void*));
+ if (newList == NULL) {
+ LOGE("Failed expanding ptr set (alloc=%d)\n", pSet->alloc);
+ dvmAbort();
+ }
+ pSet->list = newList;
+ }
+
+ if (pSet->count == 0) {
+ /* empty list */
+ assert(nearby == 0);
+ } else {
+ /*
+ * Determine the insertion index. The binary search might have
+ * terminated "above" or "below" the value.
+ */
+ if (nearby != 0 && ptr < pSet->list[nearby-1]) {
+ //LOGD("nearby-1=%d %p, inserting %p at -1\n",
+ // nearby-1, pSet->list[nearby-1], ptr);
+ nearby--;
+ } else if (ptr < pSet->list[nearby]) {
+ //LOGD("nearby=%d %p, inserting %p at +0\n",
+ // nearby, pSet->list[nearby], ptr);
+ } else {
+ //LOGD("nearby+1=%d %p, inserting %p at +1\n",
+ // nearby+1, pSet->list[nearby+1], ptr);
+ nearby++;
+ }
+
+ /*
+ * Move existing values, if necessary.
+ */
+ if (nearby != pSet->count) {
+ /* shift up */
+ memmove(&pSet->list[nearby+1], &pSet->list[nearby],
+ (pSet->count - nearby) * sizeof(pSet->list[0]));
+ }
+ }
+
+ pSet->list[nearby] = ptr;
+ pSet->count++;
+
+ assert(verifySorted(pSet));
+ return true;
+}
+
+/*
+ * Returns "true" if the element was successfully removed.
+ */
+bool dvmPointerSetRemoveEntry(PointerSet* pSet, const void* ptr)
+{
+ int where;
+
+ if (!dvmPointerSetHas(pSet, ptr, &where))
+ return false;
+
+ if (where != pSet->count-1) {
+ /* shift down */
+ memmove(&pSet->list[where], &pSet->list[where+1],
+ (pSet->count-1 - where) * sizeof(pSet->list[0]));
+ }
+
+ pSet->count--;
+ pSet->list[pSet->count] = (const void*) 0xdecadead; // debug
+ return true;
+}
+
+/*
+ * Returns the index if "ptr" appears in the list. If it doesn't appear,
+ * this returns a negative index for a nearby element.
+ */
+bool dvmPointerSetHas(const PointerSet* pSet, const void* ptr, int* pIndex)
+{
+ int hi, lo, mid;
+
+ lo = mid = 0;
+ hi = pSet->count-1;
+
+ /* array is sorted, use a binary search */
+ while (lo <= hi) {
+ mid = (lo + hi) / 2;
+ const void* listVal = pSet->list[mid];
+
+ if (ptr > listVal) {
+ lo = mid + 1;
+ } else if (ptr < listVal) {
+ hi = mid - 1;
+ } else /* listVal == ptr */ {
+ if (pIndex != NULL)
+ *pIndex = mid;
+ return true;
+ }
+ }
+
+ if (pIndex != NULL)
+ *pIndex = mid;
+ return false;
+}
+
+/*
+ * Compute the intersection of the set and the array of pointers passed in.
+ *
+ * Any pointer in "pSet" that does not appear in "ptrArray" is removed.
+ */
+void dvmPointerSetIntersect(PointerSet* pSet, const void** ptrArray, int count)
+{
+ int i, j;
+
+ for (i = 0; i < pSet->count; i++) {
+ for (j = 0; j < count; j++) {
+ if (pSet->list[i] == ptrArray[j]) {
+ /* match, keep this one */
+ break;
+ }
+ }
+
+ if (j == count) {
+ /* no match, remove entry */
+ if (i != pSet->count-1) {
+ /* shift down */
+ memmove(&pSet->list[i], &pSet->list[i+1],
+ (pSet->count-1 - i) * sizeof(pSet->list[0]));
+ }
+
+ pSet->count--;
+ pSet->list[pSet->count] = (const void*) 0xdecadead; // debug
+ i--; /* adjust loop counter */
+ }
+ }
+}
+
+/*
+ * Print the list contents to stdout. For debugging.
+ */
+void dvmPointerSetDump(const PointerSet* pSet)
+{
+ int i;
+ for (i = 0; i < pSet->count; i++)
+ printf(" %p", pSet->list[i]);
+}