Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/cubeb/src/cubeb_utils.h
4246 views
1
/*
2
* Copyright © 2016 Mozilla Foundation
3
*
4
* This program is made available under an ISC-style license. See the
5
* accompanying file LICENSE for details.
6
*/
7
8
#if !defined(CUBEB_UTILS)
9
#define CUBEB_UTILS
10
11
#include "cubeb/cubeb.h"
12
13
#ifdef __cplusplus
14
15
#include <assert.h>
16
#include <mutex>
17
#include <stdint.h>
18
#include <string.h>
19
#include <type_traits>
20
#if defined(_WIN32)
21
#include "cubeb_utils_win.h"
22
#else
23
#include "cubeb_utils_unix.h"
24
#endif
25
26
/** Similar to memcpy, but accounts for the size of an element. */
27
template <typename T>
28
void
29
PodCopy(T * destination, const T * source, size_t count)
30
{
31
static_assert(std::is_trivial<T>::value, "Requires trivial type");
32
assert(destination && source);
33
memcpy(destination, source, count * sizeof(T));
34
}
35
36
/** Similar to memmove, but accounts for the size of an element. */
37
template <typename T>
38
void
39
PodMove(T * destination, const T * source, size_t count)
40
{
41
static_assert(std::is_trivial<T>::value, "Requires trivial type");
42
assert(destination && source);
43
memmove(destination, source, count * sizeof(T));
44
}
45
46
/** Similar to a memset to zero, but accounts for the size of an element. */
47
template <typename T>
48
void
49
PodZero(T * destination, size_t count)
50
{
51
static_assert(std::is_trivial<T>::value, "Requires trivial type");
52
assert(destination);
53
memset(destination, 0, count * sizeof(T));
54
}
55
56
namespace {
57
template <typename T, typename Trait>
58
void
59
Copy(T * destination, const T * source, size_t count, Trait)
60
{
61
for (size_t i = 0; i < count; i++) {
62
destination[i] = source[i];
63
}
64
}
65
66
template <typename T>
67
void
68
Copy(T * destination, const T * source, size_t count, std::true_type)
69
{
70
PodCopy(destination, source, count);
71
}
72
} // namespace
73
74
/**
75
* This allows copying a number of elements from a `source` pointer to a
76
* `destination` pointer, using `memcpy` if it is safe to do so, or a loop that
77
* calls the constructors and destructors otherwise.
78
*/
79
template <typename T>
80
void
81
Copy(T * destination, const T * source, size_t count)
82
{
83
assert(destination && source);
84
Copy(destination, source, count, typename std::is_trivial<T>::type());
85
}
86
87
namespace {
88
template <typename T, typename Trait>
89
void
90
ConstructDefault(T * destination, size_t count, Trait)
91
{
92
for (size_t i = 0; i < count; i++) {
93
destination[i] = T();
94
}
95
}
96
97
template <typename T>
98
void
99
ConstructDefault(T * destination, size_t count, std::true_type)
100
{
101
PodZero(destination, count);
102
}
103
} // namespace
104
105
/**
106
* This allows zeroing (using memset) or default-constructing a number of
107
* elements calling the constructors and destructors if necessary.
108
*/
109
template <typename T>
110
void
111
ConstructDefault(T * destination, size_t count)
112
{
113
assert(destination);
114
ConstructDefault(destination, count, typename std::is_arithmetic<T>::type());
115
}
116
117
template <typename T> class auto_array {
118
public:
119
explicit auto_array(uint32_t capacity = 0)
120
: data_(capacity ? new T[capacity] : nullptr), capacity_(capacity),
121
length_(0)
122
{
123
}
124
125
~auto_array() { delete[] data_; }
126
127
/** Get a constant pointer to the underlying data. */
128
T * data() const { return data_; }
129
130
T * end() const { return data_ + length_; }
131
132
const T & at(size_t index) const
133
{
134
assert(index < length_ && "out of range");
135
return data_[index];
136
}
137
138
T & at(size_t index)
139
{
140
assert(index < length_ && "out of range");
141
return data_[index];
142
}
143
144
/** Get how much underlying storage this auto_array has. */
145
size_t capacity() const { return capacity_; }
146
147
/** Get how much elements this auto_array contains. */
148
size_t length() const { return length_; }
149
150
/** Keeps the storage, but removes all the elements from the array. */
151
void clear() { length_ = 0; }
152
153
/** Change the storage of this auto array, copying the elements to the new
154
* storage.
155
* @returns true in case of success
156
* @returns false if the new capacity is not big enough to accomodate for the
157
* elements in the array.
158
*/
159
bool reserve(size_t new_capacity)
160
{
161
if (new_capacity < length_) {
162
return false;
163
}
164
T * new_data = new T[new_capacity];
165
if (data_ && length_) {
166
PodCopy(new_data, data_, length_);
167
}
168
capacity_ = new_capacity;
169
delete[] data_;
170
data_ = new_data;
171
172
return true;
173
}
174
175
/** Append `length` elements to the end of the array, resizing the array if
176
* needed.
177
* @parameter elements the elements to append to the array.
178
* @parameter length the number of elements to append to the array.
179
*/
180
void push(const T * elements, size_t length)
181
{
182
if (length_ + length > capacity_) {
183
reserve(length_ + length);
184
}
185
if (data_) {
186
PodCopy(data_ + length_, elements, length);
187
}
188
length_ += length;
189
}
190
191
/** Append `length` zero-ed elements to the end of the array, resizing the
192
* array if needed.
193
* @parameter length the number of elements to append to the array.
194
*/
195
void push_silence(size_t length)
196
{
197
if (length_ + length > capacity_) {
198
reserve(length + length_);
199
}
200
if (data_) {
201
PodZero(data_ + length_, length);
202
}
203
length_ += length;
204
}
205
206
/** Prepend `length` zero-ed elements to the front of the array, resizing and
207
* shifting the array if needed.
208
* @parameter length the number of elements to prepend to the array.
209
*/
210
void push_front_silence(size_t length)
211
{
212
if (length_ + length > capacity_) {
213
reserve(length + length_);
214
}
215
if (data_) {
216
PodMove(data_ + length, data_, length_);
217
PodZero(data_, length);
218
}
219
length_ += length;
220
}
221
222
/** Return the number of free elements in the array. */
223
size_t available() const { return capacity_ - length_; }
224
225
/** Copies `length` elements to `elements` if it is not null, and shift
226
* the remaining elements of the `auto_array` to the beginning.
227
* @parameter elements a buffer to copy the elements to, or nullptr.
228
* @parameter length the number of elements to copy.
229
* @returns true in case of success.
230
* @returns false if the auto_array contains less than `length` elements. */
231
bool pop(T * elements, size_t length)
232
{
233
if (length > length_) {
234
return false;
235
}
236
if (!data_) {
237
return true;
238
}
239
if (elements) {
240
PodCopy(elements, data_, length);
241
}
242
PodMove(data_, data_ + length, length_ - length);
243
244
length_ -= length;
245
246
return true;
247
}
248
249
void set_length(size_t length)
250
{
251
assert(length <= capacity_);
252
length_ = length;
253
}
254
255
private:
256
/** The underlying storage */
257
T * data_;
258
/** The size, in number of elements, of the storage. */
259
size_t capacity_;
260
/** The number of elements the array contains. */
261
size_t length_;
262
};
263
264
struct auto_array_wrapper {
265
virtual void push(void * elements, size_t length) = 0;
266
virtual size_t length() = 0;
267
virtual void push_silence(size_t length) = 0;
268
virtual bool pop(size_t length) = 0;
269
virtual void * data() = 0;
270
virtual void * end() = 0;
271
virtual void clear() = 0;
272
virtual bool reserve(size_t capacity) = 0;
273
virtual void set_length(size_t length) = 0;
274
virtual ~auto_array_wrapper() {}
275
};
276
277
template <typename T>
278
struct auto_array_wrapper_impl : public auto_array_wrapper {
279
auto_array_wrapper_impl() {}
280
281
explicit auto_array_wrapper_impl(uint32_t size) : ar(size) {}
282
283
void push(void * elements, size_t length) override
284
{
285
ar.push(static_cast<T *>(elements), length);
286
}
287
288
size_t length() override { return ar.length(); }
289
290
void push_silence(size_t length) override { ar.push_silence(length); }
291
292
bool pop(size_t length) override { return ar.pop(nullptr, length); }
293
294
void * data() override { return ar.data(); }
295
296
void * end() override { return ar.end(); }
297
298
void clear() override { ar.clear(); }
299
300
bool reserve(size_t capacity) override { return ar.reserve(capacity); }
301
302
void set_length(size_t length) override { ar.set_length(length); }
303
304
~auto_array_wrapper_impl() { ar.clear(); }
305
306
private:
307
auto_array<T> ar;
308
};
309
310
extern "C" {
311
size_t
312
cubeb_sample_size(cubeb_sample_format format);
313
}
314
315
using auto_lock = std::lock_guard<owned_critical_section>;
316
#endif // __cplusplus
317
318
#endif /* CUBEB_UTILS */
319
320