diff --git a/CMakeLists.txt b/CMakeLists.txt index d46a70f..1eb36ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7dd3624 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/circular_buffer.h b/circular_buffer.h index 8b9033f..0ce1fcd 100644 --- a/circular_buffer.h +++ b/circular_buffer.h @@ -6,6 +6,7 @@ #include #include #include +#include template class CircularBuffer { @@ -28,6 +29,24 @@ class CircularBuffer { explicit CircularBuffer(size_t size) :_buff{std::unique_ptr(new T[size])}, _max_size{size}{} + CircularBuffer(const CircularBuffer& other) + :_buff{std::unique_ptr(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(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(); @@ -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; @@ -53,6 +76,7 @@ class CircularBuffer { void _decrement_bufferstate(); mutable std::mutex _mtx; std::unique_ptr _buff; + size_type _head = 0; size_type _tail = 0; size_type _size = 0; @@ -234,7 +258,8 @@ typename CircularBuffer::reference CircularBuffer::back() { std::lock_guard _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 @@ -252,14 +277,15 @@ typename CircularBuffer::const_reference CircularBuffer::back() const{ std::lock_guard _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 void CircularBuffer::push_back(const T& data){ std::lock_guard _lck(_mtx); - if(full()) - _buff[_head].~T(); + //if(full()) + // _buff[_tail].~T(); _buff[_head] = data; _increment_bufferstate(); } @@ -271,8 +297,7 @@ void CircularBuffer::_increment_bufferstate(){ _tail = (_tail + 1)%_max_size; else ++_size; - _head = (_head + 1)%_max_size; - _full = (_head == _tail); + _head = (_head + 1)%_max_size; } template @@ -280,14 +305,13 @@ inline void CircularBuffer::pop_front(){ std::lock_guard _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 inline void CircularBuffer::_decrement_bufferstate(){ - //_full = false; --_size; _tail = (_tail + 1)%_max_size; } @@ -295,8 +319,9 @@ void CircularBuffer::_decrement_bufferstate(){ template inline typename CircularBuffer::reference CircularBuffer::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 _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]; @@ -305,7 +330,30 @@ typename CircularBuffer::reference CircularBuffer::operator[](size_t index template inline typename CircularBuffer::const_reference CircularBuffer::operator[](size_t index) const { - if((index<0)||(index>_max_size)) + std::lock_guard _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 +inline +typename CircularBuffer::reference CircularBuffer::at(size_t index) { + std::lock_guard _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 +inline +typename CircularBuffer::const_reference CircularBuffer::at(size_t index) const { + std::lock_guard _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; diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 095cb21..34ae026 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -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 + ) diff --git a/samples/sample_circularbuffer.cpp b/samples/sample_circularbuffer.cpp index 76c3053..8244114 100644 --- a/samples/sample_circularbuffer.cpp +++ b/samples/sample_circularbuffer.cpp @@ -1,8 +1,6 @@ #include "circular_buffer.h" #include #include -#include "gtest/gtest.h" - #include "circular_buffer.h" #include #include @@ -13,7 +11,8 @@ struct test_struct{ test_struct(){ bytes = (char*)malloc(100); std::cout<<"constructing test_struct: "< test_structbuf{5}; + std::cout<<"Checking [] operator"< test_stringbufcopy{test_stringbuf}; + std::cout<<"Checking maxsize of copy buffer"< +#include +#include "circular_buffer.h" +#include +#include + +int main(int argc, char *argv[]) +{ + + CircularBuffer test{5}; + //std::cout<<"size of data "< test_stringbuf{10}; + std::cout<<"Checking is buffer empty function "< test_structbuf{5}; + std::cout<<"Checking [] operator"< test_stringbufcopy{test_stringbuf}; + std::cout<<"Checking maxsize of copy buffer"< #include "gtest/gtest.h" +#define TEST_BUFFER_SIZE 100 class CircularBufferTest : public ::testing::Test{ protected: - CircularBuffer test{5}; + CircularBuffer test{TEST_BUFFER_SIZE}; }; TEST_F(CircularBufferTest, CapacityTest){ - EXPECT_EQ(5, test.capacity()); + EXPECT_EQ(TEST_BUFFER_SIZE, test.capacity()); EXPECT_FALSE(test.capacity() == 0); } @@ -24,7 +25,14 @@ TEST_F(CircularBufferTest, EmptyTest){ EXPECT_FALSE(test.empty()); test.pop_front(); test.pop_front(); - EXPECT_TRUE(test.empty()); + EXPECT_TRUE(test.empty()); + for(int i=0; i