veil_bitmap.c

Go to the documentation of this file.
00001 /**
00002  * @file   veil_bitmap.c
00003  * \code
00004  *     Author:       Marc Munro
00005  *     Copyright (c) 2005 - 2010 Marc Munro
00006  *     License:      BSD
00007  * $Id: veil_bitmap.c,v 1.7 2008/08/25 23:46:22 bloodnok Exp $
00008  * \endcode
00009  * @brief  
00010  * Functions for manipulating Bitmaps, BitmapHashes and BitmapArrays
00011  * 
00012  */
00013 
00014 #include <stdio.h>
00015 #include "postgres.h"
00016 #include "veil_datatypes.h"
00017 #include "veil_funcs.h"
00018 
00019 
00020 
00021 /**
00022  * Array of bit positions for int32, indexed by bitno.
00023  */
00024 static
00025 uint32 bitmasks[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, 
00026                      0x00000010, 0x00000020, 0x00000040, 0x00000080, 
00027                      0x00000100, 0x00000200, 0x00000400, 0x00000800, 
00028                      0x00001000, 0x00002000, 0x00004000, 0x00008000,
00029                      0x00010000, 0x00020000, 0x00040000, 0x00080000,
00030                      0x00100000, 0x00200000, 0x00400000, 0x00800000,
00031                      0x01000000, 0x02000000, 0x04000000, 0x08000000,
00032                      0x10000000, 0x20000000, 0x40000000, 0x80000000};
00033 
00034 
00035 /** 
00036  * Clear all bits in a ::Bitmap.
00037  * 
00038  * @param bitmap The ::Bitmap in which all bits are to be cleared
00039  */
00040 void
00041 vl_ClearBitmap(Bitmap *bitmap)
00042 {
00043     int elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
00044     int i;
00045     
00046     for (i = 0; i < elems; i++) {
00047         bitmap->bitset[i] = 0;
00048     }
00049 }
00050 
00051 /** 
00052  * Return a newly initialised (empty) ::Bitmap.  The bitmap may already
00053  * exist in which case it will be re-used if possible.  The bitmap may
00054  * be created in either session or shared memory depending on the value
00055  * of shared.
00056  * 
00057  * @param p_bitmap Pointer to an existing bitmap if one exists
00058  * @param shared Whether to create the bitmap in shared memory
00059  * @param min The smallest bit to be stored in the bitmap
00060  * @param max The largest bit to be stored in the bitmap
00061  */
00062 void
00063 vl_NewBitmap(Bitmap **p_bitmap, bool shared,
00064              int32 min, int32 max)
00065 {
00066     Bitmap *bitmap = *p_bitmap;
00067     int     elems = ARRAYELEMS(min, max);
00068 
00069     if (bitmap) {
00070         int cur_elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
00071         // OK, there is an old bitmap in place.  If it is the same size
00072         // or larger than we need we will re-use it, otherwise we will
00073         // dispose of it and get a new one.
00074 
00075         if (elems <= cur_elems) {
00076             vl_ClearBitmap(bitmap);
00077         }
00078         else {
00079             if (shared) {
00080                 vl_free(bitmap);
00081             }
00082             else {
00083                 pfree(bitmap);
00084             }
00085             bitmap = NULL;
00086         }
00087     }
00088     if (!bitmap) {
00089         // We need a new bitmap
00090         if (shared) {
00091             bitmap = vl_shmalloc(sizeof(Bitmap) + (sizeof(int32) * elems));
00092         }
00093         else {
00094             bitmap = vl_malloc(sizeof(Bitmap) + (sizeof(int32) * elems));
00095         }
00096     }
00097 
00098     DBG_SET_CANARY(*bitmap);
00099     DBG_SET_ELEMS(*bitmap, elems);
00100     DBG_SET_TRAILER(*bitmap, bitset);
00101     bitmap->type = OBJ_BITMAP;
00102     bitmap->bitzero = min;
00103     bitmap->bitmax = max;
00104     vl_ClearBitmap(bitmap);
00105 
00106     DBG_TEST_CANARY(*bitmap);
00107     DBG_TEST_TRAILER(*bitmap, bitset);
00108     *p_bitmap = bitmap;
00109 }
00110 
00111 /** 
00112  * Set a bit within a ::Bitmap.  If the bit is outside of the acceptable
00113  * range, raise an error.
00114  * 
00115  * @param bitmap The ::Bitmap within which the bit is to be set. 
00116  * @param bit The bit to be set.
00117  */
00118 void
00119 vl_BitmapSetbit(Bitmap *bitmap,
00120                 int32 bit)
00121 {
00122     int relative_bit = bit - BITZERO(bitmap->bitzero);
00123     int element = BITSET_ELEM(relative_bit);
00124 
00125     if ((bit > bitmap->bitmax) ||
00126         (bit < bitmap->bitzero)) 
00127     {
00128         ereport(ERROR,
00129                 (errcode(ERRCODE_INTERNAL_ERROR),
00130                  errmsg("Bitmap range error"),
00131                  errdetail("Bit (%d) not in range %d..%d.  ", bit,
00132                            bitmap->bitzero, bitmap->bitmax)));
00133     }
00134 
00135     DBG_CHECK_INDEX(*bitmap, element);
00136     bitmap->bitset[element] |= bitmasks[BITSET_BIT(relative_bit)];
00137     DBG_TEST_CANARY(*bitmap);
00138     DBG_TEST_TRAILER(*bitmap, bitset);
00139 }
00140 
00141 /** 
00142  * Clear a bit within a ::Bitmap.  If the bit is outside of the acceptable
00143  * range, raise an error.
00144  * 
00145  * @param bitmap The ::Bitmap within which the bit is to be cleared. 
00146  * @param bit The bit to be cleared.
00147  */
00148 void
00149 vl_BitmapClearbit(Bitmap *bitmap,
00150                   int32 bit)
00151 {
00152     int relative_bit = bit - BITZERO(bitmap->bitzero);
00153     int element = BITSET_ELEM(relative_bit);
00154 
00155     if ((bit > bitmap->bitmax) ||
00156         (bit < bitmap->bitzero)) 
00157     {
00158         ereport(ERROR,
00159                 (errcode(ERRCODE_INTERNAL_ERROR),
00160                  errmsg("Bitmap range error"),
00161                  errdetail("Bit (%d) not in range %d..%d.  ", bit,
00162                            bitmap->bitzero, bitmap->bitmax)));
00163     }
00164 
00165     bitmap->bitset[element] &= ~(bitmasks[BITSET_BIT(relative_bit)]);
00166 }
00167 
00168 /** 
00169  * Test a bit within a ::Bitmap.  If the bit is outside of the acceptable
00170  * range return false.
00171  * 
00172  * @param bitmap The ::Bitmap within which the bit is to be set. 
00173  * @param bit The bit to be tested.
00174  * 
00175  * @return True if the bit is set, false otherwise.
00176  */
00177 bool
00178 vl_BitmapTestbit(Bitmap *bitmap,
00179                  int32 bit)
00180 {
00181     int relative_bit = bit - BITZERO(bitmap->bitzero);
00182     int element = BITSET_ELEM(relative_bit);
00183 
00184     if ((bit > bitmap->bitmax) ||
00185         (bit < bitmap->bitzero)) 
00186     {
00187         return false;
00188     }
00189 
00190     return (bitmap->bitset[element] & bitmasks[BITSET_BIT(relative_bit)]) != 0;
00191 }
00192 
00193 /** 
00194  * Create the union of two bitmaps, updating the first with the result.
00195  * 
00196  * @param target The ::Bitmap into which the result will be placed.
00197  * @param source The ::Bitmap to be unioned into target.
00198  */
00199 void
00200 vl_BitmapUnion(Bitmap *target,
00201                Bitmap *source)
00202 {
00203     int i;
00204     int elems = ARRAYELEMS(target->bitzero, target->bitmax);
00205 
00206     // TODO: Make this tolerant of range mismatches.
00207     if ((target->bitzero != source->bitzero) ||
00208         (target->bitmax != source->bitmax))
00209     {
00210         ereport(ERROR,
00211                 (errcode(ERRCODE_INTERNAL_ERROR),
00212                  errmsg("Incompatible bitmaps"),
00213                  errdetail("Target range is %d..%d.  Source range %d..%d.",
00214                            target->bitzero, target->bitmax,
00215                            source->bitzero, source->bitmax)));
00216     }
00217     for (i = 0; i < elems; i++) {
00218         target->bitset[i] |= source->bitset[i];
00219     }
00220 }
00221 
00222 /** 
00223  * Create the intersection of two bitmaps, updating the first with the
00224  * result.
00225  * 
00226  * @param target The ::Bitmap into which the result will be placed.
00227  * @param source The ::Bitmap to be intersected into target.
00228  */
00229 void
00230 vl_BitmapIntersect(Bitmap *target,
00231                    Bitmap *source)
00232 {
00233     int i;
00234     int elems = ARRAYELEMS(target->bitzero, target->bitmax);
00235 
00236     // TODO: Make this tolerant of range mismatches.
00237     if ((target->bitzero != source->bitzero) ||
00238         (target->bitmax != source->bitmax))
00239     {
00240         ereport(ERROR,
00241                 (errcode(ERRCODE_INTERNAL_ERROR),
00242                  errmsg("Incompatible bitmaps"),
00243                  errdetail("Target range is %d..%d.  Source range %d..%d.",
00244                            target->bitzero, target->bitmax,
00245                            source->bitzero, source->bitmax)));
00246     }
00247     for (i = 0; i < elems; i++) {
00248         target->bitset[i] &= source->bitset[i];
00249     }
00250 }
00251 
00252 /** 
00253  * Return the next set bit in the ::Bitmap.
00254  * 
00255  * @param bitmap The ::Bitmap being scanned.
00256  * @param bit The starting bit from which to scan the bitmap
00257  * @param found Boolean that will be set to true when a set bit has been
00258  * found.
00259  * 
00260  * @return The bit id of the found bit, or zero if no set bits were found. 
00261  */
00262 int32
00263 vl_BitmapNextBit(Bitmap *bitmap,
00264                  int32 bit,
00265                  bool *found)
00266 {
00267     while (bit <= bitmap->bitmax) {
00268         if (vl_BitmapTestbit(bitmap, bit)) {
00269             *found = true;
00270             return bit;
00271         }
00272         bit++;
00273     }
00274     *found = false;
00275     return 0;
00276 }
00277 
00278 /** 
00279  * Return a specified ::Bitmap from a ::BitmapArray.
00280  * 
00281  * @param bmarray The ::BitmapArray from which the result is to be
00282  * returned.
00283  * @param elem The index of the ::Bitmap within the array. 
00284  * 
00285  * @return The bitmap corresponding to the parameters, or NULL if no
00286  *such entry exists within the array.
00287  */
00288 Bitmap *
00289 vl_BitmapFromArray(BitmapArray *bmarray,
00290                    int32 elem)
00291 {
00292     DBG_TEST_CANARY(*bmarray);
00293     DBG_TEST_TRAILER(*bmarray, bitmap);
00294     if ((elem < bmarray->arrayzero) || (elem > bmarray->arraymax)) {
00295         return NULL;
00296     }
00297     else {
00298         DBG_CHECK_INDEX(*bmarray, elem - bmarray->arrayzero);
00299         return bmarray->bitmap[elem - bmarray->arrayzero];
00300     }
00301 }
00302 
00303 /** 
00304  * Clear all bitmaps in the given ::BitmapArray
00305  * 
00306  * @param bmarray The ::BitmapArray to be cleared
00307  */
00308 void
00309 vl_ClearBitmapArray(BitmapArray *bmarray)
00310 {
00311     int bitmaps = bmarray->arraymax + 1 - bmarray->arrayzero;
00312     int i;
00313 
00314     DBG_TEST_CANARY(*bmarray);
00315     DBG_TEST_TRAILER(*bmarray, bitmap);
00316     for (i = 0; i < bitmaps; i++) {
00317         DBG_CHECK_INDEX(*bmarray, i);
00318         vl_ClearBitmap(bmarray->bitmap[i]);
00319     }
00320 }
00321 
00322 /** 
00323  * Return a newly initialised (empty) ::BitmapArray.  It may already
00324  * exist in which case it will be re-used if possible.  It may
00325  * be created in either session or shared memory depending on the value
00326  * of shared.
00327  * 
00328  * @param p_bmarray Pointer to an existing bitmap if one exists.
00329  * @param shared Whether to create the bitmap in shared memory
00330  * @param arrayzero The lowest array index
00331  * @param arraymax The highest array index
00332  * @param bitzero The smallest bit to be stored in the bitmap
00333  * @param bitmax The largest bit to be stored in the bitmap
00334  */
00335 void
00336 vl_NewBitmapArray(BitmapArray **p_bmarray, bool shared,
00337                   int32 arrayzero, int32 arraymax,
00338                   int32 bitzero, int32 bitmax)
00339 {
00340     BitmapArray *bmarray = *p_bmarray;
00341     int bitsetelems = ARRAYELEMS(bitzero, bitmax);
00342     int bitmaps = arraymax + 1 - arrayzero;
00343     int i;
00344 
00345     if (bmarray) {
00346         // We already have a bitmap array.  If possible, we re-use it.
00347         int cur_elems = ARRAYELEMS(bmarray->bitzero, bmarray->bitmax);
00348         int cur_maps = bmarray->arraymax + 1 - bmarray->arrayzero;
00349 
00350         DBG_TEST_CANARY(*bmarray);
00351         DBG_TEST_TRAILER(*bmarray, bitmap);
00352         if ((cur_elems >= bitsetelems) && (cur_maps >= bitmaps)) {
00353             vl_ClearBitmapArray(bmarray);
00354         }
00355         else {
00356             if (shared) {
00357                 for (i = 0; i < cur_maps; i++) {
00358                     vl_free(bmarray->bitmap[i]);
00359                 }
00360                 vl_free(bmarray);
00361             }
00362             else {
00363                 for (i = 0; i < cur_maps; i++) {
00364                     pfree(bmarray->bitmap[i]);
00365                 }
00366                 pfree(bmarray);
00367             }
00368             bmarray = NULL;
00369         }
00370     }
00371 
00372     if (!bmarray) {
00373         if (shared) {
00374             bmarray = vl_shmalloc(sizeof(BitmapArray) + 
00375                                  (sizeof(Bitmap *) * bitmaps));
00376 
00377         }
00378         else {
00379             bmarray = vl_malloc(sizeof(BitmapArray) + 
00380                                 (sizeof(Bitmap *) * bitmaps));
00381         }
00382 
00383         for (i = 0; i < bitmaps; i++) {
00384             bmarray->bitmap[i] = NULL;
00385             vl_NewBitmap(&(bmarray->bitmap[i]), shared, bitzero, bitmax);
00386         }
00387 
00388         bmarray->type = OBJ_BITMAP_ARRAY;
00389         DBG_SET_CANARY(*bmarray);
00390         DBG_SET_ELEMS(*bmarray, bitmaps);
00391         DBG_SET_TRAILER(*bmarray, bitmap);
00392     }
00393     bmarray->bitzero = bitzero;
00394     bmarray->bitmax = bitmax;
00395     bmarray->arrayzero = arrayzero;
00396     bmarray->arraymax = arraymax;
00397 
00398     for (i = 0; i < bitmaps; i++) {
00399         bmarray->bitmap[i]->type = OBJ_BITMAP;
00400         bmarray->bitmap[i]->bitzero = bitzero;
00401         bmarray->bitmap[i]->bitmax = bitmax;
00402     }
00403 
00404     *p_bmarray = bmarray;
00405 }
00406 
00407 /** 
00408  * Create a new hash table.  This is allocated from session memory as
00409  * BitmapHashes may not be declared as shared variables.
00410  * 
00411  * @param name The name of the hash to be created.  Note that we prefix
00412  * this with "vl_" to prevent name collisions from other subsystems.
00413  * 
00414  * @return Pointer to the newly created hash table.
00415  */
00416 static HTAB *
00417 new_hash(char *name)
00418 {
00419     char     vl_name[HASH_KEYLEN];
00420     HTAB    *hash;
00421     HASHCTL  hashctl;
00422 
00423     (void) snprintf(vl_name, HASH_KEYLEN - 1, "vl_%s", name);
00424 
00425     hashctl.keysize = HASH_KEYLEN;
00426     hashctl.entrysize = sizeof(VarEntry);
00427 
00428     hash = hash_create(vl_name, 200, &hashctl, HASH_ELEM);
00429     return hash;
00430 }
00431 
00432 /** 
00433  * Utility function for scanning the hash table of a BitmapHash.
00434  * 
00435  * @param hash The hash table being scanned
00436  * @param prev The entry from which to scan, starting with NULL.
00437  * 
00438  * @return The next element in the hash table (a VarEntry) or NULL when
00439  * the last element has already been scanned.
00440  */
00441 VarEntry *
00442 vl_NextHashEntry(HTAB *hash,
00443                  VarEntry *prev)
00444 {
00445     VarEntry *next;
00446     static HASH_SEQ_STATUS status;
00447     if (!prev) {
00448         // Initialise the hash search
00449         
00450         hash_seq_init(&status, hash);
00451     }
00452     next = (VarEntry *) hash_seq_search(&status);
00453     return (next);
00454 }
00455 
00456 /** 
00457  * Return a newly initialised (empty) ::BitmapHash.  It may already
00458  * exist in which case it will be re-used if possible.  BitmapHash
00459  * variables may only be created as session (not shared) variables.
00460  * 
00461  * @param p_bmhash Pointer to an existing bitmap if one exists.
00462  * @param name The name to be used for the hash table
00463  * @param bitzero The smallest bit to be stored in the bitmap
00464  * @param bitmax The largest bit to be stored in the bitmap
00465  */
00466 void
00467 vl_NewBitmapHash(BitmapHash **p_bmhash, char *name,
00468                  int32 bitzero, int32 bitmax)
00469 {
00470     BitmapHash *bmhash = *p_bmhash;
00471 
00472     if (bmhash) {
00473         VarEntry *entry = NULL;
00474         HTAB *hash = bmhash->hash;
00475         bool found;
00476 
00477         while ((entry = vl_NextHashEntry(hash, entry))) {
00478             if (entry->obj) {
00479                 if (entry->obj->type != OBJ_BITMAP) {
00480                     ereport(ERROR,
00481                             (errcode(ERRCODE_INTERNAL_ERROR),
00482                              errmsg("Bitmap hash contains invalid object %d",
00483                                     entry->obj->type),
00484                              errdetail("Object type is %d, expected is %d.",
00485                                        entry->obj->type, OBJ_BITMAP)));
00486                 }
00487                 pfree(entry->obj);  // Free the bitmap
00488             }
00489             // Now remove the entry from the hash
00490             (void) hash_search(hash, entry->key, HASH_REMOVE, &found);
00491         }
00492     }
00493     else {
00494         bmhash = vl_malloc(sizeof(BitmapHash));
00495         bmhash->type = OBJ_BITMAP_HASH;
00496         bmhash->hash = new_hash(name);
00497     }
00498     bmhash->bitzero = bitzero;
00499     bmhash->bitmax = bitmax;
00500 
00501     *p_bmhash = bmhash;
00502 }
00503 
00504 /** 
00505  * Return a specified ::Bitmap from a ::BitmapHash.  Raise an error if
00506  * the returned object from the hash search is not a bitmap.
00507  * 
00508  * @param bmhash The ::BitmapHash from which the result is to be
00509  * returned.
00510  * @param hashelem The key of the ::Bitmap within the hash. 
00511  * 
00512  * @return The bitmap corresponding to the parameters, or NULL if no
00513  *such entry exists within the hash.
00514  */
00515 Bitmap *
00516 vl_BitmapFromHash(BitmapHash *bmhash,
00517                   char *hashelem)
00518 {
00519     VarEntry *var;
00520     Bitmap   *bitmap;
00521     bool      found;
00522 
00523     var = hash_search(bmhash->hash, hashelem, HASH_FIND, &found);
00524     if (!found) {
00525         return NULL;
00526     }
00527     
00528     if (!var->obj) {
00529         ereport(ERROR,
00530                 (errcode(ERRCODE_INTERNAL_ERROR),
00531                  errmsg("BitmapFromHash - empty VarEntry")));
00532     }
00533 
00534     if (var->obj->type != OBJ_BITMAP) {
00535         ereport(ERROR,
00536                 (errcode(ERRCODE_INTERNAL_ERROR),
00537                  errmsg("Bitmap hash contains invalid object %d",
00538                         var->obj->type),
00539                  errdetail("Object type is %d, expected is %d.",
00540                            var->obj->type, OBJ_BITMAP)));
00541     }
00542 
00543     bitmap = (Bitmap *) var->obj;
00544     return bitmap;
00545 }
00546 
00547 /** 
00548  * Create a newly allocated empty ::Bitmap to a ::BitmapHash
00549  * 
00550  * @param bmhash The ::BitmapHash to which to add the new ::Bitmap.
00551  * @param hashelem The key for the new entry
00552  * 
00553  * @return Pointer to the newly allocated empty ::Bitmap.
00554  */
00555 Bitmap *
00556 vl_AddBitmapToHash(BitmapHash *bmhash,
00557                    char *hashelem)
00558 {
00559     VarEntry *var;
00560     Bitmap   *bitmap = NULL;
00561     bool      found;
00562 
00563     var = hash_search(bmhash->hash, hashelem, HASH_ENTER, &found);
00564     if (found) {
00565         if (!var->obj) {
00566             ereport(ERROR,
00567                     (errcode(ERRCODE_INTERNAL_ERROR),
00568                      errmsg("AddBitmapToHash - empty VarEntry")));
00569         }
00570         if (var->obj->type != OBJ_BITMAP) {
00571             ereport(ERROR,
00572                     (errcode(ERRCODE_INTERNAL_ERROR),
00573                      errmsg("AddBitmapToHash - type mismatch %d",
00574                             var->obj->type),
00575                      errdetail("Object type is %d, expected is %d.",
00576                                var->obj->type, OBJ_BITMAP)));
00577         }
00578         return (Bitmap *) var->obj;
00579     }
00580 
00581     // We've created a new entry.  Now create the bitmap for it.
00582 
00583     vl_NewBitmap(&bitmap, FALSE, bmhash->bitzero, bmhash->bitmax);
00584     var->obj = (Object *) bitmap;
00585     return bitmap;
00586 }
00587 
00588 /** 
00589  * Determine whether the supplied key exists in the ::BitmapHash.
00590  * 
00591  * @param bmhash The ::BitmapHash to be tested
00592  * @param hashelem The key to be tested
00593  * 
00594  * @return True if the key already exists in the hash.
00595  */
00596 bool
00597 vl_BitmapHashHasKey(BitmapHash *bmhash,
00598                     char *hashelem)
00599 {
00600     VarEntry *var;
00601     bool      found;
00602 
00603     var = hash_search(bmhash->hash, hashelem, HASH_FIND, &found);
00604     return found;
00605 }

Generated on Fri Mar 12 08:38:37 2010 for Veil by  doxygen 1.5.6