简体   繁体   English

实现循环缓冲区以在单个调用中写入/读取任意数量的数据

[英]Implement circular buffer to write/read arbitrary amount of data in a single call

Most of circular buffer assumes to only read/write ONE object each time, the only link I found to operates on binary data in form of (const char *bytes, size_t byte_count) is http://www.asawicki.info/news_1468_circular_buffer_of_raw_binary_data_in_c.html , which I feel is not incorrect and a little long. 大多数循环缓冲区假定每次只读/写一个对象,我发现以(const char * bytes,size_t byte_count)的形式对二进制数据进行操作的唯一链接是http://www.asawicki.info/news_1468_circular_buffer_of_raw_binary_data_in_c。 html ,我觉得这不是不正确而且有点长。 What is the right implementation for that? 什么是正确的实施?

I created one myself. 我自己创造了一个。 but it is still long. 但它仍然很长。 Can anybody share a more elegant version? 任何人都可以分享更优雅的版本吗? or can you point out is there any thing I can improve in my code to make it short? 或者你能指出我的代码中有什么东西可以改进吗?

class Pipe{
    Pipe(size_t capacity): _capacity(capacity){ init();  }
    ~Pipe(){delete [] _buf; }
    size_t read(char* data, size_t bytes);
    size_t write(const char* data, size_t bytes);
   private: 
    //only _capacity-1 is used, one is to identify full or empty.
    void init(){_buf = new char[_capacity]; 
     _wptr = 0; _rptr = 0; _used_size = 0; 
    }
    char* _buf;
    size_t _capacity, _wptr, _rptr, _used_size;
    bool isFull(){return (_wptr + 1 ) % (_capacity) == _rptr;} 
    bool isEmpty(){return _wptr == _rptr;} 
}; 
size_t Pipe::read(char* data, size_t bytes){
    if (isEmpty() || bytes == 0) return 0;
    size_t bytes_read1 = 0, bytes_read2 = 0;
    if (_rptr>=_wptr+1) { //two piece can be read
        bytes_read1 = min(bytes, _capacity - _rptr);
        memcpy(data, _buf + _rptr, bytes_read1);
        _rptr += bytes_read1;
        bytes -= bytes_read1;
        if (_rptr == _capacity) _rptr = 0;
        if (bytes > 0){
        bytes_read2 = min(bytes, _wptr);
            memcpy(_buf + _rptr, data, bytes_read2);
            _rptr += bytes_read2;
            bytes -= bytes_read2;
        }
    }
    else{//one piece can be read
    bytes_read1 = min(bytes, _wptr - _rptr); 
    memcpy(_buf + _wptr, data, bytes_read1);
    _rptr += bytes_read1;
    bytes -= bytes_read1;
    }
    return bytes_read1 + bytes_read2; 
}

size_t Pipe::write(const char* data, size_t bytes){
    if (isFull() || bytes == 0) return 0;
    size_t bytes_write1 = 0, bytes_write2 = 0;
    if (_wptr>=_rptr) { //two piece can be written
        bytes_write1 = min(bytes, _capacity - _wptr); 
        memcpy(_buf + _wptr, data, bytes_write1);
        _wptr += bytes_write1;
        bytes -= bytes_write1;
        if (_wptr == _capacity) _wptr = 0;
        if (bytes > 0){ //_wptr must be 0 here.
            bytes_write2 = min(bytes, _rptr-1);//-1 bcz there is one     
    slot to check empty/full
            memcpy(_buf + _wptr, data+ bytes_write1, bytes_write2);
            _wptr += bytes_write2;
            bytes -= bytes_write2;
        }
    }
    else{ //one piece can be written
        bytes_write1 = min(bytes, _rptr - _wptr -1); 
        memcpy(_buf + _wptr, data, bytes_write1);
        _wptr += bytes_write1;
        bytes -= bytes_write1;
    }
    return bytes_write1 + bytes_write2; 
}

