Roc Toolkit internal modules
Roc Toolkit: real-time audio streaming
Toggle main menu visibility
Loading...
Searching...
No Matches
ring_queue.h
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2024 Roc Streaming authors
3
*
4
* This Source Code Form is subject to the terms of the Mozilla Public
5
* License, v. 2.0. If a copy of the MPL was not distributed with this
6
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
*/
8
9
//! @file roc_core/ring_queue.h
10
//! @brief Queue on continuous memory buffer.
11
12
#ifndef ROC_CORE_RING_QUEUE_H_
13
#define ROC_CORE_RING_QUEUE_H_
14
15
#include "
roc_core/array.h
"
16
#include "
roc_core/iarena.h
"
17
#include "
roc_core/log.h
"
18
#include "
roc_core/noncopyable.h
"
19
#include "
roc_core/panic.h
"
20
21
namespace
roc
{
22
namespace
core
{
23
24
//! Queue on continuous memory buffer.
25
//!
26
//! Elements are stored continuously in a memory chunk allocated using IArena,
27
//! or directly in Array object when number of elements is small.
28
//!
29
//! RingQueue supports inserting and removing elements to the beginning and to
30
//! the end with O(1) complexity.
31
//!
32
//! @tparam T defines array element type. It should have default constructor
33
//! and copy constructor.
34
//!
35
//! @tparam EmbeddedCapacity defines number of elements in the fixed-size chunk
36
//! embedded directly into RingQueue object.
37
template
<
class
T,
size_t
EmbeddedCapacity = 0>
class
RingQueue
:
public
NonCopyable<> {
38
public
:
39
//! Initialize.
40
//! @remarks
41
//! Preallocate buffer in @p arena with @p max_len number of elements.
42
RingQueue
(
core::IArena
& arena,
size_t
max_len)
43
: buff_(NULL)
44
, buff_len_(max_len)
45
, begin_(0)
46
, end_(0)
47
, arena_(arena) {
48
if
(max_len == 0) {
49
roc_panic
(
"ring queue: the length must be greater than 0"
);
50
}
51
52
buff_ = allocate_(max_len);
53
}
54
55
~RingQueue
() {
56
if
(buff_) {
57
deallocate_(buff_);
58
}
59
}
60
61
//! Check that initial allocation succeeded.
62
bool
is_valid
()
const
{
63
return
buff_ != NULL;
64
}
65
66
//! Get maximum number of elements in queue/
67
size_t
capacity
()
const
{
68
return
buff_len_;
69
}
70
71
//! Get current number of elements in the queue.
72
size_t
size
()
const
{
73
return
(end_ - begin_ + buff_len_) % buff_len_;
74
}
75
76
//! Is the queue empty.
77
bool
is_empty
() {
78
return
begin_ == end_;
79
}
80
81
//! Is the queue full.
82
bool
is_full
() {
83
return
size
() ==
capacity
();
84
}
85
86
//! Get reference of the front element.
87
//! @pre
88
//! Queue should not be empty.
89
T&
front
() {
90
if
(
is_empty
()) {
91
roc_panic
(
"ring queue: front() called on empty buffer"
);
92
}
93
return
buff_[begin_];
94
}
95
96
//! Get reference of the front element.
97
//! @pre
98
//! Queue should not be empty.
99
const
T&
front
()
const
{
100
if
(
is_empty
()) {
101
roc_panic
(
"ring queue: front() called on empty buffer"
);
102
}
103
return
buff_[begin_];
104
}
105
106
//! Get reference of the back element.
107
//! @pre
108
//! Queue should not be empty.
109
T&
back
() {
110
if
(
is_empty
()) {
111
roc_panic
(
"ring queue: back() called on empty buffer"
);
112
}
113
return
buff_[(end_ - 1 + buff_len_) % buff_len_];
114
}
115
116
//! Get reference of the back element.
117
//! @pre
118
//! Queue should not be empty.
119
const
T&
back
()
const
{
120
if
(
is_empty
()) {
121
roc_panic
(
"ring queue: back() called on empty buffer"
);
122
}
123
return
buff_[(end_ - 1 + buff_len_) % buff_len_];
124
}
125
126
//! Push an element to the front of the queue.
127
//! @pre
128
//! Queue should not be full.
129
void
push_front
(
const
T& x) {
130
if
(
is_full
()) {
131
roc_panic
(
"ring queue: buffer overflow"
);
132
}
133
begin_ = (begin_ - 1 + buff_len_) % buff_len_;
134
new
(&buff_[begin_]) T(x);
135
}
136
137
//! Remove the first element from the front.
138
//! @pre
139
//! Queue should not be empty.
140
void
pop_front
() {
141
if
(
is_empty
()) {
142
roc_panic
(
"ring queue: pop_front() called on empty buffer"
);
143
}
144
buff_[begin_].~T();
145
begin_ = (begin_ + 1) % buff_len_;
146
}
147
148
//! Push an element to the backside of the queue.
149
//! @pre
150
//! Queue should not be full.
151
void
push_back
(
const
T& x) {
152
if
(
is_full
()) {
153
roc_panic
(
"ring queue: buffer overflow"
);
154
}
155
new
(&buff_[end_]) T(x);
156
end_ = (end_ + 1) % buff_len_;
157
}
158
159
//! Remove the first element from the back.
160
//! @pre
161
//! Queue should not be empty.
162
void
pop_back
() {
163
if
(
is_empty
()) {
164
roc_panic
(
"ring queue: pop_back() called on empty buffer"
);
165
}
166
buff_[end_].~T();
167
end_ = (end_ - 1 + buff_len_) % buff_len_;
168
}
169
170
private
:
171
T* allocate_(
size_t
n_elems) {
172
T* data = NULL;
173
174
if
(n_elems <= EmbeddedCapacity) {
175
data = (T*)embedded_data_.memory();
176
}
else
{
177
data = (T*)arena_.
allocate
(n_elems *
sizeof
(T));
178
}
179
180
if
(!data) {
181
roc_log
(
LogError
,
182
"ring queue: can't allocate memory:"
183
" requested_cap=%lu embedded_cap=%lu"
,
184
(
unsigned
long
)n_elems, (
unsigned
long
)EmbeddedCapacity);
185
}
186
187
return
data;
188
}
189
190
void
deallocate_(T* data) {
191
if
((
void
*)data != (
void
*)embedded_data_.memory()) {
192
arena_.deallocate(data);
193
}
194
}
195
196
T* buff_;
197
size_t
buff_len_;
198
size_t
begin_;
199
size_t
end_;
200
201
AlignedStorage<EmbeddedCapacity *
sizeof
(T)> embedded_data_;
202
IArena& arena_;
203
};
204
205
}
// namespace core
206
}
// namespace roc
207
208
#endif
// ROC_CORE_RING_QUEUE_H_
array.h
Dynamic array.
roc::core::IArena
Memory arena interface.
Definition
iarena.h:23
roc::core::IArena::allocate
virtual void * allocate(size_t size)=0
Allocate memory.
roc::core::RingQueue
Queue on continuous memory buffer.
Definition
ring_queue.h:37
roc::core::RingQueue::is_valid
bool is_valid() const
Check that initial allocation succeeded.
Definition
ring_queue.h:62
roc::core::RingQueue::RingQueue
RingQueue(core::IArena &arena, size_t max_len)
Initialize.
Definition
ring_queue.h:42
roc::core::RingQueue::front
const T & front() const
Get reference of the front element.
Definition
ring_queue.h:99
roc::core::RingQueue::push_front
void push_front(const T &x)
Push an element to the front of the queue.
Definition
ring_queue.h:129
roc::core::RingQueue::is_full
bool is_full()
Is the queue full.
Definition
ring_queue.h:82
roc::core::RingQueue::pop_back
void pop_back()
Remove the first element from the back.
Definition
ring_queue.h:162
roc::core::RingQueue::is_empty
bool is_empty()
Is the queue empty.
Definition
ring_queue.h:77
roc::core::RingQueue::capacity
size_t capacity() const
Get maximum number of elements in queue/.
Definition
ring_queue.h:67
roc::core::RingQueue::back
T & back()
Get reference of the back element.
Definition
ring_queue.h:109
roc::core::RingQueue::back
const T & back() const
Get reference of the back element.
Definition
ring_queue.h:119
roc::core::RingQueue::pop_front
void pop_front()
Remove the first element from the front.
Definition
ring_queue.h:140
roc::core::RingQueue::size
size_t size() const
Get current number of elements in the queue.
Definition
ring_queue.h:72
roc::core::RingQueue::push_back
void push_back(const T &x)
Push an element to the backside of the queue.
Definition
ring_queue.h:151
roc::core::RingQueue::front
T & front()
Get reference of the front element.
Definition
ring_queue.h:89
iarena.h
Memory arena interface.
log.h
Logging.
roc_log
#define roc_log(level,...)
Print message to log.
Definition
log.h:31
roc::core
General-purpose building blocks and platform abstraction layer.
roc
Root namespace.
roc::LogError
@ LogError
Error message.
Definition
log.h:45
noncopyable.h
Non-copyable object.
panic.h
Panic.
roc_panic
#define roc_panic(...)
Print error message and terminate program gracefully.
Definition
panic.h:50
roc_core
ring_queue.h
Generated by
1.17.0