{"id":23150090,"url":"https://github.com/wa1tnr/cbuf-a2","last_synced_at":"2026-05-02T05:41:22.855Z","repository":{"id":56441224,"uuid":"310845607","full_name":"wa1tnr/cbuf-a2","owner":"wa1tnr","description":"Arduino Circular Buffer - local experiments November 2020 - CPX initial substrate","archived":false,"fork":false,"pushed_at":"2021-10-29T15:30:10.000Z","size":116,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-05T15:47:00.594Z","etag":null,"topics":["arduino","ring-buffer","serial"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wa1tnr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["rlogiacco"],"custom":["https://www.paypal.me/rlogiacco"]}},"created_at":"2020-11-07T12:59:51.000Z","updated_at":"2022-05-11T02:31:13.000Z","dependencies_parsed_at":"2022-08-15T18:50:17.544Z","dependency_job_id":null,"html_url":"https://github.com/wa1tnr/cbuf-a2","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/wa1tnr/cbuf-a2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wa1tnr%2Fcbuf-a2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wa1tnr%2Fcbuf-a2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wa1tnr%2Fcbuf-a2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wa1tnr%2Fcbuf-a2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wa1tnr","download_url":"https://codeload.github.com/wa1tnr/cbuf-a2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wa1tnr%2Fcbuf-a2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32524565,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T01:12:54.858Z","status":"online","status_checked_at":"2026-05-02T02:00:05.923Z","response_time":132,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","ring-buffer","serial"],"created_at":"2024-12-17T18:16:14.611Z","updated_at":"2026-05-02T05:41:22.839Z","avatar_url":"https://github.com/wa1tnr.png","language":"C++","funding_links":["https://github.com/sponsors/rlogiacco","https://www.paypal.me/rlogiacco"],"categories":[],"sub_categories":[],"readme":"### **UPSTREAM** code base for CircularBuffer\n\n# Sat Nov  7 11:16:41 UTC 2020\n\nhttps://github.com/rlogiacco/CircularBuffer.git\n\nFrom the original README.md, which is in the .zip\nand is unpacked, here, as well. -wa1tnr 7 Nov 2020\n\n\n# SEE ALSO\n\nhttps://github.com/Locoduino/RingBuffer\n\nhttps://www.arduino.cc/reference/en/libraries/ringbuffer/\n\n - -\n\noriginal README.md follows. -wa1tnr\n\n\n### \u0026#x26A0; **IMPORTANT**\n \n\u003e Please, before submitting a support request read carefully this README and check if an answer already exists among [previously answered questions](https://github.com/rlogiacco/CircularBuffer/issues?q=label:question): do not abuse of the Github issue tracker.\n\n\u003c!-- omit in toc --\u003e\nCircularBuffer\n[![GitHub stars](https://img.shields.io/github/stars/rlogiacco/CircularBuffer.svg?style=social\u0026label=Star)](https://github.com/rlogiacco/CircularBuffer/stargazers) \n[![GitHub forks](https://img.shields.io/github/forks/rlogiacco/CircularBuffer.svg?style=social\u0026label=Fork)](https://github.com/rlogiacco/CircularBuffer/network)\n[![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Roll%20your%20data%20on%20embedded%20devices%20easily!\u0026url=https://github.com/rlogiacco/CircularBuffer\u0026hashtags=IoT,Arduino,ESP8266,ESP32)\n=============\n\n[![GitHub version](https://img.shields.io/github/release/rlogiacco/CircularBuffer.svg)](https://github.com/rlogiacco/CircularBuffer/releases)\n[![GitHub download](https://img.shields.io/github/downloads/rlogiacco/CircularBuffer/total.svg)](https://github.com/rlogiacco/CircularBuffer/releases/latest)\n[![GitHub stars](https://img.shields.io/github/stars/rlogiacco/CircularBuffer.svg)](https://github.com/rlogiacco/CircularBuffer/stargazers)\n[![GitHub issues](https://img.shields.io/github/issues/rlogiacco/CircularBuffer.svg)](https://github.com/rlogiacco/CircularBuffer/issues)\n[![Build Status](https://img.shields.io/travis/rlogiacco/CircularBuffer.svg?branch=master)](https://travis-ci.org/rlogiacco/CircularBuffer)\n[![License](https://img.shields.io/badge/license-LGPL%203-blue.svg)](https://github.com/rlogiacco/CircularBuffer/blob/master/LICENSE)\n\n\nThe library itself has an implicit memory consumption of about *0.5Kb*: 580 bytes (max) of code and 8 bytes of memory, to my calculations. That does not consider the space used to store the items themselves, obviously.\n\n\u003c!-- toc --\u003e\n  - [Usage](#usage)\n    - [Declare and initialize](#declare-and-initialize)\n    - [Store data](#store-data)\n    - [Retrieve data](#retrieve-data)\n    - [Additional operations](#additional-operations)\n  - [Advanced Usage](#advanced-usage)\n    - [Automatic optimization](#automatic-optimization)\n    - [Legacy optimization](#legacy-optimization)\n    - [Interrupts](#interrupts)\n  - [Examples](#examples)\n  - [Limitations](#limitations)\n    - [Reclaim dynamic memory](#reclaim-dynamic-memory)\n  - [CHANGE LOG](#change-log)\n    - [1.3.3](#133)\n    - [1.3.2](#132)\n    - [1.3.1](#131)\n    - [1.3.0](#130)\n    - [1.2.0](#120)\n    - [1.1.1](#111)\n    - [1.1.0](#110)\n    - [1.0.0](#100)\n\u003c!-- tocstop --\u003e\n\n## Usage\n\n### Declare and initialize\n\nWhen 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.\n\n``` cpp\n#include \u003cCircularBuffer.h\u003e\n\nCircularBuffer\u003cbyte,100\u003e bytes;     // uses 538 bytes\nCircularBuffer\u003cint,100\u003e ints;       // uses 638 bytes\nCircularBuffer\u003clong,100\u003e longs;     // uses 838 bytes\nCircularBuffer\u003cfloat,100\u003e floats;   // uses 988 bytes\nCircularBuffer\u003cdouble,100\u003e doubles; // uses 988 bytes\nCircularBuffer\u003cchar,100\u003e chars;     // uses 538 bytes \nCircularBuffer\u003cvoid*,100\u003e pointers; // uses 638 bytes\n```\n\n**Please note**: the memory usage reported above includes the program memory used by the library code, the heap memory is much less and is comparable to an array of the same size and type of the buffer.\n\n### Store data\n\nLet's start making things clear: the library doesn't support inserting data in the middle of the buffer.\nYou can add data to the buffer either before the first element via an `unshift()` operation or after the last element via a `push()` operation.\nYou can keep adding data beyond the buffer maximum capacity, but you'll lose the least significant information:\n\n* since `unshift()` adds to the _head_, adding beyond capacity causes the element at _tail_ to be overwritten and lost\n* since `push()` adds to the _tail_, adding beyond capacity causes the element at _head_ to be overwritten and lost\n\nBoth `unshift()` and `push()` return `true` if the addition didn't cause any information loss, `false` if an overwrite occurred:\n\n``` cpp\nCircularBuffer\u003cint,5\u003e buffer; // buffer capacity is 5\n\n// all of the following return true\nbuffer.unshift(1); // [1] \nbuffer.unshift(2); // [2,1]\nbuffer.unshift(3); // [3,2,1]\nbuffer.push(0);  // [3,2,1,0]\nbuffer.push(5);  // [3,2,1,0,5]\n\n// buffer is now at full capacity, from now on any addition returns false\nbuffer.unshift(2);  // [2,3,2,1,0] returns false\nbuffer.unshift(10); // [10,2,3,2,1] returns false\nbuffer.push(-5);  // [2,3,2,1,-5] returns false\n```\n\n### Retrieve data\n\nSimilarly 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.\n\n\u003e \u0026#x26A0; 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_](#additional-operations) listed in the next section. The library will behave differently depending on the data type and allocation method, but you can safely assume your program will crash if you don't watch your steps.\n\nNon-destructive read operations are also available:\n\n* `first()` returns the element at _head_\n* `last()` returns the element at _tail_\n* an array-like indexed read operation is also available so you can read any element in the buffer using the `[]` operator\n\n\n``` cpp\nCircularBuffer\u003cchar, 50\u003e buffer; // ['a','b','c','d','e','f','g']\n\nbuffer.first(); // ['a','b','c','d','e','f','g'] returns 'a'\nbuffer.last(); // ['a','b','c','d','e','f','g'] returns 'g'\nbuffer.pop(); // ['a','b','c','d','e','f'] returns 'g'\nbuffer.pop(); // ['a','b','c','d','e'] returns 'f'\nbuffer.shift(); // ['b','c','d','e'] returns 'a'\nbuffer.shift(); // ['c','d','e'] returns 'b'\nbuffer[0]; // ['c','d','e'] returns 'c'\nbuffer[1]; // ['c','d','e'] returns 'd'\nbuffer[2]; // ['c','d','e'] returns 'e'\n\nbuffer[10]; // ['c','d','e'] returned value is unpredictable\nbuffer[15]; // ['c','d','e'] returned value is unpredictable\n```\n\n### Additional operations\n\n* `isEmpty()` returns `true` only if no data is stored in the buffer\n* `isFull()` returns `true` if no data can be further added to the buffer without causing overwrites/data loss\n* `size()` 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 always `0` (if buffer is not empty), the last element index is always `size() - 1`\n* `available()` returns the number of elements that can be added before saturating the buffer\n* `capacity()` returns the number of elements the buffer can store, for completeness only as it's user-defined and never changes **REMOVED** from `1.3.0` replaced by the read-only member variable `capacity`\n* `clear()` resets the whole buffer to its initial state (pay attention though, if you had dynamically allocated objects in your buffer, memory used by such object is *not* released: iterate over the buffer contents and release object accordingly to their allocation method)\n\n## Advanced Usage\n\n### Automatic optimization\n\nStarting from version `1.3.0` the library is capable to automatically detect which data type should be used for the index based on the buffer capacity: \n* if you declare a buffer with a capacity greater than `65535` then your index is going to be an `unsigned long`\n* `unsigned int` for buffers with a declared capacity greater than `255`\n* otherwise a `byte` is going to suffice\n\nIn addition, you can mix in the same code buffers with small index and buffers with normal index: previously this was not possible.\n\n``` cpp\nCircularBuffer\u003cchar,100\u003e optimizedBuffer; // reduced memory footprint, index type is uint8_t (a.k.a. byte)\nCircularBuffer\u003clong,500\u003e normalBuffer;    // standard memory footprint, index type is unit16_t (a.k.a. unsigned int)\nCircularBuffer\u003cint,66000\u003e hugeBuffer;     // extended memory footprint, index type is unit32_t (a.k.a. unsigned long)\n```\n\nTo obtain the maximum advantage of the optimization above, anytime you need to refer to the buffer index you should use the most appropriate type: this can be easily achieved using the `decltype` specifier, like in the following example:\n\n```cpp\n// the iterator variable i is of the correct type, even if  \n// we don't know what's the buffer declared capacity\nfor (decltype(buffer)::index_t i = 0; i \u003c buffer.size(); i++) {\n    avg += buffer[i] / buffer.size();\n}\n```\n\nIf you prefer, you can alias the index type and refer to such alias:\n\n```cpp\nusing index_t = decltype(buffer)::index_t;\nfor (index_t i = 0; i \u003c buffer.size(); i++) {\n    avg += buffer[i] / buffer.size();\n}\n```\n\n### Legacy optimization\n\n_The following applies to versions prior to `1.3.0` only._\n\nBy default the library uses `unsigned int` indexes, allowing for a maximum of `65535` items, but you'll rarely need such a huge store.\n\nYou can switch the library indexes to `byte` type defining the `CIRCULAR_BUFFER_XS` macro **BEFORE** the `#include` directive: this reduces the memory used by the library itself by only `36` bytes, but allows you to potentially squeeze out much more whenever you perform an indexed access, if you do any, by using the smaller data type.\n\n``` cpp\n#define CIRCULAR_BUFFER_XS\n#include \u003cCircularBuffer.h\u003e\n\nCircularBuffer\u003cshort,100\u003e buffer;\n\nvoid setup() { }\n\nvoid loop() {\n\t  // here i should be declared of type byte rather than unsigned int\n    // in order to maximize the effects of the optimization\n    for (byte i = 0; i \u003c buffer.size() - 1; i++) {\n        Serial.print(buffer[i]);\n    }\n}\n```\n\n**Please note**: this _macro switch_ forces the buffer to use an 8 bits data type as internal index, as such **all** your buffers will be limited to a maximum capacity of `255`.\n\n### Interrupts\n\nThe 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. The `#define` statement needs to be put somewhere before the `#include` statement:\n\n```cpp\n#define CIRCULAR_BUFFER_INT_SAFE\n#include \u003cCircularBuffer.h\u003e\nCircularBuffer\u003cunsigned long, 10\u003e timings;\n\nvoid count() {\n  timings.push(millis());\n}\n\nvoid setup() {\n    attachInterrupt(digitalPinToInterrupt(2), count, RISING);\n}\n\nvoid loop() {\n    Serial.print(\"buffer size is \"); Serial.println(timings.size());\n    delay(250);\n}\n\n```\n\n\u003e Please note this does **NOT** make the library _interrupt safe_, but it does help its usage in interrupt driven firmwares.\n\n## Examples\n\nMultiple examples are available in the `examples` folder of the library:\n\n * [CircularBuffer.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/CircularBuffer/CircularBuffer.ino) shows how you can use the library to create a continous averaging of the most recent readings\n * [EventLogging.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/EventLogging/EventLogging.ino) focuses on dumping the buffer when it becomes full and printing the buffer contents periodically at the same time\n * [Object.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/Object/Object.ino) is meant to demonstrate how to use the buffer to store dynamic structures\n * [Queue.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/Queue/Queue.ino) is a classical example of a queue, or a FIFO data structure\n * [Stack.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/Stack/Stack.ino) on the other end shows how to use the library to represent a LIFO data structure\n * [Struct.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/Struct/Struct.ino) answers to the question _can this library store structured data?_\n * [Interrupts.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/Interrupts/Interrupts.ino) demonstrates the use of the library in interrupt driven code\n\n## Limitations\n\n### Reclaim dynamic memory\n\nIf you use this library to store dynamically allocated objects, refrain from using the `clear()` method as that will **not** perform memory deallocation: you need to iterate over your buffer content and release memory accordingly to the allocation method used, either via `delete` (if you had used `new`) or `free` (in case of `malloc`):\n\n```cpp\nwhile (!buffer.isEmpty()) {\n    // pick the correct one\n    delete buffer.pop();\n    free(buffer.pop());\n}\n```\n\nThe very same applies for the `pop()` and `shift()` operations as any dynamically allocated object is only _detached_ from the buffer, but the memory it uses is **not** automagically released (see the [Object.ino](https://github.com/rlogiacco/CircularBuffer/blob/master/examples/Object/Object.ino) example)\n\n```cpp\nRecord* record = new Record(millis(), sample);  // a dynamically allocated object\nbuffer.push(record);\n\n// somewhere else\nif (!buffer.isEmpty()) {\n    Record* current = buffer.pop();\n    Serial.println(current.value());\n    delete current; // not doing this will leaves the object in memory!!!\n}\n```\n\n------------------------\n## CHANGE LOG\n\n### 1.3.3\n* Fixes #27 compilation error\n\n### 1.3.2\n* Fixes #2 preventing `shift()` and `pop()` operations misuse to mess up the buffer\n* Fixes #2 preventing _out of boundary_ access using the `[]` operator\n\n### 1.3.1\n* Fixes #21 _call to `abort()` is AVR-specific\n\n### 1.3.0\n\nMost of the major improvements below have been contributed by [Erlkoenig90](https://github.com/Erlkoenig90): thank you Niklas!\n\n* Slightly reduced both flash and heap footprint\n* Introduced _instance based_ control over index data type\n* Replaced method `capacity()` in favour of the constant instance attribute `capacity`\n* Added the `EventLogging` and `Interrupts` examples\n* Dropped the `CIRCULAT_BUFFER_XS` _macro switch_ in favor of automatic index type identification\n* Added support for very large buffers (capacity can go up to `UINT32_MAX`)\n\n### 1.2.0\n* Added interrupt related macro switch `CIRCULAR_BUFFER_INT_SAFE`\n* Dropped unecessary call to `memset` when clearing\n\n### 1.1.1\n* Added tests\n* Fixed `clear()` function\n* Fixed `pop()` function\n\n### 1.1.0\n* Improved robustness against access outside the buffer boundaries\n* Fixed `pop()` and `shift()` implementations\n* Added test sketch\n* Added `capacity()` function\n* Added `debug()` function, disabled by pre processor by default\n\n### 1.0.0\n* Initial implementation\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwa1tnr%2Fcbuf-a2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwa1tnr%2Fcbuf-a2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwa1tnr%2Fcbuf-a2/lists"}