Home | History | Annotate | Download | only in util
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 VMware, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /**
     29  * @file
     30  * Generic handle table implementation.
     31  *
     32  * @author Jos Fonseca <jfonseca (at) vmware.com>
     33  */
     34 
     35 
     36 #include "pipe/p_compiler.h"
     37 #include "util/u_debug.h"
     38 
     39 #include "util/u_memory.h"
     40 #include "util/u_handle_table.h"
     41 
     42 
     43 #define HANDLE_TABLE_INITIAL_SIZE 16
     44 
     45 
     46 struct handle_table
     47 {
     48    /** Object array. Empty handles have a null object */
     49    void **objects;
     50 
     51    /** Number of objects the handle can currently hold */
     52    unsigned size;
     53    /** Number of consecutive objects allocated at the start of the table */
     54    unsigned filled;
     55 
     56    /** Optional object destructor */
     57    void (*destroy)(void *object);
     58 };
     59 
     60 
     61 struct handle_table *
     62 handle_table_create(void)
     63 {
     64    struct handle_table *ht;
     65 
     66    ht = MALLOC_STRUCT(handle_table);
     67    if (!ht)
     68       return NULL;
     69 
     70    ht->objects = (void **)CALLOC(HANDLE_TABLE_INITIAL_SIZE, sizeof(void *));
     71    if(!ht->objects) {
     72       FREE(ht);
     73       return NULL;
     74    }
     75 
     76    ht->size = HANDLE_TABLE_INITIAL_SIZE;
     77    ht->filled = 0;
     78 
     79    ht->destroy = NULL;
     80 
     81    return ht;
     82 }
     83 
     84 
     85 void
     86 handle_table_set_destroy(struct handle_table *ht,
     87                          void (*destroy)(void *object))
     88 {
     89    assert(ht);
     90    if (!ht)
     91       return;
     92    ht->destroy = destroy;
     93 }
     94 
     95 
     96 /**
     97  * Resize the table if necessary
     98  */
     99 static inline int
    100 handle_table_resize(struct handle_table *ht,
    101                     unsigned minimum_size)
    102 {
    103    unsigned new_size;
    104    void **new_objects;
    105 
    106    if(ht->size > minimum_size)
    107       return ht->size;
    108 
    109    new_size = ht->size;
    110    while(!(new_size > minimum_size))
    111       new_size *= 2;
    112    assert(new_size);
    113 
    114    new_objects = (void **)REALLOC((void *)ht->objects,
    115 				  ht->size*sizeof(void *),
    116 				  new_size*sizeof(void *));
    117    if (!new_objects)
    118       return 0;
    119 
    120    memset(new_objects + ht->size, 0, (new_size - ht->size)*sizeof(void *));
    121 
    122    ht->size = new_size;
    123    ht->objects = new_objects;
    124 
    125    return ht->size;
    126 }
    127 
    128 
    129 static inline void
    130 handle_table_clear(struct handle_table *ht,
    131                    unsigned index)
    132 {
    133    void *object;
    134 
    135    /* The order here is important so that the object being destroyed is not
    136     * present in the table when seen by the destroy callback, because the
    137     * destroy callback may directly or indirectly call the other functions in
    138     * this module.
    139     */
    140 
    141    object = ht->objects[index];
    142    if (object) {
    143       ht->objects[index] = NULL;
    144 
    145       if(ht->destroy)
    146          ht->destroy(object);
    147    }
    148 }
    149 
    150 
    151 unsigned
    152 handle_table_add(struct handle_table *ht,
    153                  void *object)
    154 {
    155    unsigned index;
    156    unsigned handle;
    157 
    158    assert(ht);
    159    assert(object);
    160    if(!object || !ht)
    161       return 0;
    162 
    163    /* linear search for an empty handle */
    164    while(ht->filled < ht->size) {
    165       if(!ht->objects[ht->filled])
    166 	 break;
    167       ++ht->filled;
    168    }
    169 
    170    index = ht->filled;
    171    handle = index + 1;
    172 
    173    /* check integer overflow */
    174    if(!handle)
    175       return 0;
    176 
    177    /* grow the table if necessary */
    178    if(!handle_table_resize(ht, index))
    179       return 0;
    180 
    181    assert(!ht->objects[index]);
    182    ht->objects[index] = object;
    183    ++ht->filled;
    184 
    185    return handle;
    186 }
    187 
    188 
    189 unsigned
    190 handle_table_set(struct handle_table *ht,
    191                  unsigned handle,
    192                  void *object)
    193 {
    194    unsigned index;
    195 
    196    assert(ht);
    197    assert(handle);
    198    if(!handle || !ht)
    199       return 0;
    200 
    201    assert(object);
    202    if (!object)
    203       return 0;
    204 
    205    index = handle - 1;
    206 
    207    /* grow the table if necessary */
    208    if(!handle_table_resize(ht, index))
    209       return 0;
    210 
    211    handle_table_clear(ht, index);
    212 
    213    ht->objects[index] = object;
    214 
    215    return handle;
    216 }
    217 
    218 
    219 void *
    220 handle_table_get(struct handle_table *ht,
    221                  unsigned handle)
    222 {
    223    void *object;
    224 
    225    assert(ht);
    226    assert(handle);
    227    if(!handle || !ht || handle > ht->size)
    228       return NULL;
    229 
    230    object = ht->objects[handle - 1];
    231 
    232    return object;
    233 }
    234 
    235 
    236 void
    237 handle_table_remove(struct handle_table *ht,
    238                     unsigned handle)
    239 {
    240    void *object;
    241    unsigned index;
    242 
    243    assert(ht);
    244    assert(handle);
    245    if(!handle || !ht || handle > ht->size)
    246       return;
    247 
    248    index = handle - 1;
    249    object = ht->objects[index];
    250    if (!object)
    251       return;
    252 
    253    handle_table_clear(ht, index);
    254 
    255    if(index < ht->filled)
    256       ht->filled = index;
    257 }
    258 
    259 
    260 unsigned
    261 handle_table_get_next_handle(struct handle_table *ht,
    262                              unsigned handle)
    263 {
    264    unsigned index;
    265 
    266    for(index = handle; index < ht->size; ++index) {
    267       if(ht->objects[index])
    268 	 return index + 1;
    269    }
    270 
    271    return 0;
    272 }
    273 
    274 
    275 unsigned
    276 handle_table_get_first_handle(struct handle_table *ht)
    277 {
    278    return handle_table_get_next_handle(ht, 0);
    279 }
    280 
    281 
    282 void
    283 handle_table_destroy(struct handle_table *ht)
    284 {
    285    unsigned index;
    286    assert(ht);
    287 
    288    if (!ht)
    289       return;
    290 
    291    if(ht->destroy)
    292       for(index = 0; index < ht->size; ++index)
    293          handle_table_clear(ht, index);
    294 
    295    FREE(ht->objects);
    296    FREE(ht);
    297 }
    298 
    299