ringbuff

 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;
// }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值