@@ -52,21 +52,24 @@ memory_pool::memory_pool(std::size_t size) {
5252}
5353
5454[[nodiscard]] pointer memory_pool::allocate (std::size_t bytes) {
55+ return reinterpret_cast <pointer>(new std::byte[bytes]);
5556 // Compute the smallest possible block size that would fit this allocation
5657 std::size_t const block_size = std::max (min_block_size, plib::next_pow_two (bytes));
5758 // Find a block, possibly subdividing blocks
5859 block* block = find_block (root_block.get (), block_size);
5960 // If no block was found, return a null pointer
6061 if (!block) return null_pointer;
62+ // Add the block to the allocated block cache, so it can be found easily when freeing
63+ allocated_block_lookup[block->ptr ] = block;
6164 // Mark it as allocated and return the pointer
6265 block->free = false ;
6366 return block->ptr ;
6467}
6568
6669void memory_pool::free (ps::pointer ptr) {
6770 if (!verify_pointer (ptr)) return ;
68-
69- free_block (root_block. get (), nullptr , ptr);
71+ delete[] decode_pointer (ptr);
72+ free_block (ptr);
7073}
7174
7275[[nodiscard]] bool memory_pool::verify_pointer (ps::pointer ptr) const noexcept {
@@ -109,64 +112,34 @@ void memory_pool::verify_pointer_throw(ps::pointer ptr) const {
109112 return find_block (root->right .get (), block_size);
110113}
111114
112- bool memory_pool::free_block (block* root, block* parent, ps::pointer ptr) {
115+ bool memory_pool::free_block (ps::pointer ptr) {
113116 // We need to find the block holding the allocated pointer.
114117 // This is going to be the block with the free flag on false, and holding this pointer.
115118
116- if (!root) return false ;
117-
118- // Found matching pointer. This will be the allocated block if it has no child buddies.
119- if (root->ptr == ptr && !root->left && !root->right ) {
120- // Mark the block as free
121- root->free = true ;
122- // Zero out block memory
123- std::memset (decode_pointer (root->ptr ), 0 , root->size );
124- // If this was a small block, and there is space left in the small block cache, add it to the cache.
125- if (root->size == min_block_size && num_small_blocks != small_block_cache.size ()) {
126- small_block_cache[num_small_blocks++] = root;
127- }
128- // If there is a parent, check if both left and right of it are free
129- if (parent && parent->left ->free && parent->right ->free ) {
130- // If so, merge those blocks
131- bool success = merge_blocks (parent);
132- // Something went wrong
133- if (!success) return false ;
134- }
135- return true ; // freed a block, return true
136-
137- } else {
138- // This isn't the block holding the allocation, try to free in left and right
139-
140- // Has no children, early exit.
141- if (!root->left || !root->right ) return false ;
142-
143- // We can make a small optimization by comparing the pointer with the pointer of the right child.
144- if (ptr < root->right ->ptr ) {
145- // Block must be in left child
146- bool free = free_block (root->left .get (), root, ptr);
147-
148- // Once again try to merge
149- if (free && parent && parent->free && parent->left ->free && parent->right ->free ) {
150- bool success = merge_blocks (parent);
151- if (!success) return false ;
152- }
153-
154- return free;
155- } else {
156- // Block must be in right child
157- bool free = free_block (root->right .get (), root, ptr);
158-
159- // Once again try to merge
160- if (free && parent && parent->free && parent->left ->free && parent->right ->free ) {
161- bool success = merge_blocks (parent);
162- if (!success) return false ;
163- }
119+ block* b = allocated_block_lookup.at (ptr);
120+ // Mark the block as free
121+ b->free = true ;
122+ // Zero out block memory
123+ std::memset (decode_pointer (ptr), 0 , b->size );
124+ // If this was a small block, and there is space left in the small block cache, add it to the cache.
125+ if (b->size == min_block_size && num_small_blocks != small_block_cache.size ()) {
126+ small_block_cache[num_small_blocks++] = b;
127+ }
128+ // If there is a parent, check if both left and right of it are free.
129+ // We repeat this process up the tree as long as we can
130+ block* cur = b;
131+ std::size_t merge_i = 0 ;
132+ // we limit the amount of merges to make sure we keep some smaller blocks around.
133+ while (merge_i++ < max_consecutive_merges && cur->parent && cur->parent ->left ->free && cur->parent ->right ->free ) {
134+ // If so, merge those blocks
135+ block* parent = cur->parent ;
136+ [[maybe_unused]] bool _ = merge_blocks (parent);
137+ cur = parent;
138+ }
164139
165- return free;
166- }
140+ allocated_block_lookup.erase (ptr);
167141
168- PLIB_UNREACHABLE ();
169- }
142+ return true ;
170143}
171144
172145[[nodiscard]] bool memory_pool::subdivide_block (block *b) {
@@ -219,12 +192,15 @@ bool memory_pool::free_block(block* root, block* parent, ps::pointer ptr) {
219192}
220193
221194[[nodiscard]] ps::byte* memory_pool::decode_pointer (ps::pointer ptr) {
195+ return reinterpret_cast <std::byte*>(ptr);
222196 // TODO: possibly add toggle to disable this
223197 verify_pointer_throw (ptr);
224198 return &memory[ptr];
225199}
226200
227201[[nodiscard]] ps::byte const * memory_pool::decode_pointer (ps::pointer ptr) const {
202+ return reinterpret_cast <std::byte*>(ptr);
203+
228204 verify_pointer_throw (ptr);
229205 return &memory[ptr];
230206}
0 commit comments