Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/circularbuffer_build_pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Build and Test

on: [push]

env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release

jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally
# well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: cmake -E make_directory ${{github.workspace}}/build

- name: Configure CMake
# Use a bash shell so we can use the same syntax for environment variable
# access regardless of the host operating system
shell: bash
working-directory: ${{github.workspace}}/build
# Note the current convention is to use the -S and -B options here to specify source
# and build directories, but this is only available with CMake 3.13 and higher.
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE

- name: Build
working-directory: ${{github.workspace}}/build
shell: bash
# Execute the build. You can specify a specific target with "--target <NAME>"
run: cmake --build . --config $BUILD_TYPE

- name: Test
working-directory: ${{github.workspace}}/build
shell: bash
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C $BUILD_TYPE
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,33 @@
#A simple, general purpose STL style circular buffer in C++
CircularBuffer
===========

[![Actions Status](https://github.com/vinitjames/circularbuffer_CPP/workflows/Build%20and%20Test/badge.svg)](https://github.com/vinitjames/circularbuffer_CPP/actions) &nbsp; [![MIT License](https://img.shields.io/github/license/vinitjames/circularbuffer?color=blue)](https://github.com/vinitjames/circularbuffer/blob/master/LICENSE)
## About
circularbuffer_CPP is a simple, general purpose STL style [circularbuffer](https://en.wikipedia.org/wiki/Circular_buffer) implementation in C++.


## Features
* STL style implementaion of Circular Buffer
* Lightweight (only single header file)
* Simple API conforming to STL container semantics.
* Random Access Iterator for easy forwad and reverse iteration and looping through elements.
* Test suites

## Installation
Run:
```
git clone https://github.com/vinitjames/circularbuffer_CPP.git
```
## Without CMAKE
copy circular_buffer.h to your project

## With CMAKE
To locally build and run test run the following commands
```sh
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build .
$ ctest
```
To include in project as a submodule just clone the repo in a subdirectory and use `add_subdirectory()` in the top level `CMakeLists.txt`
67 changes: 47 additions & 20 deletions circular_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,10 @@ class CircularBuffer {
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template <bool isConst>
struct BufferIterator;
typedef BufferIterator<false> iterator;
typedef BufferIterator<true> const_iterator;
template <bool isConst> struct BufferIterator;


public:

explicit CircularBuffer(size_t size)
:_buff{std::unique_ptr<T[]>(new value_type[size])}, _max_size{size}{}

Expand Down Expand Up @@ -104,10 +101,15 @@ class CircularBuffer {
const_reference at(size_type index) const;
reference at(size_type index);

typedef BufferIterator<false> iterator;
typedef BufferIterator<true> const_iterator;

iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;

private:
void _increment_bufferstate();
Expand All @@ -127,14 +129,15 @@ class CircularBuffer {
typedef std::random_access_iterator_tag iterator_type;
typedef typename std::conditional<isConst, const value_type&, value_type&>::type reference;
typedef typename std::conditional<isConst, const value_type*, value_type*>::type pointer;
typedef CircularBuffer* cbuf_pointer;
typedef typename std::conditional<isConst, const CircularBuffer<value_type>*,
CircularBuffer<value_type>*>::type cbuf_pointer;

cbuf_pointer _ptrToBuffer;
size_type _offset;
size_type _index;
bool _reverse;

bool _comparable(const BufferIterator& other){
bool _comparable(const BufferIterator<isConst>& other) const{
return (_ptrToBuffer == other._ptrToBuffer)&&(_reverse == other._reverse);
}

Expand Down Expand Up @@ -191,6 +194,7 @@ class CircularBuffer {
rhsiter._index += n;
return rhsiter;
}


BufferIterator& operator+=(difference_type n){
_index += n;
Expand All @@ -207,37 +211,37 @@ class CircularBuffer {
return *this;
}

bool operator==(const BufferIterator& other){
bool operator==(const BufferIterator& other) const{
if (!_comparable(other))
return false;
return ((_index == other._index)&&(_offset == other._offset));
}

bool operator!=(const BufferIterator& other){
bool operator!=(const BufferIterator& other) const{
if (!_comparable(other))
return true;
return ((_index != other._index)||(_offset != other._offset));
}

bool operator<(const BufferIterator& other){
bool operator<(const BufferIterator& other) const {
if (!_comparable(other))
return false;
return ((_index + _offset)<(other._index+other._offset));
}

bool operator>(const BufferIterator& other){
bool operator>(const BufferIterator& other) const{
if (!_comparable(other))
return false;
return ((_index + _offset)>(other._index+other._offset));
}

bool operator<=(const BufferIterator& other){
bool operator<=(const BufferIterator& other) const {
if (!_comparable(other))
return false;
return ((_index + _offset)<=(other._index+other._offset));
}

bool operator>=(const BufferIterator& other){
bool operator>=(const BufferIterator& other) const {
if (!_comparable(other))
return false;
return ((_index + _offset)>=(other._index+other._offset));
Expand Down Expand Up @@ -268,7 +272,7 @@ template<typename T>
inline
void CircularBuffer<T>::clear(){
std::lock_guard<std::mutex> _lck(_mtx);
_head = _tail = _size = _max_size = 0;
_head = _tail = _size = 0;
}

template<typename T>
Expand Down Expand Up @@ -363,8 +367,8 @@ template<typename T>
inline
typename CircularBuffer<T>::reference CircularBuffer<T>::operator[](size_t index) {
std::lock_guard<std::mutex> _lck(_mtx);
if((index<0)||(index>=_max_size))
throw std::out_of_range("Index is out of Range of buffer capacity");
if((index<0)||(index>=_size))
throw std::out_of_range("Index is out of Range of buffer size");
index += _tail;
index %= _max_size;
return _buff[index];
Expand All @@ -374,8 +378,8 @@ template<typename T>
inline
typename CircularBuffer<T>::const_reference CircularBuffer<T>::operator[](size_t index) const {
std::lock_guard<std::mutex> _lck(_mtx);
if((index<0)||(index>=_max_size))
throw std::out_of_range("Index is out of Range of buffer capacity");
if((index<0)||(index>=_size))
throw std::out_of_range("Index is out of Range of buffer size");
index += _tail;
index %= _max_size;
return _buff[index];
Expand Down Expand Up @@ -419,7 +423,7 @@ template<typename T>
inline
typename CircularBuffer<T>::const_iterator CircularBuffer<T>::begin() const{
std::lock_guard<std::mutex> _lck(_mtx);
iterator iter;
const_iterator iter;
iter._ptrToBuffer = this;
iter._offset = _tail;
iter._index = 0;
Expand All @@ -443,12 +447,35 @@ template<typename T>
inline
typename CircularBuffer<T>::const_iterator CircularBuffer<T>::end() const{
std::lock_guard<std::mutex> _lck(_mtx);
iterator iter;
const_iterator iter;
iter._ptrToBuffer = this;
iter._offset = _tail;
iter._index = _size;
iter._reverse = false;
return iter;
}

template<typename T>
inline
typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cbegin() const noexcept{
std::lock_guard<std::mutex> _lck(_mtx);
const_iterator iter;
iter._ptrToBuffer = this;
iter._offset = _tail;
iter._index = 0;
iter._reverse = false;
return iter;
}

template<typename T>
inline
typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cend() const noexcept{
std::lock_guard<std::mutex> _lck(_mtx);
const_iterator iter;
iter._ptrToBuffer = this;
iter._offset = _tail;
iter._index = _size;
iter._reverse = false;
return iter;
}
#endif /* CIRCULAR_BUFFER_H */
15 changes: 12 additions & 3 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,18 @@ add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)

add_executable(circularbuffer_int circularbuffer_int.cpp)
target_link_libraries(circularbuffer_int
add_executable(int_buffer int_buffer.cpp)
target_link_libraries(int_buffer
circularbuffer
gtest_main
)
add_test(NAME test_circularbuffer_int COMMAND circularbuffer_int)
add_test(NAME test_int_buffer COMMAND int_buffer)

add_executable(string_buffer string_buffer.cpp)
target_link_libraries(string_buffer
circularbuffer
gtest_main
)
add_test(NAME test_string_buffer COMMAND string_buffer)


1 change: 1 addition & 0 deletions tests/circularbuffer_int.cpp → tests/int_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ TEST_F(CircularBufferTest, PushAndPopTest){
test.push_back(i);
EXPECT_EQ(TEST_BUFFER_SIZE, test.size());
EXPECT_EQ(test.size(), test.capacity());

for(int i=0; i<TEST_BUFFER_SIZE - 1; i++)
test.pop_front();
EXPECT_EQ(1, test.size());
Expand Down
Loading