对象池C++11实现

内存分配器
class MallocAllocator {
public:
    MallocAllocator() = default;
    ~MallocAllocator() = default;

    void * allocate(SizeType size) {
        return ::malloc(size);
    }

    void * reallocate(void * ptr, std::size_t newSize) {
        return ::realloc(ptr, newSize);
    }

    void deallocate(void * ptr) {
        free(ptr);
    }
};

using DefaultMemoryAllocator = MallocAllocator;
对象池
template<typename Type, typename Allocator = DefaultMemoryAllocator>
class ObjectPool {
private:
    using ObjectType = Type;
    using ObjectPtrType = Type *;
    using ObjectRefType = Type &;
    using ConstObjectPtrType = const Type *;
    using ConstObjectRefType = const Type &;

    struct BlockInfo {  // 8 bytes
        static const BlockInfo NIL;

        BlockInfo(std::uint32_t blockIndexInChunk, std::uint32_t chunkIndexInChunks)
        : next(blockIndexInChunk, chunkIndexInChunks) {

        }

        struct Next {
            static constexpr std::uint16_t MAGIC_TAG = 1693689493U % 65535U;

            Next(std::uint32_t bi, std::uint32_t ci)
            : blockIndexInChunk(bi), chunkIndexInChunks(ci), magicTag(MAGIC_TAG) {

            }

            std::uint16_t magicTag;
            std::uint16_t blockIndexInChunk;
            std::uint32_t chunkIndexInChunks;
        } next;
    };

    static constexpr std::size_t DEFAULT_BLOCK_SIZE = max(sizeof(Type), sizeof(BlockInfo));
    static constexpr std::uint16_t DEFAULT_BLOCK_NUM_PER_CHUNK = 64;
    static constexpr std::uint32_t DEFAULT_CHUNK_NUM = 8;

public:
    explicit ObjectPool(uint32_t chunksCapacity = DEFAULT_CHUNK_NUM)
    : m_chunkNum(1),
      m_chunksCapacity(chunksCapacity),
      m_topBlockInfo(0, 0) {
        m_chunks = reinterpret_cast<void**>(m_allocator.allocate(sizeof(void *) * chunksCapacity));
        m_chunks[0] = m_allocator.allocate(DEFAULT_BLOCK_SIZE * DEFAULT_BLOCK_NUM_PER_CHUNK);
        initChunk(m_chunks[0], 0);
    }

    ~ObjectPool() {
        for (std::uint32_t i = 0; i < m_chunkNum; ++i) {  // release chunk in chunks one by one
            Byte * pBlock = reinterpret_cast<Byte *>(m_chunks[i]);
            for (std::uint16_t j = 0; j < DEFAULT_BLOCK_NUM_PER_CHUNK; ++j, pBlock += DEFAULT_BLOCK_SIZE) {  // deconstruct objects
                if (checkBlockUsed(pBlock)) {  // deconstruct object
                    auto pObject = reinterpret_cast<ObjectPtrType>(m_chunks[i]);
                    pObject->~ObjectType();
                }
            }
            m_allocator.deallocate(m_chunks[i]);  // release chunk
        }

        // release chunk-array
        m_allocator.deallocate(m_chunks);
    }

    template<typename... Args>
    ObjectPtrType createObject(Args && ... args) {
        //  extend(); if the top_block_info == NIL

        Byte * ptr = reinterpret_cast<Byte *>(m_chunks[m_topBlockInfo.next.chunkIndexInChunks]);  // find chunk in chunks
        ptr += m_topBlockInfo.next.blockIndexInChunk * DEFAULT_BLOCK_SIZE;  // find block in chunk

        m_topBlockInfo = *reinterpret_cast<BlockInfo *>(ptr);  // update the m_topBlockInfo

        return new (ptr) ObjectType(std::forward<Args>(args)...);  // construct object and return
    }

    void destroyObject(ObjectPtrType /*&*/ ptr) {
        ptr->~ObjectType();  // construct object
        new (ptr) BlockInfo(m_topBlockInfo);  // construct BlockInfo on *ptr
        getBlockIndex(  // update the m_topBlockInfo
            ptr,
            &m_topBlockInfo.next.blockIndexInChunk,
            &m_topBlockInfo.next.chunkIndexInChunks
        );
        ptr = nullptr;
    }

private:
    void initChunk(void * pChunk, uint32_t chunkIndexInChunks) {  // link all blocks in the chunk
        Byte * pbChunk = reinterpret_cast<Byte *>(pChunk);
        BlockInfo * ptr = nullptr;

        PGJSON_STATIC_ASSERT(DEFAULT_BLOCK_NUM_PER_CHUNK >= 1);
        for (std::uint16_t i = 0; i < DEFAULT_BLOCK_NUM_PER_CHUNK - 1; ++i, pbChunk += DEFAULT_BLOCK_SIZE) {
            ptr = reinterpret_cast<BlockInfo *>(pbChunk);
            new (ptr) BlockInfo(i + 1, chunkIndexInChunks);
        }
        ptr = reinterpret_cast<BlockInfo *>(pbChunk);
        new (ptr) BlockInfo(BlockInfo::NIL);
    }

    bool checkBlockUsed(void * pBlock) {  // check : if the block was used by checking : magicTag == MAGIC_TAG
        BlockInfo * ptr = nullptr;
        ptr = reinterpret_cast<BlockInfo *>(pBlock);
        return ptr->next.magicTag != BlockInfo::Next::MAGIC_TAG;
    }

    void getBlockIndex(void * ptr, std::uint16_t * pBlockIndexInChunk, std::uint32_t * pChunkIndexInChunks) {
        std::uint32_t i = 0;
        std::uint64_t diff = 0;
        for (; i < m_chunkNum; ++i) {
            if (ptr >= m_chunks[i]) {
                diff = (reinterpret_cast<Byte *>(ptr) - reinterpret_cast<Byte *>(m_chunks[i])) / DEFAULT_BLOCK_SIZE;
                if (diff < DEFAULT_BLOCK_NUM_PER_CHUNK) {
                    pBlockIndexInChunk && (*pBlockIndexInChunk = diff);
                    pChunkIndexInChunks && (*pChunkIndexInChunks = i);
                    return;
                }
            }
        }
    }

private:
    void ** m_chunks = nullptr;
    std::uint32_t m_chunkNum;
    std::uint32_t m_chunksCapacity;
    BlockInfo m_topBlockInfo;
    Allocator m_allocator;
};

template<typename Type, typename Allocator>
const typename ObjectPool<Type, Allocator>::BlockInfo ObjectPool<Type, Allocator>::BlockInfo::NIL{
    std::numeric_limits<std::uint16_t>::max(),
    std::numeric_limits<std::uint32_t>::max()
};
附 constexpr max函数实现 :
template<typename T1, typename T2>
inline constexpr auto max(const T1 & n1, const T2 & n2) -> decltype(n1 > n2 ? n1 : n2) {
    return n1 > n2 ? n1 : n2;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值