/* * BoundedBuffer.hh * * Created on: Dec 12, 2017 * Author: Hovanes Egiyan */ #ifndef BOUNDEDBUFFER_HH_ #define BOUNDEDBUFFER_HH_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for auto_cpu_timer namespace VETROC { template class BoundedBuffer { public: typedef boost::circular_buffer container_type; typedef typename container_type::size_type size_type; typedef typename container_type::value_type value_type; typedef typename container_type::reference reference; typedef typename boost::call_traits::param_type param_type; explicit BoundedBuffer( size_type capacity = 0 ) : m_unread( 0 ), m_container( capacity ) { std::cout << "Created BoundedBuffer with capacity " << this->capacity() << std::endl; } BoundedBuffer( const BoundedBuffer& b) { *this = operator=( b ); } virtual ~BoundedBuffer() {} BoundedBuffer& operator =( const BoundedBuffer& b ) { if ( this != &b ) { m_unread = b.m_unread; m_container = b.m_container; } return *this; } // explicit BoundedBuffer( size_type capacity, param_type initItem ) : // m_unread( 0 ), m_container( capacity, initItem ) { // } void reset() { boost::mutex::scoped_lock lock( m_mutex ); m_unread = 0; } void push_front( typename boost::call_traits::param_type item ) { // `param_type` represents the "best" way to pass a parameter of type `value_type` to a method. boost::mutex::scoped_lock lock( m_mutex ); m_not_full.wait( lock, boost::bind( &BoundedBuffer::is_not_full, this ) ); m_container.push_front( item ); ++m_unread; lock.unlock(); m_not_empty.notify_one(); } void pop_back( value_type* pItem ) { // std::cout << "BoundedBuffer is trying to take lock for " << std::hex << std::showbase << this << std::endl; boost::mutex::scoped_lock lock( m_mutex ); // std::cout << "Lock taken " << std::endl; m_not_empty.wait( lock, boost::bind( &BoundedBuffer::is_not_empty, this ) ); // std::cout << "BoundedBuffer waiting is done for " << std::hex << std::showbase << this << std::endl; *pItem = this->m_container[--(this->m_unread)]; lock.unlock(); m_not_full.notify_one(); } reference operator[]( unsigned i ) { return m_container[i]; } reference backElement() { if( this->m_unread > 0 ) { return m_container[this->m_unread-1]; } else { return m_container[0]; } } reference frontElement() { return m_container[0]; } virtual void pushFront(typename boost::call_traits::param_type item) { push_front( item ); } virtual void popBack(value_type* pItem) { pop_back( pItem ); } bool is_not_empty() const { return m_unread > 0; } bool is_not_full() const { return m_unread < m_container.capacity(); } size_type size() const { return m_container.size(); } size_type capacity() const { return m_container.capacity(); } size_type getUnread() { return m_unread; } template friend std::ostream& operator<<( std::ostream& os, BoundedBuffer& buffer ); private: protected: size_type m_unread; container_type m_container; boost::mutex m_mutex; boost::condition m_not_empty; boost::condition m_not_full; }; template std::ostream& operator<<( std::ostream& os, BoundedBuffer& buffer ) { os << std::endl; D value; boost::mutex::scoped_lock lock( buffer.m_mutex ); while( buffer.is_not_empty() ) { // boost::mutex::scoped_lock lock( buffer.m_mutex ); // buffer.m_not_empty.wait( lock, // boost::bind( &BoundedBuffer::is_not_empty, this ) ); value = buffer.m_container[--(buffer.m_unread)]; // lock.unlock(); buffer.m_not_full.notify_one(); os << value << " "; } os << std::endl; return os; } } /* namespace VETROC */ #endif /* BOUNDEDBUFFER_HH_ */