环形队列的实现对比

环形队列可以通过维护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;
   m_readPos += fillDataSize;
 
   // 数据不足填0补充
   int fiillZeroSize = wantSize - count;
   if(fiillZeroSize > 0){
      memset(outBuf + outBufOffset,  0, fiillZeroSize);
   }

   count -= rSize;
   return rSize;
}
posted @ 2023-07-18 11:05  woder  阅读(40)  评论(0编辑  收藏  举报