Please, for support requests use the CircularBuffer Forum, running a search before submitting a new case: do not abuse the Github issue tracker.
By default the library uses unsigned int
indexes, allowing for a maximum of 65536 items, but you'll rarely need such a huge store. Defining the CIRCULAR_BUFFER_XS
macro you can reduce the library indexes to unsigned short
with no actual impact on the memory used by the library itself, but allowing you to squeeze out those few extra bytes whenever you perform an indexed access, if you do any. Obviously, the consequence is having a maximum element capacity of 512 items, still plenty in most cases.
The library itself has an implicit memory consumption of about 0.5Kb: 580b (max) of code and 8b of memory, to my calculations. That does not consider the space used to store the items themselves, obviously.
When declaring your buffer you should specify the data type it must handle and the buffer capacity: those two parameters will influence the memory consumed by the buffer.
#include <CircularBuffer.h>
CircularBuffer<byte,100> bytes; // uses 538 bytes
CircularBuffer<int,100> ints; // uses 638 bytes
CircularBuffer<long,100> longs; // uses 838 bytes
CircularBuffer<float,100> floats; // uses 988 bytes
CircularBuffer<double,100> doubles; // uses 988 bytes
CircularBuffer<char,100> chars; // uses 538 bytes
CircularBuffer<void*,100> pointers; // uses 638 bytes
If you are close to using all your memory you can try to squeeze out a few bytes by defining CIRCULAR_BUFFER_XS
BEFORE including the library:
#define CIRCULAR_BUFFER_XS
#include <CircularBuffer.h>
CircularBuffer<short,100> buffer;
Please note the reduced memory usage will not occur unless you were using the array-like access operator AND you start using unsigned int
data type for the index access.
Let's start making things clear: the library doesn't support inserting data in the middle of the buffer.
You can add data to the buffer either before the first element via an unshift()
operation or after the last element via a push()
operation.
You can keep adding data beyond the buffer maximum capacity, but you'll lose the least significant information:
- since
unshift()
adds to the head, adding beyond capacity causes the element at tail to be overwritten and lost - since
push()
adds to the tail, adding beyond capacity causes the element at head to be overwritten and lost
Both unshift()
and push()
return true
if the addition didn't cause any information loss, false
if an overwrite occurred:
CircularBuffer<int,5> buffer; // buffer capacity is 5
// all of the following return true
buffer.unshift(1); // [1]
buffer.unshift(2); // [2,1]
buffer.unshift(3); // [3,2,1]
buffer.push(0); // [3,2,1,0]
buffer.push(5); // [3,2,1,0,5]
buffer.unshift(2); // [2,3,2,1,0] returns false
buffer.unshift(10); // [10,2,3,2,1] returns false
buffer.push(-5); // [2,3,2,1,-5] returns false
Similarly to data addition, data retrieval can be performed at tail via a pop()
operation or from head via an shift()
operation: both cause the element being read to be removed from the buffer.
Reading from an empty buffer is forbidden (the library will generate a segfault, which most probably will crash the program): see the additional operations listed in the next section to verify the status of the buffer.
Non-destructive read operations are also available:
first()
returns the element at headlast()
returns the element at tail- an array-like indexed read operation is also available so you can read any element in the buffer using the
[]
operator
Reading data beyond the actual buffer size has an undefined behaviour and is user's responsibility to prevent such boundary violations using the additional operations listed in the next section.
CircularBuffer<char, 50> buffer; // ['a','b','c','d','e','f','g']
buffer.first(); // ['a','b','c','d','e','f','g'] returns 'a'
buffer.last(); // ['a','b','c','d','e','f','g'] returns 'g'
buffer.pop(); // ['a','b','c','d','e','f'] returns 'g'
buffer.pop(); // ['a','b','c','d','e'] returns 'f'
buffer.shift(); // ['b','c','d','e'] returns 'a'
buffer.shift(); // ['c','d','e'] returns 'b'
buffer[0]; // ['c','d','e'] returns 'c'
buffer[1]; // ['c','d','e'] returns 'd'
buffer[2]; // ['c','d','e'] returns 'e'
buffer[10]; // ['c','d','e'] returned value is unpredictable
buffer[15]; // ['c','d','e'] returned value is unpredictable
isEmpty()
returnstrue
only if no data is stored in the bufferisFull()
returnstrue
if no data can be further added to the buffer without causing overwrites/data losssize()
returns the number of elements currently stored in the buffer; it should be used in conjunction with the[]
operator to avoid boundary violations: the first element index is always0
(if buffer is not empty), the last element index is alwayssize() - 1
available()
returns the number of elements that can be added before saturating the buffercapacity()
returns the number of elements the buffer can store, for completeness only as it's user-defined and never changesclear()
resets the whole buffer to its initial state
The library does help working with interrupts defining the CIRCULAR_BUFFER_INT_SAFE
macro switch, which introduces the volatile
modifier to the count
variable, making the whole library more interrupt friendly at the price of disabling some compiler optimizations.
#define CIRCULAR_BUFFER_INT_SAFE
CircularBuffer<volatile long, 10> times;
void setup() {
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), count, RISING);
}
long time = 0;
void loop() {
Serial.print("buffer count is "); Serial.println(times.count());
delay(250);
if (millis() - time >= 10000 && !times.isEmpty()) {
Serial.print("popping "); Serial.println(times.pop());
time = millis();
}
}
void count() {
times.unshift(millis());
}
Please note this does NOT make the library interrupt safe, but it does help its usage in interrupt driven firmwares.
- Added interrupt related macro switch
CIRCULAR_BUFFER_INT_SAFE
- Dropped unecessary call to
memset
when clearing
- Added tests
- Fixed
clear()
function - Fixed
pop()
function
- Improved robustness against access outside the buffer boundaries
- Fixed
pop()
andshift()
implementations - Added test sketch
- Added
capacity()
function - Added
debug()
function, disabled by pre processor by default
- Initial implementation