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
getSize(void) const44 int getSize(void) const
45 {
46 return m_size;
47 }
getNumElements(void) const48 int getNumElements(void) const
49 {
50 return m_numElements;
51 }
getNumFree(void) const52 int getNumFree(void) const
53 {
54 return m_size - m_numElements;
55 }
56
57 void pushFront(const T &elem);
58 void pushFront(const T *elemBuf, int count);
59
60 void peekBack(T *elemBuf, int count) const;
61 T peekBack(int offset) const;
62
63 T popBack(void);
popBack(T * elemBuf,int count)64 void popBack(T *elemBuf, int count)
65 {
66 peekBack(elemBuf, count);
67 popBack(count);
68 }
69 void popBack(int count);
70
71 protected:
72 int m_numElements;
73 int m_front;
74 int m_back;
75
76 T *m_buffer;
77 int m_size;
78 };
79
80 // RingBuffer implementation.
81
82 template <typename T>
RingBuffer(int size)83 RingBuffer<T>::RingBuffer(int size) : m_numElements(0)
84 , m_front(0)
85 , m_back(0)
86 , m_size(size)
87 {
88 DE_ASSERT(size > 0);
89 m_buffer = new T[m_size];
90 }
91
92 template <typename T>
~RingBuffer()93 RingBuffer<T>::~RingBuffer()
94 {
95 delete[] m_buffer;
96 }
97
98 template <typename T>
clear(void)99 void RingBuffer<T>::clear(void)
100 {
101 m_numElements = 0;
102 m_front = 0;
103 m_back = 0;
104 }
105
106 template <typename T>
resize(int newSize)107 void RingBuffer<T>::resize(int newSize)
108 {
109 DE_ASSERT(newSize >= m_numElements);
110 T *buf = new T[newSize];
111
112 try
113 {
114 // Copy old elements.
115 for (int ndx = 0; ndx < m_numElements; ndx++)
116 buf[ndx] = m_buffer[(m_back + ndx) % m_size];
117
118 // Reset pointers.
119 m_front = m_numElements;
120 m_back = 0;
121 m_size = newSize;
122
123 DE_SWAP(T *, buf, m_buffer);
124 delete[] buf;
125 }
126 catch (...)
127 {
128 delete[] buf;
129 throw;
130 }
131 }
132
133 template <typename T>
pushFront(const T & elem)134 inline void RingBuffer<T>::pushFront(const T &elem)
135 {
136 DE_ASSERT(getNumFree() > 0);
137 m_buffer[m_front] = elem;
138 m_front = (m_front + 1) % m_size;
139 m_numElements += 1;
140 }
141
142 template <typename T>
pushFront(const T * elemBuf,int count)143 void RingBuffer<T>::pushFront(const T *elemBuf, int count)
144 {
145 DE_ASSERT(de::inRange(count, 0, getNumFree()));
146 for (int i = 0; i < count; i++)
147 m_buffer[(m_front + i) % m_size] = elemBuf[i];
148 m_front = (m_front + count) % m_size;
149 m_numElements += count;
150 }
151
152 template <typename T>
popBack()153 inline T RingBuffer<T>::popBack()
154 {
155 DE_ASSERT(getNumElements() > 0);
156 int ndx = m_back;
157 m_back = (m_back + 1) % m_size;
158 m_numElements -= 1;
159 return m_buffer[ndx];
160 }
161
162 template <typename T>
peekBack(int offset) const163 inline T RingBuffer<T>::peekBack(int offset) const
164 {
165 DE_ASSERT(de::inBounds(offset, 0, getNumElements()));
166 return m_buffer[(m_back + offset) % m_size];
167 }
168
169 template <typename T>
peekBack(T * elemBuf,int count) const170 void RingBuffer<T>::peekBack(T *elemBuf, int count) const
171 {
172 DE_ASSERT(de::inRange(count, 0, getNumElements()));
173 for (int i = 0; i < count; i++)
174 elemBuf[i] = m_buffer[(m_back + i) % m_size];
175 }
176
177 template <typename T>
popBack(int count)178 void RingBuffer<T>::popBack(int count)
179 {
180 DE_ASSERT(de::inRange(count, 0, getNumElements()));
181 m_back = (m_back + count) % m_size;
182 m_numElements -= count;
183 }
184
185 } // namespace de
186
187 #endif // _DERINGBUFFER_HPP
188