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