From ce9d00067346ad4c2d88427daee3a82693170088 Mon Sep 17 00:00:00 2001 From: Ferdinand Bachmann Date: Sat, 18 Apr 2020 11:36:18 +0200 Subject: [PATCH] initial import --- .gitignore | 1 + CMakeLists.txt | 18 +++ include/ring-buffer.h | 268 ++++++++++++++++++++++++++++++++++++++++++ test.cpp | 0 test/CMakeLists.txt | 33 ++++++ test/simple.cpp | 25 ++++ 6 files changed, 345 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 include/ring-buffer.h create mode 100644 test.cpp create mode 100644 test/CMakeLists.txt create mode 100644 test/simple.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..077e840 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.14) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +project(test-project CXX) + +option(RING_BUFFER_BUILD_TESTS "build test cases for the ring buffer library" ON) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +add_library(ring-buffer INTERFACE) +target_include_directories(ring-buffer INTERFACE include/) + +if(RING_BUFFER_BUILD_TESTS) + add_subdirectory(test) +endif() diff --git a/include/ring-buffer.h b/include/ring-buffer.h new file mode 100644 index 0000000..e291055 --- /dev/null +++ b/include/ring-buffer.h @@ -0,0 +1,268 @@ +#include +#include +#include + +template +class ring_buffer_iterator { +private: + using size_type = typename Container::size_type; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using reference = typename std::iterator_traits::reference; + using pointer = typename std::iterator_traits::pointer; + + Container* container; + size_type front; + size_type index; + +public: + ring_buffer_iterator() = default; + ~ring_buffer_iterator() = default; + ring_buffer_iterator(Container& container, size_type front = 0, size_type index = 0) : container(&container), front(front), index(index) {} + ring_buffer_iterator(const ring_buffer_iterator&) = default; + ring_buffer_iterator(ring_buffer_iterator&&) = default; + ring_buffer_iterator& operator=(const ring_buffer_iterator&) = default; + ring_buffer_iterator& operator=(ring_buffer_iterator&&) = default; + + ring_buffer_iterator& operator+=(difference_type n) { + index += n; + } + ring_buffer_iterator& operator-=(difference_type n) { + index -= n; + } + + ring_buffer_iterator operator+(difference_type n) const { + return {container, front, index + n}; + } + ring_buffer_iterator operator-(difference_type n) const { + return {container, front, index - n}; + } + + reference operator*() { + return *(container->begin() + (front + index) % container->size()); + } + pointer operator->() { + return &**this; + } + reference operator[](difference_type n) { + return *(*this + n); + } + + ring_buffer_iterator& operator++() { + index++; + return *this; + } + ring_buffer_iterator operator++(int) { + ring_buffer_iterator old = *this; + *this++; + return old; + } + ring_buffer_iterator& operator--() { + index--; + return *this; + } + ring_buffer_iterator operator--(int) { + ring_buffer_iterator old = *this; + *this--; + return old; + } + + bool operator==(const ring_buffer_iterator& other) const { + return index == other.index; + } + bool operator!=(const ring_buffer_iterator& other) const { + return index != other.index; + } + + bool operator<(const ring_buffer_iterator& other) const { + return index < other.index; + } + bool operator>(const ring_buffer_iterator& other) const { + return index > other.index; + } + bool operator<=(const ring_buffer_iterator& other) const { + return index <= other.index; + } + bool operator>=(const ring_buffer_iterator& other) const { + return index >= other.index; + } + + friend ring_buffer_iterator operator+( difference_type n, const ring_buffer_iterator& it) { + return it + n; + } + friend void swap(ring_buffer_iterator& a, ring_buffer_iterator& b) { + using std::swap; + swap(a.container, b.container); + swap(a.front, b.front); + swap(a.index, b.index); + } +}; + +template +class ring_buffer_const_iterator { +private: + using size_type = typename Container::size_type; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using reference = typename std::iterator_traits::reference; + using pointer = typename std::iterator_traits::pointer; + + const Container* container; + size_type front{}; + size_type index{}; + +public: + ring_buffer_const_iterator() = default; + ~ring_buffer_const_iterator() = default; + ring_buffer_const_iterator(const Container& container, size_type front = 0, size_type index = 0) : container(&container), front(front), index(index) {} + ring_buffer_const_iterator(const ring_buffer_const_iterator&) = default; + ring_buffer_const_iterator(ring_buffer_const_iterator&&) = default; + ring_buffer_const_iterator& operator=(const ring_buffer_const_iterator&) = default; + ring_buffer_const_iterator& operator=(ring_buffer_const_iterator&&) = default; + + ring_buffer_const_iterator& operator+=(difference_type n) { + index += n; + } + ring_buffer_const_iterator& operator-=(difference_type n) { + index -= n; + } + + ring_buffer_const_iterator operator+(difference_type n) const { + return {container, front, index + n}; + } + ring_buffer_const_iterator operator-(difference_type n) const { + return {container, front, index - n}; + } + + reference operator*() const { + return *(container->begin() + (front + index) % container->size()); + } + pointer operator->() const { + return &**this; + } + reference operator[](difference_type n) const { + return *(*this + n); + } + + ring_buffer_const_iterator& operator++() { + index++; + return *this; + } + ring_buffer_const_iterator operator++(int) { + ring_buffer_const_iterator old = *this; + *this++; + return old; + } + ring_buffer_const_iterator& operator--() { + index--; + return *this; + } + ring_buffer_const_iterator operator--(int) { + ring_buffer_const_iterator old = *this; + *this--; + return old; + } + + bool operator==(const ring_buffer_const_iterator& other) const { + return index == other.index; + } + bool operator!=(const ring_buffer_const_iterator& other) const { + return index != other.index; + } + + bool operator<(const ring_buffer_const_iterator& other) const { + return index < other.index; + } + bool operator>(const ring_buffer_const_iterator& other) const { + return index > other.index; + } + bool operator<=(const ring_buffer_const_iterator& other) const { + return index <= other.index; + } + bool operator>=(const ring_buffer_const_iterator& other) const { + return index >= other.index; + } + + friend ring_buffer_const_iterator operator+( difference_type n, const ring_buffer_const_iterator& it) { + return it + n; + } + friend void swap(ring_buffer_const_iterator& a, ring_buffer_const_iterator& b) { + using std::swap; + swap(a.container, b.container); + swap(a.front, b.front); + swap(a.index, b.index); + } +}; + +template +class basic_ring_buffer { +public: + using value_type = typename Container::value_type; + using size_type = typename Container::size_type; + using iterator = ring_buffer_iterator; + using const_iterator = ring_buffer_const_iterator; + +private: + Container container; + size_type front_index{}; + +public: + basic_ring_buffer() noexcept = default; + ~basic_ring_buffer() noexcept = default; + basic_ring_buffer(const basic_ring_buffer& other) = default; + basic_ring_buffer(basic_ring_buffer&& other) = default; + basic_ring_buffer& operator=(const basic_ring_buffer& other) = default; + basic_ring_buffer& operator=(basic_ring_buffer&& other) = default; + + Container& buffer() { + return container; + } + const Container& buffer() const { + return container; + } + + void push_back(const value_type& value) { + container[front_index] = value; + front_index = (front_index + 1) % container.size(); + } + + iterator begin() { + return {container, front_index, 0}; + } + iterator end() { + return {container, front_index, container.size()}; + } + + const_iterator cbegin() const { + return {container, front_index, 0}; + } + const_iterator cend() const { + return {container, front_index, container.size()}; + } +}; + +namespace std { + template + class iterator_traits> { + public: + using difference_type = typename std::make_signed::type; + using value_type = typename Container::value_type; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::random_access_iterator_tag; + }; + + template + class iterator_traits> { + public: + using difference_type = typename std::make_signed::type; + using value_type = const typename Container::value_type; + using pointer = const value_type*; + using reference = const value_type&; + using iterator_category = std::random_access_iterator_tag; + }; +} + +#include +template +using ring_buffer = basic_ring_buffer>; diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..e69de29 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..1f1dd51 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,33 @@ +set(test-targets "") + +file(GLOB test-sources *.cpp) +foreach(test-source ${test-sources}) + get_filename_component(test-name ${test-source} NAME_WE) + set(test-target test-${test-name}) + list(APPEND test-targets ${test-target}) + + add_executable(${test-target} ${test-source}) + target_link_libraries(${test-target} PRIVATE ring-buffer) +endforeach() + +file(GLOB test-directories *) +foreach(test-directory ${test-directories}) + if(NOT IS_DIRECTORY ${test-directory}) + continue() + endif() + + set(test-name ${test-directory}) + set(test-target test-${test-name}) + list(APPEND test-targets ${test-target}) + + if(IS_DIRECTORY ${test-directory}/src) + file(GLOB_RECURSE test-directory-sources ${test-directory}/src/*.cpp) + else() + file(GLOB test-directory-sources ${test-directory}/*.cpp) + endif() + add_executable(${test-target} ${test-directory-sources}) + if(IS_DIRECTORY ${test-directory}/include) + target_include_directories(${test-target} PRIVATE ${test-directory}/include) + endif() + target_link_libraries(${test-target} PRIVATE ring-buffer) +endforeach() diff --git a/test/simple.cpp b/test/simple.cpp new file mode 100644 index 0000000..08f44ce --- /dev/null +++ b/test/simple.cpp @@ -0,0 +1,25 @@ +#include +#include + +int main() { + ring_buffer buf; + + buf.push_back(1); + buf.push_back(2); + buf.push_back(3); + buf.push_back(4); + buf.push_back(5); + buf.push_back(6); + + std::cout << "before\n"; + for (int& i : buf) { + std::cout << i << "\n"; + } + + buf.push_back(7); + + std::cout << "after\n"; + for (int& i : buf) { + std::cout << i << "\n"; + } +}