block.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* block.h */
  2. /*
  3. Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. */
  16. /*
  17. Template classes Block and DBlock
  18. Implement adding and deleting items of the same type in blocks.
  19. If there there are many items then using Block or DBlock
  20. is more efficient than using 'new' and 'delete' both in terms
  21. of memory and time since
  22. (1) On some systems there is some minimum amount of memory
  23. that 'new' can allocate (e.g., 64), so if items are
  24. small that a lot of memory is wasted.
  25. (2) 'new' and 'delete' are designed for items of varying size.
  26. If all items has the same size, then an algorithm for
  27. adding and deleting can be made more efficient.
  28. (3) All Block and DBlock functions are inline, so there are
  29. no extra function calls.
  30. Differences between Block and DBlock:
  31. (1) DBlock allows both adding and deleting items,
  32. whereas Block allows only adding items.
  33. (2) Block has an additional operation of scanning
  34. items added so far (in the order in which they were added).
  35. (3) Block allows to allocate several consecutive
  36. items at a time, whereas DBlock can add only a single item.
  37. Note that no constructors or destructors are called for items.
  38. Example usage for items of type 'MyType':
  39. ///////////////////////////////////////////////////
  40. #include "block.h"
  41. #define BLOCK_SIZE 1024
  42. typedef struct { int a, b; } MyType;
  43. MyType *ptr, *array[10000];
  44. ...
  45. Block<MyType> *block = new Block<MyType>(BLOCK_SIZE);
  46. // adding items
  47. for (int i=0; i<sizeof(array); i++)
  48. {
  49. ptr = block -> New();
  50. ptr -> a = ptr -> b = rand();
  51. }
  52. // reading items
  53. for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext())
  54. {
  55. printf("%d %d\n", ptr->a, ptr->b);
  56. }
  57. delete block;
  58. ...
  59. DBlock<MyType> *dblock = new DBlock<MyType>(BLOCK_SIZE);
  60. // adding items
  61. for (int i=0; i<sizeof(array); i++)
  62. {
  63. array[i] = dblock -> New();
  64. }
  65. // deleting items
  66. for (int i=0; i<sizeof(array); i+=2)
  67. {
  68. dblock -> Delete(array[i]);
  69. }
  70. // adding items
  71. for (int i=0; i<sizeof(array); i++)
  72. {
  73. array[i] = dblock -> New();
  74. }
  75. delete dblock;
  76. ///////////////////////////////////////////////////
  77. Note that DBlock deletes items by marking them as
  78. empty (i.e., by adding them to the list of free items),
  79. so that this memory could be used for subsequently
  80. added items. Thus, at each moment the memory allocated
  81. is determined by the maximum number of items allocated
  82. simultaneously at earlier moments. All memory is
  83. deallocated only when the destructor is called.
  84. */
  85. #ifndef __BLOCK_H__
  86. #define __BLOCK_H__
  87. #include <stdlib.h>
  88. namespace OBJREC {
  89. /***********************************************************************/
  90. /***********************************************************************/
  91. /***********************************************************************/
  92. template <class Type> class Block
  93. {
  94. public:
  95. /* Constructor. Arguments are the block size and
  96. (optionally) the pointer to the function which
  97. will be called if allocation failed; the message
  98. passed to this function is "Not enough memory!" */
  99. Block(int size, void (*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; }
  100. /* Destructor. Deallocates all items added so far */
  101. ~Block() { while (first) { block *next = first -> next; delete [] first; first = next; } }
  102. /* Allocates 'num' consecutive items; returns pointer
  103. to the first item. 'num' cannot be greater than the
  104. block size since items must fit in one block */
  105. Type *New(int num = 1)
  106. {
  107. Type *t;
  108. if (!last || last->current + num > last->last)
  109. {
  110. if (last && last->next) last = last -> next;
  111. else
  112. {
  113. block *next = (block *) new char [sizeof(block) + (block_size-1)*sizeof(Type)];
  114. if (!next) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
  115. if (last) last -> next = next;
  116. else first = next;
  117. last = next;
  118. last -> current = & ( last -> data[0] );
  119. last -> last = last -> current + block_size;
  120. last -> next = NULL;
  121. }
  122. }
  123. t = last -> current;
  124. last -> current += num;
  125. return t;
  126. }
  127. /* Returns the first item (or NULL, if no items were added) */
  128. Type *ScanFirst()
  129. {
  130. scan_current_block = first;
  131. if (!scan_current_block) return NULL;
  132. scan_current_data = & ( scan_current_block -> data[0] );
  133. return scan_current_data ++;
  134. }
  135. /* Returns the next item (or NULL, if all items have been read)
  136. Can be called only if previous ScanFirst() or ScanNext()
  137. call returned not NULL. */
  138. Type *ScanNext()
  139. {
  140. if (scan_current_data >= scan_current_block -> current)
  141. {
  142. scan_current_block = scan_current_block -> next;
  143. if (!scan_current_block) return NULL;
  144. scan_current_data = & ( scan_current_block -> data[0] );
  145. }
  146. return scan_current_data ++;
  147. }
  148. /* Marks all elements as empty */
  149. void Reset()
  150. {
  151. block *b;
  152. if (!first) return;
  153. for (b=first; ; b=b->next)
  154. {
  155. b -> current = & ( b -> data[0] );
  156. if (b == last) break;
  157. }
  158. last = first;
  159. }
  160. /***********************************************************************/
  161. private:
  162. typedef struct block_st
  163. {
  164. Type *current, *last;
  165. struct block_st *next;
  166. Type data[1];
  167. } block;
  168. int block_size;
  169. block *first;
  170. block *last;
  171. block *scan_current_block;
  172. Type *scan_current_data;
  173. void (*error_function)(char *);
  174. };
  175. /***********************************************************************/
  176. /***********************************************************************/
  177. /***********************************************************************/
  178. template <class Type> class DBlock
  179. {
  180. public:
  181. /* Constructor. Arguments are the block size and
  182. (optionally) the pointer to the function which
  183. will be called if allocation failed; the message
  184. passed to this function is "Not enough memory!" */
  185. DBlock(int size, void (*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; }
  186. /* Destructor. Deallocates all items added so far */
  187. ~DBlock() { while (first) { block *next = first -> next;
  188. delete [] first;
  189. first = next; } }
  190. /* Allocates one item */
  191. Type *New()
  192. {
  193. block_item *item;
  194. if (!first_free)
  195. {
  196. block *next = first;
  197. first = (block *) new char [sizeof(block) + (block_size-1)*sizeof(block_item)];
  198. if (!first) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
  199. first_free = & (first -> data[0] );
  200. for (item=first_free; item<first_free+block_size-1; item++)
  201. item -> next_free = item + 1;
  202. item -> next_free = NULL;
  203. first -> next = next;
  204. }
  205. item = first_free;
  206. first_free = item -> next_free;
  207. return (Type *) item;
  208. }
  209. /* Deletes an item allocated previously */
  210. void Delete(Type *t)
  211. {
  212. ((block_item *) t) -> next_free = first_free;
  213. first_free = (block_item *) t;
  214. }
  215. /***********************************************************************/
  216. private:
  217. typedef union block_item_st
  218. {
  219. Type t;
  220. block_item_st *next_free;
  221. } block_item;
  222. typedef struct block_st
  223. {
  224. struct block_st *next;
  225. block_item data[1];
  226. } block;
  227. int block_size;
  228. block *first;
  229. block_item *first_free;
  230. void (*error_function)(char *);
  231. };
  232. }
  233. #endif