block.h
Go to the documentation of this file.
00001 /* block.h */
00002 /*
00003         Template classes Block and DBlock
00004         Implement adding and deleting items of the same type in blocks.
00005 
00006         If there there are many items then using Block or DBlock
00007         is more efficient than using 'new' and 'delete' both in terms
00008         of memory and time since
00009         (1) On some systems there is some minimum amount of memory
00010             that 'new' can allocate (e.g., 64), so if items are
00011             small that a lot of memory is wasted.
00012         (2) 'new' and 'delete' are designed for items of varying size.
00013             If all items has the same size, then an algorithm for
00014             adding and deleting can be made more efficient.
00015         (3) All Block and DBlock functions are inline, so there are
00016             no extra function calls.
00017 
00018         Differences between Block and DBlock:
00019         (1) DBlock allows both adding and deleting items,
00020             whereas Block allows only adding items.
00021         (2) Block has an additional operation of scanning
00022             items added so far (in the order in which they were added).
00023         (3) Block allows to allocate several consecutive
00024             items at a time, whereas DBlock can add only a single item.
00025 
00026         Note that no constructors or destructors are called for items.
00027 
00028         Example usage for items of type 'MyType':
00029 
00031         #include "block.h"
00032         #define BLOCK_SIZE 1024
00033         typedef struct { int a, b; } MyType;
00034         MyType *ptr, *array[10000];
00035 
00036         ...
00037 
00038         Block<MyType> *block = new Block<MyType>(BLOCK_SIZE);
00039 
00040         // adding items
00041         for (int i=0; i<sizeof(array); i++)
00042         {
00043                 ptr = block -> New();
00044                 ptr -> a = ptr -> b = rand();
00045         }
00046 
00047         // reading items
00048         for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext())
00049         {
00050                 printf("%d %d\n", ptr->a, ptr->b);
00051         }
00052 
00053         delete block;
00054 
00055         ...
00056 
00057         DBlock<MyType> *dblock = new DBlock<MyType>(BLOCK_SIZE);
00058         
00059         // adding items
00060         for (int i=0; i<sizeof(array); i++)
00061         {
00062                 array[i] = dblock -> New();
00063         }
00064 
00065         // deleting items
00066         for (int i=0; i<sizeof(array); i+=2)
00067         {
00068                 dblock -> Delete(array[i]);
00069         }
00070 
00071         // adding items
00072         for (int i=0; i<sizeof(array); i++)
00073         {
00074                 array[i] = dblock -> New();
00075         }
00076 
00077         delete dblock;
00078 
00080 
00081         Note that DBlock deletes items by marking them as
00082         empty (i.e., by adding them to the list of free items),
00083         so that this memory could be used for subsequently
00084         added items. Thus, at each moment the memory allocated
00085         is determined by the maximum number of items allocated
00086         simultaneously at earlier moments. All memory is
00087         deallocated only when the destructor is called.
00088 */
00089 
00090 #ifndef __BLOCK_H__
00091 #define __BLOCK_H__
00092 
00093 #include <stdlib.h>
00094 
00095 /***********************************************************************/
00096 /***********************************************************************/
00097 /***********************************************************************/
00098 
00099 template <class Type> class Block
00100 {
00101 public:
00102         /* Constructor. Arguments are the block size and
00103            (optionally) the pointer to the function which
00104            will be called if allocation failed; the message
00105            passed to this function is "Not enough memory!" */
00106         Block(int size, void (*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; }
00107 
00108         /* Destructor. Deallocates all items added so far */
00109         ~Block() { while (first) { block *next = first -> next; delete first; first = next; } }
00110 
00111         /* Allocates 'num' consecutive items; returns pointer
00112            to the first item. 'num' cannot be greater than the
00113            block size since items must fit in one block */
00114         Type *New(int num = 1)
00115         {
00116                 Type *t;
00117 
00118                 if (!last || last->current + num > last->last)
00119                 {
00120                         if (last && last->next) last = last -> next;
00121                         else
00122                         {
00123                                 block *next = (block *) new char [sizeof(block) + (block_size-1)*sizeof(Type)];
00124                                 if (!next) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
00125                                 if (last) last -> next = next;
00126                                 else first = next;
00127                                 last = next;
00128                                 last -> current = & ( last -> data[0] );
00129                                 last -> last = last -> current + block_size;
00130                                 last -> next = NULL;
00131                         }
00132                 }
00133 
00134                 t = last -> current;
00135                 last -> current += num;
00136                 return t;
00137         }
00138 
00139         /* Returns the first item (or NULL, if no items were added) */
00140         Type *ScanFirst()
00141         {
00142                 for (scan_current_block=first; scan_current_block; scan_current_block = scan_current_block->next)
00143                 {
00144                         scan_current_data = & ( scan_current_block -> data[0] );
00145                         if (scan_current_data < scan_current_block -> current) return scan_current_data ++;
00146                 }
00147                 return NULL;
00148         }
00149 
00150         /* Returns the next item (or NULL, if all items have been read)
00151            Can be called only if previous ScanFirst() or ScanNext()
00152            call returned not NULL. */
00153         Type *ScanNext()
00154         {
00155                 while (scan_current_data >= scan_current_block -> current)
00156                 {
00157                         scan_current_block = scan_current_block -> next;
00158                         if (!scan_current_block) return NULL;
00159                         scan_current_data = & ( scan_current_block -> data[0] );
00160                 }
00161                 return scan_current_data ++;
00162         }
00163 
00164         /* Marks all elements as empty */
00165         void Reset()
00166         {
00167                 block *b;
00168                 if (!first) return;
00169                 for (b=first; ; b=b->next)
00170                 {
00171                         b -> current = & ( b -> data[0] );
00172                         if (b == last) break;
00173                 }
00174                 last = first;
00175         }
00176 
00177 /***********************************************************************/
00178 
00179 private:
00180 
00181         typedef struct block_st
00182         {
00183                 Type                                    *current, *last;
00184                 struct block_st                 *next;
00185                 Type                                    data[1];
00186         } block;
00187 
00188         int             block_size;
00189         block   *first;
00190         block   *last;
00191 
00192         block   *scan_current_block;
00193         Type    *scan_current_data;
00194 
00195         void    (*error_function)(char *);
00196 };
00197 
00198 /***********************************************************************/
00199 /***********************************************************************/
00200 /***********************************************************************/
00201 
00202 template <class Type> class DBlock
00203 {
00204 public:
00205         /* Constructor. Arguments are the block size and
00206            (optionally) the pointer to the function which
00207            will be called if allocation failed; the message
00208            passed to this function is "Not enough memory!" */
00209         DBlock(int size, void (*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; }
00210 
00211         /* Destructor. Deallocates all items added so far */
00212         ~DBlock() { while (first) { block *next = first -> next; delete first; first = next; } }
00213 
00214         /* Allocates one item */
00215         Type *New()
00216         {
00217                 block_item *item;
00218 
00219                 if (!first_free)
00220                 {
00221                         block *next = first;
00222                         first = (block *) new char [sizeof(block) + (block_size-1)*sizeof(block_item)];
00223                         if (!first) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
00224                         first_free = & (first -> data[0] );
00225                         for (item=first_free; item<first_free+block_size-1; item++)
00226                                 item -> next_free = item + 1;
00227                         item -> next_free = NULL;
00228                         first -> next = next;
00229                 }
00230 
00231                 item = first_free;
00232                 first_free = item -> next_free;
00233                 return (Type *) item;
00234         }
00235 
00236         /* Deletes an item allocated previously */
00237         void Delete(Type *t)
00238         {
00239                 ((block_item *) t) -> next_free = first_free;
00240                 first_free = (block_item *) t;
00241         }
00242 
00243 /***********************************************************************/
00244 
00245 private:
00246 
00247         typedef union block_item_st
00248         {
00249                 Type                    t;
00250                 block_item_st   *next_free;
00251         } block_item;
00252 
00253         typedef struct block_st
00254         {
00255                 struct block_st                 *next;
00256                 block_item                              data[1];
00257         } block;
00258 
00259         int                     block_size;
00260         block           *first;
00261         block_item      *first_free;
00262 
00263         void    (*error_function)(char *);
00264 };
00265 
00266 
00267 #endif
00268 


tabletop_pushing
Author(s): Tucker Hermans
autogenerated on Wed Nov 27 2013 11:59:44