Home | History | Annotate | Download | only in decpp
      1 #ifndef _DERINGBUFFER_HPP
      2 #define _DERINGBUFFER_HPP
      3 /*-------------------------------------------------------------------------
      4  * drawElements C++ Base Library
      5  * -----------------------------
      6  *
      7  * Copyright 2014 The Android Open Source Project
      8  *
      9  * Licensed under the Apache License, Version 2.0 (the "License");
     10  * you may not use this file except in compliance with the License.
     11  * You may obtain a copy of the License at
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     15  * Unless required by applicable law or agreed to in writing, software
     16  * distributed under the License is distributed on an "AS IS" BASIS,
     17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18  * See the License for the specific language governing permissions and
     19  * limitations under the License.
     20  *
     21  *//*!
     22  * \file
     23  * \brief Ring buffer template.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "deDefs.hpp"
     27 
     28 namespace de
     29 {
     30 
     31 void RingBuffer_selfTest (void);
     32 
     33 /** Ring buffer template. */
     34 template <typename T>
     35 class RingBuffer
     36 {
     37 public:
     38 			RingBuffer		(int size);
     39 			~RingBuffer		(void);
     40 
     41 	void	clear			(void);
     42 	void	resize			(int newSize);
     43 
     44 	int		getSize			(void) const	{ return m_size;					}
     45 	int		getNumElements	(void) const	{ return m_numElements;				}
     46 	int		getNumFree		(void) const	{ return m_size - m_numElements;	}
     47 
     48 	void	pushFront		(const T& elem);
     49 	void	pushFront		(const T* elemBuf, int count);
     50 
     51 	void	peekBack		(T* elemBuf, int count) const;
     52 	T		peekBack		(int offset) const;
     53 
     54 	T		popBack			(void);
     55 	void	popBack			(T* elemBuf, int count) { peekBack(elemBuf, count); popBack(count); }
     56 	void	popBack			(int count);
     57 
     58 protected:
     59 	int		m_numElements;
     60 	int		m_front;
     61 	int		m_back;
     62 
     63 	T*		m_buffer;
     64 	int		m_size;
     65 };
     66 
     67 // RingBuffer implementation.
     68 
     69 template <typename T>
     70 RingBuffer<T>::RingBuffer (int size)
     71 	: m_numElements	(0)
     72 	, m_front		(0)
     73 	, m_back		(0)
     74 	, m_size		(size)
     75 {
     76 	DE_ASSERT(size > 0);
     77 	m_buffer = new T[m_size];
     78 }
     79 
     80 template <typename T>
     81 RingBuffer<T>::~RingBuffer ()
     82 {
     83 	delete[] m_buffer;
     84 }
     85 
     86 template <typename T>
     87 void RingBuffer<T>::clear (void)
     88 {
     89 	m_numElements	= 0;
     90 	m_front			= 0;
     91 	m_back			= 0;
     92 }
     93 
     94 template <typename T>
     95 void RingBuffer<T>::resize (int newSize)
     96 {
     97 	DE_ASSERT(newSize >= m_numElements);
     98 	T* buf = new T[newSize];
     99 
    100 	try
    101 	{
    102 		// Copy old elements.
    103 		for (int ndx = 0; ndx < m_numElements; ndx++)
    104 			buf[ndx] = m_buffer[(m_back + ndx) % m_size];
    105 
    106 		// Reset pointers.
    107 		m_front		= m_numElements;
    108 		m_back		= 0;
    109 		m_size		= newSize;
    110 
    111 		DE_SWAP(T*, buf, m_buffer);
    112 		delete[] buf;
    113 	}
    114 	catch (...)
    115 	{
    116 		delete[] buf;
    117 		throw;
    118 	}
    119 }
    120 
    121 template <typename T>
    122 inline void RingBuffer<T>::pushFront (const T& elem)
    123 {
    124 	DE_ASSERT(getNumFree() > 0);
    125 	m_buffer[m_front] = elem;
    126 	m_front = (m_front + 1) % m_size;
    127 	m_numElements += 1;
    128 }
    129 
    130 template <typename T>
    131 void RingBuffer<T>::pushFront (const T* elemBuf, int count)
    132 {
    133 	DE_ASSERT(de::inRange(count, 0, getNumFree()));
    134 	for (int i = 0; i < count; i++)
    135 		m_buffer[(m_front + i) % m_size] = elemBuf[i];
    136 	m_front = (m_front + count) % m_size;
    137 	m_numElements += count;
    138 }
    139 
    140 template <typename T>
    141 inline T RingBuffer<T>::popBack ()
    142 {
    143 	DE_ASSERT(getNumElements() > 0);
    144 	int ndx = m_back;
    145 	m_back = (m_back + 1) % m_size;
    146 	m_numElements -= 1;
    147 	return m_buffer[ndx];
    148 }
    149 
    150 template <typename T>
    151 inline T RingBuffer<T>::peekBack (int offset) const
    152 {
    153 	DE_ASSERT(de::inBounds(offset, 0, getNumElements()));
    154 	return m_buffer[(m_back + offset) % m_size];
    155 }
    156 
    157 template <typename T>
    158 void RingBuffer<T>::peekBack (T* elemBuf, int count) const
    159 {
    160 	DE_ASSERT(de::inRange(count, 0, getNumElements()));
    161 	for (int i = 0; i < count; i++)
    162 		elemBuf[i] = m_buffer[(m_back + i) % m_size];
    163 }
    164 
    165 template <typename T>
    166 void RingBuffer<T>::popBack (int count)
    167 {
    168 	DE_ASSERT(de::inRange(count, 0, getNumElements()));
    169 	m_back = (m_back + count) % m_size;
    170 	m_numElements -= count;
    171 }
    172 
    173 } // de
    174 
    175 #endif // _DERINGBUFFER_HPP
    176