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