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

Generated on Tue Mar 11 10:20:03 2008 for Veil by  doxygen 1.5.4