aboutsummaryrefslogtreecommitdiffstats
path: root/android/utils/refset.c
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2010-11-17 17:55:17 +0100
committerDavid 'Digit' Turner <digit@android.com>2010-11-17 17:55:17 +0100
commit4c0f745dc80d392fddea23eb8d4d7d86425ce0c6 (patch)
tree5da693710d1a3e81a7af3590619c8cbc6c7942d8 /android/utils/refset.c
parent44e750e6d0375543f0d91d0a68432ae9c8489ccd (diff)
downloadexternal_qemu-4c0f745dc80d392fddea23eb8d4d7d86425ce0c6.zip
external_qemu-4c0f745dc80d392fddea23eb8d4d7d86425ce0c6.tar.gz
external_qemu-4c0f745dc80d392fddea23eb8d4d7d86425ce0c6.tar.bz2
Update android/utils/ with misc. new features.
This introduces a few new features to android/utils/ that will be used in later patches. + <android/utils/assert.h> to handle assertions + <android/utils/vector.h> to handle dynamic arrays + <android/utils/reflist.h> slightly updated (more docs) + <android/utils/refset.h> implements a set of pointers Change-Id: Iebc14cfefd1c0e8aaecda9958a980d40f0be610a
Diffstat (limited to 'android/utils/refset.c')
-rw-r--r--android/utils/refset.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/android/utils/refset.c b/android/utils/refset.c
new file mode 100644
index 0000000..bb9a7f1
--- /dev/null
+++ b/android/utils/refset.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include <android/utils/refset.h>
+#include <stddef.h>
+
+#define AREFSET_STEP 5
+
+AINLINED uint32_t
+_arefSet_hashItem( void* item )
+{
+ uint32_t hash;
+
+ hash = (uint32_t)(ptrdiff_t)item >> 2;
+ if (sizeof(item) > 4)
+ hash ^= ((uint64_t)(ptrdiff_t)item >> 32);
+
+ return hash;
+}
+
+static void**
+_arefSet_lookup( ARefSet* s, void* item)
+{
+ uint32_t hash = _arefSet_hashItem(item);
+ unsigned index = hash & (s->max_buckets-1);
+
+ for (;;) {
+ void** pnode = &s->buckets[index];
+
+ if (*pnode == item || *pnode == NULL)
+ return pnode;
+
+ index += AREFSET_STEP;
+ if (index >= s->max_buckets)
+ index -= s->max_buckets;
+ }
+}
+
+static void**
+_arefSet_lookupInsert( ARefSet* s, void* item)
+{
+ uint32_t hash = _arefSet_hashItem(item);
+ unsigned index = hash & (s->max_buckets-1);
+ void** insert = NULL;
+
+ for (;;) {
+ void** pnode = &s->buckets[index];
+
+ if (*pnode == NULL) {
+ return insert ? insert : pnode;
+ } else if (*pnode == AREFSET_DELETED) {
+ if (!insert)
+ insert = pnode;
+ } else if (*pnode == item)
+ return pnode;
+
+ index += AREFSET_STEP;
+ if (index >= s->max_buckets)
+ index -= s->max_buckets;
+ }
+}
+
+extern ABool
+arefSet_has( ARefSet* s, void* item )
+{
+ void** lookup;
+
+ if (item == NULL || s->max_buckets == 0)
+ return 0;
+
+ lookup = _arefSet_lookup(s, item);
+ return (*lookup == item);
+}
+
+/* the code below assumes, in the case of a down-size,
+ * that there aren't too many items in the set.
+ */
+static void
+_arefSet_resize( ARefSet* s, unsigned newSize )
+{
+ ARefSet newSet;
+ unsigned nn;
+
+ AVECTOR_INIT_ALLOC(&newSet,buckets, newSize);
+
+ for (nn = 0; nn < s->max_buckets; nn++) {
+ void* item = s->buckets[nn];
+ if (item != NULL && item != AREFSET_DELETED) {
+ void** lookup = _arefSet_lookup(&newSet, item);
+ *lookup = item;
+ }
+ }
+
+ AVECTOR_DONE(s,buckets);
+ s->buckets = newSet.buckets;
+ s->max_buckets = newSet.max_buckets;
+}
+
+extern void
+arefSet_add( ARefSet* s, void* item )
+{
+ void** lookup;
+
+ if (item == NULL)
+ return;
+
+ if (s->max_buckets == 0)
+ AVECTOR_INIT_ALLOC(s,buckets,4);
+
+ lookup = _arefSet_lookupInsert(s, item);
+ if (*lookup == item)
+ return;
+
+ *lookup = item;
+ s->num_buckets += 1;
+
+ if (s->num_buckets > s->max_buckets*0.85)
+ _arefSet_resize(s, s->max_buckets*2);
+}
+
+extern void
+arefSet_del( ARefSet* s, void* item )
+{
+ void** lookup;
+
+ if (item == NULL || s->max_buckets == 0)
+ return;
+
+ lookup = _arefSet_lookup(s, item);
+ if (*lookup != item)
+ return;
+
+ *lookup = AREFSET_DELETED;
+ s->num_buckets -= 1;
+
+ if (s->num_buckets < s->max_buckets*0.25)
+ _arefSet_resize(s, s->max_buckets/2);
+}