This commit is contained in:
lixianjing 2025-04-16 08:26:19 +08:00
commit 6d0ff6f14b
14 changed files with 1098 additions and 78 deletions

View File

@ -1,5 +1,9 @@
# 最新动态
2025/04/15
* 增加mem_allocator_fixed_blockdlist/slist/tree使用该内存分配器管理内存(感谢兆坤提供补丁)。
* 完善mem_allocator_fixed_block(感谢兆坤提供补丁)。
2025/04/14
* conf_io 支持 YAML格式。

View File

@ -27,9 +27,15 @@ static dlist_node_t* dlist_create_node(dlist_t* dlist, void* data) {
dlist_node_t* ret = NULL;
return_value_if_fail(dlist != NULL, NULL);
ret = TKMEM_ZALLOC(dlist_node_t);
if (dlist->node_allocator != NULL) {
ret = mem_allocator_alloc(dlist->node_allocator, sizeof(dlist_node_t), __FUNCTION__, __LINE__);
} else {
ret = TKMEM_ALLOC(sizeof(dlist_node_t));
}
return_value_if_fail(ret != NULL, NULL);
memset(ret, 0, sizeof(*ret));
ret->data = data;
return ret;
@ -41,7 +47,11 @@ static ret_t dlist_destroy_node(dlist_t* dlist, dlist_node_t* node) {
if (node->data != NULL) {
dlist->destroy(node->data);
}
TKMEM_FREE(node);
if (dlist->node_allocator != NULL) {
mem_allocator_free(dlist->node_allocator, node);
} else {
TKMEM_FREE(node);
}
return RET_OK;
}
@ -346,7 +356,14 @@ int32_t dlist_count(dlist_t* dlist, void* ctx) {
}
ret_t dlist_deinit(dlist_t* dlist) {
return dlist_remove_all(dlist);
ret_t ret = RET_OK;
return_value_if_fail(dlist != NULL, RET_BAD_PARAMS);
ret = dlist_remove_all(dlist);
if (RET_OK == ret) {
dlist_set_node_allocator(dlist, NULL);
}
return ret;
}
ret_t dlist_remove_all(dlist_t* dlist) {
@ -406,3 +423,18 @@ ret_t dlist_reverse(dlist_t* dlist) {
return RET_OK;
}
ret_t dlist_set_node_allocator(dlist_t* dlist, mem_allocator_t* allocator) {
return_value_if_fail(dlist != NULL, RET_BAD_PARAMS);
if (dlist->node_allocator != allocator) {
return_value_if_fail(dlist_is_empty(dlist), RET_FAIL);
if (dlist->node_allocator != NULL) {
mem_allocator_destroy(dlist->node_allocator);
}
dlist->node_allocator = allocator;
}
return RET_OK;
}

View File

@ -23,6 +23,7 @@
#define TK_DLIST_H
#include "tkc/types_def.h"
#include "tkc/mem_allocator.h"
BEGIN_C_DECLS
@ -91,6 +92,12 @@ typedef struct _dlist_t {
*
*/
tk_compare_t compare;
/**
* @property {mem_allocator_t*} node_allocator
*
*/
mem_allocator_t* node_allocator;
} dlist_t;
/**
@ -320,6 +327,16 @@ int32_t dlist_count(dlist_t* dlist, void* ctx);
*/
ret_t dlist_reverse(dlist_t* dlist);
/**
* @method dlist_set_node_allocator
*
* @param {dlist_t*} dlist
* @param {mem_allocator_t*} allocator
*
* @return {ret_t} RET_OK表示成功
*/
ret_t dlist_set_node_allocator(dlist_t* dlist, mem_allocator_t* allocator);
/**
* @method dlist_deinit
*

View File

@ -0,0 +1,587 @@
/**
* File: mem_allocator_fixed_block.c
* Author: AWTK Develop Team
* Brief:
*
* Copyright (c) 2025 - 2025 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2024-04-12 Shen ZhaoKun <shenzhaokun@zlg.cn> created
*
*/
#include "tkc/mem_allocator_fixed_block.h"
#include "tkc/mem.h"
#include "tkc/str.h"
typedef struct _mem_allocator_fixed_block_unit_t mem_allocator_fixed_block_unit_t;
struct _mem_allocator_fixed_block_unit_t {
mem_allocator_fixed_block_unit_t* prev;
mem_allocator_fixed_block_unit_t* next;
uint8_t mem[];
};
typedef struct _mem_allocator_fixed_block_pool_t mem_allocator_fixed_block_pool_t;
struct _mem_allocator_fixed_block_pool_t {
mem_allocator_fixed_block_pool_t* next;
/**
* @property {mem_allocator_fixed_block_info_t*} used_units
* 使
*/
mem_allocator_fixed_block_unit_t* used_units;
/**
* @property {mem_allocator_fixed_block_info_t*} unused_units
* 使
*/
mem_allocator_fixed_block_unit_t* unused_units;
/**
* @property {uint32_t} num
* @annotation ["readable"]
*
*/
uint32_t num;
mem_allocator_fixed_block_unit_t units;
};
typedef struct _mem_allocator_fixed_block_t {
mem_allocator_t base;
/**
* @property {mem_allocator_fixed_block_pool_t*} pools
*
*/
mem_allocator_fixed_block_pool_t* pools;
/**
* @property {uint32_t} size
* @annotation ["readable"]
*
*/
uint32_t size;
} mem_allocator_fixed_block_t;
#define MEM_ALLOCATOR_FIXED_BLOCK_UNIT_SIZE(type_size, num) \
((offsetof(mem_allocator_fixed_block_unit_t, mem) + (type_size)) * (num))
#define MEM_ALLOCATOR_FIXED_BLOCK_POOL_SIZE(unit_type_size, unit_num) \
(offsetof(mem_allocator_fixed_block_pool_t, units) + \
MEM_ALLOCATOR_FIXED_BLOCK_UNIT_SIZE(unit_type_size, unit_num))
#define MEM_ALLOCATOR_FIXED_BLOCK_GET_UNIT(units, type_size, index) \
(mem_allocator_fixed_block_unit_t*)((uint8_t*)(units) + \
MEM_ALLOCATOR_FIXED_BLOCK_UNIT_SIZE(type_size, index))
#define MEM_ALLOCATOR_FIXED_BLOCK_UNIT_ADD(unit, type_size) \
(mem_allocator_fixed_block_unit_t*)((uint8_t*)(unit) + \
MEM_ALLOCATOR_FIXED_BLOCK_UNIT_SIZE(type_size, 1))
#define MEM_ALLOCATOR_FIXED_BLOCK_NUM_EXTEND(num) (((num) >> 1) + (num) + 1)
inline static bool_t mem_allocator_fixed_block_pool_is_full(
mem_allocator_fixed_block_pool_t* pool) {
return_value_if_fail(pool != NULL, FALSE);
return pool->unused_units == NULL;
}
inline static bool_t mem_allocator_fixed_block_pool_is_empty(
mem_allocator_fixed_block_pool_t* pool) {
return_value_if_fail(pool != NULL, FALSE);
return pool->used_units == NULL;
}
inline static bool_t mem_allocator_fixed_block_is_full(mem_allocator_fixed_block_t* allocator) {
mem_allocator_fixed_block_pool_t* iter = NULL;
return_value_if_fail(allocator != NULL, FALSE);
for (iter = allocator->pools; iter != NULL; iter = iter->next) {
if (!mem_allocator_fixed_block_pool_is_full(iter)) {
return FALSE;
}
}
return TRUE;
}
inline static bool_t mem_allocator_fixed_block_is_empty(mem_allocator_fixed_block_t* allocator) {
mem_allocator_fixed_block_pool_t* iter = NULL;
return_value_if_fail(allocator != NULL, FALSE);
for (iter = allocator->pools; iter != NULL; iter = iter->next) {
if (!mem_allocator_fixed_block_pool_is_empty(iter)) {
return FALSE;
}
}
return TRUE;
}
inline static uint32_t mem_allocator_fixed_block_num(mem_allocator_fixed_block_t* allocator,
bool_t only_empty) {
uint32_t ret = 0;
mem_allocator_fixed_block_pool_t* iter = NULL;
return_value_if_fail(allocator != NULL, 0);
for (iter = allocator->pools; iter != NULL; iter = iter->next) {
if (!only_empty || mem_allocator_fixed_block_pool_is_empty(iter)) {
ret += iter->num;
}
}
return ret;
}
inline static uint32_t mem_allocator_fixed_block_pool_num(mem_allocator_fixed_block_t* allocator,
bool_t only_empty) {
uint32_t ret = 0;
mem_allocator_fixed_block_pool_t* iter = NULL;
return_value_if_fail(allocator != NULL, 0);
for (iter = allocator->pools; iter != NULL; iter = iter->next) {
if (!only_empty || mem_allocator_fixed_block_pool_is_empty(iter)) {
ret++;
}
}
return ret;
}
static ret_t mem_allocator_fixed_block_pool_init(mem_allocator_fixed_block_t* allocator,
mem_allocator_fixed_block_pool_t* pool) {
uint32_t i = 0;
mem_allocator_fixed_block_unit_t *iter = NULL, *prev = NULL;
mem_allocator_fixed_block_unit_t* start = NULL;
return_value_if_fail(allocator != NULL && pool != NULL, RET_BAD_PARAMS);
start = MEM_ALLOCATOR_FIXED_BLOCK_GET_UNIT(&pool->units, allocator->size, i);
for (iter = start, prev = NULL; iter != NULL && i < pool->num;
prev = iter, iter = iter->next, i++) {
iter->prev = prev;
if (i + 1 < pool->num) {
iter->next = MEM_ALLOCATOR_FIXED_BLOCK_UNIT_ADD(iter, allocator->size);
} else {
iter->next = NULL;
}
}
if (pool->unused_units == NULL) {
pool->unused_units = start;
} else {
prev->next = pool->unused_units;
pool->unused_units->prev = prev;
}
return RET_OK;
}
inline static mem_allocator_fixed_block_pool_t* mem_allocator_fixed_block_pool_create(
mem_allocator_fixed_block_t* allocator, uint32_t num) {
mem_allocator_fixed_block_pool_t* ret = NULL;
return_value_if_fail(allocator != NULL && num > 0, NULL);
ret = TKMEM_ALLOC(MEM_ALLOCATOR_FIXED_BLOCK_POOL_SIZE(allocator->size, num));
return_value_if_fail(ret != NULL, NULL);
ret->num = num;
ret->used_units = NULL;
ret->unused_units = NULL;
ret->next = NULL;
mem_allocator_fixed_block_pool_init(allocator, ret);
return ret;
}
static ret_t mem_allocator_fixed_block_pools_destroy(mem_allocator_fixed_block_t* allocator,
bool_t only_empty) {
mem_allocator_fixed_block_pool_t *iter = NULL, *prev = NULL;
return_value_if_fail(allocator != NULL, RET_BAD_PARAMS);
iter = allocator->pools;
allocator->pools = NULL;
while (iter != NULL) {
mem_allocator_fixed_block_pool_t* next = iter->next;
if (!only_empty || mem_allocator_fixed_block_pool_is_empty(iter)) {
if (prev != NULL && prev->next == iter) {
prev->next = NULL;
}
TKMEM_FREE(iter);
} else {
if (prev != NULL) {
prev->next = iter;
} else {
allocator->pools = iter;
}
prev = iter;
}
iter = next;
}
return RET_OK;
}
static ret_t mem_allocator_fixed_block_pools_merge(mem_allocator_fixed_block_t* allocator) {
uint32_t num = 0;
mem_allocator_fixed_block_pool_t *pool = NULL, *prev_pool = NULL;
mem_allocator_fixed_block_pool_t *iter = NULL, *prev = NULL;
return_value_if_fail(allocator != NULL, RET_BAD_PARAMS);
num = mem_allocator_fixed_block_num(allocator, TRUE);
return_value_if_fail(num > 0, RET_FAIL);
/* 保留一个空间最大的空内存池复用 */
for (iter = allocator->pools, prev = NULL; iter != NULL; prev = iter, iter = iter->next) {
if (mem_allocator_fixed_block_pool_is_empty(iter)) {
if (pool == NULL || pool->num < iter->num) {
pool = iter;
prev_pool = prev;
}
}
}
return_value_if_fail(pool != NULL, RET_FAIL);
if (allocator->pools == pool) {
allocator->pools = pool->next;
} else {
prev_pool->next = pool->next;
}
pool->next = NULL;
mem_allocator_fixed_block_pools_destroy(allocator, TRUE);
if (allocator->pools != NULL) {
pool->next = allocator->pools;
}
allocator->pools = pool;
pool = TKMEM_REALLOC(pool, MEM_ALLOCATOR_FIXED_BLOCK_POOL_SIZE(allocator->size, num));
return_value_if_fail(pool != NULL, RET_OOM);
pool->num = num;
pool->used_units = NULL;
pool->unused_units = NULL;
allocator->pools = pool;
return mem_allocator_fixed_block_pool_init(allocator, allocator->pools);
}
static ret_t mem_allocator_fixed_block_extend(mem_allocator_fixed_block_t* allocator) {
return_value_if_fail(allocator != NULL, RET_BAD_PARAMS);
if (mem_allocator_fixed_block_is_full(allocator)) {
uint32_t num = mem_allocator_fixed_block_num(allocator, FALSE);
uint32_t extend_num = MEM_ALLOCATOR_FIXED_BLOCK_NUM_EXTEND(num);
mem_allocator_fixed_block_pool_t* iter = NULL;
mem_allocator_fixed_block_pool_t* pool =
mem_allocator_fixed_block_pool_create(allocator, extend_num - num);
return_value_if_fail(pool != NULL, RET_OOM);
if (allocator->pools != NULL) {
pool->next = allocator->pools;
}
allocator->pools = pool;
}
return RET_OK;
}
static void* mem_allocator_fixed_block_allocate(mem_allocator_fixed_block_t* allocator) {
mem_allocator_fixed_block_unit_t* unit = NULL;
mem_allocator_fixed_block_pool_t *pool = NULL, *prev_pool = NULL;
return_value_if_fail(allocator != NULL, NULL);
return_value_if_fail(RET_OK == mem_allocator_fixed_block_extend(allocator), NULL);
for (pool = allocator->pools, prev_pool = NULL; pool != NULL;
prev_pool = pool, pool = pool->next) {
if (!mem_allocator_fixed_block_pool_is_full(pool)) {
break;
}
}
return_value_if_fail(pool != NULL, NULL);
unit = pool->unused_units;
pool->unused_units = unit->next;
if (pool->unused_units != NULL) {
pool->unused_units->prev = NULL;
}
unit->next = pool->used_units;
if (pool->used_units != NULL) {
pool->used_units->prev = unit;
}
pool->used_units = unit;
ENSURE(unit->prev == NULL);
/* 将当前池未满,则移至顶部 */
if (allocator->pools != pool && !mem_allocator_fixed_block_pool_is_full(pool)) {
prev_pool->next = pool->next;
pool->next = allocator->pools;
allocator->pools = pool;
}
return &unit->mem;
}
static mem_allocator_fixed_block_unit_t* mem_allocator_fixed_block_unit_find(
mem_allocator_fixed_block_t* allocator, void* ptr, mem_allocator_fixed_block_pool_t** p_pool,
mem_allocator_fixed_block_pool_t** p_prev_pool) {
mem_allocator_fixed_block_unit_t* ret = NULL;
mem_allocator_fixed_block_pool_t *pool = NULL, *prev_pool = NULL;
return_value_if_fail(allocator != NULL, NULL);
for (pool = allocator->pools, prev_pool = NULL; pool != NULL;
prev_pool = pool, pool = pool->next) {
if (pool->num > 0) {
uint8_t* start = (uint8_t*)&pool->units + offsetof(mem_allocator_fixed_block_unit_t, mem);
uint8_t* end = start + MEM_ALLOCATOR_FIXED_BLOCK_UNIT_SIZE(allocator->size, pool->num - 1);
if (start <= (uint8_t*)(ptr) && (uint8_t*)(ptr) <= end) {
const ptrdiff_t offset = (uint8_t*)(ptr)-start;
const uint32_t unit_size = MEM_ALLOCATOR_FIXED_BLOCK_UNIT_SIZE(allocator->size, 1);
bool_t ptr_align = FALSE;
return_value_if_fail(unit_size > 0, NULL);
/* 地址对齐检查 */
if ((unit_size & (unit_size - 1)) == 0) { /* 块大小是否为2的幂次方 */
ptr_align = ((offset & (unit_size - 1)) == 0);
} else {
ptr_align = ((offset % unit_size) == 0);
}
return_value_if_fail(ptr_align, NULL);
ret = (mem_allocator_fixed_block_unit_t*)((uint8_t*)(ptr)-offsetof(
mem_allocator_fixed_block_unit_t, mem));
if (p_pool != NULL) {
*p_pool = pool;
}
if (p_prev_pool != NULL) {
*p_prev_pool = prev_pool;
}
break;
}
}
}
return ret;
}
static ret_t mem_allocator_fixed_block_deallocate(mem_allocator_fixed_block_t* allocator,
void* ptr) {
mem_allocator_fixed_block_unit_t* unit = NULL;
mem_allocator_fixed_block_pool_t *pool = NULL, *prev_pool = NULL;
return_value_if_fail(allocator != NULL, RET_BAD_PARAMS);
if (ptr == NULL) {
return RET_OK;
}
unit = mem_allocator_fixed_block_unit_find(allocator, ptr, &pool, &prev_pool);
return_value_if_fail(unit != NULL, RET_NOT_FOUND);
if (unit == pool->used_units) {
pool->used_units = unit->next;
}
if (mem_allocator_fixed_block_pool_is_empty(pool) &&
mem_allocator_fixed_block_pool_num(allocator, TRUE) > 1) {
mem_allocator_fixed_block_pools_merge(allocator);
} else {
if (unit->prev != NULL) {
unit->prev->next = unit->next;
}
if (unit->next != NULL) {
unit->next->prev = unit->prev;
}
unit->prev = NULL;
unit->next = pool->unused_units;
if (pool->unused_units != NULL) {
pool->unused_units->prev = unit;
}
pool->unused_units = unit;
/* 如果顶池已满,将当前活跃池移至顶部 */
if (allocator->pools != pool && mem_allocator_fixed_block_pool_is_full(allocator->pools)) {
prev_pool->next = pool->next;
pool->next = allocator->pools;
allocator->pools = pool;
}
}
return RET_OK;
}
inline static ret_t mem_allocator_fixed_block_clear(mem_allocator_fixed_block_t* allocator) {
mem_allocator_fixed_block_pool_t* iter = NULL;
return_value_if_fail(allocator != NULL, RET_BAD_PARAMS);
if (allocator->pools == NULL) {
return RET_OK;
}
for (iter = allocator->pools; iter != NULL; iter = iter->next) {
iter->used_units = NULL;
iter->unused_units = NULL;
}
if (mem_allocator_fixed_block_pool_num(allocator, FALSE) > 1) {
return mem_allocator_fixed_block_pools_merge(allocator);
} else {
return mem_allocator_fixed_block_pool_init(allocator, allocator->pools);
}
}
inline static ret_t mem_allocator_fixed_block_deinit(mem_allocator_fixed_block_t* allocator) {
return mem_allocator_fixed_block_pools_destroy(allocator, FALSE);
}
static ret_t mem_allocator_fixed_block_destroy(mem_allocator_t* allocator) {
mem_allocator_fixed_block_t* fixed_block_allocator = (mem_allocator_fixed_block_t*)allocator;
return_value_if_fail(fixed_block_allocator != NULL, RET_BAD_PARAMS);
mem_allocator_fixed_block_deinit(fixed_block_allocator);
TKMEM_FREE(fixed_block_allocator);
return RET_OK;
}
static void* mem_allocator_fixed_block_alloc(mem_allocator_t* allocator, uint32_t size,
const char* func, uint32_t line) {
mem_allocator_fixed_block_t* fixed_block_allocator = (mem_allocator_fixed_block_t*)allocator;
(void)func, (void)line;
return_value_if_fail(fixed_block_allocator != NULL, NULL);
return_value_if_fail(fixed_block_allocator->size == size, NULL);
return mem_allocator_fixed_block_allocate(fixed_block_allocator);
}
static void* mem_allocator_fixed_block_realloc(mem_allocator_t* allocator, void* ptr, uint32_t size,
const char* func, uint32_t line) {
mem_allocator_fixed_block_t* fixed_block_allocator = (mem_allocator_fixed_block_t*)allocator;
return_value_if_fail(fixed_block_allocator != NULL, NULL);
return_value_if_fail(fixed_block_allocator->size == size, NULL);
if (ptr != NULL) {
return_value_if_fail(
mem_allocator_fixed_block_unit_find(fixed_block_allocator, ptr, NULL, NULL) != NULL, NULL);
return ptr;
} else {
return mem_allocator_fixed_block_alloc(allocator, size, func, line);
}
}
static void mem_allocator_fixed_block_free(mem_allocator_t* allocator, void* ptr) {
mem_allocator_fixed_block_t* fixed_block_allocator = (mem_allocator_fixed_block_t*)allocator;
mem_allocator_fixed_block_deallocate(fixed_block_allocator, ptr);
}
static ret_t mem_allocator_fixed_block_dump(mem_allocator_t* allocator) {
str_t dump;
mem_allocator_fixed_block_pool_t* pool = NULL;
uint32_t total_bytes = 0;
uint32_t total_nr = 0;
uint32_t total_used_nr = 0;
uint32_t i = 0;
mem_allocator_fixed_block_t* fixed_block_allocator = (mem_allocator_fixed_block_t*)allocator;
return_value_if_fail(fixed_block_allocator != NULL, RET_BAD_PARAMS);
if (log_get_log_level() > LOG_LEVEL_DEBUG) {
return RET_OK;
}
str_init(&dump, 512);
str_append_format(&dump, 40, "%s {\n", __FUNCTION__);
str_append(&dump, " pools: [\n");
for (pool = fixed_block_allocator->pools, i = 0; pool != NULL; pool = pool->next, i++) {
mem_allocator_fixed_block_unit_t* unit = NULL;
uint32_t used_nr = 0;
uint32_t bytes = MEM_ALLOCATOR_FIXED_BLOCK_POOL_SIZE(fixed_block_allocator->size, pool->num);
total_bytes += bytes;
total_nr += pool->num;
for (unit = pool->used_units; unit != NULL; unit = unit->next) {
used_nr++;
}
total_used_nr += used_nr;
str_append_format(&dump, 48, " [%u]: {\n", i);
str_append_format(&dump, 64, " ptr: %p\n", pool);
str_append_format(&dump, 64, " mem: %u bytes\n", bytes);
str_append_format(&dump, 64, " nr: %u\n", pool->num);
str_append_format(&dump, 88, " used rate: %u/%u = %.2f%%\n", used_nr, pool->num,
used_nr * 100.0f / pool->num);
str_append(&dump, " }\n");
}
str_append(&dump, " ]\n");
str_append_format(&dump, 64, " type size: %u\n", fixed_block_allocator->size);
str_append_format(&dump, 64, " mem: %u bytes\n", total_bytes);
str_append_format(&dump, 64, " nr: %u\n", total_nr);
str_append_format(&dump, 88, " used rate: %u/%u = %.2f%%\n", total_used_nr, total_nr,
total_used_nr * 100.0f / total_nr);
str_append(&dump, "}\n");
log_debug("%s", dump.str);
str_reset(&dump);
return RET_OK;
}
static const mem_allocator_vtable_t s_mem_allocator_fixed_block_vtable = {
.alloc = mem_allocator_fixed_block_alloc,
.realloc = mem_allocator_fixed_block_realloc,
.free = mem_allocator_fixed_block_free,
.dump = mem_allocator_fixed_block_dump,
.destroy = mem_allocator_fixed_block_destroy,
};
inline static ret_t mem_allocator_fixed_block_init(mem_allocator_fixed_block_t* allocator,
uint32_t size, uint32_t num) {
return_value_if_fail(allocator != NULL && size > 0, RET_BAD_PARAMS);
memset(allocator, 0, sizeof(mem_allocator_fixed_block_t));
allocator->base.vt = &s_mem_allocator_fixed_block_vtable;
allocator->size = size;
if (num > 0) {
allocator->pools = mem_allocator_fixed_block_pool_create(allocator, num);
goto_error_if_fail(allocator->pools != NULL);
}
return RET_OK;
error:
mem_allocator_fixed_block_deinit(allocator);
return RET_OOM;
}
mem_allocator_t* mem_allocator_fixed_block_create(uint32_t size, uint32_t num) {
mem_allocator_fixed_block_t* ret = NULL;
return_value_if_fail(size > 0, NULL);
ret = TKMEM_ALLOC(sizeof(mem_allocator_fixed_block_t));
return_value_if_fail(ret != NULL, NULL);
goto_error_if_fail(RET_OK == mem_allocator_fixed_block_init(ret, size, num));
return &ret->base;
error:
mem_allocator_fixed_block_deinit(ret);
return NULL;
}
uint32_t mem_allocator_fixed_block_size(mem_allocator_t* allocator) {
mem_allocator_fixed_block_t* fixed_block_allocator = (mem_allocator_fixed_block_t*)allocator;
return_value_if_fail(fixed_block_allocator != NULL, 0);
return fixed_block_allocator->size;
}

View File

@ -0,0 +1,68 @@
/**
* File: mem_allocator_fixed_block.h
* Author: AWTK Develop Team
* Brief:
*
* Copyright (c) 2025 - 2025 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2024-04-12 Shen ZhaoKun <shenzhaokun@zlg.cn> created
*
*/
#ifndef TK_MEM_ALLOCATOR_FIXED_BLOCK_H
#define TK_MEM_ALLOCATOR_FIXED_BLOCK_H
#include "tkc/mem_allocator.h"
BEGIN_C_DECLS
/**
* @class mem_allocator_fixed_block_t
* @parent mem_allocator_t
* @annotation ["fake"]
*
*
* mem_allocator\_fixed\_block\_create创建时mem\_allocator\_destroy销毁
*
* ```c
* mem_allocator_t* allocator = mem_allocator_fixed_block_create(sizeof(int), 32);
* ...
* mem_allocator_destroy(allocator);
* ```
*/
/**
* @method mem_allocator_fixed_block_create
* @annotation ["constructor"]
*
*
* @param {uint32_t} size
* @param {uint32_t} num
*
* @return {allocator_t*}
*/
mem_allocator_t* mem_allocator_fixed_block_create(uint32_t size, uint32_t num);
/**
* @method mem_allocator_fixed_block_size
*
*
* @param {mem_allocator_t*} allocator
*
* @return {uint32_t}
*/
uint32_t mem_allocator_fixed_block_size(mem_allocator_t* allocator);
END_C_DECLS
#endif /*TK_MEM_ALLOCATOR_FIXED_BLOCK_H*/

View File

@ -27,9 +27,15 @@ static slist_node_t* slist_create_node(slist_t* slist, void* data) {
slist_node_t* ret = NULL;
return_value_if_fail(slist != NULL, NULL);
ret = TKMEM_ZALLOC(slist_node_t);
if (slist->node_allocator != NULL) {
ret = mem_allocator_alloc(slist->node_allocator, sizeof(slist_node_t), __FUNCTION__, __LINE__);
} else {
ret = TKMEM_ALLOC(sizeof(slist_node_t));
}
return_value_if_fail(ret != NULL, NULL);
memset(ret, 0, sizeof(*ret));
ret->data = data;
return ret;
@ -41,7 +47,11 @@ static ret_t slist_destroy_node(slist_t* slist, slist_node_t* node) {
if (node->data != NULL) {
slist->destroy(node->data);
}
TKMEM_FREE(node);
if (slist->node_allocator != NULL) {
mem_allocator_free(slist->node_allocator, node);
} else {
TKMEM_FREE(node);
}
return RET_OK;
}
@ -302,7 +312,14 @@ int32_t slist_count(slist_t* slist, void* ctx) {
}
ret_t slist_deinit(slist_t* slist) {
return slist_remove_all(slist);
ret_t ret = RET_OK;
return_value_if_fail(slist != NULL, RET_BAD_PARAMS);
ret = slist_remove_all(slist);
if (RET_OK == ret) {
slist_set_node_allocator(slist, NULL);
}
return ret;
}
ret_t slist_remove_all(slist_t* slist) {
@ -367,3 +384,18 @@ ret_t slist_reverse(slist_t* slist) {
return RET_OK;
}
ret_t slist_set_node_allocator(slist_t* slist, mem_allocator_t* allocator) {
return_value_if_fail(slist != NULL, RET_BAD_PARAMS);
if (slist->node_allocator != allocator) {
return_value_if_fail(slist_is_empty(slist), RET_FAIL);
if (slist->node_allocator != NULL) {
mem_allocator_destroy(slist->node_allocator);
}
slist->node_allocator = allocator;
}
return RET_OK;
}

View File

@ -23,6 +23,7 @@
#define TK_SLIST_H
#include "tkc/types_def.h"
#include "tkc/mem_allocator.h"
BEGIN_C_DECLS
@ -90,6 +91,12 @@ typedef struct _slist_t {
*
*/
tk_compare_t compare;
/**
* @property {mem_allocator_t*} node_allocator
*
*/
mem_allocator_t* node_allocator;
} slist_t;
/**
@ -288,6 +295,16 @@ int32_t slist_count(slist_t* slist, void* ctx);
*/
ret_t slist_reverse(slist_t* slist);
/**
* @method slist_set_node_allocator
*
* @param {slist_t*} slist
* @param {mem_allocator_t*} allocator
*
* @return {ret_t} RET_OK表示成功
*/
ret_t slist_set_node_allocator(slist_t* slist, mem_allocator_t* allocator);
/**
* @method slist_deinit
*

View File

@ -25,6 +25,8 @@
#include "tkc/utils.h"
#include "tkc/darray.h"
static ret_t tree_node_destroy(tree_node_t* node, tk_destroy_t destroy, mem_allocator_t* allocator);
bool_t tree_node_is_ancestor(const tree_node_t* node, const tree_node_t* ancestor) {
return_value_if_fail(node != NULL && ancestor != NULL, FALSE);
@ -132,7 +134,8 @@ static ret_t tree_node_link_sibling(tree_node_t* node, tree_node_t* prev_sibling
}
static ret_t tree_node_foreach_breadth_first(tree_node_t* node, tk_visit_t visit,
tk_destroy_t destroy, void* ctx) {
tk_destroy_t destroy, mem_allocator_t* allocator,
void* ctx) {
uint32_t i = 0;
darray_t queue;
darray_init(&queue, 64, NULL, NULL);
@ -143,7 +146,7 @@ static ret_t tree_node_foreach_breadth_first(tree_node_t* node, tk_visit_t visit
ret_t ret = visit(ctx, iter);
if (ret == RET_REMOVE) {
tree_node_destroy(node, destroy);
tree_node_destroy(node, destroy, allocator);
continue;
} else if (ret != RET_OK) {
break;
@ -160,7 +163,7 @@ static ret_t tree_node_foreach_breadth_first(tree_node_t* node, tk_visit_t visit
}
static ret_t tree_node_foreach_preorder(tree_node_t* node, tk_visit_t visit, tk_destroy_t destroy,
void* ctx) {
mem_allocator_t* allocator, void* ctx) {
darray_t stack;
darray_init(&stack, 16, NULL, NULL);
darray_push(&stack, node);
@ -174,7 +177,7 @@ static ret_t tree_node_foreach_preorder(tree_node_t* node, tk_visit_t visit, tk_
}
if (ret == RET_REMOVE) {
tree_node_destroy(node, destroy);
tree_node_destroy(node, destroy, allocator);
continue;
} else if (ret != RET_OK) {
break;
@ -192,7 +195,7 @@ static ret_t tree_node_foreach_preorder(tree_node_t* node, tk_visit_t visit, tk_
}
static ret_t tree_node_foreach_postorder(tree_node_t* node, tk_visit_t visit, tk_destroy_t destroy,
void* ctx) {
mem_allocator_t* allocator, void* ctx) {
darray_t result_stack;
darray_t process_stack;
darray_init(&result_stack, 128, NULL, NULL);
@ -213,7 +216,7 @@ static ret_t tree_node_foreach_postorder(tree_node_t* node, tk_visit_t visit, tk
ret_t ret = visit(ctx, iter);
if (ret == RET_REMOVE) {
tree_node_destroy(node, destroy);
tree_node_destroy(node, destroy, allocator);
continue;
} else if (ret != RET_OK) {
break;
@ -227,15 +230,16 @@ static ret_t tree_node_foreach_postorder(tree_node_t* node, tk_visit_t visit, tk
}
inline static ret_t tree_node_foreach(tree_node_t* node, tree_foreach_type_t foreach_type,
tk_visit_t visit, tk_destroy_t destroy, void* ctx) {
tk_visit_t visit, tk_destroy_t destroy,
mem_allocator_t* allocator, void* ctx) {
if (node != NULL) {
switch (foreach_type) {
case TREE_FOREACH_TYPE_BREADTH_FIRST:
return tree_node_foreach_breadth_first(node, visit, destroy, ctx);
return tree_node_foreach_breadth_first(node, visit, destroy, allocator, ctx);
case TREE_FOREACH_TYPE_PREORDER:
return tree_node_foreach_preorder(node, visit, destroy, ctx);
return tree_node_foreach_preorder(node, visit, destroy, allocator, ctx);
case TREE_FOREACH_TYPE_POSTORDER:
return tree_node_foreach_postorder(node, visit, destroy, ctx);
return tree_node_foreach_postorder(node, visit, destroy, allocator, ctx);
default:
ENSURE(!"Not support foreach type!");
return RET_NOT_IMPL;
@ -245,15 +249,27 @@ inline static ret_t tree_node_foreach(tree_node_t* node, tree_foreach_type_t for
return RET_OK;
}
tree_node_t* tree_node_create(void* data) {
tree_node_t* ret = TKMEM_ZALLOC(tree_node_t);
static inline tree_node_t* tree_node_create(void* data, mem_allocator_t* allocator) {
tree_node_t* ret = NULL;
if (allocator != NULL) {
ret = mem_allocator_alloc(allocator, sizeof(tree_node_t), __FUNCTION__, __LINE__);
} else {
ret = TKMEM_ALLOC(sizeof(tree_node_t));
}
return_value_if_fail(ret != NULL, NULL);
memset(ret, 0, sizeof(*ret));
ret->data = data;
return ret;
}
tree_node_t* tree_create_node(tree_t* tree, void* data) {
return_value_if_fail(tree != NULL, NULL);
return tree_node_create(data, tree->node_allocator);
}
int32_t tree_node_degree(tree_node_t* node) {
return_value_if_fail(node != NULL, -1);
@ -283,28 +299,45 @@ tree_node_t* tree_node_get_child(tree_node_t* node, uint32_t index) {
return NULL;
}
static ret_t tree_node_destroy_impl(tree_node_t* node, tk_destroy_t destroy) {
static ret_t tree_node_destroy_impl(tree_node_t* node, tk_destroy_t destroy,
mem_allocator_t* allocator) {
return_value_if_fail(node != NULL && destroy != NULL, RET_BAD_PARAMS);
destroy(node->data);
TKMEM_FREE(node);
if (node->data != NULL) {
destroy(node->data);
}
if (allocator != NULL) {
mem_allocator_free(allocator, node);
} else {
TKMEM_FREE(node);
}
return RET_OK;
}
typedef struct _tree_node_destroy_on_visit_ctx_t {
tk_destroy_t destroy;
mem_allocator_t* allocator;
} tree_node_destroy_on_visit_ctx_t;
static ret_t tree_node_destroy_on_visit(void* ctx, const void* data) {
tk_destroy_t destroy = (tk_destroy_t)(ctx);
tree_node_destroy_on_visit_ctx_t* actx = (tree_node_destroy_on_visit_ctx_t*)(ctx);
tree_node_t* node = (tree_node_t*)(data);
tree_node_destroy_impl(node, destroy);
tree_node_destroy_impl(node, actx->destroy, actx->allocator);
return RET_OK;
}
ret_t tree_node_destroy(tree_node_t* node, tk_destroy_t destroy) {
inline static ret_t tree_node_destroy(tree_node_t* node, tk_destroy_t destroy,
mem_allocator_t* allocator) {
tree_node_destroy_on_visit_ctx_t ctx = {
.destroy = destroy,
.allocator = allocator,
};
return_value_if_fail(node != NULL && destroy != NULL, RET_BAD_PARAMS);
return_value_if_fail(RET_OK == tree_node_unlink(node), RET_FAIL);
return tree_node_foreach(node, TREE_FOREACH_TYPE_POSTORDER, tree_node_destroy_on_visit, destroy,
destroy);
allocator, &ctx);
}
tree_t* tree_create(tk_destroy_t destroy, tk_compare_t compare) {
@ -322,7 +355,8 @@ error:
ret_t tree_init(tree_t* tree, tk_destroy_t destroy, tk_compare_t compare) {
return_value_if_fail(tree != NULL, RET_BAD_PARAMS);
tree->root = NULL;
memset(tree, 0, sizeof(tree_t));
tree->destroy = destroy != NULL ? destroy : dummy_destroy;
tree->compare = compare != NULL ? compare : pointer_compare;
@ -434,7 +468,7 @@ ret_t tree_remove_ex(tree_t* tree, tree_node_t* node, tree_foreach_type_t foreac
ret_t tree_remove_node(tree_t* tree, tree_node_t* node) {
return_value_if_fail(tree != NULL && node != NULL, RET_BAD_PARAMS);
return tree_node_destroy(node, tree->destroy);
return tree_node_destroy(node, tree->destroy, tree->node_allocator);
}
ret_t tree_unlink_node(tree_t* tree, tree_node_t* node) {
@ -529,7 +563,7 @@ ret_t tree_foreach(tree_t* tree, tree_node_t* node, tree_foreach_type_t foreach_
node = tree->root;
}
return tree_node_foreach(node, foreach_type, visit, tree->destroy, ctx);
return tree_node_foreach(node, foreach_type, visit, tree->destroy, tree->node_allocator, ctx);
}
bool_t tree_is_empty(tree_t* tree, tree_node_t* node) {
@ -714,10 +748,30 @@ ret_t tree_to_string(tree_t* tree, tree_node_t* node, str_t* result,
return tree_foreach(tree, node, TREE_FOREACH_TYPE_PREORDER, tree_to_string_on_visit, &ctx);
}
ret_t tree_deinit(tree_t* tree) {
ret_t tree_set_node_allocator(tree_t* tree, mem_allocator_t* allocator) {
return_value_if_fail(tree != NULL, RET_BAD_PARAMS);
return tree_clear(tree);
if (tree->node_allocator != allocator) {
return_value_if_fail(tree_is_empty(tree, NULL), RET_FAIL);
if (tree->node_allocator != NULL) {
mem_allocator_destroy(tree->node_allocator);
}
tree->node_allocator = allocator;
}
return RET_OK;
}
ret_t tree_deinit(tree_t* tree) {
ret_t ret = RET_OK;
return_value_if_fail(tree != NULL, RET_BAD_PARAMS);
ret = tree_clear(tree);
if (RET_OK == ret) {
tree_set_node_allocator(tree, NULL);
}
return ret;
}
ret_t tree_destroy(tree_t* tree) {

View File

@ -23,6 +23,7 @@
#define TK_TREE_H
#include "tkc/types_def.h"
#include "tkc/mem_allocator.h"
#include "tkc/str.h"
BEGIN_C_DECLS
@ -41,16 +42,6 @@ struct _tree_node_t {
void* data;
};
/**
* @method tree_node_create
* @annotation ["constructor"]
*
* @param {void*} data
*
* @return {tree_node_t*}
*/
tree_node_t* tree_node_create(void* data);
/**
* @method tree_node_degree
*
@ -90,17 +81,6 @@ tree_node_t* tree_node_get_sibling(tree_node_t* node, uint32_t index);
*/
tree_node_t* tree_node_get_child(tree_node_t* node, uint32_t index);
/**
* @method tree_node_destroy
* @annotation ["deconstructor"]
*
* @param {tree_node_t*} node
* @param {tk_destroy_t} destroy
*
* @return {ret_t} RET_OK表示成功
*/
ret_t tree_node_destroy(tree_node_t* node, tk_destroy_t destroy);
/**
* @enum tree_foreach_type_t
* @prefix TREE_FOREACH_TYPE_
@ -167,6 +147,12 @@ typedef struct _tree_t {
*
*/
tk_compare_t compare;
/**
* @property {mem_allocator_t*} node_allocator
*
*/
mem_allocator_t* node_allocator;
} tree_t;
/**
@ -249,6 +235,16 @@ ret_t tree_remove(tree_t* tree, tree_node_t* node, tree_foreach_type_t foreach_t
ret_t tree_remove_ex(tree_t* tree, tree_node_t* node, tree_foreach_type_t foreach_type,
tk_compare_t compare, void* ctx, int32_t remove_size);
/**
* @method tree_create_node
*
* @param {tree_t*} tree
* @param {void*} data
*
* @return {tree_node_t*}
*/
tree_node_t* tree_create_node(tree_t* tree, void* data);
/**
* @method tree_remove_node
*
@ -443,6 +439,16 @@ int32_t tree_degree(tree_t* tree);
ret_t tree_to_string(tree_t* tree, tree_node_t* node, str_t* result,
tk_visit_t node_str_append_func);
/**
* @method tree_set_node_allocator
*
* @param {tree_t*} tree
* @param {mem_allocator_t*} allocator
*
* @return {ret_t} RET_OK表示成功
*/
ret_t tree_set_node_allocator(tree_t* tree, mem_allocator_t* allocator);
/**
* @method tree_deinit
*

View File

@ -51,6 +51,7 @@
#define TK_MAYBE_UNUSED
#endif
#include <stddef.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>

View File

@ -1,5 +1,6 @@
#include "tkc/utils.h"
#include "tkc/dlist.h"
#include "tkc/mem_allocator_fixed_block.h"
#include "gtest/gtest.h"
#include <string>
@ -50,6 +51,39 @@ TEST(DList, basic) {
dlist_deinit(s);
}
TEST(DList, node_allocator) {
dlist_t dlist;
dlist_t* s = &dlist;
dlist_init(s, NULL, NULL);
ASSERT_EQ(dlist_set_node_allocator(s, mem_allocator_fixed_block_create(sizeof(dlist_node_t), 2)),
RET_OK);
ASSERT_EQ(dlist_size(s), 0);
ASSERT_EQ(dlist_append(s, TO_POINTER(1)), RET_OK);
ASSERT_EQ(dlist_size(s), 1);
ASSERT_EQ(dlist_append(s, TO_POINTER(2)), RET_OK);
ASSERT_EQ(dlist_size(s), 2);
ASSERT_EQ(dlist_append(s, TO_POINTER(3)), RET_OK);
ASSERT_EQ(dlist_size(s), 3);
ASSERT_EQ(dlist_prepend(s, TO_POINTER(4)), RET_OK);
ASSERT_EQ(dlist_size(s), 4);
ASSERT_EQ(dlist_prepend(s, TO_POINTER(5)), RET_OK);
ASSERT_EQ(dlist_size(s), 5);
dlist_deinit(s);
}
TEST(DList, find) {
dlist_t dlist;
dlist_t* s = &dlist;

View File

@ -0,0 +1,121 @@
#include "gtest/gtest.h"
#include "tkc/mem_allocator_fixed_block.h"
TEST(MemAllocatorFixedBlock, base) {
int* user = NULL;
ptrdiff_t diff = 0;
mem_allocator_t* allocator = mem_allocator_fixed_block_create(sizeof(int), 0);
ASSERT_EQ(allocator != NULL, TRUE);
user = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator),
__FUNCTION__, __LINE__);
ASSERT_EQ(user != NULL, TRUE);
*user = 1;
ASSERT_EQ(*user, 1);
mem_allocator_free(allocator, user);
ASSERT_EQ(mem_allocator_destroy(allocator), RET_OK);
}
TEST(MemAllocatorFixedBlock, multiple_alloc) {
int *p1 = NULL, *p2 = NULL, *p3 = NULL;
ptrdiff_t diff = 0;
mem_allocator_t* allocator = mem_allocator_fixed_block_create(sizeof(int), 2);
ASSERT_EQ(allocator != NULL, TRUE);
// 测试初始容量
p1 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
p2 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
ASSERT_EQ(p1 != NULL && p2 != NULL, TRUE);
*p1 = 1;
*p2 = 2;
// 测试扩容
p3 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
ASSERT_EQ(p3 != NULL, TRUE);
*p3 = 3;
mem_allocator_dump(allocator);
ASSERT_EQ(*p1, 1);
ASSERT_EQ(*p2, 2);
ASSERT_EQ(*p3, 3);
mem_allocator_free(allocator, p2);
mem_allocator_free(allocator, p1);
mem_allocator_free(allocator, p3);
ASSERT_EQ(mem_allocator_destroy(allocator), RET_OK);
}
TEST(MemAllocatorFixedBlock, reuse) {
int *p1 = NULL, *p2 = NULL;
mem_allocator_t* allocator = mem_allocator_fixed_block_create(sizeof(int), 2);
p1 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
mem_allocator_free(allocator, p1);
// 测试内存重用
p2 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
ASSERT_EQ(p1, p2); // 指针应该相同
ASSERT_EQ(mem_allocator_destroy(allocator), RET_OK);
}
TEST(MemAllocatorFixedBlock, invalid_free) {
int dummy = 0;
int *p1 = NULL, *p2 = NULL, *p3 = NULL;
ptrdiff_t diff = 0;
mem_allocator_t* allocator = mem_allocator_fixed_block_create(sizeof(int), 2);
// 测试无效指针释放
ASSERT_EQ(mem_allocator_realloc(allocator, &dummy, mem_allocator_fixed_block_size(allocator),
__FUNCTION__, __LINE__) == NULL,
TRUE);
p1 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
p2 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
p3 = (int*)mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
// 测试无效指针释放
ASSERT_EQ(mem_allocator_realloc(allocator, &dummy, mem_allocator_fixed_block_size(allocator),
__FUNCTION__, __LINE__) == NULL,
TRUE);
ASSERT_EQ(mem_allocator_realloc(allocator, (uint8_t*)(p1) + 1,
mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__) == NULL,
TRUE);
ASSERT_EQ(mem_allocator_destroy(allocator), RET_OK);
}
TEST(MemAllocatorFixedBlock, realloc) {
/* size = 16 为了测试快速地址对齐检查 */
mem_allocator_t* allocator = mem_allocator_fixed_block_create(16, 2);
void* p1 = mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
void* p2 = mem_allocator_alloc(allocator, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
p2 = mem_allocator_realloc(allocator, p2, mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__);
ASSERT_EQ(mem_allocator_realloc(allocator, (uint8_t*)(p1) + 1,
mem_allocator_fixed_block_size(allocator), __FUNCTION__,
__LINE__) == NULL,
TRUE);
ASSERT_EQ(mem_allocator_destroy(allocator), RET_OK);
}

View File

@ -1,5 +1,6 @@
#include "tkc/utils.h"
#include "tkc/slist.h"
#include "tkc/mem_allocator_fixed_block.h"
#include "gtest/gtest.h"
#include <string>
@ -50,6 +51,39 @@ TEST(SList, basic) {
slist_deinit(s);
}
TEST(SList, node_allocator) {
slist_t slist;
slist_t* s = &slist;
slist_init(s, NULL, NULL);
ASSERT_EQ(slist_set_node_allocator(s, mem_allocator_fixed_block_create(sizeof(slist_node_t), 2)),
RET_OK);
ASSERT_EQ(slist_size(s), 0);
ASSERT_EQ(slist_append(s, TO_POINTER(1)), RET_OK);
ASSERT_EQ(slist_size(s), 1);
ASSERT_EQ(slist_append(s, TO_POINTER(2)), RET_OK);
ASSERT_EQ(slist_size(s), 2);
ASSERT_EQ(slist_append(s, TO_POINTER(3)), RET_OK);
ASSERT_EQ(slist_size(s), 3);
ASSERT_EQ(slist_prepend(s, TO_POINTER(4)), RET_OK);
ASSERT_EQ(slist_size(s), 4);
ASSERT_EQ(slist_prepend(s, TO_POINTER(5)), RET_OK);
ASSERT_EQ(slist_size(s), 5);
slist_deinit(s);
}
TEST(SList, find) {
slist_t slist;
slist_t* s = &slist;

View File

@ -1,7 +1,7 @@
#include "gtest/gtest.h"
#include "tkc/tree.h"
#include "tkc/utils.h"
#include "tkc/fs.h"
#include "tkc/mem_allocator_fixed_block.h"
TEST(Tree, create) {
tree_t* tree = tree_create(NULL, NULL);
@ -17,26 +17,26 @@ TEST(Tree, insert_child) {
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(0, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(0));
node = tree_create_node(&tree, tk_pointer_from_int(0));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(0, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_set_root(&tree, node));
ASSERT_EQ(tree.root == node, TRUE);
ASSERT_EQ(1, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(1));
node = tree_create_node(&tree, tk_pointer_from_int(1));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(1, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_append_child_node(&tree, NULL, node));
ASSERT_EQ(2, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(2));
node = tree_create_node(&tree, tk_pointer_from_int(2));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(2, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_prepend_child_node(&tree, NULL, node));
ASSERT_EQ(3, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(3));
node = tree_create_node(&tree, tk_pointer_from_int(3));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(3, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_insert_child_node(&tree, NULL, 1, node));
@ -52,28 +52,28 @@ TEST(Tree, insert_sibling) {
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(0, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(0));
node = tree_create_node(&tree, tk_pointer_from_int(0));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(RET_OK, tree_set_root(&tree, node));
ASSERT_EQ(tree.root != NULL, TRUE);
insert_pos = tree_node_create(tk_pointer_from_int(1));
insert_pos = tree_create_node(&tree, tk_pointer_from_int(1));
ASSERT_EQ(insert_pos != NULL, TRUE);
ASSERT_EQ(RET_OK, tree_append_child_node(&tree, NULL, insert_pos));
node = tree_node_create(tk_pointer_from_int(2));
node = tree_create_node(&tree, tk_pointer_from_int(2));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(2, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_append_sibling_node(&tree, insert_pos, node));
ASSERT_EQ(3, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(3));
node = tree_create_node(&tree, tk_pointer_from_int(3));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(3, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_prepend_sibling_node(&tree, insert_pos, node));
ASSERT_EQ(4, tree_size(&tree, NULL));
node = tree_node_create(tk_pointer_from_int(4));
node = tree_create_node(&tree, tk_pointer_from_int(4));
ASSERT_EQ(node != NULL, TRUE);
ASSERT_EQ(4, tk_pointer_to_int(node->data));
ASSERT_EQ(RET_OK, tree_insert_sibling_node(&tree, insert_pos, 1, node));
@ -106,52 +106,52 @@ static ret_t build_tree_for_test(tree_t* tree) {
*/
// 创建根节点
tree_node_t* root = tree_node_create(tk_pointer_from_int(0));
tree_node_t* root = tree_create_node(tree, tk_pointer_from_int(0));
tree_set_root(tree, root);
// 第一层子节点(使用节点操作接口)
tree_node_t* node1 = tree_node_create(tk_pointer_from_int(1));
tree_node_t* node1 = tree_create_node(tree, tk_pointer_from_int(1));
tree_prepend_child_node(tree, NULL, node1);
tree_node_t* node3 = tree_node_create(tk_pointer_from_int(3));
tree_node_t* node3 = tree_create_node(tree, tk_pointer_from_int(3));
tree_append_child_node(tree, NULL, node3);
tree_node_t* node2 = tree_node_create(tk_pointer_from_int(2));
tree_node_t* node2 = tree_create_node(tree, tk_pointer_from_int(2));
tree_insert_child_node(tree, NULL, 1, node2);
// 第二层子节点
tree_node_t* node11 = tree_node_create(tk_pointer_from_int(11));
tree_node_t* node11 = tree_create_node(tree, tk_pointer_from_int(11));
tree_prepend_child_node(tree, node1, node11);
tree_node_t* node12 = tree_node_create(tk_pointer_from_int(12));
tree_node_t* node12 = tree_create_node(tree, tk_pointer_from_int(12));
tree_append_child_node(tree, node1, node12);
tree_node_t* node21 = tree_node_create(tk_pointer_from_int(21));
tree_node_t* node21 = tree_create_node(tree, tk_pointer_from_int(21));
tree_append_child_node(tree, node2, node21);
tree_node_t* node22 = tree_node_create(tk_pointer_from_int(22));
tree_node_t* node22 = tree_create_node(tree, tk_pointer_from_int(22));
tree_append_sibling_node(tree, node21, node22);
tree_node_t* node23 = tree_node_create(tk_pointer_from_int(23));
tree_node_t* node23 = tree_create_node(tree, tk_pointer_from_int(23));
tree_append_sibling_node(tree, node22, node23);
tree_node_t* node31 = tree_node_create(tk_pointer_from_int(31));
tree_node_t* node31 = tree_create_node(tree, tk_pointer_from_int(31));
tree_append_child_node(tree, node3, node31);
tree_node_t* node32 = tree_node_create(tk_pointer_from_int(32));
tree_node_t* node32 = tree_create_node(tree, tk_pointer_from_int(32));
tree_append_child_node(tree, node3, node32);
// 第三层子节点
tree_append_child_node(tree, node12, tree_node_create(tk_pointer_from_int(121)));
tree_append_child_node(tree, node12, tree_node_create(tk_pointer_from_int(122)));
tree_append_child_node(tree, node12, tree_node_create(tk_pointer_from_int(123)));
tree_append_child_node(tree, node12, tree_create_node(tree, tk_pointer_from_int(121)));
tree_append_child_node(tree, node12, tree_create_node(tree, tk_pointer_from_int(122)));
tree_append_child_node(tree, node12, tree_create_node(tree, tk_pointer_from_int(123)));
tree_node_t* node221 = tree_node_create(tk_pointer_from_int(221));
tree_node_t* node221 = tree_create_node(tree, tk_pointer_from_int(221));
tree_append_child_node(tree, node22, node221);
// 第四层子节点
tree_append_child_node(tree, node221, tree_node_create(tk_pointer_from_int(2211)));
tree_append_child_node(tree, node221, tree_node_create(tk_pointer_from_int(2212)));
tree_append_child_node(tree, node221, tree_create_node(tree, tk_pointer_from_int(2211)));
tree_append_child_node(tree, node221, tree_create_node(tree, tk_pointer_from_int(2212)));
return RET_OK;
}
@ -433,3 +433,16 @@ TEST(Tree, to_string) {
tree_deinit(&tree);
str_reset(&str);
}
TEST(Tree, node_allocator) {
tree_t tree;
ASSERT_EQ(tree_init(&tree, NULL, NULL), RET_OK);
ASSERT_EQ(
tree_set_node_allocator(&tree, mem_allocator_fixed_block_create(sizeof(tree_node_t), 5)),
RET_OK);
ASSERT_EQ(build_tree_for_test(&tree), RET_OK);
mem_allocator_dump(tree.node_allocator);
tree_deinit(&tree);
}