N.B. I'm writing my comments as I am reading your code. Please, don't take offense from my criticism, it is meant to be constructive, albeit concise.
/*
* @brief Retrieve a continuous block of
* valid buffered data.
* @param num_reads_requested How many reads are required.
* @param skip Whether to increment the read position
* automatically, (false for manual skip
* control)
* @return A block of items containing the maximum
* number the buffer can provide at this time.
/
Block<T> Read(unsigned int num_reads_requested)
Where is skip?
> if (buffer_full)
> {
> /
> * Tried to append a value while the buffer is full.
> /
> overrun_flag = true;
> }
> else
> {
> /
> * Buffer isn't full yet, write to the curr write position
> * and increment it by 1.
> /
> overrun_flag = false;
> data[write_position] = value;
> write_position = (write_position + 1U) % LENGTH;
> }
You don't write in the case of an "overrun". Isn't that one of the most interesting property of a ringbuffer? It seems that your implementation is specific to your use case (buffering to sd cards?). I don't think your _current_ implementation is apropriate for a _general_ purpose ring buffer mostly because of api concerns. It may be interesting to emphasis this part in your doc.
> reads_to_end = LENGTH - read_position;
> req_surpasses_buffer_end = num_reads_requested > reads_to_end;
>
> if (req_surpasses_buffer_end)
> {
> /
> * If the block requested exceeds the buffer end. Then
> * return a block that reaches the end and no more.
> /
> block.SetStart(&(data[read_position]));
> block.SetLength(reads_to_end);
> }
> else
> {
> /
> * If the block requested does not exceed 0
> * then return a block that reaches the number of reads required.
> */
> block.SetStart(&(data[read_position]));
> block.SetLength(num_reads_requested);
> }
/* * @brief Retrieve a continuous block of * valid buffered data. * @param num_reads_requested How many reads are required. * @param skip Whether to increment the read position * automatically, (false for manual skip * control) * @return A block of items containing the maximum * number the buffer can provide at this time. / Block<T> Read(unsigned int num_reads_requested)
Where is skip?
> if (buffer_full) > { > / > * Tried to append a value while the buffer is full. > / > overrun_flag = true; > } > else > { > / > * Buffer isn't full yet, write to the curr write position > * and increment it by 1. > / > overrun_flag = false; > data[write_position] = value; > write_position = (write_position + 1U) % LENGTH; > }
You don't write in the case of an "overrun". Isn't that one of the most interesting property of a ringbuffer? It seems that your implementation is specific to your use case (buffering to sd cards?). I don't think your _current_ implementation is apropriate for a _general_ purpose ring buffer mostly because of api concerns. It may be interesting to emphasis this part in your doc.
> reads_to_end = LENGTH - read_position; > req_surpasses_buffer_end = num_reads_requested > reads_to_end; > > if (req_surpasses_buffer_end) > { > / > * If the block requested exceeds the buffer end. Then > * return a block that reaches the end and no more. > / > block.SetStart(&(data[read_position])); > block.SetLength(reads_to_end); > } > else > { > / > * If the block requested does not exceed 0 > * then return a block that reaches the number of reads required. > */ > block.SetStart(&(data[read_position])); > block.SetLength(num_reads_requested); > }
Maybe : > reads_to_end = LENGTH - read_position; > eff_reads = (num_reads_requested > reads_to_end) ? reads_to_end : num_reads_requested; > //or : eff_reads = std::min(num_reads_requested, reads_to_end) > block.SetStart(&(data[read_position])); > block.SetLength(eff_reads);
Still, I understand the need to be very explicit in an embedded context.
Same principle for ``if (!bridges_zero)`` (the ``else`` case)