RTS2D
include/graph/block.h
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 
 Todos Classes Funções