Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenstorage.c
Go to the documentation of this file.
00001 /* 00002 * Various storage structures (pool allocation, vector, hash table) 00003 * 00004 * Copyright (C) 1993, Eric Youngdale. 00005 * 2004, Eric Pouech 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 00023 #include "config.h" 00024 #include <assert.h> 00025 #include <stdlib.h> 00026 #include "wine/debug.h" 00027 00028 #include "dbghelp_private.h" 00029 #ifdef USE_STATS 00030 #include <math.h> 00031 #endif 00032 00033 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); 00034 00035 struct pool_arena 00036 { 00037 struct list entry; 00038 char *current; 00039 char *end; 00040 }; 00041 00042 void pool_init(struct pool* a, size_t arena_size) 00043 { 00044 list_init( &a->arena_list ); 00045 list_init( &a->arena_full ); 00046 a->arena_size = arena_size; 00047 } 00048 00049 void pool_destroy(struct pool* pool) 00050 { 00051 struct pool_arena* arena; 00052 struct pool_arena* next; 00053 00054 #ifdef USE_STATS 00055 size_t alloc, used, num; 00056 00057 alloc = used = num = 0; 00058 LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry ) 00059 { 00060 alloc += arena->end - (char *)arena; 00061 used += arena->current - (char*)arena; 00062 num++; 00063 } 00064 LIST_FOR_EACH_ENTRY( arena, &pool->arena_full, struct pool_arena, entry ) 00065 { 00066 alloc += arena->end - (char *)arena; 00067 used += arena->current - (char*)arena; 00068 num++; 00069 } 00070 if (alloc == 0) alloc = 1; /* avoid division by zero */ 00071 FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas, non-allocation ratio: %.2f%%\n", 00072 pool, (unsigned)(alloc >> 10), (unsigned)(used >> 10), (unsigned)num, 00073 100.0 - (float)used / (float)alloc * 100.0); 00074 #endif 00075 00076 LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_list, struct pool_arena, entry ) 00077 { 00078 list_remove( &arena->entry ); 00079 HeapFree(GetProcessHeap(), 0, arena); 00080 } 00081 LIST_FOR_EACH_ENTRY_SAFE( arena, next, &pool->arena_full, struct pool_arena, entry ) 00082 { 00083 list_remove( &arena->entry ); 00084 HeapFree(GetProcessHeap(), 0, arena); 00085 } 00086 } 00087 00088 void* pool_alloc(struct pool* pool, size_t len) 00089 { 00090 struct pool_arena* arena; 00091 void* ret; 00092 size_t size; 00093 00094 len = (len + 3) & ~3; /* round up size on DWORD boundary */ 00095 00096 LIST_FOR_EACH_ENTRY( arena, &pool->arena_list, struct pool_arena, entry ) 00097 { 00098 if (arena->end - arena->current >= len) 00099 { 00100 ret = arena->current; 00101 arena->current += len; 00102 if (arena->current + 16 >= arena->end) 00103 { 00104 list_remove( &arena->entry ); 00105 list_add_tail( &pool->arena_full, &arena->entry ); 00106 } 00107 return ret; 00108 } 00109 } 00110 00111 size = max( pool->arena_size, len ); 00112 arena = HeapAlloc(GetProcessHeap(), 0, size + sizeof(struct pool_arena)); 00113 if (!arena) return NULL; 00114 00115 ret = arena + 1; 00116 arena->current = (char*)ret + len; 00117 arena->end = (char*)ret + size; 00118 if (arena->current + 16 >= arena->end) 00119 list_add_tail( &pool->arena_full, &arena->entry ); 00120 else 00121 list_add_head( &pool->arena_list, &arena->entry ); 00122 return ret; 00123 } 00124 00125 char* pool_strdup(struct pool* pool, const char* str) 00126 { 00127 char* ret; 00128 if ((ret = pool_alloc(pool, strlen(str) + 1))) strcpy(ret, str); 00129 return ret; 00130 } 00131 00132 void vector_init(struct vector* v, unsigned esz, unsigned bucket_sz) 00133 { 00134 v->buckets = NULL; 00135 /* align size on DWORD boundaries */ 00136 v->elt_size = (esz + 3) & ~3; 00137 switch (bucket_sz) 00138 { 00139 case 2: v->shift = 1; break; 00140 case 4: v->shift = 2; break; 00141 case 8: v->shift = 3; break; 00142 case 16: v->shift = 4; break; 00143 case 32: v->shift = 5; break; 00144 case 64: v->shift = 6; break; 00145 case 128: v->shift = 7; break; 00146 case 256: v->shift = 8; break; 00147 case 512: v->shift = 9; break; 00148 case 1024: v->shift = 10; break; 00149 default: assert(0); 00150 } 00151 v->num_buckets = 0; 00152 v->buckets_allocated = 0; 00153 v->num_elts = 0; 00154 } 00155 00156 unsigned vector_length(const struct vector* v) 00157 { 00158 return v->num_elts; 00159 } 00160 00161 void* vector_at(const struct vector* v, unsigned pos) 00162 { 00163 unsigned o; 00164 00165 if (pos >= v->num_elts) return NULL; 00166 o = pos & ((1 << v->shift) - 1); 00167 return (char*)v->buckets[pos >> v->shift] + o * v->elt_size; 00168 } 00169 00170 void* vector_add(struct vector* v, struct pool* pool) 00171 { 00172 unsigned ncurr = v->num_elts++; 00173 00174 /* check that we don't wrap around */ 00175 assert(v->num_elts > ncurr); 00176 if (ncurr == (v->num_buckets << v->shift)) 00177 { 00178 if(v->num_buckets == v->buckets_allocated) 00179 { 00180 /* Double the bucket cache, so it scales well with big vectors.*/ 00181 unsigned new_reserved; 00182 void* new; 00183 00184 new_reserved = 2*v->buckets_allocated; 00185 if(new_reserved == 0) new_reserved = 1; 00186 00187 /* Don't even try to resize memory. 00188 Pool datastructure is very inefficient with reallocs. */ 00189 new = pool_alloc(pool, new_reserved * sizeof(void*)); 00190 memcpy(new, v->buckets, v->buckets_allocated * sizeof(void*)); 00191 v->buckets = new; 00192 v->buckets_allocated = new_reserved; 00193 } 00194 v->buckets[v->num_buckets] = pool_alloc(pool, v->elt_size << v->shift); 00195 return v->buckets[v->num_buckets++]; 00196 } 00197 return vector_at(v, ncurr); 00198 } 00199 00200 /* We construct the sparse array as two vectors (of equal size) 00201 * The first vector (key2index) is the lookup table between the key and 00202 * an index in the second vector (elements) 00203 * When inserting an element, it's always appended in second vector (and 00204 * never moved in memory later on), only the first vector is reordered 00205 */ 00206 struct key2index 00207 { 00208 unsigned long key; 00209 unsigned index; 00210 }; 00211 00212 void sparse_array_init(struct sparse_array* sa, unsigned elt_sz, unsigned bucket_sz) 00213 { 00214 vector_init(&sa->key2index, sizeof(struct key2index), bucket_sz); 00215 vector_init(&sa->elements, elt_sz, bucket_sz); 00216 } 00217 00218 /****************************************************************** 00219 * sparse_array_lookup 00220 * 00221 * Returns the first index which key is >= at passed key 00222 */ 00223 static struct key2index* sparse_array_lookup(const struct sparse_array* sa, 00224 unsigned long key, unsigned* idx) 00225 { 00226 struct key2index* pk2i; 00227 unsigned low, high; 00228 00229 if (!sa->elements.num_elts) 00230 { 00231 *idx = 0; 00232 return NULL; 00233 } 00234 high = sa->elements.num_elts; 00235 pk2i = vector_at(&sa->key2index, high - 1); 00236 if (pk2i->key < key) 00237 { 00238 *idx = high; 00239 return NULL; 00240 } 00241 if (pk2i->key == key) 00242 { 00243 *idx = high - 1; 00244 return pk2i; 00245 } 00246 low = 0; 00247 pk2i = vector_at(&sa->key2index, low); 00248 if (pk2i->key >= key) 00249 { 00250 *idx = 0; 00251 return pk2i; 00252 } 00253 /* now we have: sa(lowest key) < key < sa(highest key) */ 00254 while (low < high) 00255 { 00256 *idx = (low + high) / 2; 00257 pk2i = vector_at(&sa->key2index, *idx); 00258 if (pk2i->key > key) high = *idx; 00259 else if (pk2i->key < key) low = *idx + 1; 00260 else return pk2i; 00261 } 00262 /* binary search could return exact item, we search for highest one 00263 * below the key 00264 */ 00265 if (pk2i->key < key) 00266 pk2i = vector_at(&sa->key2index, ++(*idx)); 00267 return pk2i; 00268 } 00269 00270 void* sparse_array_find(const struct sparse_array* sa, unsigned long key) 00271 { 00272 unsigned idx; 00273 struct key2index* pk2i; 00274 00275 if ((pk2i = sparse_array_lookup(sa, key, &idx)) && pk2i->key == key) 00276 return vector_at(&sa->elements, pk2i->index); 00277 return NULL; 00278 } 00279 00280 void* sparse_array_add(struct sparse_array* sa, unsigned long key, 00281 struct pool* pool) 00282 { 00283 unsigned idx, i; 00284 struct key2index* pk2i; 00285 struct key2index* to; 00286 00287 pk2i = sparse_array_lookup(sa, key, &idx); 00288 if (pk2i && pk2i->key == key) 00289 { 00290 FIXME("re adding an existing key\n"); 00291 return NULL; 00292 } 00293 to = vector_add(&sa->key2index, pool); 00294 if (pk2i) 00295 { 00296 /* we need to shift vector's content... */ 00297 /* let's do it brute force... (FIXME) */ 00298 assert(sa->key2index.num_elts >= 2); 00299 for (i = sa->key2index.num_elts - 1; i > idx; i--) 00300 { 00301 pk2i = vector_at(&sa->key2index, i - 1); 00302 *to = *pk2i; 00303 to = pk2i; 00304 } 00305 } 00306 00307 to->key = key; 00308 to->index = sa->elements.num_elts; 00309 00310 return vector_add(&sa->elements, pool); 00311 } 00312 00313 unsigned sparse_array_length(const struct sparse_array* sa) 00314 { 00315 return sa->elements.num_elts; 00316 } 00317 00318 static unsigned hash_table_hash(const char* name, unsigned num_buckets) 00319 { 00320 unsigned hash = 0; 00321 while (*name) 00322 { 00323 hash += *name++; 00324 hash += (hash << 10); 00325 hash ^= (hash >> 6); 00326 } 00327 hash += (hash << 3); 00328 hash ^= (hash >> 11); 00329 hash += (hash << 15); 00330 return hash % num_buckets; 00331 } 00332 00333 void hash_table_init(struct pool* pool, struct hash_table* ht, unsigned num_buckets) 00334 { 00335 ht->num_elts = 0; 00336 ht->num_buckets = num_buckets; 00337 ht->pool = pool; 00338 ht->buckets = NULL; 00339 } 00340 00341 void hash_table_destroy(struct hash_table* ht) 00342 { 00343 #if defined(USE_STATS) 00344 int i; 00345 unsigned len; 00346 unsigned min = 0xffffffff, max = 0, sq = 0; 00347 struct hash_table_elt* elt; 00348 double mean, variance; 00349 00350 for (i = 0; i < ht->num_buckets; i++) 00351 { 00352 for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++; 00353 if (len < min) min = len; 00354 if (len > max) max = len; 00355 sq += len * len; 00356 } 00357 mean = (double)ht->num_elts / ht->num_buckets; 00358 variance = (double)sq / ht->num_buckets - mean * mean; 00359 FIXME("STATS: elts[num:%-4u size:%u mean:%f] buckets[min:%-4u variance:%+f max:%-4u]\n", 00360 ht->num_elts, ht->num_buckets, mean, min, variance, max); 00361 #if 1 00362 for (i = 0; i < ht->num_buckets; i++) 00363 { 00364 for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++; 00365 if (len == max) 00366 { 00367 FIXME("Longuest bucket:\n"); 00368 for (elt = ht->buckets[i]; elt; elt = elt->next) 00369 FIXME("\t%s\n", elt->name); 00370 break; 00371 } 00372 00373 } 00374 #endif 00375 #endif 00376 } 00377 00378 void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt) 00379 { 00380 unsigned hash = hash_table_hash(elt->name, ht->num_buckets); 00381 00382 if (!ht->buckets) 00383 { 00384 ht->buckets = pool_alloc(ht->pool, ht->num_buckets * sizeof(struct hash_table_bucket)); 00385 assert(ht->buckets); 00386 memset(ht->buckets, 0, ht->num_buckets * sizeof(struct hash_table_bucket)); 00387 } 00388 00389 /* in some cases, we need to get back the symbols of same name in the order 00390 * in which they've been inserted. So insert new elements at the end of the list. 00391 */ 00392 if (!ht->buckets[hash].first) 00393 { 00394 ht->buckets[hash].first = elt; 00395 } 00396 else 00397 { 00398 ht->buckets[hash].last->next = elt; 00399 } 00400 ht->buckets[hash].last = elt; 00401 elt->next = NULL; 00402 ht->num_elts++; 00403 } 00404 00405 void hash_table_iter_init(const struct hash_table* ht, 00406 struct hash_table_iter* hti, const char* name) 00407 { 00408 hti->ht = ht; 00409 if (name) 00410 { 00411 hti->last = hash_table_hash(name, ht->num_buckets); 00412 hti->index = hti->last - 1; 00413 } 00414 else 00415 { 00416 hti->last = ht->num_buckets - 1; 00417 hti->index = -1; 00418 } 00419 hti->element = NULL; 00420 } 00421 00422 void* hash_table_iter_up(struct hash_table_iter* hti) 00423 { 00424 if (!hti->ht->buckets) return NULL; 00425 00426 if (hti->element) hti->element = hti->element->next; 00427 while (!hti->element && hti->index < hti->last) 00428 hti->element = hti->ht->buckets[++hti->index].first; 00429 return hti->element; 00430 } Generated on Sun May 27 2012 04:23:25 for ReactOS by
1.7.6.1
|