The code in OP may be simplified by excluding all conditionals. 可以通过排除所有条件来简化OP中的代码。 Original interface and memcpy for implementation is retained (only constructor/destructor/read/write made public and unused _used_size may be dropped). 保留了用于实现的原始接口和memcpy (只有构造函数/析构函数/读/写为public,未使用的_used_size可能被删除)。

size_t Pipe::read(char* data, size_t bytes)
{
    bytes = min(bytes, getUsed());
    const size_t bytes_read1 = min(bytes, _capacity - _rptr);
    memcpy(data, _buf + _rptr, bytes_read1);
    memcpy(data + bytes_read1, _buf, bytes - bytes_read1);
    updateIndex(_rptr, bytes);
    return bytes;
}

size_t Pipe::write(const char* data, size_t bytes)
{
    bytes = min(bytes, getFree());
    const size_t bytes_write1 = min(bytes, _capacity - _wptr); 
    memcpy(_buf + _wptr, data, bytes_write1);
    memcpy(_buf, data + bytes_write1, bytes - bytes_write1);
    updateIndex(_wptr, bytes);
    return bytes;
}

Several private methods used here may have this simple implementation: 这里使用的几个私有方法可能有这个简单的实现:

size_t Pipe::getUsed()
{ return (_capacity - _rptr + _wptr) % _capacity; }

size_t Pipe::getFree()
{ return (_capacity - 1 - _wptr + _rptr) % _capacity; }

void Pipe::updateIndex(size_t& index, size_t bytes)
{ index = (index + bytes) % _capacity; }

This implementation has one disadvantage: it is broken when _capacity is close to maximum size_t value (because of overflows). 此实现有一个缺点:当_capacity接近最大size_t值(因为溢出)时它会被破坏。 This may be fixed by substituting modulo with conditionals in free/used calculations and index updates. 这可以通过在自由/使用的计算和索引更新中用模数替换modulo来修复。 Here are modifications for methods used in read : 以下是对read使用的方法的修改:

size_t Pipe::getUsed()
{
    if (_wptr >= _rptr)
        return _wptr - _rptr;
    else
        return _capacity - _rptr + _wptr;
}

void Pipe::updateIndex(size_t& index, size_t bytes)
{
    if (bytes >= _capacity - index)
        index = index + bytes - _capacity;
    else
        index = index + bytes;
}

You can make it more short by using boost circular buffer. 您可以使用boost循环缓冲区使其更短。 ( http://www.boost.org/doc/libs/1_55_0/doc/html/circular_buffer.html ). http://www.boost.org/doc/libs/1_55_0/doc/html/circular_buffer.html )。 All boost libraries are usually very good polished for performance and for implicit specialties on all platforms, so usually I have preference to use them instead of writing my custom codes doing same 所有的boost库通常都非常适合性能和所有平台上的隐式特性,所以通常我更喜欢使用它们而不是编写我的自定义代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将数据读入循环缓冲区 - Read data into a circular buffer C++如何定义操作符[]来写入和读取循环缓冲区的一项 - C++ how to define the operator [] to write and read an item of the circular buffer 如何将读/写数据作为模块缓冲 - How to buffer read/write data as a module 将结构数据存储在循环缓冲区中 - storing structure data in circular buffer 无缓冲区溢出的任意写入漏洞 - Arbitrary write vulnerability without buffer overflow 单生产者多消费者循环缓冲区 - Single Producer Multiple Consumer Circular Buffer 具有单个生产者单个使用者的无锁循环缓冲器 - Lockless circular buffer with single producer singular consumer select()是否可以实现单插槽读/写超时? - Is select() Ok to implement single socket read/write timeout? 是否可以在System V共享内存中实现无锁循环队列(C++写,Python读) - Is it possible to implement a lock free circular queue in System V shared memory (write by C++, read by Python) 如何读取和写入许多对象(或任何数据)到缓冲区? - How to read and write many objects (or any data) to a buffer?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM