Circular Buffer of Raw Binary Data in C++
2017-12-07 21:25
295 查看
http://www.asawicki.info/news_1468_circular_buffer_of_raw_binary_data_in_c.html
C++ video cyclic buffer
https://github.com/lmtanco/videoDelayLine http://www.boost.org/doc/libs/1_39_0/libs/circular_buffer/doc/circular_buffer.html
音频类 环形缓存
//环形缓存https://github.com/michaeltyson/TPCircularBuffer
//https://github.com/TheAmazingAudioEngine/TheAmazingAudioEngine
Warning! Some information on this page is older than 5 years now. I keep it for reference, but it probably doesn't reflect my current knowledge and beliefs.
# Circular Buffer of Raw Binary Data in C++
15:47
Fri
21
Oct 2011
Circular Buffer, Cyclic Buffer or Ring Buffer is a data structure that effectively manages a queue of some items. Items can be added at the back and removed from the front. It has limited capacity because it is based on preallocated array. Functionality is
implemented using two pointers or indices - pointing to the first and past the last valid element. The Begin pointer is incremented whenever an item is popped from the front so that it "chases" the End pointer, which is incremented whenever a new item is pushed
to the back. They can both wrap around the size of the array. Both operations are done very effectively - in constant time O(1) and no reallocations are needed. This makes circular buffers perfect solution for queues of some data streams, like video or audio.
It's not very sophisticated data structure, but there is one problem. Sample codes of circular buffers you can find on the Internet, just like for many other data structures, operate usually on a single object of some user-defined type. What if we need a buffer
for raw binary data, stored as array of bytes? We can treat single bytes as data items, but enqueueing and dequeueing single bytes with separate function calls would not be efficient. We can, on the other hand, define some block of data (like 4096 bytes) as
the type of item, but this limits us to operating on on such block at a time.
Best solution would be to write an implementation that operates on binary data in form of (const char *bytes, size_t byte_count) and allows writing and reading arbitrary amount of data in a single call, just like functions for writing and reading files do.
The only problem that arises in such code is that sometimes the block of data you want to write to or read from the buffer is not in a continuous region of memory, but wraps around to the beginning of the array so we have to process it on two parts - first
at the end of the array and the second at the beginning.
Here is my C++ implementation of a circular buffer for raw binary data:
#include <algorithm> // for std::min
class CircularBuffer
{
public:
CircularBuffer(size_t capacity);
~CircularBuffer();
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
// Return number of bytes written.
size_t write(const char *data, size_t bytes);
// Return number of bytes read.
size_t read(char *data, size_t bytes);
private:
size_t beg_index_, end_index_, size_, capacity_;
char *data_;
};
CircularBuffer::CircularBuffer(size_t capacity)
: beg_index_(0)
, end_index_(0)
, size_(0)
, capacity_(capacity)
{
data_ = new char[capacity];
}
CircularBuffer::~CircularBuffer()
{
delete [] data_;
}
size_t CircularBuffer::write(const char *data, size_t bytes)
{
if (bytes == 0) return 0;
size_t capacity = capacity_;
size_t bytes_to_write = std::min(bytes, capacity - size_);
// Write in a single step
if (bytes_to_write <= capacity - end_index_)
{
memcpy(data_ + end_index_, data, bytes_to_write);
end_index_ += bytes_to_write;
if (end_index_ == capacity) end_index_ = 0;
}
// Write in two steps
else
{
size_t size_1 = capacity - end_index_;
memcpy(data_ + end_index_, data, size_1);
size_t size_2 = bytes_to_write - size_1;
memcpy(data_, data + size_1, size_2);
end_index_ = size_2;
}
size_ += bytes_to_write;
return bytes_to_write;
}
size_t CircularBuffer::read(char *data, size_t bytes)
{
if (bytes == 0) return 0;
size_t capacity = capacity_;
size_t bytes_to_read = std::min(bytes, size_);
// Read in a single step
if (bytes_to_read <= capacity - beg_index_)
{
memcpy(data, data_ + beg_index_, bytes_to_read);
beg_index_ += bytes_to_read;
if (beg_index_ == capacity) beg_index_ = 0;
}
// Read in two steps
else
{
size_t size_1 = capacity - beg_index_;
memcpy(data, data_ + beg_index_, size_1);
size_t size_2 = bytes_to_read - size_1;
memcpy(data + size_1, data_, size_2);
beg_index_ = size_2;
}
size_ -= bytes_to_read;
return bytes_to_read;
}
Similar phenomenon can be observed in API of the FMOD sound library. Just like graphical textures in DirectX, sound samples in FMOD can also be "locked" to get pointer to a raw memory we can read or fill. But DirectX textures lie in the continuous memory region,
so we get a single pointer. The only difficult thing in understanding locking textures is the concept of "stride", which can be greater than the width of a single row. Here in FMOD the Sound::lock() method returns two pointers and two lengths, probably because
the locked region can wrap over end of internally used circular buffer like the one shown above.
C++ video cyclic buffer
https://github.com/lmtanco/videoDelayLine http://www.boost.org/doc/libs/1_39_0/libs/circular_buffer/doc/circular_buffer.html
音频类 环形缓存
//环形缓存https://github.com/michaeltyson/TPCircularBuffer
//https://github.com/TheAmazingAudioEngine/TheAmazingAudioEngine
Warning! Some information on this page is older than 5 years now. I keep it for reference, but it probably doesn't reflect my current knowledge and beliefs.
# Circular Buffer of Raw Binary Data in C++
15:47
Fri
21
Oct 2011
Circular Buffer, Cyclic Buffer or Ring Buffer is a data structure that effectively manages a queue of some items. Items can be added at the back and removed from the front. It has limited capacity because it is based on preallocated array. Functionality is
implemented using two pointers or indices - pointing to the first and past the last valid element. The Begin pointer is incremented whenever an item is popped from the front so that it "chases" the End pointer, which is incremented whenever a new item is pushed
to the back. They can both wrap around the size of the array. Both operations are done very effectively - in constant time O(1) and no reallocations are needed. This makes circular buffers perfect solution for queues of some data streams, like video or audio.
It's not very sophisticated data structure, but there is one problem. Sample codes of circular buffers you can find on the Internet, just like for many other data structures, operate usually on a single object of some user-defined type. What if we need a buffer
for raw binary data, stored as array of bytes? We can treat single bytes as data items, but enqueueing and dequeueing single bytes with separate function calls would not be efficient. We can, on the other hand, define some block of data (like 4096 bytes) as
the type of item, but this limits us to operating on on such block at a time.
Best solution would be to write an implementation that operates on binary data in form of (const char *bytes, size_t byte_count) and allows writing and reading arbitrary amount of data in a single call, just like functions for writing and reading files do.
The only problem that arises in such code is that sometimes the block of data you want to write to or read from the buffer is not in a continuous region of memory, but wraps around to the beginning of the array so we have to process it on two parts - first
at the end of the array and the second at the beginning.
Here is my C++ implementation of a circular buffer for raw binary data:
#include <algorithm> // for std::min
class CircularBuffer
{
public:
CircularBuffer(size_t capacity);
~CircularBuffer();
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
// Return number of bytes written.
size_t write(const char *data, size_t bytes);
// Return number of bytes read.
size_t read(char *data, size_t bytes);
private:
size_t beg_index_, end_index_, size_, capacity_;
char *data_;
};
CircularBuffer::CircularBuffer(size_t capacity)
: beg_index_(0)
, end_index_(0)
, size_(0)
, capacity_(capacity)
{
data_ = new char[capacity];
}
CircularBuffer::~CircularBuffer()
{
delete [] data_;
}
size_t CircularBuffer::write(const char *data, size_t bytes)
{
if (bytes == 0) return 0;
size_t capacity = capacity_;
size_t bytes_to_write = std::min(bytes, capacity - size_);
// Write in a single step
if (bytes_to_write <= capacity - end_index_)
{
memcpy(data_ + end_index_, data, bytes_to_write);
end_index_ += bytes_to_write;
if (end_index_ == capacity) end_index_ = 0;
}
// Write in two steps
else
{
size_t size_1 = capacity - end_index_;
memcpy(data_ + end_index_, data, size_1);
size_t size_2 = bytes_to_write - size_1;
memcpy(data_, data + size_1, size_2);
end_index_ = size_2;
}
size_ += bytes_to_write;
return bytes_to_write;
}
size_t CircularBuffer::read(char *data, size_t bytes)
{
if (bytes == 0) return 0;
size_t capacity = capacity_;
size_t bytes_to_read = std::min(bytes, size_);
// Read in a single step
if (bytes_to_read <= capacity - beg_index_)
{
memcpy(data, data_ + beg_index_, bytes_to_read);
beg_index_ += bytes_to_read;
if (beg_index_ == capacity) beg_index_ = 0;
}
// Read in two steps
else
{
size_t size_1 = capacity - beg_index_;
memcpy(data, data_ + beg_index_, size_1);
size_t size_2 = bytes_to_read - size_1;
memcpy(data + size_1, data_, size_2);
beg_index_ = size_2;
}
size_ -= bytes_to_read;
return bytes_to_read;
}
Similar phenomenon can be observed in API of the FMOD sound library. Just like graphical textures in DirectX, sound samples in FMOD can also be "locked" to get pointer to a raw memory we can read or fill. But DirectX textures lie in the continuous memory region,
so we get a single pointer. The only difficult thing in understanding locking textures is the concept of "stride", which can be greater than the width of a single row. Here in FMOD the Sound::lock() method returns two pointers and two lengths, probably because
the locked region can wrap over end of internally used circular buffer like the one shown above.
相关文章推荐
- Summarizes chapter one of datastructures and program design in C++
- How to create a hex dump from binary data in C++
- This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary log
- This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary
- in its raw version as part of a circular reference
- This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary log
- This function has none of Deterministic,no sql,or reads sql data in its declaration and binary logging is enabled(you *might* want to use the less safe log_bin_trust_function_creators variable
- This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary log
- how many does the factorial of n(in binary data ) have zero?
- The state of binary data in the browser
- An implementation of the skip list data structure written in C++
- 基于二进制程序的类型推导--TIE: Principled Reverse Engineering of Types in Binary Programs
- The Delicate Art of Organizing Data in HBase
- static data in c++ class
- postman中 form-data、x-www-form-urlencoded、raw、binary的区别
- inside the C++ object model chapter 3 the semantics of data
- kingofark's Ineffective C/C++:自白2:有符号、无符号还有位运算,我的天!
- kingofark's Ineffective C/C++:自白1:返回值的运用
- How do you copy the contents of an array to a std::vector in C++ without looping? (From stack over flow)
- Fundamentals of OOP and Data Structures in Java