Roc Toolkit internal modules
Roc Toolkit: real-time audio streaming
Toggle main menu visibility
Loading...
Searching...
No Matches
array.h
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2015 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/array.h
10
//! @brief Dynamic array.
11
12
#ifndef ROC_CORE_ARRAY_H_
13
#define ROC_CORE_ARRAY_H_
14
15
#include "
roc_core/aligned_storage.h
"
16
#include "
roc_core/attributes.h
"
17
#include "
roc_core/iarena.h
"
18
#include "
roc_core/log.h
"
19
#include "
roc_core/noncopyable.h
"
20
#include "
roc_core/panic.h
"
21
#include "
roc_core/stddefs.h
"
22
23
namespace
roc
{
24
namespace
core
{
25
26
//! Dynamic array.
27
//!
28
//! Elements are stored continuously in a memory chunk allocated using IArena,
29
//! or directly in Array object when number of elements is small.
30
//!
31
//! Array supports resizing and inserting and removing elements in the end with
32
//! amortized O(1) complexity.
33
//!
34
//! @tparam T defines array element type. It should have default constructor,
35
//! copy constructor, and assignment operator.
36
//!
37
//! @tparam EmbeddedCapacity defines number of elements in the fixed-size chunk
38
//! embedded directly into Array object; it is used instead of dynamic memory if
39
//! the array size is small enough.
40
template
<
class
T,
size_t
EmbeddedCapacity = 0>
class
Array
:
public
NonCopyable<> {
41
public
:
42
//! Initialize empty array with arena.
43
//! @remarks
44
//! Array capacity may grow using arena.
45
explicit
Array
(
IArena
& arena)
46
: data_(NULL)
47
, size_(0)
48
, capacity_(0)
49
, arena_(arena) {
50
}
51
52
~Array
() {
53
clear
();
54
55
if
(data_) {
56
deallocate_(data_);
57
}
58
}
59
60
//! Get maximum number of elements that can be added without reallocation.
61
size_t
capacity
()
const
{
62
return
capacity_;
63
}
64
65
//! Get number of elements.
66
size_t
size
()
const
{
67
return
size_;
68
}
69
70
//! Check if size is zero.
71
bool
is_empty
()
const
{
72
return
size_ == 0;
73
}
74
75
//! Get pointer to first element.
76
//! @remarks
77
//! Returns null if the array is empty.
78
T*
data
() {
79
if
(size_ == 0) {
80
roc_panic
(
"array: is empty"
);
81
}
82
return
data_;
83
}
84
85
//! Get pointer to first element.
86
//! @remarks
87
//! Returns null if the array is empty.
88
const
T*
data
()
const
{
89
if
(size_ == 0) {
90
roc_panic
(
"array: is empty"
);
91
}
92
return
data_;
93
}
94
95
//! Get element at given position.
96
//! @pre
97
//! Panics if index is out of bounds.
98
T&
operator[]
(
size_t
index) {
99
roc_panic_if_msg
(index >= size_,
100
"array: subscript out of range: index=%lu size=%lu"
,
101
(
unsigned
long
)index, (
unsigned
long
)size_);
102
103
return
data_[index];
104
}
105
106
//! Get element at given position.
107
//! @pre
108
//! Panics if index is out of bounds.
109
const
T&
operator[]
(
size_t
index)
const
{
110
roc_panic_if_msg
(index >= size_,
111
"array: subscript out of range: index=%lu size=%lu"
,
112
(
unsigned
long
)index, (
unsigned
long
)size_);
113
114
return
data_[index];
115
}
116
117
//! Get reference to first element.
118
T&
front
() {
119
if
(size_ == 0) {
120
roc_panic
(
"array: is empty"
);
121
}
122
return
data_[0];
123
}
124
125
//! Get const reference to first element.
126
const
T&
front
()
const
{
127
if
(size_ == 0) {
128
roc_panic
(
"array: is empty"
);
129
}
130
return
data_[0];
131
}
132
133
//! Get reference to last element.
134
T&
back
() {
135
if
(size_ == 0) {
136
roc_panic
(
"array: is empty"
);
137
}
138
return
data_[size_ - 1];
139
}
140
141
//! Get const reference to last element.
142
const
T&
back
()
const
{
143
if
(size_ == 0) {
144
roc_panic
(
"array: is empty"
);
145
}
146
return
data_[size_ - 1];
147
}
148
149
//! Append element to array.
150
//! @returns
151
//! false if the allocation failed.
152
//! @note
153
//! has amortized O(1) complexity, O(n) in worst case.
154
ROC_ATTR_NODISCARD
bool
push_back
(
const
T& value) {
155
if
(!
grow_exp
(size_ + 1)) {
156
return
false
;
157
}
158
159
new
(data_ + size_) T(value);
160
size_++;
161
162
return
true
;
163
}
164
165
//! Remove last element from the array.
166
//! @pre
167
//! Panics if array is empty.
168
void
pop_back
() {
169
if
(size_ == 0) {
170
roc_panic
(
"array: array is empty"
);
171
}
172
173
// Destruct object
174
data_[size_ - 1].~T();
175
size_--;
176
}
177
178
//! Set array size.
179
//! @remarks
180
//! Calls grow() to ensure that there is enough space in array.
181
//! @returns
182
//! false if the allocation failed
183
ROC_ATTR_NODISCARD
bool
resize
(
size_t
new_size) {
184
// Move objects to a new memory region if necessary.
185
if
(!
grow
(new_size)) {
186
return
false
;
187
}
188
189
// Construct new objects if size increased.
190
for
(
size_t
n = size_; n < new_size; n++) {
191
new
(data_ + n) T();
192
}
193
194
// Destruct old objects (in reversed order) if size decreased.
195
for
(
size_t
n = size_; n > new_size; n--) {
196
data_[n - 1].~T();
197
}
198
199
size_ = new_size;
200
201
return
true
;
202
}
203
204
//! Set array size to zero.
205
//! @remarks
206
//! Never fails.
207
void
clear
() {
208
(void)
resize
(0);
209
}
210
211
//! Increase array capacity.
212
//! @remarks
213
//! If @p min_capacity is greater than the current capacity, a larger memory
214
//! region is allocated and the array elements are copied there.
215
//! @returns
216
//! false if the allocation failed.
217
ROC_ATTR_NODISCARD
bool
grow
(
size_t
min_capacity) {
218
if
(min_capacity <= capacity_) {
219
return
true
;
220
}
221
222
T* new_data = allocate_(min_capacity);
223
if
(!new_data) {
224
return
false
;
225
}
226
227
if
(new_data != data_) {
228
// Copy old objects to new memory.
229
for
(
size_t
n = 0; n < size_; n++) {
230
new
(new_data + n) T(data_[n]);
231
}
232
233
// Destruct objects in old memory (in reversed order).
234
for
(
size_t
n = size_; n > 0; n--) {
235
data_[n - 1].~T();
236
}
237
238
// Free old memory.
239
if
(data_) {
240
deallocate_(data_);
241
}
242
243
data_ = new_data;
244
}
245
246
capacity_ = min_capacity;
247
return
true
;
248
}
249
250
//! Increase array capacity exponentially.
251
//! @remarks
252
//! If @p min_capacity is greater than the current capacity, a larger memory
253
//! region is allocated and the array elements are copied there.
254
//! The size growth will follow the sequence: 0, 2, 4, 8, 16, ... until
255
//! it reaches some threshold, and then starts growing linearly.
256
//! @returns
257
//! false if the allocation failed.
258
ROC_ATTR_NODISCARD
bool
grow_exp
(
size_t
min_capacity) {
259
if
(min_capacity <= capacity_) {
260
return
true
;
261
}
262
263
const
size_t
new_capacity = next_capacity_(min_capacity);
264
265
return
grow
(new_capacity);
266
}
267
268
private
:
269
T* allocate_(
size_t
n_elems) {
270
T*
data
= NULL;
271
272
if
(n_elems <= EmbeddedCapacity) {
273
data
= (T*)embedded_data_.memory();
274
}
else
{
275
data
= (T*)arena_.
allocate
(n_elems *
sizeof
(T));
276
}
277
278
if
(!
data
) {
279
roc_log
(
LogError
,
280
"array: can't allocate memory:"
281
" current_cap=%lu requested_cap=%lu embedded_cap=%lu"
,
282
(
unsigned
long
)capacity_, (
unsigned
long
)n_elems,
283
(
unsigned
long
)EmbeddedCapacity);
284
}
285
286
return
data
;
287
}
288
289
void
deallocate_(T*
data
) {
290
if
((
void
*)
data
!= (
void
*)embedded_data_.memory()) {
291
arena_.deallocate(
data
);
292
}
293
}
294
295
size_t
next_capacity_(
size_t
min_size)
const
{
296
size_t
new_capacity = capacity_;
297
298
if
(capacity_ < 1024) {
299
while
(min_size > new_capacity) {
300
new_capacity = (new_capacity == 0) ? 2 : new_capacity * 2;
301
}
302
}
else
{
303
while
(min_size > new_capacity) {
304
new_capacity += new_capacity / 4;
305
}
306
}
307
308
return
new_capacity;
309
}
310
311
T* data_;
312
size_t
size_;
313
size_t
capacity_;
314
315
IArena& arena_;
316
317
AlignedStorage<EmbeddedCapacity *
sizeof
(T)> embedded_data_;
318
};
319
320
}
// namespace core
321
}
// namespace roc
322
323
#endif
// ROC_CORE_ARRAY_H_
aligned_storage.h
Aligned storage.
attributes.h
Compiler attributes.
ROC_ATTR_NODISCARD
#define ROC_ATTR_NODISCARD
Emit warning if function result is not checked.
Definition
attributes.h:31
roc::core::Array
Dynamic array.
Definition
array.h:40
roc::core::Array::front
T & front()
Get reference to first element.
Definition
array.h:118
roc::core::Array::data
T * data()
Get pointer to first element.
Definition
array.h:78
roc::core::Array::front
const T & front() const
Get const reference to first element.
Definition
array.h:126
roc::core::Array::pop_back
void pop_back()
Remove last element from the array.
Definition
array.h:168
roc::core::Array::clear
void clear()
Set array size to zero.
Definition
array.h:207
roc::core::Array::data
const T * data() const
Get pointer to first element.
Definition
array.h:88
roc::core::Array::back
T & back()
Get reference to last element.
Definition
array.h:134
roc::core::Array::push_back
ROC_ATTR_NODISCARD bool push_back(const T &value)
Append element to array.
Definition
array.h:154
roc::core::Array::Array
Array(IArena &arena)
Initialize empty array with arena.
Definition
array.h:45
roc::core::Array::grow_exp
ROC_ATTR_NODISCARD bool grow_exp(size_t min_capacity)
Increase array capacity exponentially.
Definition
array.h:258
roc::core::Array::is_empty
bool is_empty() const
Check if size is zero.
Definition
array.h:71
roc::core::Array::grow
ROC_ATTR_NODISCARD bool grow(size_t min_capacity)
Increase array capacity.
Definition
array.h:217
roc::core::Array::back
const T & back() const
Get const reference to last element.
Definition
array.h:142
roc::core::Array::capacity
size_t capacity() const
Get maximum number of elements that can be added without reallocation.
Definition
array.h:61
roc::core::Array::operator[]
const T & operator[](size_t index) const
Get element at given position.
Definition
array.h:109
roc::core::Array::operator[]
T & operator[](size_t index)
Get element at given position.
Definition
array.h:98
roc::core::Array::resize
ROC_ATTR_NODISCARD bool resize(size_t new_size)
Set array size.
Definition
array.h:183
roc::core::Array::size
size_t size() const
Get number of elements.
Definition
array.h:66
roc::core::IArena
Memory arena interface.
Definition
iarena.h:23
roc::core::IArena::allocate
virtual void * allocate(size_t size)=0
Allocate memory.
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_if_msg
#define roc_panic_if_msg(x,...)
Panic if condition is true, printing custom message.
Definition
panic.h:40
roc_panic
#define roc_panic(...)
Print error message and terminate program gracefully.
Definition
panic.h:50
stddefs.h
Commonly used types and functions.
roc_core
array.h
Generated by
1.17.0