Double pointer memory pool

 avatar
unknown
c_cpp
5 days ago
6.5 kB
41
Indexable
#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>

class MemoryPool {
public:
    MemoryPool(size_t size)
        : poolSize(size), used(0)
    {
        pool = new char[size];
    }

    ~MemoryPool() {
        delete[] pool;
        for (auto& block : blocks) {
            delete block.handle;
        }
    }

    char** allocate(size_t size) {
        for (auto it = freeList.begin(); it != freeList.end(); ++it) {
            if (it->size >= size) {
                size_t offset = it->offset;
                char* blockPtr = pool + offset;

                if (it->size == size) {
                    freeList.erase(it);
                }
                else {
                    it->offset += size;
                    it->size -= size;
                }

                char** handle = new char*;
                *handle = blockPtr;
                Block info;
                info.handle = handle;
                info.size = size;
                info.offset = offset;
                blocks.push_back(info);
                return handle;
            }
        }

        if (used + size > poolSize) {
            std::cerr << "Not enough memory in the pool" << std::endl;
            return nullptr;
        }
        size_t offset = used;
        char* blockPtr = pool + offset;
        used += size;
        char** handle = new char*;
        *handle = blockPtr;
        Block info;
        info.handle = handle;
        info.size = size;
        info.offset = offset;
        blocks.push_back(info);
        return handle;
    }

    void free(char** handle) {
        auto it = std::find_if(blocks.begin(), blocks.end(),
            [handle](const Block& block) { return block.handle == handle; });
        if (it == blocks.end()) {
            std::cerr << "Block not found" << std::endl;
            return;
        }
        size_t offset = it->offset;
        size_t size = it->size;
        blocks.erase(it);
        delete handle;

        freeList.push_back({ offset, size });
        mergeFreeList();
    }

    void defragment() {

        std::sort(blocks.begin(), blocks.end(), [](const Block& a, const Block& b) {
            return a.offset < b.offset;
            });

        size_t newOffset = 0;
        for (auto& block : blocks) {
            if (block.offset != newOffset) {
                memmove(pool + newOffset, pool + block.offset, block.size);
                block.offset = newOffset;
                *block.handle = pool + newOffset;
            }
            newOffset += block.size;
        }
        used = newOffset;
        freeList.clear();
        if (used < poolSize) {
            freeList.push_back({ used, poolSize - used });
        }
    }

    void printBlocks() {
        std::cout << "MemoryPool blocks:" << std::endl;
        for (size_t i = 0; i < blocks.size(); i++) {
            std::cout << "Block " << i << ": "
                << static_cast<void*>(*blocks[i].handle)
                << ", Size: " << blocks[i].size
                << ", Offset: " << blocks[i].offset
                << std::endl;
        }
    }

    // Debug: Print the entire pool's contents.
    void printPool() {
        std::cout << "MemoryPool contains:" << std::endl;
        for (size_t i = 0; i < poolSize; i++) {
            std::cout << pool[i];
        }
        std::cout << std::endl;
    }

private:
    // Structure for allocated blocks – now with offset.
    struct Block {
        char** handle;
        size_t size;
        size_t offset;
    };

    // Structure for free blocks in the free list.
    struct FreeBlock {
        size_t offset;
        size_t size;
    };

    char* pool;              // The entire memory pool
    size_t poolSize;         // Total size of the pool
    size_t used;             // How much memory is used
    std::vector<Block> blocks;      // List of allocated blocks
    std::vector<FreeBlock> freeList;  // Free list with free areas

    // Merges adjacent free blocks to reduce fragmentation.
    void mergeFreeList() {
        std::sort(freeList.begin(), freeList.end(), [](const FreeBlock& a, const FreeBlock& b) {
            return a.offset < b.offset;
            });
        std::vector<FreeBlock> merged;
        for (const auto& block : freeList) {
            if (!merged.empty() && merged.back().offset + merged.back().size == block.offset) {
                merged.back().size += block.size;
            }
            else {
                merged.push_back(block);
            }
        }
        freeList = std::move(merged);
    }
};

int main() {
    MemoryPool pool(100);

    // Allocate some blocks.
    char** ptr1 = pool.allocate(10); // Block 0
    char** ptr2 = pool.allocate(20); // Block 1
    char** ptr3 = pool.allocate(15); // Block 2
    char** ptr4 = pool.allocate(5);  // Block 3

    strcpy(*ptr1, "[1111111]");
    strcpy(*ptr2, "[22222222222222222]");
    strcpy(*ptr3, "[333333333333]");
    strcpy(*ptr4, "[44]");

    std::cout << "Before free:" << std::endl;
    pool.printBlocks();
    pool.printPool();

    pool.free(ptr2);

    std::cout << "\nAfter freeing ptr2:" << std::endl;
    pool.printBlocks();
    pool.printPool();

    // Allocate a new block that should take place in a hole from the free list.
    char** ptr5 = pool.allocate(16);
    strcpy(*ptr5, "[5555555555555]");

    std::cout << "\nAfter allocating new block:" << std::endl;
    pool.printBlocks();
    pool.printPool();

    // Perform defragmentation.
    pool.defragment();
    std::cout << "\nAfter defragementation:" << std::endl;
    pool.printBlocks();
    pool.printPool();

    // Check the contents via the original pointers:
    std::cout << "\nExisting pointers:" << std::endl;
    std::cout << "ptr1: " << *ptr1 << std::endl;
    std::cout << "ptr3: " << *ptr3 << std::endl;
    std::cout << "ptr4: " << *ptr4 << std::endl;
    std::cout << "ptr5: " << *ptr5 << std::endl;

	// Buffer overflow test ptr1
	strcpy(*ptr1, "[11111111111]");

	std::cout << "\nAfter buffer overflow test ptr1:" << std::endl;
	pool.printPool();

    std::cout << "ptr1: " << *ptr1 << std::endl;
    std::cout << "ptr3: " << *ptr3 << std::endl;
    std::cout << "ptr4: " << *ptr4 << std::endl;
    std::cout << "ptr5: " << *ptr5 << std::endl;

    return 0;
}
Editor is loading...
Leave a Comment