mirror of
https://github.com/RubyMetric/chsrc
synced 2026-04-16 17:12:42 +08:00
Modify mempool.h to fit format.
This commit is contained in:
317
lib/mempool.h
Normal file
317
lib/mempool.h
Normal 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
|
||||
51
lib/xy.h
51
lib/xy.h
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user