ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

storage.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.