glbinding  3.3.0.0
A C++ binding for the OpenGL API, generated using the gl.xml specification.
Loading...
Searching...
No Matches
RingBuffer.inl
Go to the documentation of this file.
1
2#pragma once
3
4#include <iomanip>
5#include <iterator>
6#include <cassert>
7#include <cmath>
8
9
10namespace glbinding { namespace aux
11{
12
13
14template <typename T>
16: m_size{maxSize+1}
17, m_head{0}
18{
19 m_buffer.resize(m_size);
20}
21
22template <typename T>
24{
25 m_size = newSize + 1;
26 m_buffer.resize(m_size);
27}
28
29template <typename T>
30T RingBuffer<T>::nextHead(bool & available) const
31{
32 const auto head = m_head.load(std::memory_order_relaxed);
33 const auto nextHead = next(head);
34
35 if (isFull(nextHead))
36 {
37 available = false;
38 return nullptr;
39 }
40
41 available = true;
42 return m_buffer[nextHead];
43}
44
45template <typename T>
46bool RingBuffer<T>::push(T && entry)
47{
48 const auto head = m_head.load(std::memory_order_relaxed);
49 const auto nextHead = next(head);
50
51 if (isFull(nextHead))
52 {
53 return false;
54 }
55
56 assert(head < m_size);
57
58 if (m_buffer.size() <= head)
59 {
60 // This should never happen because m_buffer is reserving m_size
61 m_buffer.push_back(entry);
62 }
63 else
64 {
65 m_buffer[head] = entry;
66 }
67
68 m_head.store(nextHead, std::memory_order_release);
69
70 return true;
71}
72
73template <typename T>
74bool RingBuffer<T>::push(T & entry)
75{
76 auto head = m_head.load(std::memory_order_relaxed);
77 auto nextHead = next(head);
78
79 if (isFull(nextHead))
80 {
81 return false;
82 }
83
84 assert(head < m_size);
85
86 if (m_buffer.size() <= head)
87 {
88 m_buffer.push_back(entry);
89 }
90 else
91 {
92 m_buffer[head] = entry;
93 }
94
95 m_head.store(nextHead, std::memory_order_release);
96
97 return true;
98}
99
100template <typename T>
102{
103 // Just use the next key instead in O(1) of reusing keys using a O(n*log(n)) algorithm.
104 const auto it = m_tails.rbegin();
105 const auto i = TailIdentifier(it == m_tails.rend() ? 0 : it->first + 1);
106
107 m_tails[i] = m_head.load(std::memory_order_acquire);
108
109 return i;
110}
111
112template <typename T>
114{
115 m_tails.erase(key);
116}
117
118template <typename T>
119const typename std::vector<T>::const_iterator RingBuffer<T>::cbegin(TailIdentifier key) const
120{
121 auto tail = m_tails.at(key).load(std::memory_order_relaxed);
122 auto i = m_buffer.cbegin();
123
124 std::advance(i, tail);
125
126 return i;
127}
128
129template <typename T>
130bool RingBuffer<T>::valid(TailIdentifier /*key*/, const typename std::vector<T>::const_iterator & it) const
131{
132 auto pos = std::abs(std::distance(m_buffer.cbegin(), it));
133 auto head = m_head.load(std::memory_order_acquire);
134
135 return (static_cast<SizeType>(pos) != head);
136}
137
138template <typename T>
139const typename std::vector<T>::const_iterator RingBuffer<T>::next(TailIdentifier key, const typename std::vector<T>::const_iterator & it)
140{
141 auto tail = m_tails[key].load(std::memory_order_acquire);
142
143 if (tail == m_head.load(std::memory_order_acquire))
144 {
145 return it;
146 }
147
148 auto nextTail = next(tail);
149
150 m_tails[key].store(nextTail, std::memory_order_release);
151
152 return cbegin(key);
153}
154
155template <typename T>
157{
158 auto head = m_head.load(std::memory_order_acquire);
159 auto tail = m_tails[key].load(std::memory_order_acquire);
160
161 return size(head, tail);
162}
163
164template <typename T>
166{
167 return m_size - 1;
168}
169
170template <typename T>
172{
173 auto head = m_head.load(std::memory_order_acquire);
174 auto tail = lastTail();
175
176 return size(head, tail);
177}
178
179template <typename T>
181{
182 auto head = m_head.load(std::memory_order_relaxed);
183 auto nextHead = next(head);
184
185 return isFull(nextHead);
186}
187
188template <typename T>
190{
191 auto tail = lastTail();
192
193 return tail == m_head.load(std::memory_order_acquire);
194}
195
196
197//protected
198
199template <typename T>
201{
202 return (current + 1) % m_size;
203}
204
205template <typename T>
206bool RingBuffer<T>::isFull(SizeType nextHead) const
207{
208 for (auto it = m_tails.cbegin(); it != m_tails.cend(); ++it)
209 {
210 auto tailPos = it->second.load(std::memory_order_acquire);
211
212 if (nextHead == tailPos)
213 return true;
214 }
215
216 return false;
217}
218
219template <typename T>
221{
222 auto head = m_head.load(std::memory_order_relaxed);
223 auto last = head + m_size;
224
225 for (auto it = m_tails.cbegin(); it != m_tails.cend(); ++it)
226 {
227 auto tailPos = it->second.load(std::memory_order_acquire);
228 if (tailPos <= head)
229 tailPos += m_size;
230
231 if (tailPos < last)
232 last = tailPos;
233 }
234
235 return last % m_size;
236}
237
238template <typename T>
240{
241 if (head < tail)
242 {
243 return m_size - tail + head;
244 }
245 else
246 {
247 return head - tail;
248 }
249}
250
251
252} } // namespace glbinding::aux
SizeType size() const
Query current size.
Definition RingBuffer.inl:171
std::vector< T > m_buffer
Internal buffer.
Definition RingBuffer.h:244
TailIdentifier addTail()
Add a new tail to the buffer.
Definition RingBuffer.inl:101
bool valid(TailIdentifier key, const typename std::vector< T >::const_iterator &it) const
Check if iterator is valid.
Definition RingBuffer.inl:130
void removeTail(TailIdentifier key)
Remove a tail from the buffer.
Definition RingBuffer.inl:113
unsigned int SizeType
Numeric type employed for indices, sizes and distances.
Definition RingBuffer.h:26
SizeType lastTail() const
Determine last (furthest behind) index still in use.
Definition RingBuffer.inl:220
unsigned int TailIdentifier
Identifier type for tails.
Definition RingBuffer.h:27
void resize(SizeType newSize)
Resize buffer.
Definition RingBuffer.inl:23
bool push(T &&entry)
Add an element to the buffer, if possible.
Definition RingBuffer.inl:46
RingBuffer(SizeType maxSize)
Constructor.
Definition RingBuffer.inl:15
bool isFull() const
Query if buffer is full.
Definition RingBuffer.inl:180
T nextHead(bool &available) const
Retrieve element beyond current head.
Definition RingBuffer.inl:30
bool isEmpty() const
Query if buffer is empty.
Definition RingBuffer.inl:189
const std::vector< T >::const_iterator next(TailIdentifier key, const typename std::vector< T >::const_iterator &it)
Advance the iterator of a tail.
Definition RingBuffer.inl:139
const std::vector< T >::const_iterator cbegin(TailIdentifier key) const
Retrieve the iterator for a tail.
Definition RingBuffer.inl:119
SizeType m_size
Size of buffer.
Definition RingBuffer.h:245
SizeType maxSize() const
Query maximum size.
Definition RingBuffer.inl:165
Contains all the classes of glbinding.