简单实用的环形缓冲器

简单实用的环形缓冲器

近来处理音频rawdata时需要一个FIFO的内存缓冲,自己写了一个基于环形结构的缓冲器。

  • 可处理任意大小输入,输出
  • 数据不够时可强制获取剩余数据
  • 代码极简
  • 线程安全

bug可能有,暂时没发现。

/*
* CREATE: tifentan
* DATE: 2017/8/23
* MODIFY: 2017/8/23
* NOTE:
*
*
*/

#ifndef __CIRCLEBUFFER_H__
#define __CIRCLEBUFFER_H__

#include <pthread.h>
class CircleBuffer
{
public:
    //请输入正数
    CircleBuffer(int len);
    ~CircleBuffer();

    void clear();

    //返回size
    int push_data(char* src,int len);

    //force 强行不够指定的len也拿出来,有多少拿多少
    //outlen 返回实际取出的大小
    //返回size, -1代表参数出错
    int pop_data(char* dst,int len,int* outlen,bool force = 0);

    int size();

public:

    pthread_mutex_t     data_mtx_;
    char                *p_buf_;

    int                 len_; //总长度
    int                 size_;  //有效长度

private:
    char*               ptr_w_;   //写指针
    char*               ptr_r_;   //读指针
    int                 diff_to_end_w_;
    int                 diff_to_end_r_;


};


#endif
/*
* CREATE: tifentan
* DATE: 2017/8/23
* MODIFY: 2017/8/23
* NOTE:
*
*
*/


#include "circlebuffer.h"
#include <android/log.h>
#define ANDROID_LOG_MSG(...) __android_log_print(ANDROID_LOG_INFO, __VA_ARGS__)

CircleBuffer::CircleBuffer(int len):
    len_(len),
    size_(0),
    diff_to_end_w_(len),
    diff_to_end_r_(len)
{
    pthread_mutex_init(&data_mtx_, NULL);
    p_buf_ = (char*)malloc(len);
    ptr_w_ = ptr_r_ = p_buf_;
}

CircleBuffer::~CircleBuffer()
{
    free(p_buf_);
}

void CircleBuffer::clear()
{
    pthread_mutex_lock(&data_mtx_);
    ptr_w_ = ptr_r_ = p_buf_;
    size_ = 0;
    diff_to_end_w_ = diff_to_end_r_ = len_;
    pthread_mutex_unlock(&data_mtx_);
}

int CircleBuffer::push_data(char * src, int len)
{
    if (src == 0 || len <= 0)
        return 0;

    int endsize = 0;
    int oversize = 0;
    int loopsize = 0;

    //当输入的src比总长度还长,保留src后面len_大小的内存,前面的丢弃
    if (len > len_) {
        src = src + len - len_;
        len = len_;
    }

    pthread_mutex_lock(&data_mtx_);

    oversize = len + size_ - len_;
    loopsize = len - diff_to_end_w_;
    //loop back
    if (loopsize > 0) {
        memcpy(ptr_w_, src, diff_to_end_w_);
        memcpy(p_buf_, src + diff_to_end_w_, loopsize);
        ptr_w_ = p_buf_ + loopsize;
        diff_to_end_w_ = len_ - loopsize;
    }
    else {
        memcpy(ptr_w_, src, len);
        if (loopsize == 0) { //刚好到p_buf_最后
            ptr_w_ = p_buf_;
            diff_to_end_w_ = len_;
        }else {
            ptr_w_ += len;
            diff_to_end_w_ -= len;
        }       
    }

    //满了,覆盖旧的
    if (oversize > 0) {
        size_ = len_;
        ptr_r_ = ptr_w_;
        diff_to_end_r_ = diff_to_end_w_;
        ANDROID_LOG_MSG("CircleBuffer", "buffer full!! overwrite[%d]", oversize);
    }else {
        size_ += len;
    }
    endsize = size_;
    pthread_mutex_unlock(&data_mtx_);

    return endsize;
}

int CircleBuffer::pop_data(char * dst, int len, int* outlen, bool force)
{
    if (dst == 0 || len <= 0 || outlen == 0) {
        return -1;
    }

    int endsize = 0;
    int loopsize = 0;

    pthread_mutex_lock(&data_mtx_);

    if (len > size_) {
        if (force) {
            len = size_;
        }else {
            *outlen = 0;
            goto END;
        }
    }

    *outlen = len;

    loopsize = len - diff_to_end_r_;

    //loop back
    if (loopsize > 0) {
        memcpy(dst, ptr_r_, diff_to_end_r_);
        memcpy(dst + diff_to_end_r_,p_buf_, loopsize);
        ptr_r_ = p_buf_ + loopsize;
        diff_to_end_r_ = len_ - loopsize;
    }
    else {
        memcpy(dst, ptr_r_, len);
        if (loopsize == 0) {
            ptr_r_ = p_buf_;
            diff_to_end_r_ = len_;
        }else {
            ptr_r_ += len;
            diff_to_end_r_ -= len;
        }
    }
    size_ -= len;


END:
    endsize = size_;
    pthread_mutex_unlock(&data_mtx_);

    return endsize;
}

int CircleBuffer::size()
{
    int endsize = 0;

    //多数平台支持int的原子操作下,不用锁应该没问题
    //pthread_mutex_lock(&data_mtx_);
    endsize = size_;
    //pthread_mutex_unlock(&data_mtx_);
    return endsize;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值