1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: m_random.h 3799 2013-04-24 03:12:44Z mike $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //	Memory pool allocation
21 //	Allocates a large pool of memory and allocates blocks of it when asked.
22 //	Memory can only be freed by the clear() function for simplicity. If
23 //	the intial memory pool is exhausted, additional pools are allocated. These
24 //	are consolodated into one large pool the next time clear() is called.
25 //
26 //-----------------------------------------------------------------------------
27 
28 
29 #ifndef __M_MEMPOOL__
30 #define __M_MEMPOOL__
31 
32 #include "doomtype.h"
33 #include <cstring>
34 
35 class MemoryPool
36 {
37 public:
MemoryPool(size_t initial_size)38 	MemoryPool(size_t initial_size) :
39 		num_blocks(0), block_size(NULL), data_block(NULL), free_block(NULL)
40 	{
41 		resize(initial_size);
42 	}
43 
~MemoryPool()44 	~MemoryPool()
45 	{
46 		free_data();
47 	}
48 
clear()49 	void clear()
50 	{
51 		if (num_blocks <= 1)
52 		{
53 			free_block = data_block[0];
54 			return;
55 		}
56 
57 		size_t new_size = 0;
58 		if (block_size != NULL)
59 			new_size = block_size[num_blocks - 1];
60 		free_data();
61 		resize(new_size);
62 	}
63 
64 	template<typename T>
alloc(size_t count)65 	T* alloc(size_t count)
66 	{
67 		while (free_block + count * sizeof(T) >
68 				data_block[num_blocks - 1] + block_size[num_blocks - 1])
69 			resize(2 * block_size[num_blocks - 1]);
70 
71 		T* ptr = reinterpret_cast<T*>(free_block);
72 		free_block += count * sizeof(T);
73 		return ptr;
74 	}
75 
76 private:
resize(size_t new_size)77 	void resize(size_t new_size)
78 	{
79 		if (new_size == 0)
80 			return;
81 
82 		num_blocks++;
83 
84 		size_t* new_block_size = new size_t[num_blocks];
85 		if (block_size != NULL)
86 		{
87 			memcpy(new_block_size, block_size, (num_blocks - 1) * sizeof(size_t));
88 			delete [] block_size;
89 		}
90 		new_block_size[num_blocks - 1] = new_size;
91 		block_size = new_block_size;
92 
93 		byte** new_data_block = new byte*[num_blocks];
94 		if (data_block != NULL)
95 		{
96 			memcpy(new_data_block, data_block, (num_blocks - 1) * sizeof(byte*));
97 			delete [] data_block;
98 		}
99 		new_data_block[num_blocks - 1] = new byte[new_size];
100 		data_block = new_data_block;
101 
102 		free_block = data_block[num_blocks - 1];
103 	}
104 
free_data()105 	void free_data()
106 	{
107 		for (size_t i = 0; i < num_blocks; i++)
108 			delete [] data_block[i];
109 
110 		delete [] block_size;
111 		delete [] data_block;
112 		num_blocks = 0;
113 		block_size = NULL;
114 		data_block = NULL;
115 		free_block = NULL;
116 	}
117 
118 	size_t		num_blocks;
119 	size_t*		block_size;
120 	byte**		data_block;
121 	byte*		free_block;
122 };
123 
124 #endif // __M_MEMPOOL__
125