mirror of
https://github.com/zlgopen/awtk.git
synced 2025-05-08 11:33:48 +08:00
Merge branch 'master' of https://github.com/zlgopen/awtk
This commit is contained in:
commit
6d0ff6f14b
@ -1,5 +1,9 @@
|
||||
# 最新动态
|
||||
|
||||
2025/04/15
|
||||
* 增加mem_allocator_fixed_block,dlist/slist/tree使用该内存分配器管理内存(感谢兆坤提供补丁)。
|
||||
* 完善mem_allocator_fixed_block(感谢兆坤提供补丁)。
|
||||
|
||||
2025/04/14
|
||||
* conf_io 支持 YAML格式。
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
* 清除双向链表中的元素。
|
||||
|
587
src/tkc/mem_allocator_fixed_block.c
Normal file
587
src/tkc/mem_allocator_fixed_block.c
Normal 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;
|
||||
}
|
68
src/tkc/mem_allocator_fixed_block.h
Normal file
68
src/tkc/mem_allocator_fixed_block.h
Normal 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*/
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
* 清除单向链表中的元素。
|
||||
|
102
src/tkc/tree.c
102
src/tkc/tree.c
@ -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) {
|
||||
|
@ -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
|
||||
* 清除树结构中的元素。
|
||||
|
@ -51,6 +51,7 @@
|
||||
#define TK_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
@ -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;
|
||||
|
121
tests/mem_allocator_fixed_block_test.cc
Normal file
121
tests/mem_allocator_fixed_block_test.cc
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user