[英]circular buffer implementation
再次是,我再次提出了非常简单的实现,如下所示:
// write data always! if buffer is already full, overwrite old data!
void Put( const CONTENT_TYPE &data )
{
buffer[ inOffset++] = data;
inOffset%=size;
// was data overwritten, skip it by increment read offset
if ( inOffset == outOffset )
{
outOffset++;
outOffset%=size;
std::cout << "Overwrite" << std::endl;
}
}
CONTENT_TYPE Pull()
{
CONTENT_TYPE data = buffer[ outOffset++ ];
outOffset %= size;
return data;
}
但是,这种简单的算法仅利用大小为1的缓冲区元素!
如果我想避免这种情况,我只找到了添加另一个计数器变量的解决方案,这浪费了我sizeof(counter_var)-sizeof(element)个字节。
问:有没有不浪费内存的解决方案? 它看起来很简单,但我抓不到:-)
备注:还有更多的代码行可以保护空读取和其他内容,但这对这个问题并不重要。 而且它没有被标记为c ++,因为该算法不依赖于语言,即使我举一个c ++代码示例也是如此。
您可以使用两个整数并填充所有插槽(如果一个是索引,另一个是元素计数),然后立即进行转换以找到第二个索引:
void put(const ELEMENT& element) {
if (nElements == size) throw "put: buffer full";
buffer[(start + nElements++) % size] = element;
}
ELEMENT get() {
if (nElements == 0) throw "get: buffer empty";
ELEMENT& value = buffer[start];
start = (start + 1) % size;
--nElements;
return value;
}
当然,您可以用if (foo > size) foo -= size;
替换mod操作if (foo > size) foo -= size;
如果你喜欢。
您可以通过使用不同的时间点进行模运算来解决这个问题。 假设我们在每次访问后都增加了读写指针。 如果现在我们在增加之后立即执行读指针的模,而就在读之前立即写写指针的模,则| write-read | 完整缓冲区的长度将是缓冲区的长度,无需任何特殊情况处理。 为此,您的写指针应始终使用 % buffer_length
,但应存储 % (2 * buffer_length)
。
我不特别喜欢Mark的答案,因为按特殊情况处理事物通常不是一个好主意,在您通常使用size_t
(即无符号整数)的地方,引入负的前哨值就少了。
您可以对偏移量之一使用特殊的前哨值,例如-1,以指示缓冲区已满或为空。 这会使检查和修改偏移量的代码复杂化。
// write data always! if buffer is already full, overwrite old data!
void Put( const CONTENT_TYPE &data )
{
buffer[ inOffset++] = data;
inOffset%=size;
// was data overwritten, skip it by setting read offset to sentinel
if ( inOffset == outOffset || outOffset == -1 )
{
outOffset = -1;
std::cout << "Overwrite" << std::endl;
}
}
CONTENT_TYPE Pull()
{
if (outOffset == -1)
outOffset = inOffset;
CONTENT_TYPE data = buffer[ outOffset++ ];
outOffset %= size;
return data;
}
bool IsEmpty()
{
return outOffset == inOffset;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.