451 lines
12 KiB
C
451 lines
12 KiB
C
/**
|
||
* @file sqqueue.c
|
||
* @author xxx
|
||
* @date 2023-06-25 13:07:02
|
||
* @brief 提供循环队列功能
|
||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||
*/
|
||
|
||
#include "../inc/sqqueue.h"
|
||
#include "../inc/osel_arch.h"
|
||
|
||
#define SQQ_ENTRY_SIZE (queue_ptr->entry_size)
|
||
#define SQQ_LEN (queue_ptr->sqq_len)
|
||
|
||
/**
|
||
* @brief 初始化队列控制结构体
|
||
* @param p_this 队列控制结构体的指针
|
||
* @param entry_size 队列中每个元素的大小
|
||
* @param sqq_len 队列的最大长度
|
||
* @return {BOOL} 初始化成功返回true,否则返回false
|
||
* @note 此函数用于初始化队列控制结构体,确保队列有足够的空间存储元素
|
||
*/
|
||
static BOOL sqqueue_init(sqqueue_ctrl_t *const p_this,
|
||
uint8_t entry_size,
|
||
uint16_t sqq_len)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
sqqueue_t *queue_ptr = &(p_this->sqq);
|
||
|
||
if (queue_ptr != NULL)
|
||
{
|
||
queue_ptr->entry_size = entry_size;
|
||
queue_ptr->sqq_len = sqq_len + 1;
|
||
if (queue_ptr->base != NULL)
|
||
{
|
||
osel_mem_free(queue_ptr->base);
|
||
queue_ptr->base = NULL;
|
||
}
|
||
|
||
queue_ptr->base = (uint8_t *)osel_mem_alloc(SQQ_LEN * SQQ_ENTRY_SIZE);
|
||
if (queue_ptr->base == NULL)
|
||
{
|
||
return FALSE;
|
||
}
|
||
queue_ptr->front = 0;
|
||
queue_ptr->rear = 0;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 销毁顺序队列
|
||
*
|
||
* 销毁给定的顺序队列,释放其占用的内存空间。
|
||
*
|
||
* @param p_this 顺序队列控制块指针
|
||
*/
|
||
void sqqueue_dinit(sqqueue_ctrl_t *const p_this)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
sqqueue_t *queue_ptr = &(p_this->sqq);
|
||
|
||
if (queue_ptr != NULL)
|
||
{
|
||
if (queue_ptr->base != NULL)
|
||
{
|
||
osel_mem_free(queue_ptr->base);
|
||
queue_ptr->base = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取队列的长度
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @return {uint16_t} 队列的长度
|
||
* @note 此函数用于获取队列的长度,包括队列中元素的数量和最大长度
|
||
*/
|
||
static uint16_t sqqueue_length(const sqqueue_ctrl_t *const p_this)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
const sqqueue_t *const queue_ptr = &(p_this->sqq);
|
||
uint16_t length = 0;
|
||
if (p_this != NULL)
|
||
{
|
||
length = (queue_ptr->rear + SQQ_LEN - queue_ptr->front);
|
||
|
||
if (length >= SQQ_LEN)
|
||
{
|
||
length -= SQQ_LEN;
|
||
}
|
||
}
|
||
|
||
return length;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取队列的长度
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @return {uint16_t} 队列的长度
|
||
* @note 此函数用于获取队列的长度,包括队列中元素的数量和最大长度
|
||
*/
|
||
static BOOL sqqueue_full(const sqqueue_ctrl_t *const p_this)
|
||
{
|
||
uint16_t rear = 0;
|
||
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
|
||
if (p_this != NULL)
|
||
{
|
||
const sqqueue_t *const queue_ptr = &(p_this->sqq);
|
||
rear = queue_ptr->rear + 1;
|
||
if (rear >= SQQ_LEN)
|
||
{
|
||
rear -= SQQ_LEN;
|
||
}
|
||
if (rear == queue_ptr->front)
|
||
{
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 将元素添加到队列中
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @param {void} *e 要添加的元素
|
||
* @return {BOOL} 添加成功返回true,否则返回false
|
||
* @note 此函数用于将元素添加到队列中,确保队列有足够的空间存储元素
|
||
*/
|
||
static BOOL enter_sqqueue(sqqueue_ctrl_t *const p_this, const void *const e)
|
||
{
|
||
uint16_t rear = 0;
|
||
sqqueue_t *queue_ptr = &(p_this->sqq);
|
||
|
||
if ((p_this != NULL) && (e != NULL))
|
||
{
|
||
rear = queue_ptr->rear + 1;
|
||
if (rear >= SQQ_LEN)
|
||
{
|
||
rear -= SQQ_LEN;
|
||
}
|
||
|
||
if (rear == queue_ptr->front)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
/* 根据e的长度进行内存拷贝 */
|
||
DBG_ASSERT(queue_ptr->rear != SQQ_LEN __DBG_LINE);
|
||
osel_memcpy(queue_ptr->base + (queue_ptr->rear * SQQ_ENTRY_SIZE),
|
||
e,
|
||
SQQ_ENTRY_SIZE);
|
||
queue_ptr->rear = rear;
|
||
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 将字符串添加到队列中
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @param {const void} *string 要添加的字符串
|
||
* @param {uint16_t} cnt 要添加的字符串的长度
|
||
* @return {BOOL} 添加成功返回true,否则返回false
|
||
* @note 此函数用于将字符串添加到队列中,确保队列有足够的空间存储字符串
|
||
*/
|
||
static BOOL string_enter_sqqueue(sqqueue_ctrl_t *const p_this,
|
||
const void *const string,
|
||
uint16_t cnt)
|
||
{
|
||
uint16_t rear = 0;
|
||
uint16_t length = 0;
|
||
sqqueue_t *queue_ptr = &(p_this->sqq);
|
||
|
||
if ((p_this != NULL) && (string != NULL))
|
||
{
|
||
/* 判断是否超出队列长度 */
|
||
length = sqqueue_length(p_this); // 已有元素个数
|
||
if (length == 0xFFFF)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
length = (SQQ_LEN - 1) - length; // 可写入个数
|
||
if (length < cnt)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
rear = queue_ptr->rear + cnt;
|
||
if (rear >= SQQ_LEN)
|
||
{
|
||
rear -= SQQ_LEN;
|
||
uint8_t half = SQQ_LEN - queue_ptr->rear;
|
||
osel_memcpy(queue_ptr->base + (queue_ptr->rear * SQQ_ENTRY_SIZE),
|
||
string, half * SQQ_ENTRY_SIZE);
|
||
uint8_t *half_p = (uint8_t *)string;
|
||
osel_memcpy(queue_ptr->base, (uint8_t *)&half_p[half], rear * SQQ_ENTRY_SIZE);
|
||
}
|
||
else
|
||
{
|
||
osel_memcpy(queue_ptr->base + (queue_ptr->rear * SQQ_ENTRY_SIZE),
|
||
string, SQQ_ENTRY_SIZE * cnt);
|
||
}
|
||
|
||
queue_ptr->rear = rear;
|
||
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 从队列中删除元素
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @return {void *} 删除的元素,如果队列为空则返回NULL
|
||
* @note 此函数用于从队列中删除元素,确保队列中有足够的空间存储元素
|
||
*/
|
||
static void *delete_sqqueue(sqqueue_ctrl_t *const p_this)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
uint16_t front = 0;
|
||
|
||
sqqueue_t *queue_ptr = NULL;
|
||
|
||
if (p_this != NULL)
|
||
{
|
||
void *p_elem = NULL;
|
||
queue_ptr = &(p_this->sqq);
|
||
if (queue_ptr->rear == queue_ptr->front)
|
||
{
|
||
return NULL;
|
||
}
|
||
/* 根据元素类型大小计算出偏移量,得到该元素首地址 */
|
||
p_elem = (void *)((queue_ptr->base) + (queue_ptr->front * SQQ_ENTRY_SIZE));
|
||
front = queue_ptr->front + 1;
|
||
if (front >= SQQ_LEN)
|
||
{
|
||
front -= SQQ_LEN;
|
||
}
|
||
queue_ptr->front = front;
|
||
|
||
return p_elem;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/**
|
||
* @brief 撤销队列中的一个元素
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @return {*} 返回被撤销的元素,如果队列为空则返回NULL
|
||
* @note
|
||
*/
|
||
static void *revoke_sqqueue(sqqueue_ctrl_t *const p_this)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
uint16_t rear = 0;
|
||
sqqueue_t *queue_ptr = NULL;
|
||
|
||
if (p_this != NULL)
|
||
{
|
||
void *p_elem = NULL;
|
||
|
||
queue_ptr = &(p_this->sqq);
|
||
if (queue_ptr->rear == queue_ptr->front)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
rear = queue_ptr->rear;
|
||
if (rear == 0)
|
||
{
|
||
rear = SQQ_LEN - 1;
|
||
}
|
||
else
|
||
{
|
||
rear--;
|
||
}
|
||
queue_ptr->rear = rear;
|
||
/* 根据元素类型大小计算出偏移量,得到该元素首地址*/
|
||
p_elem = (void *)((queue_ptr->base) + (queue_ptr->rear * SQQ_ENTRY_SIZE));
|
||
|
||
return p_elem;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/**
|
||
* @brief 清空队列
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @return {void}
|
||
* @note
|
||
*/
|
||
static void clear_sqq(sqqueue_ctrl_t *const p_this)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
|
||
sqqueue_t *queue_ptr = &(p_this->sqq);
|
||
if (p_this != NULL)
|
||
{
|
||
queue_ptr->front = 0;
|
||
queue_ptr->rear = 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 遍历队列
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @param {void (*)(const void *e)} vi 遍历函数,参数为队列中的一个元素
|
||
* @return {void}
|
||
* @note
|
||
*/
|
||
static void traverse(sqqueue_ctrl_t *const p_this, void (*vi)(const void *e))
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
sqqueue_t *queue_ptr = NULL;
|
||
uint16_t i = 0;
|
||
|
||
if (p_this != NULL)
|
||
{
|
||
queue_ptr = &(p_this->sqq);
|
||
|
||
if (queue_ptr->rear == queue_ptr->front)
|
||
{
|
||
return;
|
||
}
|
||
|
||
i = queue_ptr->front;
|
||
while (i != queue_ptr->rear)
|
||
{
|
||
vi((void *)((queue_ptr->base) + (i * SQQ_ENTRY_SIZE)));
|
||
if (++i >= SQQ_LEN)
|
||
{
|
||
i = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 从队列中删除一个元素
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @param {uint16_t} offset_to_front 要删除的元素在队列中的偏移量,从队头开始
|
||
* @return {void}
|
||
* @note
|
||
*/
|
||
static void qremove(sqqueue_ctrl_t *const p_this, uint16_t offset_to_front)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
sqqueue_t *queue_ptr = NULL;
|
||
uint16_t i = 0;
|
||
|
||
if (p_this != NULL)
|
||
{
|
||
queue_ptr = &(p_this->sqq);
|
||
DBG_ASSERT(offset_to_front < SQQ_LEN __DBG_LINE);
|
||
|
||
if (queue_ptr->rear == queue_ptr->front)
|
||
{
|
||
return;
|
||
}
|
||
|
||
uint16_t j = 0;
|
||
|
||
for (i = offset_to_front; i > 0; i--)
|
||
{
|
||
/* 定位待删除元素在队列中的位置 */
|
||
j = queue_ptr->front + i;
|
||
|
||
if (j >= SQQ_LEN)
|
||
{
|
||
j -= SQQ_LEN;
|
||
}
|
||
|
||
if (j == 0) // 在翻转位置特殊处理拷贝的源地址
|
||
{
|
||
osel_memcpy(queue_ptr->base + (0 * SQQ_ENTRY_SIZE),
|
||
queue_ptr->base + ((SQQ_LEN - 1) * SQQ_ENTRY_SIZE),
|
||
SQQ_ENTRY_SIZE);
|
||
}
|
||
else
|
||
{
|
||
osel_memcpy(queue_ptr->base + (j * SQQ_ENTRY_SIZE),
|
||
queue_ptr->base + ((j - 1) * SQQ_ENTRY_SIZE),
|
||
SQQ_ENTRY_SIZE);
|
||
}
|
||
}
|
||
|
||
/* 减少队列长度 */
|
||
uint16_t front = queue_ptr->front + 1;
|
||
if (front >= SQQ_LEN)
|
||
{
|
||
front -= SQQ_LEN;
|
||
}
|
||
|
||
queue_ptr->front = front;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化队列控制结构体
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @param {uint8_t} entry_size 队列中每个元素的类型大小
|
||
* @param {uint16_t} sqq_len 队列的最大长度
|
||
* @return {BOOL} 初始化成功返回true,否则返回false
|
||
* @note
|
||
*/
|
||
BOOL sqqueue_ctrl_init(sqqueue_ctrl_t *const p_this,
|
||
uint8_t entry_size,
|
||
uint16_t sqq_len)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
|
||
if (p_this != NULL)
|
||
{
|
||
if (sqqueue_init(p_this, entry_size, sqq_len) != FALSE)
|
||
{
|
||
p_this->enter = enter_sqqueue;
|
||
p_this->string_enter = string_enter_sqqueue;
|
||
p_this->del = delete_sqqueue;
|
||
p_this->revoke = revoke_sqqueue;
|
||
p_this->get_len = sqqueue_length;
|
||
p_this->full = sqqueue_full;
|
||
p_this->clear_sqq = clear_sqq;
|
||
p_this->traverse = traverse;
|
||
p_this->remove = qremove;
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 销毁队列控制结构体
|
||
* @param {sqqueue_ctrl_t} *p_this 队列控制结构体的指针
|
||
* @return {void}
|
||
* @note
|
||
*/
|
||
void sqqueue_ctrl_dinit(sqqueue_ctrl_t *const p_this)
|
||
{
|
||
DBG_ASSERT(p_this != NULL __DBG_LINE);
|
||
sqqueue_dinit(p_this);
|
||
}
|