// ----------------------------------------------------------------------------------------
//
//  common/util/cbuffer.inl
//    
//  Bob Cook Development, Robotics Library
//  http://www.bobcookdev.com/rl/
//    
//  This file provides a circular buffer template.
//
//  Copyright (C) 2007 Bob Cook
//
//      This program is free software; you can redistribute it and/or modify it
//      under the terms of the GNU General Public License as published by the
//      Free Software Foundation; either version 2 of the License, or (at your
//      option) any later version.
//    
//      This program is distributed in the hope that it will be useful, but 
//      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
//      or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
//      for more details.
//    
//      You should have received a copy of the GNU General Public License along
//      with this program; if not, write to the Free Software Foundation, Inc., 
//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// ----------------------------------------------------------------------------------------


// ----------------------------------------------------------------------------------------

template< typename T_ELEM_TYPE, typename T_SIZE_TYPE, int T_SIZE >
inline cbuffer< T_ELEM_TYPE, T_SIZE_TYPE, T_SIZE >::cbuffer()
    :   m_buffer()
    ,   m_head( 0 )
    ,   m_tail( 0 )
{
}

        
// ----------------------------------------------------------------------------------------

template< typename T_ELEM_TYPE, typename T_SIZE_TYPE, int T_SIZE >
inline bool cbuffer< T_ELEM_TYPE, T_SIZE_TYPE, T_SIZE >::is_full() const
{
    T_SIZE_TYPE tmp_head = ( m_head + 1 ) & ( T_SIZE - 1 );
    return ( tmp_head == m_tail );
}


// ----------------------------------------------------------------------------------------

template< typename T_ELEM_TYPE, typename T_SIZE_TYPE, int T_SIZE >
inline bool cbuffer< T_ELEM_TYPE, T_SIZE_TYPE, T_SIZE >::is_empty() const
{
    return ( m_head == m_tail );
}


// ----------------------------------------------------------------------------------------

template< typename T_ELEM_TYPE, typename T_SIZE_TYPE, int T_SIZE >
inline void cbuffer< T_ELEM_TYPE, T_SIZE_TYPE, T_SIZE >::push( const T_ELEM_TYPE& element )
{
    T_SIZE_TYPE tmp_head = ( m_head + 1 ) & ( T_SIZE - 1 );

    m_buffer[ tmp_head ] = element;
    m_head = tmp_head;
}


// ----------------------------------------------------------------------------------------

template< typename T_ELEM_TYPE, typename T_SIZE_TYPE, int T_SIZE >
inline void cbuffer< T_ELEM_TYPE, T_SIZE_TYPE, T_SIZE >::wait_and_push
(
    const T_ELEM_TYPE& element
)
{
    T_SIZE_TYPE tmp_head = ( m_head + 1 ) & ( T_SIZE - 1 );
    while ( tmp_head == m_tail ) ; // wait for available space
    m_buffer[ tmp_head ] = element;
    m_head = tmp_head;
}


// ----------------------------------------------------------------------------------------

template< typename T_ELEM_TYPE, typename T_SIZE_TYPE, int T_SIZE >
inline T_ELEM_TYPE cbuffer< T_ELEM_TYPE, T_SIZE_TYPE, T_SIZE >::pop()
{
    m_tail = ( m_tail + 1 ) & ( T_SIZE - 1 );
    return m_buffer[ m_tail ];
}


// ----------------------------------------------------------------------------------------

template< typename T_ELEM_TYPE, typename T_SIZE_TYPE, int T_SIZE >
inline T_ELEM_TYPE cbuffer< T_ELEM_TYPE, T_SIZE_TYPE, T_SIZE >::wait_and_pop()
{
    while ( m_head == m_tail ) ; // wait for available data
    m_tail = ( m_tail + 1 ) & ( T_SIZE - 1 );
    return m_buffer[ m_tail ];
}


// ----------------------------------------------------------------------------------------
//  end of cbuffer.inl
// ----------------------------------------------------------------------------------------

