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
6 changes: 4 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(${PROJECT_NAME} INTERFACE)

target_include_directories(${PROJECT_NAME} INTERFACE ${${PROJECT_NAME}_SOURCE_DIR})

enable_testing()
add_subdirectory(samples)
add_subdirectory(tests)

add_subdirectory(samples)

install(TARGETS circularbuffer DESTINATION lib)
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 Vinit James

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
70 changes: 59 additions & 11 deletions circular_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <memory>
#include <iterator>
#include <type_traits>
#include <algorithm>

template<typename T>
class CircularBuffer {
Expand All @@ -28,6 +29,24 @@ class CircularBuffer {
explicit CircularBuffer(size_t size)
:_buff{std::unique_ptr<T[]>(new T[size])}, _max_size{size}{}

CircularBuffer(const CircularBuffer& other)
:_buff{std::unique_ptr<T[]>(new T[other.capacity()])},
_max_size{other.capacity()},
_size{other._size},
_head{other._head},
_tail{other._tail},
_full{other._full}{

std::copy(other.data(), other.data() + _max_size, _buff.get());
}

CircularBuffer& operator=(const CircularBuffer& other){
_buff = std::unique_ptr<T[]>(new T[other.capacity()]);
_max_size = other.capacity();
std::copy(other.data(), other.data() + _max_size, _buff.get());
return *this;
}

void push_back(const value_type& data);
void pop_front();
reference front();
Expand All @@ -40,8 +59,12 @@ class CircularBuffer {
size_type capacity() const ;
size_type size() const;
size_type buffer_size() const {return sizeof(T)*_max_size;};
const_pointer data() const { return _buff.get(); }

const_reference operator[](size_type index) const;
reference operator[](size_type index);
const_reference at(size_type index) const;
reference at(size_type index);

iterator begin();
const_iterator begin() const;
Expand All @@ -53,6 +76,7 @@ class CircularBuffer {
void _decrement_bufferstate();
mutable std::mutex _mtx;
std::unique_ptr<T[]> _buff;

size_type _head = 0;
size_type _tail = 0;
size_type _size = 0;
Expand Down Expand Up @@ -234,7 +258,8 @@ typename CircularBuffer<T>::reference CircularBuffer<T>::back() {
std::lock_guard<std::mutex> _lck(_mtx);
if(empty())
throw std::length_error("back function called on empty buffer");
return _buff[_head-1];
//return _buff[_head - 1];
return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
}

template<typename T>
Expand All @@ -252,14 +277,15 @@ typename CircularBuffer<T>::const_reference CircularBuffer<T>::back() const{
std::lock_guard<std::mutex> _lck(_mtx);
if(empty())
throw std::length_error("back function called on empty buffer");
return _buff[_head - 1];
//return _buff[_head - 1];
return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
}

template<typename T>
void CircularBuffer<T>::push_back(const T& data){
std::lock_guard<std::mutex> _lck(_mtx);
if(full())
_buff[_head].~T();
//if(full())
// _buff[_tail].~T();
_buff[_head] = data;
_increment_bufferstate();
}
Expand All @@ -271,32 +297,31 @@ void CircularBuffer<T>::_increment_bufferstate(){
_tail = (_tail + 1)%_max_size;
else
++_size;
_head = (_head + 1)%_max_size;
_full = (_head == _tail);
_head = (_head + 1)%_max_size;
}

template<typename T>
inline
void CircularBuffer<T>::pop_front(){
std::lock_guard<std::mutex> _lck(_mtx);
if(empty())
throw std::length_error("pop_back called on empty buffer");
throw std::length_error("pop_front called on empty buffer");
_decrement_bufferstate();
}

template<typename T>
inline
void CircularBuffer<T>::_decrement_bufferstate(){
//_full = false;
--_size;
_tail = (_tail + 1)%_max_size;
}

template<typename T>
inline
typename CircularBuffer<T>::reference CircularBuffer<T>::operator[](size_t index) {
if((index<0)||(index>_max_size))
throw std::out_of_range("Index is out of Range of buffer size");
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");
index += _tail;
index %= _max_size;
return _buff[index];
Expand All @@ -305,7 +330,30 @@ typename CircularBuffer<T>::reference CircularBuffer<T>::operator[](size_t index
template<typename T>
inline
typename CircularBuffer<T>::const_reference CircularBuffer<T>::operator[](size_t index) const {
if((index<0)||(index>_max_size))
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");
index += _tail;
index %= _max_size;
return _buff[index];
}

template<typename T>
inline
typename CircularBuffer<T>::reference CircularBuffer<T>::at(size_t index) {
std::lock_guard<std::mutex> _lck(_mtx);
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];
}

template<typename T>
inline
typename CircularBuffer<T>::const_reference CircularBuffer<T>::at(size_t index) const {
std::lock_guard<std::mutex> _lck(_mtx);
if((index<0)||(index>=_size))
throw std::out_of_range("Index is out of Range of buffer size");
index += _tail;
index %= _max_size;
Expand Down
6 changes: 6 additions & 0 deletions samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ target_link_libraries(sample_circularbuffer
PRIVATE
circularbuffer
)

add_executable(sample_stringbuffer sample_stringbuffer.cpp)
target_link_libraries(sample_stringbuffer
PRIVATE
circularbuffer
)
38 changes: 33 additions & 5 deletions samples/sample_circularbuffer.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#include "circular_buffer.h"
#include <iostream>
#include <string.h>
#include "gtest/gtest.h"

#include "circular_buffer.h"
#include <iostream>
#include <string.h>
Expand All @@ -13,7 +11,8 @@ struct test_struct{
test_struct(){
bytes = (char*)malloc(100);
std::cout<<"constructing test_struct: "<<count++<<"\n";
}
}

test_struct(const test_struct& other){
bytes = (char*)malloc(100);
memcpy(bytes, other.bytes,100);
Expand All @@ -28,9 +27,12 @@ struct test_struct{
}

~test_struct(){
std::cout<<"destructing test_struct"<<--count<<"\n";
free(bytes);
}

friend std::ostream& operator<<(std::ostream& os, const test_struct& ts){
return os<<"\ntest";
}


};
Expand Down Expand Up @@ -90,14 +92,34 @@ int main(int argc, char *argv[])
std::cout<<"Checking deference ++ operator "<<*(++it)<<"\n";
std::cout<<"Checking deference -- operator "<<*(--it)<<"\n";


std::cout<<"Checking iterator for loop \n";
for(auto it:test_stringbuf)
std::cout<<"Checking for loop function "<<it<<"\n";

std::cout<<"Checking for loop with iterator \n";
for(auto it = test_stringbuf.begin(); it != test_stringbuf.end(); it++)
std::cout<<"Checking for loop function "<<*it<<"\n";

CircularBuffer<test_struct> test_structbuf{5};
std::cout<<"Checking [] operator"<<test_structbuf[0]<<"\n";

auto temp_struct = test_struct();

test_structbuf.push_back(temp_struct);
std::cout<<"Checking [] operator"<<test_structbuf[1]<<"\n";
std::cout<<"Checking at operator"<<test_structbuf.at(0)<<"\n";

test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(1)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(2)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(3)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(4)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(0)<<"\n";
test_structbuf.push_back(temp_struct);
test_structbuf.push_back(temp_struct);
test_structbuf.push_back(temp_struct);
Expand All @@ -106,8 +128,14 @@ int main(int argc, char *argv[])

test_structbuf.pop_front();


CircularBuffer<std::string> test_stringbufcopy{test_stringbuf};
std::cout<<"Checking maxsize of copy buffer"<<test_stringbufcopy.capacity()<<"\n";
std::cout<<"Checking size of copy buffer"<<test_stringbufcopy.size()<<"\n";
std::cout<<"Checking [] in copybuffer"<<test_stringbufcopy[1]<<"\n";
std::cout<<"Checking maxsize buffer"<<test_stringbuf.capacity()<<"\n";
std::cout<<"Checking size buffer"<<test_stringbuf.size()<<"\n";
return 0;
}



107 changes: 107 additions & 0 deletions samples/sample_stringbuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "circular_buffer.h"
#include <iostream>
#include <string.h>
#include "circular_buffer.h"
#include <iostream>
#include <string.h>

int main(int argc, char *argv[])
{

CircularBuffer<int> test{5};
//std::cout<<"size of data "<<sizeof(data[1].bytes)<<"\n";
std::cout<<"length of buffer "<<test.size()<<"\n";
std::cout<<"size of buffer in bytes "<<test.buffer_size()<<"\n";
std::cout<<"Max capacity of buffer "<<test.capacity()<<"\n";
std::cout<<"Checking is buffer empty function "<<test.empty()<<"\n";
std::cout<<"Pushing back data in bufffer \n";
for(int i = 0; i<100;i++){
test.push_back(i);
std::cout<<"Pushing back i"<<std::endl;
}

CircularBuffer<std::string> test_stringbuf{10};
std::cout<<"Checking is buffer empty function "<<test_stringbuf.empty()<<"\n";
std::cout<<"Checking length of string buffer "<<test_stringbuf.size()<<"\n";
std::cout<<"size of buffer in bytes "<<test_stringbuf.buffer_size()<<"\n";
std::cout<<"Max capacity of buffer "<<test_stringbuf.capacity()<<"\n";

for(int i = 0; i<10;i++){
test_stringbuf.push_back("this is a string" + std::to_string(i));
std::cout<<"Pushing back string "<<i<<std::endl;
}

std::cout<<"Checking is buffer empty function "<<test_stringbuf.empty()<<"\n";
std::cout<<"Checking length of buffer after modification "<<test_stringbuf.size()<<"\n";
std::cout<<"Checking front function "<<test_stringbuf.front()<<"\n";
std::cout<<"Checking back function "<<test_stringbuf.back()<<"\n";

for(int i = 0; i<7;i++){
test_stringbuf.pop_front();
std::cout<<"Poping "<<i<<std::endl;
}

std::cout<<"Checking is buffer empty function "<<test_stringbuf.empty()<<"\n";
std::cout<<"Checking length of buffer after modification "<<test_stringbuf.size()<<"\n";
std::cout<<"Checking front function "<<test_stringbuf.front()<<"\n";
std::cout<<"Checking back function "<<test_stringbuf.back()<<"\n";
/*
//test_stringbuf.pop_front();
std::cout<<"Checking length of buffer after modification "<<test_stringbuf.size()<<"\n";
std::cout<<"Checking front function "<<test_stringbuf.front()<<"\n";
std::cout<<"Checking back function "<<test_stringbuf.back()<<"\n";

/*
std::cout<<"Checking iterator function\n";
auto it = test_stringbuf.begin();

std::cout<<"Checking deference * operator "<<*it<<"\n";
std::cout<<"Checking deference ++ operator "<<*(++it)<<"\n";
std::cout<<"Checking deference -- operator "<<*(--it)<<"\n";


std::cout<<"Checking iterator for loop \n";
for(auto it:test_stringbuf)
std::cout<<"Checking for loop function "<<it<<"\n";

std::cout<<"Checking for loop with iterator \n";
for(auto it = test_stringbuf.begin(); it != test_stringbuf.end(); it++)
std::cout<<"Checking for loop function "<<*it<<"\n";

CircularBuffer<test_struct> test_structbuf{5};
std::cout<<"Checking [] operator"<<test_structbuf[0]<<"\n";

auto temp_struct = test_struct();

test_structbuf.push_back(temp_struct);
std::cout<<"Checking [] operator"<<test_structbuf[1]<<"\n";
std::cout<<"Checking at operator"<<test_structbuf.at(0)<<"\n";

test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(1)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(2)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(3)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(4)<<"\n";
test_structbuf.push_back(temp_struct);
std::cout<<"Checking at operator"<<test_structbuf.at(0)<<"\n";
test_structbuf.push_back(temp_struct);
test_structbuf.push_back(temp_struct);
test_structbuf.push_back(temp_struct);
test_structbuf.push_back(temp_struct);


test_structbuf.pop_front();

CircularBuffer<std::string> test_stringbufcopy{test_stringbuf};
std::cout<<"Checking maxsize of copy buffer"<<test_stringbufcopy.capacity()<<"\n";
std::cout<<"Checking size of copy buffer"<<test_stringbufcopy.size()<<"\n";
std::cout<<"Checking [] in copybuffer"<<test_stringbufcopy[1]<<"\n";
std::cout<<"Checking maxsize buffer"<<test_stringbuf.capacity()<<"\n";
std::cout<<"Checking size buffer"<<test_stringbuf.size()<<"\n";
*/
std::cout<<"end is reached"<<std::endl;
return 0;
}
Loading