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