#include "lfds611_ringbuffer_internal.h"





/****************************************************************************/
struct lfds611_freelist_element *lfds611_ringbuffer_get_read_element( struct lfds611_ringbuffer_state *rs, struct lfds611_freelist_element **fe )
{
  assert( rs != NULL );
  assert( fe != NULL );

  lfds611_queue_dequeue( rs->qs, (void **) fe );

  return( *fe );
}





/****************************************************************************/
struct lfds611_freelist_element *lfds611_ringbuffer_get_write_element( struct lfds611_ringbuffer_state *rs, struct lfds611_freelist_element **fe, int *overwrite_flag )
{
  assert( rs != NULL );
  assert( fe != NULL );
  // TRD : overwrite_flag can be NULL

  /* TRD : we try to obtain an element from the lfds611_freelist
           if we can, we populate it and add it to the lfds611_queue

           if we cannot, then the lfds611_ringbuffer is full
           so instead we grab the current read element and
           use that instead

           dequeue may fail since the lfds611_queue may be emptied
           during our dequeue attempt

           so what we actually do here is a loop, attempting
           the lfds611_freelist and if it fails then a dequeue, until
           we obtain an element

           once we have an element, we lfds611_queue it

           you may be wondering why this operation is in a loop
           remember - these operations are lock-free; anything
           can happen in between

           so for example the pop could fail because the lfds611_freelist
           is empty; but by the time we go to get an element from
           the lfds611_queue, the whole lfds611_queue has been emptied back into
           the lfds611_freelist!

           if overwrite_flag is provided, we set it to 0 if we
           obtained a new element from the lfds611_freelist, 1 if we
           stole an element from the lfds611_queue
  */

  do {
    if( overwrite_flag != NULL )
      *overwrite_flag = 0;

    lfds611_freelist_pop( rs->fs, fe );

    if( *fe == NULL ) {
      lfds611_ringbuffer_get_read_element( rs, fe );

      if( overwrite_flag != NULL and *fe != NULL )
        *overwrite_flag = 1;
    }
  } while( *fe == NULL );

  return( *fe );
}





/****************************************************************************/
void lfds611_ringbuffer_put_read_element( struct lfds611_ringbuffer_state *rs, struct lfds611_freelist_element *fe )
{
  assert( rs != NULL );
  assert( fe != NULL );

  lfds611_freelist_push( rs->fs, fe );

  return;
}





/****************************************************************************/
void lfds611_ringbuffer_put_write_element( struct lfds611_ringbuffer_state *rs, struct lfds611_freelist_element *fe )
{
  assert( rs != NULL );
  assert( fe != NULL );

  lfds611_queue_enqueue( rs->qs, fe );

  return;
}

