一个简单的循环缓冲区实现
com_def.h
#ifndef __COM_DEF_H__
#define __COM_DEF_H__
#include <stdint.h>
#include <stdbool.h>
typedef enum _StateFlag
{
Off = false, On = true,
Low = false, High = true,
No = false, Yes = true,
Invalid = false, Valid = true,
Reset = false, Set = true,
Nok = false, Ok = true,
}StateFlag;
#define RET_IF(x) if(x) return
#define RETX_IF(x, y) if(x) return (y)
#define FLAG_SET(set, flag) if(set) (flag) = Set
#define FLAG_RESET(reset, flag) if(reset) (flag) = Reset
#define FLAG_SET_REST(condition, flag) if(condition) (flag) = Set; else (flag) = Reset
#define FLAG_SET_RESET_EX(set, reset, flag) if(set) (flag) = Set; else if(reset) (flag) = Reset
#define VALUE_SET(condition, dst, value) if(condition) (dst) = (value)
#endif
circular_buffer.h
#ifndef __CIRCULAR_BUFFER_H__
#define __CIRCULAR_BUFFER_H__
#include "com_def.h"
#define CBUF_ENTITY_CNT 4
typedef struct _CircularBuffer
{
uint8_t* buf;//数据缓冲区buf由外部提供
uint8_t itemSize;//需要指定item的size
uint8_t itemCntMax;//缓冲区可容纳的最大的item的counts
}CircularBuffer;
void CircularBufferCreate(const CircularBuffer* cfg, uint8_t bufId);
StateFlag CircularBufferPop(void* item, uint8_t bufId);
void CircularBufferPush(void* item, uint8_t bufId);
#endif //__CIRCULAR_BUFFER_H__
circular_buffer.c
#include "circular_buffer.h"
typedef struct _CircularBufImpl
{
uint8_t* buf;
uint8_t itemSize;
uint8_t itemCntMax;
uint8_t head;
uint8_t tail;
StateFlag full;
}CircularBufImpl;
#define COPY_ITEM(src, dst) do{ \
for(uint8_t i = 0; i < p->itemSize; ++i){\
*((uint8_t*)(dst) + i) = *((uint8_t*)(src) + i);\
} \
}while(0)
static CircularBufImpl cBufObjs[CBUF_ENTITY_CNT] = { 0 };
void CircularBufferCreate(const CircularBuffer* cfg, uint8_t bufId)
{
RET_IF(!cfg || !cfg->buf || !cfg->itemSize || !cfg->itemCntMax || bufId >= CBUF_ENTITY_CNT);
cBufObjs[bufId].buf = cfg->buf;
cBufObjs[bufId].itemSize = cfg->itemSize;
cBufObjs[bufId].itemCntMax = cfg->itemCntMax;
cBufObjs[bufId].head = 0;
cBufObjs[bufId].tail = 0;
cBufObjs[bufId].full = No;
}
void CircularBufferPush(void* item, uint8_t bufId)
{
RET_IF(!item || bufId >= CBUF_ENTITY_CNT);
CircularBufImpl* p = &cBufObjs[bufId];
uint8_t* addr = p->buf + p->tail * p->itemSize;
COPY_ITEM(item, addr);
++p->tail;
p->tail %= p->itemCntMax;
VALUE_SET(p->tail == p->head, p->full, Yes);
if(p->full && p->tail > p->head){
++p->head;
p->head %= p->itemCntMax;
}
}
StateFlag CircularBufferPop(void* item, uint8_t bufId)
{
RETX_IF(!item || bufId > CBUF_ENTITY_CNT, Nok);
CircularBufImpl* p = &cBufObjs[bufId];
RETX_IF(p->full == No && p->head == p->tail, Nok);//empty
uint8_t* addr = p->buf + p->head * p->itemSize;
COPY_ITEM(addr, item);
++p->head;
p->head %= p->itemCntMax;
VALUE_SET(p->head > p->tail, p->full, No);
return Ok;
}
测试:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "circular_buffer.h"
typedef struct _Test
{
uint32_t p;
uint16_t b;
uint8_t a;
}Test;
#define TEST_CNT 5
static void PtBuf(Test* p)
{
for(int i = 0; i < TEST_CNT; ++i){
printf("(% 4d,% 4d,% 4d) ", p[i].p, p[i].b, p[i].a);
}
printf("\n");
}
int main(void)
{
Test buf[TEST_CNT] = { 0 };
Test t = { 4, 1, 2 };
Test m = { 0 };
CircularBuffer cfg = {
.buf = (uint8_t*)buf,
.itemSize = sizeof(Test),
.itemCntMax = TEST_CNT,
};
CircularBufferCreate(&cfg, 0);
if(CircularBufferPop(&m, 0)){
printf("(% 4d,% 4d,% 4d)\n",m.p, m.b, m.a);
}
for(uint8_t i = 0; i < 4; ++i){
CircularBufferPush(&t, 0);
PtBuf(buf);
t.p++;
}
for(uint8_t i = 0; i < 6; ++i){
if(CircularBufferPop(&m, 0)){
printf("(% 4d,% 4d,% 4d)\n", m.p, m.b, m.a);
}
}
}