沉淀之log4c的stack
log4c实现了栈操作的一组接口,相关的接口都在头文件里面进行了声明,这里栈的元素为指针,也就是说栈里面放的元素都是指向一个个结构体变量再内存中的位置的指针;另外这个栈是一个动态增长的形式实现的。
对于头文件的解释也都以注释的形式写在了代码的注释里面,具体的头文件内容如下:
stack.h
#ifndef __sd_stack_h
#define __sd_stack_h
/**
* @file stack.h @ingroup sd
*
* @brief Generic stack object.
*
* @todo documentation
* @todo API homogeneity with sd_list and sd_hash
*/
#include <stddef.h>
#include "defs.h"
__SD_BEGIN_DECLS
//栈的结构体类型,具体的结构体定义在c文件中
typedef struct __sd_stack sd_stack_t;
//创建一个栈结构,参数是这个栈的容量
extern sd_stack_t* sd_stack_new(size_t max);
//删除一个栈结构,参数是栈的名字和释放接口
extern void sd_stack_delete(sd_stack_t* astack, void (*free_data_fn)(void *));
//获得栈中当前有多少元素,参数为要查看的栈
extern size_t sd_stack_get_nelem(const sd_stack_t* astack);
//清空栈,参数为待清空的栈和释放接口
extern void sd_stack_clear(sd_stack_t* astack, void (*free_data_fn)(void *));
//入栈操作,参数为栈和待入栈的数据指针
extern int sd_stack_push(sd_stack_t* astack, void *data);
//出栈操作,参数为栈,返回值为出栈的数据
extern void* sd_stack_pop(sd_stack_t* astack);
//获得参数传入的栈的第一个位置的元素
extern void* sd_stack_begin(sd_stack_t* astack);
//获取参数传入栈的下一个位置的元素内容
extern void* sd_stack_next(sd_stack_t* astack);
//获取参数传入栈的最后一个位置的元素内容
extern void* sd_stack_end(sd_stack_t* astack);
//获得参数传入栈的栈顶元素
extern void* sd_stack_peek(sd_stack_t* astack);
__SD_END_DECLS
#endif
里面同样有defs的一套东西,之前error里已经说过了。
接下来就是stack的实现:
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include "malloc.h"
#include "stack.h"
#define SD_STACK_INIT_SIZE 32
struct __sd_stack {
size_t max; //栈内元素最大个数,即栈容量
size_t sp; //当前栈顶
size_t size; //当前栈中设置的数量
size_t iter; //栈内元素偏移指针
void **array;
};
以上是头文件包含和栈的结构体定义。具体都在里面进行了注释
sd_stack_new:
sd_stack_t* sd_stack_new(size_t max)
{
sd_stack_t* this;
//申请一个栈,大小为栈的结构体
this = sd_calloc(1, sizeof(sd_stack_t));
//栈的容量、元素大小、当前栈顶位置
this->max = max == 0 ? INT_MAX : max;
this->size = SD_STACK_INIT_SIZE;
this->sp = 0;
//申请参数传递的数量个栈元素,申请内存类型为void *
this->array = sd_calloc(this->size, sizeof(*this->array));
return this;
}
sd_stack_delete:
void sd_stack_delete(sd_stack_t* this, void (*free_data_fn)(void *))
{
//参数有效性判断
if (!this)
return;
//调用清除接口
sd_stack_clear(this, free_data_fn);
//释放内存
free(this->array);
free(this);
}
调用的清除内存接口实现如下:
sd_stack_clear:
void sd_stack_clear(sd_stack_t* this, void (*free_data_fn)(void *))
{
if (!this)
return;
//逐个释放栈元素所指向的内存
if (free_data_fn) {
while (this->sp > 0) {
free_data_fn(this->array[--(this->sp)]);
}
}
}
sd_stack_get_nelem:
size_t sd_stack_get_nelem(const sd_stack_t* this)
{
return this ? this->sp : -1;
}
sd_stack_begin:
void* sd_stack_begin(sd_stack_t* this)
{
if (!this)
return NULL;
//元素数组偏移设置为0后进行返回
this->iter = 0;
return this->array[this->iter];
}
sd_stack_next:
void* sd_stack_next(sd_stack_t* this)
{
//判断栈有效,并且当前iter偏移不高于sp返回iter的元素值
if (this && this->iter < this->sp)
return this->array[this->iter++];
return NULL;
}
sd_stack_end:
void* sd_stack_end(sd_stack_t* this)
{
return sd_stack_peek(this);
}
里面借用的sd_stack_peek的接口,实现如下
sd_stack_peek:
void* sd_stack_peek(sd_stack_t* this)
{
if (!this || !this->sp)
return NULL;
//返回栈顶元素
return this->array[this->sp - 1];
}
sd_stack_push:
int sd_stack_push(sd_stack_t* this, void *data)
{
if (this == NULL)
return -1;
//当前入栈个数已经达到了设置的数量,扩充
if (this->sp == this->size)
{
size_t new_size;
//是否达到了最大数量
if (this->size == this->max)
return -1;
//设置为最大数量或者为当前数量的二倍
if (this->size * 2 > this->max) {
new_size = this->max;
} else {
new_size = this->size * 2;
}
//重新进行元素栈内存的分配,realloc呵呵
this->size = new_size;
this->array = sd_realloc(this->array, sizeof(*this->array) * this->size);
}
//正确性验证
assert(this->sp <= this->size);
//入栈
this->array[this->sp++] = data;
return 0;
}
sd_stack_pop:
void* sd_stack_pop(sd_stack_t* this)
{
if (this == NULL || this->sp == 0)
return NULL;
//判断栈不为空且栈中数量可以进行缩减。其实不建议这么搞
if (this->size >= SD_STACK_INIT_SIZE * 4 && this->sp < this->size / 4) {
size_t new_size = this->size / 2;
this->size = new_size;
this->array = sd_realloc(this->array, sizeof(*this->array) * this->size);
}
//验证数据并进行出栈操作
assert(this->sp > 0 && this->sp <= this->size);
return this->array[--(this->sp)];
}
比较简单明了的实现。