Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

mem_push.C

Go to the documentation of this file.
00001 /* Copyright 1992, Brown Computer Graphics Group.  All Rights Reserved. */
00002 
00003 /* -------------------------------------------------------------------------
00004  * DESCR   :   mem_push.C - Pushdown storage object
00005  *
00006  * DETAILS :   Two "current" offsets are kept into the set of allocated
00007  *              memory to keep track of the bottom and top of the pushdown 
00008  *              store.  The "top" grows downward in memory, so at any time
00009  *              the "top" of the store should have an offset value less than
00010  *              that of the "bottom".  If the "top" is greater than the
00011  *              "bottom", then the objects in the store have "wrapped around"
00012  *              the available storage so that the top of the store resides at
00013  *              the end of the allocated memory and the bottom is at the
00014  *              beginning.
00015  *
00016  *
00017  *              Blocks   0     1     2     3     4     5     6 ...
00018  *                    *-----*-----*-----*-----*-----*-----*-----*-----*-----*
00019  *                            ######################################
00020  *                    *-----*-^---*-----*-----*-----*-----*-----*---^-*-----*
00021  *                            Top                                   Bottom
00022  *
00023  *              Blocks   0     1     2     3     4     5     6 ...
00024  *                    *-----*-----*-----*-----*-----*-----*-----*-----*-----*
00025  *                    ####################                    ###############
00026  *                    *-----*-----*-----*-^---*-----*-----*---^-*-----*-----*
00027  *                                        Bottom              Top
00028  *
00029  *              ### = used by store
00030  *
00031  * Author: crb (Chris R. Brown)
00032  * ------------------------------------------------------------------------- */
00033 
00034 #include "std/support.H"
00035 #include "mem_push.H"
00036 #define MIN(A,B) (A < B ? A :  B)
00037 static const int MEM_PUSHDOWN_BLOCK_COUNT  = 4096;
00038 
00039 /* -----------------------  Private Methods  ------------------------------- */
00040 
00041 
00042 /* -------------------------------------------------------------------------
00043  * DESCR   :   Increases the number of allocated blocks to accomodate
00044  *       incoming data.
00045  * ------------------------------------------------------------------------- */
00046 void
00047 mem_push::increase_mem (
00048    size_t amount
00049    )
00050 {
00051    size_t mem_avail  = num_blocks * block_size;
00052    size_t mem_in_use = num_objects * obj_size;
00053    size_t i;
00054 
00055    /* Reallocation is tricky, but fairly infrequent */
00056    if (amount + mem_in_use >= mem_avail 
00057       || block_index(bottom + amount - 1) > num_blocks - 1)
00058    {
00059       size_t new_size = (amount + mem_in_use > mem_avail) ?
00060           amount + mem_in_use : bottom + amount;
00061       size_t new_num_blocks = (new_size - 1) / block_size + 1;
00062       const int num_b = num_blocks;
00063       static const int ptr_size = sizeof(char **);
00064       blocks = (char **) realloc(blocks, new_num_blocks * ptr_size);
00065       for (i = num_b; i < new_num_blocks; i++)
00066          blocks[i] = NULL;
00067 
00068       /*
00069        * If our pushdown 'wraps around', we need to copy the "top" portion
00070        * (the part that physically lies at the end of allocated memory) upward
00071        */
00072       if (top > bottom)
00073       {
00074          size_t  old_index, blocks_to_move, new_index, new_top;
00075          int flag;
00076 
00077          flag = (block_index (top) == block_index (bottom));
00078 
00079          old_index      = block_index (top) + (flag ? 1 : 0);
00080          blocks_to_move = num_blocks - old_index;
00081          new_index      = new_num_blocks - blocks_to_move;
00082          new_top        = top + blocks_to_move * block_size;
00083 
00084          /* move whole blocks indirectly */
00085          memmove ((char *)(blocks + new_index),
00086                   (char *)(blocks + old_index),
00087                    blocks_to_move  * sizeof(UGAptr));
00088 
00089          for (i = old_index; i < new_index; i++)
00090              blocks[i] = (UGAptr)malloc(block_size);
00091 
00092          /* finally, copy the "top-most" portion */
00093          if (flag)
00094             memmove((char *)(block_addr (new_top)),
00095                     (char *)(block_addr (top)),
00096                     block_left (top));
00097          top = new_top;
00098       }
00099       else {
00100          for (i = num_b; i < new_num_blocks; i++)
00101             blocks[i] = (UGAptr)malloc(block_size);
00102       }
00103 
00104       num_blocks = new_num_blocks;
00105    }
00106 }
00107 
00108 
00109 /* -------------------------------------------------------------------------
00110  * DESCR   :   Decreases the allocated blocks to allow for objects that
00111  *       have been removed.
00112  * ------------------------------------------------------------------------- */
00113 void
00114 mem_push::decrease_mem (
00115    size_t                       /* unused */
00116    )
00117 {
00118    if (num_objects == 0 && blocks)
00119    {
00120 #ifdef later
00121       for (int i = 0; i < num_blocks; i++)
00122           free(blocks[i]);
00123       if (blocks) free(blocks);
00124       num_blocks = 0;
00125 #endif
00126 
00127       top = bottom = 0;
00128    }
00129 }
00130 
00131 
00132 /* ----------------------- Protected Methods ------------------------------- */
00133 
00134 
00135 /* -------------------------------------------------------------------------
00136  * DESCR   :   Inserts new objects at the top of the store.  If @obj_count@
00137  *       > 1,  then objects are copied into the store starting from
00138  *            the leftmost object in the array pointed to by the @objects@
00139  *       parameter. 
00140  * ------------------------------------------------------------------------- */
00141 void
00142 mem_push::insert_top (
00143    UGAptr       objects,
00144    size_t       obj_count
00145    )
00146 {
00147    if (objects && obj_count)
00148    {
00149       register size_t obj_mem = obj_count * obj_size;
00150       size_t avail_mem;
00151 
00152       increase_mem (obj_mem);
00153       avail_mem = num_blocks * block_size;
00154 
00155       /* Copy data into top of store, left to right */
00156       while (obj_mem > 0)
00157       {
00158          register size_t temp_count = MIN (block_offset (top), obj_mem);
00159          temp_count = MIN (temp_count, obj_size);
00160 
00161          int signed_top = top - temp_count;
00162          if (signed_top < 0)
00163             top = top + avail_mem - temp_count;
00164          else
00165             top -= temp_count;
00166 
00167          memmove(block_addr (top), objects, temp_count);
00168 
00169          objects   += temp_count;
00170          obj_mem   -= temp_count;
00171       }
00172       num_objects += obj_count;
00173    }
00174 }
00175 
00176 
00177 /* -------------------------------------------------------------------------
00178  * DESCR :  Inserts new objects in the bottom of the store.  If
00179  *       @obj_count@ > 1, then the @objects@ parameter is
00180  *       interpreted as an array of objects to be inserted, starting
00181  *       with the first element in the array.
00182  * ------------------------------------------------------------------------- */
00183 void
00184 mem_push::insert_bottom (
00185    const char *objects,
00186    size_t      obj_count
00187    )
00188 {
00189    if (objects && obj_count)
00190    {
00191       register size_t obj_mem = obj_count * obj_size;
00192 
00193       increase_mem (obj_mem);
00194 
00195       /* copy objects into list, left to right */
00196       while (obj_mem > 0)
00197       {
00198          register size_t temp_count = MIN (block_left (bottom), obj_mem);
00199 
00200          memmove(block_addr(bottom), objects, temp_count);
00201 
00202          bottom    += temp_count;
00203 
00204          objects   += temp_count;
00205          obj_mem   -= temp_count;
00206       }
00207       num_objects += obj_count;
00208    }
00209 }
00210 
00211 
00212 /* -------------------------------------------------------------------------
00213  * DESCR :  Removes objects from the top of the pushdown.  If the
00214  *       @obj_count@ parameter is larger than 1, objects will be
00215  *       removed and copied into the array pointed to by @objects@
00216  *       starting at the left of the array.
00217  *
00218  * RETURNS :    The number of objects actually removed from the store.
00219  * ------------------------------------------------------------------------- */
00220 size_t
00221 mem_push::remove_top (
00222    UGAptr objects,
00223    size_t obj_count
00224    )
00225 {
00226    size_t return_val = MIN (obj_count, num_objects);
00227 
00228    peek_top (objects, return_val);
00229 
00230    num_objects -= return_val;
00231    top += return_val;
00232 
00233 // bcz: I think these lines are bogus as long as decrease_mem has
00234 //      all of its contents ifdef'd out.
00235 //   size_t avail_mem = num_blocks * block_size;
00236 //   if (top >= avail_mem)
00237 //      top -= avail_mem;
00238 
00239    decrease_mem (obj_count * obj_size);
00240 
00241    return (return_val);
00242 }
00243 
00244 
00245 /* -------------------------------------------------------------------------
00246  * DESCR   :   Extracts objects from the top of the pushdown store without
00247  *       removing them, as the @pop@ method describes above.
00248  *
00249  * RETURNS :    The number of objects actually transferred to the data buffer.
00250  * ------------------------------------------------------------------------- */
00251 size_t
00252 mem_push::peek_top (
00253    UGAptr objects,
00254    size_t obj_count
00255    ) const
00256 {
00257    size_t          return_val = 0;
00258 
00259    if (objects)
00260    {
00261       size_t          temp_top = top;
00262       register size_t obj_mem;
00263 
00264       return_val = MIN (obj_count, num_objects);
00265       obj_mem = return_val * obj_size;
00266 
00267       /* Copy data from store into the array, left to right */   
00268       while (obj_mem > 0)
00269       {
00270          register size_t temp_count = MIN (block_left (temp_top), obj_mem);
00271 
00272          memmove (objects, block_addr (temp_top), temp_count);
00273 
00274          temp_top  += temp_count;
00275 
00276          obj_mem   -= temp_count;
00277          objects   += temp_count;
00278       }
00279    }
00280 
00281    return (return_val);
00282 }
00283 
00284 
00285 /* -----------------------  Public Methods   ------------------------------- */
00286 
00287 /* -------------------------------------------------------------------------
00288  * DESCR   :   Constructor.  If no object size is specified, then the
00289  *       storage deals with bytes and the application is responsible
00290  *       for tracking the objects placed on the pushdown store.
00291  * ------------------------------------------------------------------------- */
00292 mem_push::mem_push (
00293    size_t object_size                 /* size of a single data object */
00294    ) :
00295    obj_size (object_size)
00296 {
00297    blocks     = NULL;
00298    num_blocks = num_objects = 0;
00299    top = bottom = 0;
00300 
00301    /* intelligently choose an allocation block size based on the data size */
00302    block_size = obj_size * MEM_PUSHDOWN_BLOCK_COUNT;
00303 }
00304 
00305 /* -------------------------------------------------------------------------
00306  * DESCR   :   Destructor.
00307  * ------------------------------------------------------------------------- */
00308 mem_push::~mem_push (void)
00309 {
00310    for (size_t i = 0; i < num_blocks; i++)
00311       free(blocks[i]);
00312    if (blocks) free(blocks);
00313 }

Generated on Mon Sep 18 11:39:32 2006 for jot by  doxygen 1.4.4