Modify mempool.h to fit format.

This commit is contained in:
guoheng
2026-03-16 20:03:37 +08:00
parent a56f330d03
commit 662d632ed2
2 changed files with 344 additions and 24 deletions

317
lib/mempool.h Normal file
View File

@@ -0,0 +1,317 @@
#ifndef MEM_POOL
#define MEM_POOL
#include <stddef.h>
/* 对齐到指针大小的倍数 */
#define ALIGN(n) (((n) + sizeof(void*) - 1) & ~(sizeof(void*) - 1))
/* 每次扩容新段的最小大小 */
#define EXPAND_MIN 4096
/* 从用户指针回退到 BlockHeader */
#define HDR(ptr) ((BlockHeader *)((char *)(ptr) - sizeof(BlockHeader)))
/* 一次完整分配需要的总字节header + 数据区 */
#define TOTAL(sz) (sizeof(BlockHeader) + (sz))
/*
* 块头:紧贴在每块分配数据的前面,记录本块数据区的对齐后大小。
* 用户拿到的指针指向 header 之后mp_free / mp_realloc 向前偏移
* sizeof(BlockHeader) 读回大小,无需调用方手动传 size。
*/
typedef struct BlockHeader {
size_t size; /* 数据区对齐后大小(不含 header 本身) */
} BlockHeader;
/* 空闲链表节点(直接复用已释放块的内存空间) */
typedef struct FreeBlock {
struct FreeBlock *next; /* 方便地插入删除 */
size_t size; /* 数据区大小,含义同 BlockHeader.size */
} FreeBlock;
/* 内存池段;多段通过 next 链接,实现自动扩容 */
typedef struct MemPool {
void *buffer; /* 线性缓冲区起始地址 */
size_t buf_size; /* 缓冲区总大小 */
size_t used; /* 已使用字节数header + 数据 + 对齐) */
FreeBlock *free_list; /* 已释放块的单链表 */
struct MemPool *next; /* 扩容后追加的下一段 */
} MemPool;
static MemPool *_mp_create (size_t initial_size);
static void *_mp_malloc (MemPool *pool, size_t size);
static void *_mp_calloc (MemPool *pool, size_t nmemb, size_t size);
static void *_mp_realloc(MemPool *pool, void *ptr, size_t new_size);
static void _mp_free (MemPool *pool, void *ptr);
static void _mp_destroy(MemPool *pool);
static MemPool* global_pool;
/* ------------------------------------------------------------------ */
/* 内部:创建一个新的池段 */
/* ------------------------------------------------------------------ */
static MemPool *
_new_segment (size_t size)
{
MemPool *seg = (MemPool *)malloc(sizeof(MemPool));
if (!seg) { return NULL; }
seg->buffer = malloc(size);
if (!seg->buffer) { free(seg); return NULL; }
seg->buf_size = size;
seg->used = 0;
seg->free_list = NULL;
seg->next = NULL;
return seg;
}
/* ------------------------------------------------------------------ */
/* 内部:核心分配(返回数据区指针,已写好 BlockHeader */
/* ------------------------------------------------------------------ */
static void *
_do_alloc (MemPool *pool, size_t size)
{
/* size 已由调用方对齐 */
size_t total = TOTAL(size);
/* 1. 空闲链表复用 */
MemPool *seg = pool;
while (seg)
{
FreeBlock **prev = &seg->free_list;
FreeBlock *blk = seg->free_list;
while (blk)
{
if (blk->size >= size)
{
*prev = blk->next;
/* 写入 header返回数据区 */
BlockHeader *hdr = (BlockHeader *)blk;
hdr->size = size;
return (char *)hdr + sizeof(BlockHeader);
}
prev = &blk->next; /* &blk->next == blk->prev because: 1 of struct is next */
blk = blk->next;
}
seg = seg->next;
}
/* 2. 线性区顺序分配 */
MemPool *last = pool;
seg = pool;
while (seg)
{
if (seg->used + total <= seg->buf_size) {
BlockHeader *hdr = (BlockHeader *)((char *)seg->buffer + seg->used);
hdr->size = size;
seg->used += total;
return (char *)hdr + sizeof(BlockHeader);
}
last = seg;
seg = seg->next;
}
/* 3. 扩容:追加新段 */
size_t new_size = (total > EXPAND_MIN) ? total * 2 : EXPAND_MIN;
MemPool *new_seg = _new_segment(new_size);
if (!new_seg) { return NULL; }
last->next = new_seg;
BlockHeader *hdr = (BlockHeader *)new_seg->buffer;
hdr->size = size;
new_seg->used = total;
return (char *)hdr + sizeof(BlockHeader);
}
/**
* @brief 创建一个新的内存池
*
* @param initial_size 初始分配的大小(字节)。如果小于内部最小阈值,将自动调整为最小值。
*
* @return 成功返回指向新内存池的指针,失败返回 NULL通常在内存不足时
*/
MemPool *
_mp_create (size_t initial_size)
{
if (initial_size < EXPAND_MIN) initial_size = EXPAND_MIN;
return _new_segment(initial_size);
}
/**
* @brief 从内存池中分配指定大小的内存块
*
* @param pool 指向内存池的指针
* @param size 需要分配的字节数
*
* @return 成功返回指向已分配内存的指针,失败返回 NULL如 pool 为空、size 为 0 或内存不足)。
* 返回的内存未初始化。
*/
void *
_mp_malloc (MemPool *pool, size_t size)
{
if (!pool || size == 0) { return NULL; }
return _do_alloc(pool, ALIGN(size));
}
/**
* @brief 从内存池中分配并清零指定大小的内存块
*
* @param pool 指向内存池的指针
* @param nmemb 元素个数
* @param size 每个元素的字节数
*
* @return 成功返回指向已分配且清零内存的指针,失败返回 NULL。
* 若发生整数溢出nmemb * size 超出范围)也会返回 NULL。
*/
void *
_mp_calloc (MemPool *pool, size_t nmemb, size_t size)
{
if (!pool || nmemb == 0 || size == 0) { return NULL; }
/* 溢出检查 */
if (size != 0 && nmemb > (size_t)-1 / size) { return NULL; }
size_t total = nmemb * size;
void *ptr = _do_alloc(pool, ALIGN(total));
if (ptr) memset(ptr, 0, total);
return ptr;
}
/**
* @brief 调整内存块的大小
*
* @param pool 指向内存池的指针
* @param ptr 指向之前分配的内存块的指针。若为 NULL则行为等同于 mp_alloc。
* @param new_size 新的请求大小(字节)。若为 0则行为等同于 mp_free 并返回 NULL。
*
* @return 成功返回指向新内存块的指针(可能已移动),失败返回 NULL。
* 若缩小或大小不变,通常原地返回;若扩大,则分配新块、拷贝数据并释放旧块。
*/
void *
_mp_realloc (MemPool *pool, void *ptr, size_t new_size)
{
/* realloc(pool, NULL, n) → alloc */
if (!ptr) { return _mp_malloc(pool, new_size); }
/* realloc(pool, ptr, 0) → free */
if (new_size == 0) { _mp_free(pool, ptr); return NULL; }
size_t aligned_new = ALIGN(new_size);
size_t old_size = HDR(ptr)->size; /* 读取块头记录的旧大小 */
/* 缩小或等大:原地返回,更新 header */
if (aligned_new <= old_size)
{
HDR(ptr)->size = aligned_new;
return ptr;
}
/* 扩大:重新分配 + 拷贝 + 释放旧块 */
void *new_ptr = _do_alloc(pool, aligned_new);
if (!new_ptr) { return NULL; }
memcpy(new_ptr, ptr, old_size);
_mp_free(pool, ptr);
return new_ptr;
}
/**
* @brief 释放之前分配的内存块回内存池
*
* @param pool 指向内存池的指针
* @param ptr 指向要释放的内存块的指针。若为 NULL 或 pool 为 NULL则直接返回。
*
* @note 该操作并非真正归还给操作系统,而是将块标记为空闲并加入空闲链表,供后续分配复用。
*/
void
_mp_free (MemPool *pool, void *ptr)
{
if (!pool || !ptr) return;
BlockHeader *hdr = HDR(ptr); /* 从块头读出大小 */
FreeBlock *blk = (FreeBlock *)hdr; /* 复用同一块内存做链表节点 */
blk->size = hdr->size;
blk->next = pool->free_list; /* 头插法插入free_list */
pool->free_list = blk;
}
/**
* @brief 销毁内存池并释放所有相关资源
*
* @param pool 指向要销毁的内存池的指针
*
* @note 此函数会释放内存池管理的所有内存段buffer以及池结构体本身。
* 调用后不应再使用该 pool 指针或其曾分配的任何指针。
*/
void
_mp_destroy (MemPool *pool)
{
MemPool *seg = pool;
while (seg)
{
MemPool *next = seg->next;
free(seg->buffer);
free(seg);
seg = next;
}
}
/**
* @brief 初始化内存池
*
* @param size 初始化内存池的大小
*
* @note 此函数在程序开始时调用,请不要在其他时刻调用
*/
__attribute__((constructor))
void
mp_initialize (size_t size)
{
MemPool *pool = _mp_create(size);
global_pool = pool;
}
/**
* @brief 销毁内存池并释放所有相关资源
*
* @param None
*
* @note 此函数在程序结束时调用,请不要在其他时刻调用
*/
__attribute__((destructor))
void
mp_finalize (void)
{
_mp_destroy(global_pool);
}
/* ------------------------------------------------------------------ */
/* API */
/* ------------------------------------------------------------------ */
void *
mp_malloc (size_t size)
{
return _mp_malloc(global_pool,size);
}
void *
mp_calloc (size_t nmemb, size_t size)
{
return _mp_calloc(global_pool,nmemb,size);
}
void *
mp_realloc (void *ptr, size_t new_size)
{
return _mp_realloc(global_pool,ptr,new_size);
}
void
mp_free (void *ptr)
{
_mp_free(global_pool,ptr);
}
#endif

