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
28namespace de
29{
30
31void RingBuffer_selfTest (void);
32
33/** Ring buffer template. */
34template <typename T>
35class RingBuffer
36{
37public:
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
58protected:
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
69template <typename T>
70RingBuffer<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
80template <typename T>
81RingBuffer<T>::~RingBuffer ()
82{
83	delete[] m_buffer;
84}
85
86template <typename T>
87void RingBuffer<T>::clear (void)
88{
89	m_numElements	= 0;
90	m_front			= 0;
91	m_back			= 0;
92}
93
94template <typename T>
95void 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
121template <typename T>
122inline 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
130template <typename T>
131void 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
140template <typename T>
141inline 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
150template <typename T>
151inline 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
157template <typename T>
158void 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
165template <typename T>
166void 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