{"id":26474182,"url":"https://github.com/mrizaln/circbuf","last_synced_at":"2025-03-19T22:45:21.607Z","repository":{"id":242215633,"uuid":"808989388","full_name":"mrizaln/circbuf","owner":"mrizaln","description":"A simple C++ circular buffer written in C++20","archived":false,"fork":false,"pushed_at":"2025-01-09T20:34:45.000Z","size":60,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-09T21:32:43.641Z","etag":null,"topics":["circular-buffer","cpp","data-structures"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrizaln.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-01T11:15:24.000Z","updated_at":"2025-01-09T20:34:49.000Z","dependencies_parsed_at":"2024-06-01T12:45:11.563Z","dependency_job_id":"9b08c944-32fc-43e5-9230-d6ecea0e8d7a","html_url":"https://github.com/mrizaln/circbuf","commit_stats":null,"previous_names":["mrizaln/circular-buffer"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrizaln%2Fcircbuf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrizaln%2Fcircbuf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrizaln%2Fcircbuf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrizaln%2Fcircbuf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrizaln","download_url":"https://codeload.github.com/mrizaln/circbuf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244520022,"owners_count":20465624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["circular-buffer","cpp","data-structures"],"created_at":"2025-03-19T22:45:20.997Z","updated_at":"2025-03-19T22:45:21.594Z","avatar_url":"https://github.com/mrizaln.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# circbuf\n\nA simple C++ circular buffer written in C++20\n\n## Usage\n\n\u003e `CMakeLists.txt`\n\n```cmake\ncmake_minimum_required(VERSION 3.14)\n\ninclude(FetchContent)\n\nFetchContent_Declare(\n  circbuf\n  GIT_REPOSITORY https://github.com/mrizaln/circbuf\n  GIT_TAG main)\nFetchContent_MakeAvailable(circbuf)\n\nadd_executable(main main.cpp)\ntarget_link_libraries(main PRIVATE circbuf)\n```\n\n\u003e `main.cpp`\n\n```cpp\n#include \u003ccircbuf/circbuf.hpp\u003e\n\n#include \u003ciostream\u003e\n#include \u003cranges\u003e\n#include \u003cstring\u003e\n\nusing circbuf::CircBuf;\n\nint main()\n{\n    // you specify the capacity of the buffer at construction (can be resized later)\n    auto queue = CircBuf\u003cstd::string\u003e{ 12 };\n\n    // pushing from the back\n    for (auto i : std::views::iota(0, 256)) {\n        queue.push_back(std::format(\"{0:0b}|{0}\", i));\n    }\n\n    // pushing from the front\n    queue.push_front(\"hello\");\n    queue.push_front(\"world\");\n\n    // you can iterate the CircBuf from head to tail\n    for (const auto\u0026 value : queue | std::views::reverse) {    // i reverse the iterator here\n        std::cout \u003c\u003c value \u003c\u003c '\\n';\n    }\n\n    // CircBuf implements a random access iterator, so you should be able to access it like an array\n    auto mid = queue.remove(6);\n    std::cout \u003c\u003c \"\u003e\u003e\u003e mid: \" \u003c\u003c mid \u003c\u003c '\\n';\n\n    std::cout \u003c\u003c \"------------\\n\";\n    for (const auto\u0026 value : queue) {\n        std::cout \u003c\u003c value \u003c\u003c '\\n';\n    }\n}\n```\n\n### Buffer policy\n\nYou can set the behavior of the circular buffer between two options\n\n- `ReplaceOnFull`: replace the head with new value if `push_back` is called and replace the tail with new value if `push_front` is called (default).\n- `ThrowOnFull`: this will throw an error when a push/insert is done into a full buffer, you must `pop_front`/`pop_back` first before adding new item.\n\n```cpp\nauto buf = CircBuf\u003cint\u003e{ 42 };                              // use ReplaceOnFull by default\nbuf.policy() = BufferPolicy::ThrowOnFull;                   // change the policy after construction\n\nauto buf2 = CircBuf\u003cint\u003e{ 42, BufferPolicy::ThrowOnFull }   // set to other policy on construction\n\n\n```\n\n### Accessing underlying buffer\n\n`circbuf::CircBuf` is an array under the hood, so you should be able to see its underlying array. The caveat is that you should only access the underlying buffer if the buffer itself is said to be **_full_** and/or **_linearized_**.\n\nThe underlying buffer can be accessed using the member function `data()`, which will return an `std::span`.\n\n\u003e - If you managed to access the non-linearized underlying data or read past the last element of the buffer while the buffer itself is not full, you will read an **uninitialized** memory.\n\u003e - In my testing, there will be no assertion error or core dump.\n\u003e - That's why I provided a check in the `data()` function to avoid this scenario.\n\u003e - The behavior when the check failed is an exception of type `std::logic_error`.\n\n- Full: the number of elements inside the buffer is equal to its capacity\n\n  ```cpp\n  int main() {\n      auto queue = CircBuf\u003cint\u003e{ 12 };\n\n      for (auto i : std::views::iota(0, 2373)) {\n          queue.push_back(i);\n      }\n      assert(queue.full());\n\n      // if you want the data to be whatever in order in the underlying buffer, then just skip linearize\n      auto raw = queue.data();\n\n      // you need to linearize your buffer if you want to access it from head to tail\n      auto buf = queue.linearize().data();\n  }\n  ```\n\n- Linearized: when the head of the buffer is at the start of the buffer, it is said that the buffer is linearized\n\n  ```cpp\n  int main() {\n      auto queue = CircBuf\u003cint\u003e{ 12 };\n\n      for (auto i : std::ranges::iota(0, 14)) {\n          queue.push_back(i);\n      }\n      assert(not queue.empty());\n\n      auto span = queue.linearize().data();\n      assert(queue.linearized());\n\n      queue.pop_front();\n      queue.pop_front();\n\n      // linearize() function is in-place, use the copy ctor to make a copy instead (policy inherited)\n      auto copy = queue;\n      assert(copy.linearized());\n\n      // or linearize_copy() to make a copy instead, you can change the policy here\n      auto copy2 = queue.linearize_copy(circbuf::BufferPolicy::ThrowOnFull);\n      assert(copy2.linearized());\n\n      assert(copy.policy() == queue.policy());\n      assert(copy.policy() != copy2.policy());\n  }\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrizaln%2Fcircbuf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrizaln%2Fcircbuf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrizaln%2Fcircbuf/lists"}