From 1d1210d7932b287d66e27157701b92df764528cb Mon Sep 17 00:00:00 2001 From: chai Date: Mon, 5 Nov 2018 07:33:41 +0800 Subject: =?UTF-8?q?+=E7=8A=B6=E6=80=81=E6=9C=BA=E6=B5=8B=E8=AF=95=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libjin/Common/je_pool.hpp | 168 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 1 deletion(-) (limited to 'src/libjin/Common/je_pool.hpp') diff --git a/src/libjin/Common/je_pool.hpp b/src/libjin/Common/je_pool.hpp index 1c74eaf..cb96c5b 100644 --- a/src/libjin/Common/je_pool.hpp +++ b/src/libjin/Common/je_pool.hpp @@ -1,11 +1,177 @@ +/// +/// An O(1) Object Pool. Original from https://www.codeproject.com/Articles/746630/O-Object-Pool-in-Cplusplus +/// #ifndef __JE_POOL_H__ #define __JE_POOL_H__ +#include +#include + +#include "je_types.h" + namespace JinEngine { + class DefaultMemoryAllocator + { + public: + static inline void *Allocate(size_t size) + { + return ::operator new(size, ::std::nothrow); + } + static inline void Deallocate(void *pointer, size_t size) + { + ::operator delete(pointer); + } + }; + + template + class Pool + { + private: + struct _Node + { + void *_memory; + size_t _capacity; + _Node *_nextNode; + + _Node(size_t capacity) + { + if (capacity < 1) + throw std::invalid_argument("capacity must be at least 1."); + + _memory = TMemoryAllocator::Allocate(_itemSize * capacity); + if (_memory == NULL) + throw std::bad_alloc(); + + _capacity = capacity; + _nextNode = NULL; + } + ~_Node() + { + TMemoryAllocator::Deallocate(_memory, _itemSize * _capacity); + } + }; + + void *_nodeMemory; + T *_firstDeleted; + size_t _countInNode; + size_t _nodeCapacity; + _Node _firstNode; + _Node *_lastNode; + size_t _maxBlockLength; + + static const size_t _itemSize; + + Pool(const Pool &source); + void operator = (const Pool &source); + + void _AllocateNewNode() + { + size_t size = _countInNode; + if (size >= _maxBlockLength) + size = _maxBlockLength; + else + { + size *= 2; + + if (size < _countInNode) + throw std::overflow_error("size became too big."); + + if (size >= _maxBlockLength) + size = _maxBlockLength; + } + + _Node *newNode = new _Node(size); + _lastNode->_nextNode = newNode; + _lastNode = newNode; + _nodeMemory = newNode->_memory; + _countInNode = 0; + _nodeCapacity = size; + } + + public: + explicit Pool(size_t initialCapacity = 32, size_t maxBlockLength = 1000000) + : _firstDeleted(NULL) + , _countInNode(0) + , _nodeCapacity(initialCapacity) + , _firstNode(initialCapacity) + , _maxBlockLength(maxBlockLength) + { + if (maxBlockLength < 1) + throw std::invalid_argument("maxBlockLength must be at least 1."); + + _nodeMemory = _firstNode._memory; + _lastNode = &_firstNode; + } + ~Pool() + { + _Node *node = _firstNode._nextNode; + while (node) + { + _Node *nextNode = node->_nextNode; + delete node; + node = nextNode; + } + } + + T *New() + { + if (_firstDeleted) + { + T *result = _firstDeleted; + _firstDeleted = *((T **)_firstDeleted); + new(result) T(); + return result; + } + + if (_countInNode >= _nodeCapacity) + _AllocateNewNode(); + + char *address = (char *)_nodeMemory; + address += _countInNode * _itemSize; + T *result = new(address) T(); + _countInNode++; + return result; + } + + // This method is useful if you want to call a non-default constructor. + // It should be used like this: + // new (pool.GetNextWithoutInitializing()) ObjectType(... parameters ...); + T *GetNextWithoutInitializing() + { + if (_firstDeleted) + { + T *result = (T *)_firstDeleted; + _firstDeleted = *((T **)_firstDeleted); + return result; + } + + if (_countInNode >= _nodeCapacity) + _AllocateNewNode(); + + char *address = (char *)_nodeMemory; + address += _countInNode * _itemSize; + _countInNode++; + return (T *)address; + } + void Delete(T *content) + { + content->~T(); + + *((T **)content) = _firstDeleted; + _firstDeleted = content; + } + void DeleteWithoutDestroying(T *content) + { + *((T **)content) = _firstDeleted; + _firstDeleted = content; + } + }; + template + const size_t Pool::_itemSize = ((sizeof(T) + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *); -} +} // namespace JinEngine #endif \ No newline at end of file -- cgit v1.1-26-g67d0