首页 > 编程语言 >c++环形队列的简单实现

c++环形队列的简单实现

时间:2023-07-18 11:12:32浏览次数:45  
标签:count outBuf 队列 readPos c++ 环形 wantSize rSize uint32

环形队列可以通过维护count来间接维护tail和head指针的关系,简化程序,避免了直接使用tail和head指针,读写时head与tail回环时的比较处理, 判断队列元素长度时的复杂处理,如下为不基于count而是直接使用head和tail指针比较的环形队列的实现, 逻辑较为复杂

uint32_t CAudioRingBuffer::DataSizeLocked() const {
     // 获取队列元素个数
    if (m_isFull) {
        return capacity;
    } else {
        return (m_writePos + capacity - m_readPos) % capacity;
    }
}

void CAudioRingBuffer::setIsFull(bool reading) {
   // 更新队列是否已满的状态
    if (m_readPos == m_writePos) {
        m_isFull = !reading;
    } else {
        m_isFull = false;
    }
}


uint32_t CAudioRingBuffer::DoRead(char* outBuf, uint32_t wantSize) {
    if (DataSizeLocked() <= 0) {
        return 0;
    }

    if (m_writePos > m_readPos) {
       // write指针在read指针右侧
        uint32_t rSize = m_writePos - m_readPos;
        if (rSize >= wantSize) {
            //右的足够多,直接拷贝相关数据
            rSize = wantSize;
        } else {
            //右的不够多,数组不足,将尾部数据补0
            memset(outBuf + rSize, 0, wantSize - rSize);
        }
        memcpy(outBuf, &m_buf[m_readPos], rSize);

        m_readPos += rSize;

        setIsFull(true);
        return rSize;
    } else {
       //write_pos <= m_readPos,写指针回环了
              

        uint32_t headLen = 0;
        uint32_t tailLen = m_sizeTotal - m_readPos;  // 计算尾部区间有多少数据
        if (tailLen >= wantSize) {
            // 尾部区间数据足够,直接拷贝
            tailLen = wantSize;
            memcpy(outBuf, &m_buf[m_readPos], wantSize);
        } else {
          // 尾部区间不够的话,再算一下头部区间
            memcpy(outBuf, &m_buf[m_readPos], tailLen);

            headLen = m_writePos;
            if (m_writePos > (wantSize - tailLen)) {
                headLen = wantSize - tailLen;
            } else {
            // 头部区间还不够的话,再算一下需要补0的数
                memset(outBuf + tailLen + headLen, 0, wantSize - tailLen - headLen);
            }
            memcpy(outBuf + tailLen, &m_buf[0], headLen);
        }

        uint32_t rTotal = headLen + tailLen;
        m_readPos       = (m_readPos + rTotal) % capacity;

        setIsFull(true);
        return rTotal;
    }
}

基于count维护之后,此三个函数逻辑变得简化而直观

uint32_t CAudioRingBuffer::DataSizeLocked() const {
     // 获取队列元素个数
    return count;
}

void CAudioRingBuffer::setIsFull(bool reading) {
    // 更新队列是否已满的状态
    m_isFull = (count == capacity); 
}

uint32_t CAudioRingBuffer::DoRead(char* outBuf, uint32_t wantSize) {
    if (count <= 0) {
        return 0;
    }

   int outBufOffset = 0;
   int rSize, fillDataSize;
   rSize = fillDataSize = (wantSize >=  count ? count : wantSize);
   int newReadPos = (readPos + fillDataSize) % capacity;
   if ( fillDataSize > 0 && newReadPos <= m_readPos) {
       // 处理回环
       int rightDataSize = capacity - m_readPos;
       memcpy(outBuf, &m_buf[m_readPos], rightDataSize);
       m_readPos = 0;
       outBufOffset += rightDataSize;
       fillDataSize -= rightDataSize;
   }

   memcpy(outBuf + outBufOffset,  &m_buf[m_readPos], fillDataSize);
   outBufOffset += fillDataSize;
 
   // 数据不足填0补充
   int fiillZeroSize = wantSize - count;
   if(fiillZeroSize > 0){
      memset(outBuf + outBufOffset,  0, fiillZeroSize);
   }

   return rSize;
}

