/* * ListOfBuffers.hh * Class to handle a set of buffer considering them as circular buffer. * Created on: Jan 11, 2018 * Author: Hovanes Egiyan */ #ifndef LISTOFBUFFERS_HH_ #define LISTOFBUFFERS_HH_ #include #include #include #include #include #include #include #include #include #include #include "BoundedBuffer.hh" #include "ReadoutBuffer.hh" namespace VETROC { template class circularIterator: public std::iterator { public: typedef typename std::iterator BaseClassType; typedef typename std::vector::iterator VectIterType; protected: VectIterType vectorIterator; std::vector* containerPtr; public: circularIterator( VectIterType posm, std::vector& container ) : vectorIterator( posm ), containerPtr( &container ) { } circularIterator( const circularIterator& otherIterator ) : vectorIterator( otherIterator.vectorIterator ), containerPtr( otherIterator.containerPtr ) { } circularIterator& operator=( const circularIterator& otherIterator ) { if ( this != &otherIterator ) { vectorIterator = otherIterator.vectorIterator; containerPtr = otherIterator.containerPtr; } return *this; } bool operator==( const circularIterator& otherIterator ) { if ( vectorIterator == otherIterator.vectorIterator && containerPtr == otherIterator.containerPtr ) { return true; } else { return false; } } circularIterator& operator++() { ++vectorIterator; if ( vectorIterator != containerPtr->end() ) { return *this; } else { vectorIterator = containerPtr->begin(); return *this; } } circularIterator operator++( int ) { // std::vector::iterator itCopy = vectorIterator; circularIterator itCopy = *this; ++(*this); return itCopy; } circularIterator& operator--() { if ( vectorIterator != containerPtr->begin() ) { --vectorIterator; return *this; } else { vectorIterator = containerPtr->end() - 1; return *this; } } circularIterator operator--( int ) { // std::vector::iterator itCopy = vectorIterator; circularIterator itCopy = *this; --(*this); return itCopy; } circularIterator operator+( typename BaseClassType::difference_type incr ) { circularIterator retIter = (*this); typename BaseClassType::difference_type leftSpace = containerPtr->end() - vectorIterator; if ( leftSpace <= incr ) { retIter.vectorIterator = containerPtr->begin() + incr - leftSpace ; } else { retIter.vectorIterator = retIter.vectorIterator + incr ; } return retIter; } typename BaseClassType::difference_type operator-( const circularIterator& other ) const { if ( this->vectorIterator >= other.vectorIterator ) { return (this->vectorIterator - other.vectorIterator); } else { return (containerPtr->size() - (other.vectorIterator - this->vectorIterator)); } } INBUFFER & operator*() const { return *vectorIterator; } INBUFFER * operator->() const { return &(*vectorIterator); } typename BaseClassType::difference_type getIndex() { return (vectorIterator - containerPtr->begin()); } }; template class ListOfBuffers { protected: std::vector > bufferVector; boost::mutex objectMutex; boost::condition emptyCondition; // boost::condition fullCondition; circularIterator > writePosition; // Last position that was written to and will be appended to next time circularIterator > readPosition; // Last position that was read from and will be read from next time public: // typedef ListOfBuffers > buffer_container_type; // typedef typename buffer_container_type::size_type buffer_size_type; // typedef typename buffer_container_type::value_type buffer_value_type; // typedef typename boost::call_traits::param_type buffer_param_type; typedef BoundedBuffer base_container_type; typedef typename base_container_type::size_type base_size_type; typedef typename base_container_type::value_type base_value_type; typedef typename boost::call_traits::param_type base_param_type; typedef typename base_container_type::value_type value_type; typedef typename boost::call_traits::param_type param_type; // Create a vector of buffers with capacity capacity, each buffer with capacity elementCapacity. ListOfBuffers( size_t capacity = 0, size_t elementCapacity = 0 ) : bufferVector( capacity, BoundedBuffer( elementCapacity ) ), objectMutex(), writePosition( bufferVector.begin(), bufferVector ), readPosition( bufferVector.begin(), bufferVector ) { std::cout << "Created ListOfBuffers with outer capacity " << capacity << " and inner capacity " << elementCapacity << std::endl; while ( this->frontElement().is_not_full() ) { bufferVector[0].pushFront( T( 0u ) ); } writePosition++; } virtual ~ListOfBuffers() { boost::mutex::scoped_lock lock( objectMutex ); bufferVector.clear(); } void pushFront( T& item ) { if ( this->frontElement().is_not_full() ) { // std::cout << "Pushing is good for ListOfBuffers for index "<< writePosition.getIndex() << std::endl; this->frontElement().pushFront( item ); // std::cout << "Size of front inner BoundedBuffer of ListOfBuffers " << " at " // << std::hex << std::showbase << &this->frontElement() << " is " << std::dec // << this->frontElement().size() << " , capacity is " // << this->frontElement().capacity() << " fullness check is " // << !this->frontElement().is_not_full() << " , unread is " // << this->frontElement().getUnread() << std::endl; if ( ! this->frontElement().is_not_full() ) { boost::mutex::scoped_lock lock( objectMutex ); if( this->isFull() ) { writePosition = readPosition + 1; this->frontElement().reset(); } else { writePosition++; this->frontElement().reset(); } // cout << "Switched write position index to " << writePosition.getIndex() << std::endl; //// std::cout << "Switched BoundedBuffer for writing in ListOfBuffers" << std::endl; // boost::mutex::scoped_lock lock( objectMutex ); //// std::cout << "ListOfBuffers lock taken, will wait" << std::cout; // fullCondition.wait( lock, boost::bind( &ListOfBuffers::isNotFull, this ) ); //// std::cout << "ListOfBuffers writing waiting is done" << std::cout; // writePosition++; // lock.unlock(); //// std::cout << "ListOfBuffers writing is unlocked" << std::cout; emptyCondition.notify_one(); } } else { boost::mutex::scoped_lock lock( objectMutex ); if( this->isFull() ) { writePosition = readPosition + 1; } else { writePosition++; } // cout << "Switched write position index to " << writePosition.getIndex() << std::endl; // std::cout << "Rare condition for writing" << std::endl; // std::cout << "Switched BoundedBuffer for writing in ListOfBuffers" << std::endl; // boost::mutex::scoped_lock lock( objectMutex ); // std::cout << "ListOfBuffers lock taken, will wait" << std::cout; // fullCondition.wait( lock, boost::bind( &ListOfBuffers::isNotFull, this ) ); // std::cout << "ListOfBuffers writing waiting is done" << std::cout; // writePosition++; // this->frontElement().pushFront( item ); // lock.unlock(); // std::cout << "ListOfBuffers writing is unlocked" << std::cout; emptyCondition.notify_one(); } } void popBack( T* item ) { if ( this->backElement().is_not_empty() ) { // std::cout << "Popping is good" << std::endl; this->backElement().popBack( item ); // std::cout << "Size of back inner buffer " << " at " << std::hex << std::showbase // << &this->backElement() << " is " << std::dec << this->backElement().size() // << " , capacity is " << this->backElement().capacity() // << " emptiness check is " << !this->backElement().is_not_empty() // << " , unread is " << this->backElement().getUnread() << std::endl; } else { // std::cout << "Switching BoundedBuffer for reading " << std::endl; boost::mutex::scoped_lock lock( objectMutex ); // std::cout << "Lock taken, will wait" << std::cout; emptyCondition.wait( lock, boost::bind( &ListOfBuffers::isNotEmpty, this ) ); // std::cout << "ListOfBuffers reading waiting is done" << std::cout; readPosition++; // cout << "Switched read position index to " << readPosition.getIndex() << std::endl; this->backElement().popBack( item ); lock.unlock(); // std::cout << "ListOfBuffers reading is unlocked" << std::cout; // fullCondition.notify_one(); } } BoundedBuffer& frontElement() { return *writePosition; } BoundedBuffer& backElement() { return *readPosition; } size_t capacity() { return bufferVector.size(); } bool isFull() const { return ((readPosition - writePosition) == 1); } bool isNotFull() const { return !this->isFull(); } bool isEmpty() const { // std::cout << "The iterator difference is " << writePosition - readPosition << std::endl; return (((writePosition - readPosition) == 0) || ((writePosition - readPosition) == 1)); } bool isNotEmpty() const { return !this->isEmpty(); } const boost::condition& getEmptyCondition() const { return emptyCondition; } // const boost::condition& getFullCondition() const { // return fullCondition; // } const boost::mutex& getObjectMutex() const { return objectMutex; } unsigned getReadPosition() const { return readPosition; } unsigned getWritePosition() const { return writePosition; } }; } /* namespace VETROC */ #endif /* LISTOFBUFFERS_HH_ */