View File

@@ -47,6 +47,8 @@
#include <unistd.h>
#include <dirent.h> // opendir() closedir()
#include "mempool.h"
#if defined(__STDC__) && __STDC_VERSION__ >= 202311
#define XY_Deprecate_This(msg) [[deprecated(msg)]]
#elif defined(__GNUC__) || defined(__clang__)
@@ -215,9 +217,10 @@ void p (const char *s) { printf ("%s\n", s); }
static inline void *
xy_malloc0 (size_t size)
{
void *ptr = malloc (size);
memset (ptr, 0, size);
return ptr;
// void *ptr = malloc (size);
// memset (ptr, 0, size);
// return ptr;
return mp_calloc(size,1);
}
@@ -234,7 +237,7 @@ xy_ptr_replace (char **pptr, char *new_mem)
xy_cant_be_null (pptr);
if (*pptr)
free (*pptr);
mp_free (*pptr);
*pptr = new_mem;
}
@@ -283,7 +286,7 @@ xy_str_gsub (const char *str, const char *pat, const char *replace)
}
// puti(count); DEBUG 匹配次数
char *ret = malloc (unit * count + len + 1);
char *ret = mp_malloc (unit * count + len + 1);
char *retcur = ret;
cur = str;
@@ -317,7 +320,7 @@ xy_2strcat (const char *str1, const char *str2)
{
size_t len = strlen (str1);
size_t size = len + strlen (str2) + 1;
char *ret = malloc (size);
char *ret = mp_malloc (size);
strcpy (ret, str1);
strcpy (ret + len, str2);
return ret;
@@ -343,7 +346,7 @@ static char *
xy_strcat (unsigned int count, ...)
{
size_t al_fixed = 256;
char *ret = calloc (1, al_fixed);
char *ret = mp_calloc (1, al_fixed);
// 已分配次数
int al_times = 1;
// 当前已分配量
@@ -375,7 +378,7 @@ xy_strcat (unsigned int count, ...)
if (need_realloc)
{
ptrdiff_t diff = cur - ret;
ret = realloc (ret, al_cur);
ret = mp_realloc (ret, al_cur);
cur = ret + diff;
}
if (NULL == ret)
@@ -489,7 +492,7 @@ _xy_str_to_terminal_style (int style, const char *str)
new_str:
// -2 把中间%s减掉
len = strlen (color_fmt_str) - 2;
char *buf = malloc (strlen (str) + len + 1);
char *buf = mp_malloc (strlen (str) + len + 1);
sprintf (buf, color_fmt_str, str);
return buf;
}
@@ -755,7 +758,7 @@ xy_file_read (const char *path)
if (read_bytes < (size_t) size && ferror (fp))
{
fclose (fp);
free (buf);
mp_free (buf);
return xy_strdup ("");
}
@@ -765,7 +768,7 @@ xy_file_read (const char *path)
char *formatted_str = xy_str_gsub (buf, "\r\n", "\n");
xy_ptr_replace (&formatted_str, xy_str_gsub (formatted_str, "\r", "\n"));
free (buf);
mp_free (buf);
return formatted_str;
}
@@ -833,7 +836,7 @@ _xy_log (int level, const char *prompt, const char *content)
{
puts (str);
}
free (str);
mp_free (str);
}
@@ -858,7 +861,7 @@ xy_log_brkt_to (const char *prompt, const char *content, FILE *stream)
{
char *str = xy_strcat (4, "[", prompt, "] ", content);
fprintf (stream, "%s\n", str);
free (str);
mp_free (str);
}
#define xy_log_brkt(prompt1,prompt2,content) _xy_log_brkt(_XY_Log_Plain, prompt1,prompt2,content)
@@ -919,7 +922,7 @@ _xy_log_brkt (int level, const char *prompt1, const char *prompt2, const char *c
{
puts (str);
}
free (str);
mp_free (str);
}
@@ -963,7 +966,7 @@ static char *
xy_run_iter_lines (const char *cmd, unsigned long n, bool (*func) (const char *))
{
const int size = 512;
char *buf = (char *) malloc (size);
char *buf = (char *) mp_malloc (size);
FILE *stream = popen (cmd, "r");
if (stream == NULL)
@@ -1051,7 +1054,7 @@ xy_run_get_stdout (const char *cmd, char **output)
if (size == cap)
{
cap *= 2;
char *new_buf = realloc (buf, cap);
char *new_buf = mp_realloc (buf, cap);
buf = new_buf;
}
}
@@ -1137,7 +1140,7 @@ _xy_win_powershell_profile ()
{
char *documents_dir = _xy_win_documents ();
char *profile_path = xy_2strcat (documents_dir, "\\PowerShell\\Microsoft.PowerShell_profile.ps1");
free (documents_dir);
mp_free (documents_dir);
return profile_path;
}
else
@@ -1157,7 +1160,7 @@ _xy_win_powershellv5_profile ()
{
char *documents_dir = _xy_win_documents ();
char *profile_path = xy_2strcat (documents_dir, "\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1");
free (documents_dir);
mp_free (documents_dir);
return profile_path;
}
else
@@ -1185,7 +1188,7 @@ xy_file_exist (const char *path)
// 0 即 F_OK
bool result = (0 == access (check_path, 0)) ? true : false;
if (expanded_path) free (expanded_path);
if (expanded_path) mp_free (expanded_path);
return result;
}
@@ -1227,7 +1230,7 @@ xy_dir_exist (const char *path)
{
result = false;
}
if (allocated_dir) free (allocated_dir);
if (allocated_dir) mp_free (allocated_dir);
return result;
#endif
}
@@ -1235,9 +1238,9 @@ xy_dir_exist (const char *path)
{
char *tmp_cmd = xy_2strcat ("test -d ", dir);
int status = system (tmp_cmd);
free (tmp_cmd);
mp_free (tmp_cmd);
bool result = (0==status);
if (allocated_dir) free (allocated_dir);
if (allocated_dir) mp_free (allocated_dir);
return result;
}
@@ -1263,7 +1266,7 @@ xy_normalize_path (const char *path)
{
char *tmp = xy_str_delete_prefix (new, "~");
char *joined = xy_2strcat (xy_os_home, tmp);
free (tmp);
mp_free (tmp);
xy_ptr_replace (&new, joined);
}
@@ -1588,7 +1591,7 @@ xy_seq_pop (XySeq_t *seq)
seq->length--;
void *data = l->data;
free (l);
mp_free (l);
return data;
}