1 /* ///////////////////////////////////////////////////////////////////////
7 * Brief: fixed_pool class - allocate a fixed-size memory block every once
10 * Copyright (c) 2008-2020, Waruqi All rights reserved.
11 * //////////////////////////////////////////////////////////////////// */
13 #ifndef EXTL_MEMORY_FIXED_POOL_H
14 #define EXTL_MEMORY_FIXED_POOL_H
17 * \brief fixed_pool class - allocate a fixed-size memory block every once
19 * Note: The size of a block must be less than 8K
23 # error fixed_pool.h need be supported by c++.
26 /* ///////////////////////////////////////////////////////////////////////
29 #include "allocator_selector.h"
30 #include "../utility/suppress_unused.h"
32 #ifdef EXTL_MEMORY_FIXED_POOL_TEST_ENABLE
33 # include "../counter/clock_counter.h"
36 /* ///////////////////////////////////////////////////////////////////////
39 /// Slightly less than 8K so that a chunk in the basic_pool will fit in 8K
40 #define EXTL_FIXED_POOL_DEFAULT_CHUNK_SIZE (8 * 1024 - 64)
41 /* ///////////////////////////////////////////////////////////////////////
46 /*!\brief fixed_pool class
48 * \param BLOCK_SIZE The size of the fixed memory block
49 * \param CHUNK_SIZE The size of a chunk
50 * \param A The allocator type
54 * -------------------- --------------------
55 * m_chunks ---> | chunk1 | ---> | chunk2 | ---> NULL
56 * -------------------- --------------------
58 * -------------------------------
59 * one chunk: m_first_free --> | block1 -|-> block2 -|-> NULL
60 * -------------------------------
62 * \ingroup extl_group_memory
64 template< e_size_t BLOCK_SIZE
65 #ifdef EXTL_TEMPLATE_CLASS_DEFAULT_ARGUMENT_SUPPORT
66 , e_size_t CHUNK_SIZE
= EXTL_FIXED_POOL_DEFAULT_CHUNK_SIZE
67 , typename_param_k A
= typename_type_def_k allocator_selector
<e_byte_t
>::allocator_type
74 #ifdef EXTL_EBO_FORM_2_SUPPORT
75 : protected A
/* if EBO is supported */
83 typedef fixed_pool
<BLOCK_SIZE
, CHUNK_SIZE
, A
> class_type
;
84 typedef void value_type
;
85 typedef A allocator_type
;
86 typedef void* pointer
;
87 typedef void const* const_pointer
;
88 typedef void reference
;
89 typedef void const_reference
;
90 typedef typename_type_k
allocator_type::size_type size_type
;
95 /// The node of the block_head
96 struct block_head
{ block_head
* next
; };
97 /// The node of the chunk_head
100 /* BCC Bug: Can not use BLOCK_SIZE directly when BLOCK_SIZE = sizeof(object) */
101 enum{en_raw_block_size
= BLOCK_SIZE
};
103 /* The size of one block is sizeof(block_head) at least */
104 #if EXTL_WORKAROUND_BORLAND(==, 0x564)
105 enum { en_block_size
=
106 BLOCK_SIZE
< sizeof(block_head
)? sizeof(block_head
) : BLOCK_SIZE
};
108 enum { en_block_size
=
109 en_raw_block_size
< sizeof(block_head
)? sizeof(block_head
) : en_raw_block_size
};
112 enum { en_data_size
= CHUNK_SIZE
};
113 enum { en_block_count
= en_data_size
/ en_block_size
};
116 e_byte_t data
[en_data_size
];
117 block_head
* first_block() { return reinterpret_cast<block_head
*>(&data
[0]); }
118 block_head
* last_block() { return reinterpret_cast<block_head
*>(data
+ (en_block_count
- 1) * en_block_size
); }
121 friend struct chunk_head
;
123 enum {en_data_size
= chunk_head::en_data_size
};
124 enum {en_block_size
= chunk_head::en_block_size
};
129 chunk_head
* m_chunks
; //!< The head of the linked list of the whole storage
130 block_head
* m_first_free
; //!< The first free block of the free linked list
131 block_head
* m_last_free
; //!< The last free block of the free linked list
132 chunk_head
* m_free_chunk
;
136 /*!\brief Prohibit copying and assignment
138 * Maybe EBO is not supported if uses extl::uncopyable,
139 * because some compilers do not support EBO_FORM_6 - EXTL_EBO_FORM_6_SUPPORT
141 fixed_pool(class_type
const&);
142 class_type
& operator=(class_type
const&);
144 /// \name Constructors
155 virtual ~fixed_pool()
162 /// Destroys the pool
165 EXTL_ASSERT(is_valid());
166 /* Releases the memory of the fixed pool */
167 chunk_head
* node
= m_chunks
;
170 chunk_head
* p
= node
;
172 allocator().deallocate(reinterpret_cast<e_byte_t
*>(p
), 0);
179 EXTL_ASSERT(is_valid());
183 /// Gets the allocator of the pool
184 allocator_type
allocator() const
186 #ifdef EXTL_EBO_FORM_2_SUPPORT
189 return allocator_type();
192 /// Allocates a fixed-size memory block
193 pointer
allocate(size_type n
= 1)
195 EXTL_SUPPRESS_UNUSED(n
);
197 EXTL_ASSERT(is_valid());
199 #ifdef EXTL_COMPILER_IS_GCC
200 EXTL_STATIC_ASSERT(size_type(en_block_size
) <= size_type(en_data_size
));
202 EXTL_STATIC_ASSERT(en_block_size
<= en_data_size
);
205 if (NULL
== m_first_free
) grow();
206 return alloc_block_from_pool();
209 /// Only puts the fixed back into the pool
210 void deallocate(pointer block
)
212 dealloc_block_to_pool(block
);
215 /// Grows the size of the pool
218 EXTL_ASSERT(is_valid());
219 EXTL_ASSERT(NULL
== m_last_free
);
220 EXTL_ASSERT(NULL
== m_first_free
);
221 /* Adds a new chunk into the pool
222 * ----------- ----------
223 * | new_chunk | - | chunk1 | - ... ...
224 * ----------- ----------
226 chunk_head
* new_chunk
= reinterpret_cast<chunk_head
*>(allocator().allocate(sizeof(chunk_head
), NULL
));
227 EXTL_ASSERT(NULL
!= new_chunk
);
228 new_chunk
->next
= m_chunks
;
229 m_chunks
= new_chunk
;
232 * -----------------------------------------
233 * | block | block | .... | | |
234 * -----------------------------------------
236 * first_free last_free
238 m_first_free
= new_chunk
->first_block();
239 m_last_free
= new_chunk
->last_block();
240 m_last_free
->next
= NULL
;
242 /* The current free chunk */
243 m_free_chunk
= new_chunk
;
244 EXTL_ASSERT(is_valid());
247 /// Allocates a free block from the pool
248 pointer
alloc_block_from_pool()
250 EXTL_ASSERT(is_valid());
251 EXTL_ASSERT(NULL
!= m_first_free
);
252 pointer p
= static_cast<pointer
>(m_first_free
);
254 /* Allocates a free block by linked list if m_free_chunk is NULL
257 * -------------- <- first_free
261 * -------------- <- next_free
266 if (NULL
== m_free_chunk
|| 1 == chunk_head::en_block_count
)
268 m_first_free
= m_first_free
->next
;
270 /* Delay to segregate a chunk for optimization
271 * The chunk is not segregated until a block in the chunk is allocated
272 * and the chunk will be segregated completely when first_free is pointed to the last block,
273 * then the blocks in the chunk will be allocated by linked list
276 * -------------- <- first_free
277 * | free_block2 | + block_size
278 * -------------- <- next_free
282 * -------------- <- first_free (complete to segregate)
289 m_first_free
= reinterpret_cast<block_head
*>
290 (reinterpret_cast<e_byte_t
*>(m_first_free
) + chunk_head::en_block_size
);
292 if (m_first_free
== m_free_chunk
->last_block())
298 /* There are not more free block after allocating a block from the chunk */
299 if (NULL
== m_first_free
)
302 EXTL_ASSERT(is_valid());
305 /// Deallocates a block to the pool
306 void dealloc_block_to_pool(pointer block
)
308 EXTL_ASSERT(is_valid());
310 block_head
* p
= static_cast<block_head
*>(block
);
313 if (NULL
== m_last_free
)
315 EXTL_ASSERT(NULL
== m_first_free
);
321 m_last_free
->next
= p
;
325 EXTL_ASSERT(is_valid());
330 e_bool_t
is_valid() const
332 if ((NULL
== m_first_free
) != (NULL
== m_last_free
))
338 /* ///////////////////////////////////////////////////////////////////////
341 #ifdef EXTL_MEMORY_FIXED_POOL_TEST_ENABLE
342 # include "unit_test/fixed_pool_test.h"
345 /* ///////////////////////////////////////////////////////////////////////
350 /* //////////////////////////////////////////////////////////////////// */
351 #endif /* EXTL_MEMORY_FIXED_POOL_H */
352 /* //////////////////////////////////////////////////////////////////// */