Program Listing for File generic_ring_buffer.h

Return to documentation for file (/tmp/ws/src/marti_common/swri_math_util/include/swri_math_util/generic_ring_buffer.h)

// *****************************************************************************
//
// Copyright (c) 2014, Southwest Research Institute® (SwRI®)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Southwest Research Institute® (SwRI®) nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// *****************************************************************************

#ifndef MATH_UTIL_GENERIC_RING_BUFFER_H_
#define MATH_UTIL_GENERIC_RING_BUFFER_H_
#ifndef NULL
#define NULL 0
#endif
#define GEN_RING_BUFF_DEFAULT_NUM_ELEMENTS 16

#include <cassert>
#include <algorithm>

namespace swri_math_util
{
  template <class T>
  class GenRingBuffer
  {
  public:
    // Default constructor
    GenRingBuffer()
    {
      NumElements = 0;
      this->alloc_mem(GEN_RING_BUFF_DEFAULT_NUM_ELEMENTS);
      this->init_array();
    }

    explicit GenRingBuffer(int NumElements2Alloc)
    {
      NumElements = 0;
      this->alloc_mem(NumElements2Alloc);
      this->init_array();
    }

    GenRingBuffer(const GenRingBuffer<T>& src)
    {
      this->alloc_mem(src.MaxNumElements);
      this->init_array();
      this->copyRB(src);
    }

    // Copy Assignment
    GenRingBuffer<T>& operator=(const GenRingBuffer<T>& src)
    {
      this->copyRB(src);
      return *this;
    }

    virtual ~GenRingBuffer()
    {
      delete [] HEAD;
    }

    void ResizeBuffer(int newSize)
    {
      this->realloc_mem(newSize);
    }

    int size() const
    {
      return NumElements;
    }

    int MaxSize() const
    {
      return MaxNumElements;
    }

    virtual T* operator[](int i)
    {
      return this->get(i);
    }

    virtual T* get(int i = 0) const
    {
      if (i >= NumElements) return NULL;
      int j = ((consumePtr-HEAD)+i)%MaxNumElements;
      return (&HEAD[j].Data);
    }

    T* getRaw(int i) const
    {
      if (i >= MaxNumElements)
      {
        return NULL;
      }
      return (&HEAD[i].Data);
    }

    T* getLoad() const
    {
      return &loadPtr->Data;
    }

    // getTail searches backward from index i
    T* getTail(int i = 0) const
    {
      if (i >= NumElements) return NULL;
      int j = ((loadPtr-1-HEAD)-i);
      if (j < 0)
      {
        j += MaxNumElements;
      }
      return (&HEAD[j].Data);
    }

    void load(const T &newElem)
    {
      this->push(newElem);
    }

    void load1(T newElem)
    {
      this->push(newElem);
    }

    T* pop()
    {
      T* temp;
      if (this->size() == 0)
      {
        return 0;
      }
      else
      {
        temp = this->get();
        this->incConsumePtr();
        NumElements--;
      }
      return temp;
    }

    bool indexValid(int i)
    {
      return (i >= 0 && i <this->NumElements);
    }

    void clear()
    {
      while (this->pop());
    }

  protected:
    void realloc_mem(int NumElements2Alloc)
    {
      temp = new ctr[std::max(2, NumElements2Alloc)];
      this->copy_elems(temp, NumElements2Alloc);
      delete [] HEAD;
      HEAD = temp;
      TAIL = HEAD+NumElements2Alloc;
      loadPtr = HEAD;
      consumePtr = HEAD;
      MaxNumElements = NumElements2Alloc;
      if (MaxNumElements < NumElements)
      {
        NumElements = MaxNumElements;
      }
      this->init_array();
    }

  private:
    struct ctr
    {
      T Data;
      ctr *next;
      ctr *prev;
    };
    ctr *temp;
    ctr *HEAD;
    ctr *TAIL;
    ctr *loadPtr;
    ctr *consumePtr;

    int NumElements;
    int MaxNumElements;


    bool copy_elems(ctr* dest, int MaxNum2Copy)
    {
      bool success;
      int Num2Copy = std::min(NumElements, MaxNum2Copy);
      if (Num2Copy !=NumElements)
      {
        success = false;
      }
      else
      {
        success = true;
      }
      for (int i = 0; i < Num2Copy; i++)
      {
        dest[i].Data = *(this->get(i));
      }
      return success;
    }

    void push(const T &newElem)
    {
      assert(NumElements <= MaxNumElements);
      loadPtr->Data = newElem;
      if (NumElements >= MaxNumElements)
      {
        this->incLoadPtr();
        this->incConsumePtr();
      }
      else
      {
        this->incLoadPtr();
        NumElements++;
      }
    }

    void incLoadPtr()
    {
      loadPtr = loadPtr->next;
    }

    void incConsumePtr()
    {
      consumePtr = consumePtr->next;
    }

    ctr* alloc_mem(int NumElems)
    {
      HEAD = new ctr[std::max(NumElems, 2)];
      TAIL = HEAD+NumElems;
      loadPtr = HEAD;
      consumePtr = HEAD;
      MaxNumElements = NumElems;
      return HEAD;
    }

    void init_array()
    {
      int j, k;
      for (int i = 0; i < MaxNumElements; i++)
      {
        j = (i+1)%MaxNumElements;
        k = (i-1)%MaxNumElements;
        HEAD[i].next = &HEAD[j];
        HEAD[i].prev = &HEAD[k];
      }
    }

    void copyRB(GenRingBuffer<T>& src)
    {
      this->clear();
      if (src.MaxNumElements != this->MaxNumElements)
      {
        this->realloc_mem(src.MaxNumElements);
      }

      // Initialize the new buffer's number of elements to zero. The for loop
      // below will take care of incrementing NumElements to the correct value.
      this->NumElements = 0;
      // This was the previously-used line of code, which resulted in the
      // copied-to buffer incorrectly having a NumElements greater than the
      // copy-from buffer by 1:
      // this->NumElements = src.NumElements;
      for (int i = 0; i < src.NumElements; ++i)
      {
        this->load(*(src[i]));
      }
    }
  };
}

#endif  // MATH_UTIL_GENERIC_RING_BUFFER_H_