标签:count,outBuf,队列,readPos,c++,环形,wantSize,rSize,uint32
From: https://www.cnblogs.com/ishen/p/17562314.html

相关文章

  • C++14指北:花里胡哨的C++
    类型!在最经典的C++代码中,我们使用类似类型名变量名=表达式;的形式声明并初始化变量,例如intx=1;inty=x;在上面代码中,我们知道y理应与x的类型相同,但是在上面代码中,如果我们后来把x的类型修改为int64_t,而忘记对应地修改y的类型,则可能导致灾难性的后果。对......
  • beginnersbook C++ 教程·翻译完成 | ApacheCN
    译者:飞龙协议:CCBY-NC-SA4.0基础HelloWorld-第一个C++程序C++中的变量C++中的数据类型C++中的运算符控制语句C++中的if语句C++中的switch-case语句C++中的for循环C++中的while循环C++中的do-while循环C++中的continue语句C++中的break语句C++中的goto语句函数C++......
  • C/C++八大排序
    排序排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。按照难易程度排序,八大排序算法可以从简单到复杂依次排列如下:冒泡排序(BubbleSort)选择排序(SelectionSort)插入排序(Inser......
  • day2 栈、队列
    功能受限的表结构:  栈:  队列:    只有两个口来进出数据,一个专门进入数据,另一个专门出数据,先进先出,FIFO表        顺序队列:      1、存储元素的连续内存的首地址      2、容量:      3、队头位置:出队......
  • c++ size_t类型
    在c++中,sizeof()返回的是size_t类型的数据,size_t可以理解为unsignedint(或者unsignedlong),作用是提高可移植性,这个类型在各个平台上都可以使用。64位下char1字节shortint2字节int4字节(unsignedint)long4字节(unsignedlong)longlong8字节(unsignedlonglong)指针统......
  • C++的多态性
    C++面向对象中的多态性是指同一种类型的对象在不同的情况下表现出不同的行为。所谓消息是指对类成员函数的调用,不同的行为是指不同的实现,也就是调用了不同的函数,从广义上说,多态性是指一段程序能够处理多种类型对象的能力。在C++中,虚函数是指在基类中声明的函数,在派生类中可以被重......
  • C++笔记(2)——函数
    六.函数6.1函数基础一个典型的函数(function)定义包括:返回类型(returntype)、函数名字,由0或多个形参(parameter)组成的列表以及函数体。我们通过调用运算符来执行函数,形式为"()"。函数调用完成两项工作:一是用实参初始化函数对应的形参,二是将控制权转移给被调用函数。此时,主调......
  • 阻塞队列
    阻塞队列是一个支持两个附加操作的队列,这两个附加操作支持阻塞的插入和移除操作。1、支持阻塞的插入方法:当队列满时,队列对阻塞插入元素的线程,直到队列不满。2、支持阻塞的移除方法:当队列为空,获取元素的线程会等待队列变味非空。阻塞队列常用的应用场景常用于生产者和消费者场景,生产......
  • C++中的异常处理详细说明
    看代码的过程中,经常看到try{}catch{}语句块,而且还经常性的看到这样的语句try{//保护代码}catch(...){//处理任何异常的代码}刚开始我对catch(...)非常困惑,因为C#中并没有这样的用法.所以,特意来了解学习一下C++中的异常处理方式通常来说,try{}catch{}块中,try......
  • 字符串,列表的内置方法(增加、修改、删除) 、可变类型与不可变类型 、字典 ,元组,集合的
    字符串的内置方法(较多,重要)old_code='KeViN'print('这是返回给用户的验证码:%s'%old_code)new_code=input('请输入你的验证码:').strip()print(new_code)#对验证码作一个判断,现在对验证码作不区分带小写#ifold_code.upper()==new_code.upper():ifold_code.......