1 /* Copyright (C) 2009 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include <android/utils/refset.h> 13 #include <stddef.h> 14 15 #define AREFSET_STEP 5 16 17 AINLINED uint32_t 18 _arefSet_hashItem( void* item ) 19 { 20 uint32_t hash; 21 22 hash = (uint32_t)(ptrdiff_t)item >> 2; 23 if (sizeof(item) > 4) 24 hash ^= ((uint64_t)(ptrdiff_t)item >> 32); 25 26 return hash; 27 } 28 29 static void** 30 _arefSet_lookup( ARefSet* s, void* item) 31 { 32 uint32_t hash = _arefSet_hashItem(item); 33 unsigned index = hash & (s->max_buckets-1); 34 35 for (;;) { 36 void** pnode = &s->buckets[index]; 37 38 if (*pnode == item || *pnode == NULL) 39 return pnode; 40 41 index += AREFSET_STEP; 42 if (index >= s->max_buckets) 43 index -= s->max_buckets; 44 } 45 } 46 47 static void** 48 _arefSet_lookupInsert( ARefSet* s, void* item) 49 { 50 uint32_t hash = _arefSet_hashItem(item); 51 unsigned index = hash & (s->max_buckets-1); 52 void** insert = NULL; 53 54 for (;;) { 55 void** pnode = &s->buckets[index]; 56 57 if (*pnode == NULL) { 58 return insert ? insert : pnode; 59 } else if (*pnode == AREFSET_DELETED) { 60 if (!insert) 61 insert = pnode; 62 } else if (*pnode == item) 63 return pnode; 64 65 index = (index + AREFSET_STEP) & (s->max_buckets-1); 66 } 67 } 68 69 extern ABool 70 arefSet_has( ARefSet* s, void* item ) 71 { 72 void** lookup; 73 74 if (item == NULL || s->max_buckets == 0) 75 return 0; 76 77 lookup = _arefSet_lookup(s, item); 78 return (*lookup == item); 79 } 80 81 /* the code below assumes, in the case of a down-size, 82 * that there aren't too many items in the set. 83 */ 84 static void 85 _arefSet_resize( ARefSet* s, unsigned newSize ) 86 { 87 ARefSet newSet; 88 unsigned nn, count = s->num_buckets; 89 90 AVECTOR_INIT_ALLOC(&newSet,buckets, newSize); 91 92 for (nn = 0; nn < s->max_buckets; nn++) { 93 void* item = s->buckets[nn]; 94 if (item != NULL && item != AREFSET_DELETED) { 95 void** lookup = _arefSet_lookup(&newSet, item); 96 *lookup = item; 97 } 98 } 99 100 AVECTOR_DONE(s,buckets); 101 s->buckets = newSet.buckets; 102 s->num_buckets = count; 103 s->max_buckets = newSet.max_buckets; 104 } 105 106 extern void 107 arefSet_add( ARefSet* s, void* item ) 108 { 109 void** lookup; 110 111 if (item == NULL) 112 return; 113 114 /* You can't add items to a set during iteration! */ 115 AASSERT(s->iteration == 0); 116 117 if (s->max_buckets == 0) 118 AVECTOR_INIT_ALLOC(s,buckets,4); 119 120 lookup = _arefSet_lookupInsert(s, item); 121 if (*lookup == item) 122 return; 123 124 *lookup = item; 125 s->num_buckets += 1; 126 127 if (s->iteration == 0) { 128 if (s->num_buckets > s->max_buckets*0.85) 129 _arefSet_resize(s, s->max_buckets*2); 130 } 131 } 132 133 extern void 134 arefSet_del( ARefSet* s, void* item ) 135 { 136 void** lookup; 137 138 if (item == NULL || s->max_buckets == 0) 139 return; 140 141 lookup = _arefSet_lookup(s, item); 142 if (*lookup != item) 143 return; 144 145 if (s->iteration == 0) { 146 /* direct deletion */ 147 *lookup = NULL; 148 s->num_buckets -= 1; 149 if (s->num_buckets < s->max_buckets*0.25) 150 _arefSet_resize(s, s->max_buckets/2); 151 } else { 152 /* deferred deletion */ 153 *lookup = AREFSET_DELETED; 154 s->num_buckets -= 1; 155 s->iteration |= 1; 156 } 157 } 158 159 void 160 _arefSet_removeDeferred( ARefSet* s ) 161 { 162 unsigned nn, newSize; 163 164 for (nn = 0; nn < s->max_buckets; nn++) { 165 if (s->buckets[nn] == AREFSET_DELETED) { 166 s->buckets[nn] = NULL; 167 } 168 } 169 s->iteration = 0; 170 171 newSize = s->max_buckets; 172 while (s->num_buckets < newSize*0.25) 173 newSize /= 2; 174 175 if (newSize != s->max_buckets) 176 _arefSet_resize(s, newSize); 177 } 178 179