Roc Toolkit internal modules
Roc Toolkit: real-time audio streaming
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"
19#include "roc_core/panic.h"
20
21namespace roc {
22namespace 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.
37template <class T, size_t EmbeddedCapacity = 0> class RingQueue : public NonCopyable<> {
38public:
39 //! Initialize.
40 //! @remarks
41 //! Preallocate buffer in @p arena with @p max_len number of elements.
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
170private:
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) {
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_
Dynamic array.
Memory arena interface.
Definition iarena.h:23
virtual void deallocate(void *ptr)=0
Deallocate previously allocated memory.
virtual void * allocate(size_t size)=0
Allocate memory.
Base class for non-copyable objects.
Definition noncopyable.h:23
Queue on continuous memory buffer.
Definition ring_queue.h:37
bool is_valid() const
Check that initial allocation succeeded.
Definition ring_queue.h:62
RingQueue(core::IArena &arena, size_t max_len)
Initialize.
Definition ring_queue.h:42
const T & front() const
Get reference of the front element.
Definition ring_queue.h:99
void push_front(const T &x)
Push an element to the front of the queue.
Definition ring_queue.h:129
bool is_full()
Is the queue full.
Definition ring_queue.h:82
void pop_back()
Remove the first element from the back.
Definition ring_queue.h:162
bool is_empty()
Is the queue empty.
Definition ring_queue.h:77
size_t capacity() const
Get maximum number of elements in queue/.
Definition ring_queue.h:67
T & back()
Get reference of the back element.
Definition ring_queue.h:109
const T & back() const
Get reference of the back element.
Definition ring_queue.h:119
void pop_front()
Remove the first element from the front.
Definition ring_queue.h:140
size_t size() const
Get current number of elements in the queue.
Definition ring_queue.h:72
void push_back(const T &x)
Push an element to the backside of the queue.
Definition ring_queue.h:151
T & front()
Get reference of the front element.
Definition ring_queue.h:89
Shared ownership intrusive pointer.
Definition shared_ptr.h:32
Memory arena interface.
Logging.
#define roc_log(level,...)
Print message to log.
Definition log.h:31
Root namespace.
@ LogError
Error message.
Definition log.h:45
Non-copyable object.
Panic.
#define roc_panic(...)
Print error message and terminate program gracefully.
Definition panic.h:50