list.h
namespace LC
{
template<typename T>
class Node final
{
public:
Node(){}
explicit Node(Node<T>* next, T&& data) noexcept : _data(std::move(data)), _next(next) {}
explicit Node(Node<T>* next, const T& data) noexcept : _data(data), _next(next) {}
explicit Node(Node<T>* pre, Node<T>* next, const T& data) noexcept : _pre(pre), _data(data), _next(next) {}
public:
inline T& data() noexcept { return _data; }
template <typename... TArgs>
inline void emplace(TArgs&& ...args){ new(&_data)T(args...); }
inline void pack(T&& data) noexcept { _data = std::move(data); }
inline void pack(const T& data) noexcept { _data = data; }
inline void link(Node<T>* next) noexcept { _next = next; if(next != nullptr) next->_pre = this; }
public:
T _data;
Node<T>* _next = nullptr;
Node<T>* _pre = nullptr;
};
template<typename T>
class List
{
public:
List() {} //init head.
~List() { while(_size > 0) pop(); }
public:
//insert at beginning.
bool push(Node<T>* node)
{
if(node == nullptr)
return false;
Node<T>* first = _root._next;
_root.link(node);
node->link(first);
++_size;
return true;
}
bool insert(const T& data)
{
Node<T>* ins = alloc();
if(ins == nullptr)
return false;
ins->pack(data);
return push(ins);
};
bool insert(T&& data)
{
Node<T>* ins = alloc();
if(ins == nullptr)
return false;
ins->pack(std::move(data));
return push(ins);
};
template<typename... TArgs>
bool emplace(TArgs&& ...args)
{
Node<T>* ins = alloc(args...);
Node<T>* first = nullptr;
if(ins == nullptr) return false;
return push(ins);
}
inline Node<T>* begin() noexcept { return _root._next; }
inline void pop() noexcept
{
delete pop_not_free();
}
inline Node<T>* pop_not_free() noexcept
{
Node<T>* first = begin();
if(first == nullptr)
return nullptr;
Node<T>* second = first->_next;
_root.link(second);
--_size;
return first;
}
inline void erase(Node<T>* node) noexcept
{
if(node == nullptr || node->_pre == nullptr)
return;
node->_pre->link(node->_next);
--_size;
delete node;
}
inline size_t size() const noexcept { return _size; }
private:
template<typename... TArgs>
inline Node<T>* alloc(TArgs&& ...args)
{
Node<T>* ret = new(std::nothrow) Node<T>();
if(ret != nullptr) ret->emplace(args...);
return ret;
}
inline Node<T>* alloc() { return new(std::nothrow) Node<T>(); }
public:
Node<T> _root;
size_t _size = 0;
};
}; // namespace LC
mempool.h
/**
* @brief Memory pool, it's not thread-safe.
* @author Even
* @date 2021-06-07
*
*/
namespace LC
{
inline static constexpr int ALIGN = 8;
inline static constexpr int BLOCK_MAX = 1024;
inline static constexpr int BLOCK_CAP = BLOCK_MAX / ALIGN;
inline static constexpr int BUCKET_CAP = BLOCK_MAX;
static_assert(ALIGN % 8 == 0);
static_assert(BLOCK_MAX % ALIGN == 0);
inline constexpr int __Align(int num_) noexcept { return (num_ + ALIGN - 1) & ~(ALIGN - 1); }
inline constexpr int __Sit(int index_) noexcept { return (index_ + 1) * ALIGN; }
inline constexpr int __Index(int num_) noexcept { return (num_ + ALIGN - 1) / ALIGN - 1; }
struct __Block
{
__Block* _next = nullptr;
};
struct __CacheBlock
{
__CacheBlock(){}
__CacheBlock(char* ptr, int size)
: _ptr(ptr), _size(size){}
std::unique_ptr<char[]> _ptr;
int _size = 0;
};
class __MemCache
{
private:
__MemCache(){}
~__MemCache(){}
private:
inline void Create(int size) { size = __Align(size); _cache.emplace((char*)malloc(size), size); }
//@return list.
struct ApplyRet{__Block* _b; __Block* _e;};
ApplyRet Apply(int& block_size, int& count);
private:
friend class MemPool;
List<__CacheBlock> _cache;
};
class MemPool
{
public:
MemPool();
~MemPool();
public:
static inline MemPool& Instance() noexcept { static MemPool ins_; return ins_; }
public:
void* Alloc(int size);
template<typename T> void* Alloc() { return Alloc(sizeof(T)); }
void Free(void* ptr, int size);
template<typename T> void Free(T* ptr) { Free(ptr, sizeof(T)); }
private:
void Fill(int index, int count);
private:
__MemCache _mem_cache;
__Block* _free[BLOCK_CAP];
};
class MemPoolThreadSafe
{
public:
struct __ThreadMemPool
{
__ThreadMemPool(){}
__ThreadMemPool(int id, MemPool* pool) : _id(id), _pool(pool) {}
int _id = 0;
std::unique_ptr<MemPool> _pool;
};
public:
MemPoolThreadSafe() noexcept;
~MemPoolThreadSafe();
public:
inline static MemPoolThreadSafe& Instance() noexcept { static MemPoolThreadSafe ins_; return ins_; }
uint32_t GetThreadID();
public:
void* Alloc(int size);
void Free(void* ptr, int size);
template<typename T> void* Alloc() { return Alloc(sizeof(T)); }
template<typename T> void Free(T* ptr) { Free(ptr, sizeof(T)); }
private:
List<__ThreadMemPool> _forThreadMemPool[__BUCKET_COUNT];
};
};
//!__MEM_POOL_H_
mempool.cpp
namespace LC
{
__MemCache::ApplyRet __MemCache::Apply(int& block_size, int& count)
{
block_size = __Align(block_size);
int need_size = block_size * count;
{
int def_size = block_size * DEFAULT_EACH_BLOCK_STORE;
auto* node = _cache.begin();
if(node == nullptr || node->data()._size <= 0)
Create(need_size > def_size ? need_size : def_size);
}
__CacheBlock& block = _cache.begin()->data();
char* ptr = block._ptr.get();
int& size = block._size;
if(size <= block_size)
{
block_size = size;
count = 1;
return ApplyRet{(__Block*)(ptr), (__Block*)(ptr)};
}
__Block * list = nullptr,
* begin = nullptr,
* end = nullptr;
int ret_count = 0;
for (;size >= block_size;)
{
char* block_ptr = ptr + size - block_size;
if(list == nullptr)
{
list = (__Block*)(block_ptr);
begin = end = list;
}
else
{
list->_next = (__Block*)(block_ptr);
end = list = list->_next;
}
size -= block_size;
++ret_count;
if(ret_count >= count)
{
count = ret_count;
return ApplyRet{begin, end};
}
}
return ApplyRet{begin, end};
}
MemPool::MemPool()
{
std::memset(_free, 0, sizeof(_free));
}
MemPool::~MemPool()
{
}
void MemPool::Fill(int index, int count)
{
int size = __Sit(index);
auto ret = _mem_cache.Apply(size, count);
__Block*& p = _free[__Index(size)];
ret._e->_next = p;
p = ret._b;
}
void* MemPool::Alloc(int size)
{
if(size > BLOCK_MAX)
return malloc(size);
if(size <= 0)
return nullptr;
LABLE_ALLOC:
const int index = __Index(size);
__Block* block = _free[index];
if(block == nullptr)
{
Fill(index, DEFAULT_EACH_BLOCK_STORE);
goto LABLE_ALLOC;
}
block = _free[index];
_free[index] = block->_next;
return block;
}
void MemPool::Free(void* ptr, int size)
{
if(ptr == nullptr)
return;
if(size > BLOCK_MAX)
{
free(ptr);
return;
}
const int index = __Index(size);
__Block* block = (__Block*)(ptr);
block->_next = _free[index];
_free[index] = block;
}
MemPoolThreadSafe::MemPoolThreadSafe() noexcept
{
}
MemPoolThreadSafe::~MemPoolThreadSafe()
{
}
uint32_t MemPoolThreadSafe::GetThreadID()
{
static __thread uint32_t id = 0;
if(id != 0) return id;
id = std::hash<std::thread::id>()(std::this_thread::get_id());
return id;
}
void* MemPoolThreadSafe::Alloc(int size)
{
uint32_t id = GetThreadID();
uint32_t index = id % __BUCKET_COUNT;
auto& list = _forThreadMemPool[index];
auto* node = list.begin();
for (; node != nullptr; )
{
if(node->data()._id != id)
{
node = node->_next;
continue;
}
break;
}
if(node == nullptr)
{
list.emplace(id, new MemPool());
node = list.begin();
}
return node->data()._pool->Alloc(size);
}
void MemPoolThreadSafe::Free(void* ptr, int size)
{
if(ptr == nullptr)
return;
if(size <= 0)
{
free(ptr);
return;
}
uint32_t id = GetThreadID();
uint32_t index = id % __BUCKET_COUNT;
auto& list = _forThreadMemPool[index];
if(list.size() <= 0)
list.emplace(id, new MemPool());
auto* node = list.begin();
for (; node != nullptr; )
{
if(node->data()._id != id)
{
node = node->_next;
continue;
}
break;
}
if(node == nullptr)
exit(3);
return node->data()._pool->Free(ptr, size);
}
};