rb.h
/**********************************************************************
* Copyright (C) 2022 ()).inc All rights reserved.
*
* @file: rb.h
* @brief: 环形缓冲数组
* 1.写满了就没法继续写入
* 2.数组空间会自动扩展为2的幂次方
* 3.尽量使用宏的函数
* @author: GuoKai (Kane)
* @maintainer: 835430683@qq.com
* @versioin: 1.0
* @data: 2022-03-30
*
**********************************************************************/
#ifndef _RB_H_
#define _RB_H_
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#ifndef MIN
#define MIN(l, r) (((l) < (r)) ? (l) : (r))
#endif
typedef struct
{
uint8_t *buf;
uint32_t size;
uint32_t read_pos;
uint32_t wirte_pos;
} ringbuff_t;
//初始化函数
#define rb_init_8(r, sz) rb_init(r, sz)
#define rb_init_16(r, sz) rb_init(r, sz * 2)
#define rb_init_32(r, sz) rb_init(r, sz * 4)
//已经使用的空间,数据数量
#define rb_length_8(r) rb_length(r, 1)
#define rb_length_16(r) rb_length(r, 2)
#define rb_length_32(r) rb_length(r, 4)
//数组剩余空间,数据数量
#define rb_remain_8(r) rb_remain(r, 1)
#define rb_remain_16(r) rb_remain(r, 2)
#define rb_remain_32(r) rb_remain(r, 4)
//写数据,写多少个数据,不关心类型
#define rb_write_8(r, buf, sz) rb_write(r, buf, sz, 1)
#define rb_write_16(r, buf, sz) rb_write(r, buf, sz, 2)
#define rb_write_32(r, buf, sz) rb_write(r, buf, sz, 4)
//从ringbuff里面读取sz个数据到buf里面,不关心类型
#define rb_read_8(r, buf, sz) rb_read(r, buf, sz, 1)
#define rb_read_16(r, buf, sz) rb_read(r, buf, sz, 2)
#define rb_read_32(r, buf, sz) rb_read(r, buf, sz, 4)
static inline int32_t rb_isempty(ringbuff_t *r); //满
static inline int32_t rb_isfull(ringbuff_t *r); //空
static inline int32_t is_power_of_two(uint32_t sz);
static inline uint32_t roundup_power_of_two(uint32_t sz);
void rb_init(ringbuff_t *r, uint32_t sz);
void rb_clear(ringbuff_t *r);
void rb_free(ringbuff_t *r);
uint32_t rb_length(ringbuff_t *r, uint32_t byteNum);
uint32_t rb_remain(ringbuff_t *r, uint32_t byteNum);
uint32_t rb_write(ringbuff_t *r, void *buf, uint32_t sz, uint32_t byteNum);
uint32_t rb_read(ringbuff_t *r, void *buf, uint32_t sz, uint32_t byteNum);
#endif // header content
rb.c
/**********************************************************************
* Copyright (C) 2022 ().inc All rights reserved.
*
* @file: rb.c
* @brief: 环形缓冲数组
* 1.写满了就没法继续写入
* 2.数组空间会自动扩展为2的幂次方
* 3.尽量使用宏的函数
* @author: GuoKai (Kane)
* @maintainer: 835430683@qq.com
* @versioin: 1.0
* @data: 2022-03-30
*
**********************************************************************/
//核心在于size是不是2的幂
//一直加,直到溢出变为0
//ringbuff只解决了数据移动频繁问题,但是没有解决固定内存分配和生产消费速度问题
//多线程环境下
//1.一对一的情况下可以不加锁,但是需要加内存屏障,类似volatile
//2.多读多写的情况下,需要加锁,并且加内存屏障,如果是自旋锁可以不加
/**
* @name rb_isempty()
* @brief 判断数据是否满(无法一次性写入所有数据)
* @author Kane (835430683@qq.com)
* @return void
*/
static inline int32_t rb_isempty(ringbuff_t *r) //满
{
return r->read_pos == r->wirte_pos; //相等为1,即为true
}
/**
* @name rb_isfull()
* @brief 判断数据是否是空的
* @author Kane (835430683@qq.com)
* @return void
*/
static inline int32_t rb_isfull(ringbuff_t *r) //空
{
return r->size == r->wirte_pos - r->read_pos;
}
//是不是2的幂
// m%2=m&(n-1)
// m%n = m - n * (floor(m/n))
/**
* @name is_power_of_two()
* @brief 判断数组空间是不是2的幂
* @uint32_t sz:多少个数据,与类型无关
* @author Kane (835430683@qq.com)
* @return void
*/
static inline int32_t is_power_of_two(uint32_t sz)
{
if (sz < 2)
return sz;
return (sz & (sz - 1)) == 0;
}
// 2的幂 优化
/**
* @name roundup_power_of_two()
* @brief 将数组空间调整为2的幂的长度
* @uint32_t sz:多少个数据,与类型无关
* @author Kane (835430683@qq.com)
* @return void
*/
static inline uint32_t roundup_power_of_two(uint32_t sz)
{
if (sz < 2)
sz = 2;
// 5 -> 101 应该为8,即1000
//******右移3次后就没有1了,然后return 1左移3次
int32_t i = 0;
for (; sz != 0; ++i)
sz = sz >> 1;
return 1U << i;
}
/**
* @name rb_init()
* @brief 初始化ringbuff,默认是uint8_t类型,
* @author Kane (835430683@qq.com)
* @uint32_t sz:多少个数据,与类型无关
* @return void
*/
void rb_init(ringbuff_t *r, uint32_t sz)
{
r->buf = (uint8_t *)malloc(sz * sizeof(uint8_t));
if (!is_power_of_two(sz)) //如果不是2的幂,就重新计算size的大小
sz = roundup_power_of_two(sz);
r->size = sz;
r->read_pos = r->wirte_pos = 0;
}
/**
* @name rb_clear()
* @brief ringbuff清空数据
* @author Kane (835430683@qq.com)
* @return void
*/
void rb_clear(ringbuff_t *r)
{
if (r == NULL)
return;
memset(r->buf, 0, r->size);
r->read_pos = r->wirte_pos = 0;
}
/**
* @name rb_free()
* @brief 销毁ringbuff
* @author Kane (835430683@qq.com)
* @return void
*/
void rb_free(ringbuff_t *r)
{
if (r->buf != 0)
{
free(r->buf);
r->buf = 0;
}
r->read_pos = r->wirte_pos = r->size = 0;
}
/**
* @name rb_length()
* @brief 已经使用了多少空间(除每个数据占用的字节数)
* uint32_t byteNum:每个数据占用的字节数,由宏自动填充
* @author Kane (835430683@qq.com)
* @return void
*/
uint32_t rb_length(ringbuff_t *r, uint32_t byteNum)
{
if (r->wirte_pos >= r->read_pos)
return (r->wirte_pos - r->read_pos) / byteNum;
else
return (r->size - r->read_pos + r->wirte_pos) / byteNum;
}
/**
* @name rb_remain()
* @brief 已经使用了多少空间(除每个数据占用的字节数)
* uint32_t byteNum:每个数据占用的字节数,由宏自动填充
* @author Kane (835430683@qq.com)
* @return void
*/
uint32_t rb_remain(ringbuff_t *r, uint32_t byteNum)
{
if (r->wirte_pos > r->read_pos)
return (r->size - r->wirte_pos + r->read_pos) / byteNum;
else if (r->wirte_pos < r->read_pos)
return (r->read_pos - r->wirte_pos) / byteNum;
else //==0
return r->size;
}
/**
* @name rb_write()
* @brief 将buf里面sz个数据写到ringbuff里面
* ringbuff_t *r:句柄,内涵了rb,被写的
* void *buf:要写的数据
* uint32_t sz:写多少
* uint32_t byteNum:要写入几个数据,不关心数据的byte,由宏自动填充
* @author Kane (835430683@qq.com)
* @return void
*/
uint32_t rb_write(ringbuff_t *r, void *buf, uint32_t sz, uint32_t byteNum)
{
sz = sz * byteNum;
if (sz > rb_remain_8(r))
return 0;
#ifdef USER_MB
//内存屏障,类似 volatile
//确保开始移动buffer时read_pos
smp_mb(); // atomic_thread_fence()
#endif
//要写的长度和剩余的长度做比较
//剩余的长度采用位运算
uint32_t i = MIN(sz, r->size - (r->wirte_pos & (r->size - 1)));
if (sz < r->size - (r->wirte_pos & (r->size - 1))) //要写的长度小于剩余的长度,直接写
{
memcpy(r->buf + (r->wirte_pos & (r->size - 1)), buf, i);
r->wirte_pos += i;
}
else
{
uint8_t *retAddr = (uint8_t *)buf;
memcpy(r->buf + (r->wirte_pos & (r->size - 1)), &retAddr[0], i);
memcpy(r->buf, &retAddr[i], sz - i);
r->wirte_pos = sz - i; //写指针偏位
}
#ifdef USER_MB
//内存屏障,类似 volatile
//确保write_pos 不会被优化到前面
smp_mb(); // atomic_thread_fence()
#endif
return sz;
}
/**
* @name rb_read()
* @brief 将ringbuff里面sz个数据读取到buf里面
* ringbuff_t *r:句柄,内涵了rb,要读的
* void *buf:度到哪儿
* uint32_t sz:读多少个
* uint32_t byteNum:不关心数据的byte,由宏自动填充
* @author Kane (835430683@qq.com)
* @return void
*/
uint32_t rb_read(ringbuff_t *r, void *buf, uint32_t sz, uint32_t byteNum)
{
if (rb_isempty(r))
{
return 0;
}
sz = sz * byteNum;
sz = MIN(sz, rb_length_8(r));
#ifdef USER_MB
//内存屏障,类似 volatile
//确保开始移动buffer时read_pos
smp_mb(); // atomic_thread_fence()
#endif
uint32_t i = MIN(sz, r->size - (r->read_pos & (r->size - 1)));
if (sz < r->size - (r->read_pos & (r->size - 1))) //要读的数据不需要回车
{
memcpy(buf, r->buf + (r->read_pos & (r->size - 1)), i);
r->read_pos += sz;
}
else //需要回车读取
{
printf("\nenter\n");
uint8_t *retAddr = (uint8_t *)buf;
memcpy(retAddr, r->buf + (r->read_pos & (r->size - 1)), i);
memcpy(&retAddr[i], r->buf, sz - i);
r->read_pos = sz - i;
}
#ifdef USER_MB
//内存屏障,类似 volatile
//确保read_pos 不会被优化到前面
smp_mb(); // atomic_thread_fence()
#endif
return sz;
}
demo
// int main()
// {
// ringbuff_t rb = {0};
// rb_init_8(&rb, 7); //9被提升到8,17被提升到8,u8字节空间
// uint8_t buf[8] = {1, 2, 3, 4, 5, 6, 7, 0};
// uint8_t put1 = rb_write_8(&rb, (void *)buf, 7);
// printf("put1=%u, wr=%u, rd=%u, l=%u sy=%u\n", put1, rb.wirte_pos, rb.read_pos, rb_length_8(&rb), rb_remain_8(&rb));
// uint8_t buf2[1024] = {0};
// //应该先读length,再read的
// uint8_t get1 = rb_read_8(&rb, buf2, 6); //是否需要双倍读出
// printf("get1=%u, wr=%u, rd=%u, l=%u sy=%u\n", get1, rb.wirte_pos, rb.read_pos, rb_length_8(&rb), rb_remain_8(&rb));
// for (int i = 0; i < 8; ++i)
// {
// printf("%d ", buf2[i]);
// }
// printf("\n");
// printf("put-------------------\n");
// uint8_t put2 = rb_write_8(&rb, (void *)buf, 4);
// printf("put2=%u, wr=%u, rd=%u, l=%u sy=%u\n", put2, rb.wirte_pos, rb.read_pos, rb_length_8(&rb), rb_remain_8(&rb));
// printf("\nget-------------------\n");
// uint8_t buf3[1024] = {0};
// uint8_t get3 = rb_read_8(&rb, buf3, 5); //是否需要双倍读出
// printf("get3=%u, wr=%u, rd=%u, l=%u sy=%u\n", get3, rb.wirte_pos, rb.read_pos, rb_length_8(&rb), rb_remain_8(&rb));
// for (int i = 0; i < 5; ++i)
// {
// printf("%d ", buf3[i]);
// }
// return 0;
// }