diff options
Diffstat (limited to 'media/libcubeb/src/cubeb_utils.h')
-rw-r--r-- | media/libcubeb/src/cubeb_utils.h | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/media/libcubeb/src/cubeb_utils.h b/media/libcubeb/src/cubeb_utils.h new file mode 100644 index 0000000000..fd7a3d7406 --- /dev/null +++ b/media/libcubeb/src/cubeb_utils.h @@ -0,0 +1,309 @@ +/* + * Copyright © 2016 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ + +#if !defined(CUBEB_UTILS) +#define CUBEB_UTILS + +#include "cubeb/cubeb.h" + +#ifdef __cplusplus + +#include <assert.h> +#include <mutex> +#include <stdint.h> +#include <string.h> +#include <type_traits> +#if defined(_WIN32) +#include "cubeb_utils_win.h" +#else +#include "cubeb_utils_unix.h" +#endif + +/** Similar to memcpy, but accounts for the size of an element. */ +template <typename T> +void +PodCopy(T * destination, const T * source, size_t count) +{ + static_assert(std::is_trivial<T>::value, "Requires trivial type"); + assert(destination && source); + memcpy(destination, source, count * sizeof(T)); +} + +/** Similar to memmove, but accounts for the size of an element. */ +template <typename T> +void +PodMove(T * destination, const T * source, size_t count) +{ + static_assert(std::is_trivial<T>::value, "Requires trivial type"); + assert(destination && source); + memmove(destination, source, count * sizeof(T)); +} + +/** Similar to a memset to zero, but accounts for the size of an element. */ +template <typename T> +void +PodZero(T * destination, size_t count) +{ + static_assert(std::is_trivial<T>::value, "Requires trivial type"); + assert(destination); + memset(destination, 0, count * sizeof(T)); +} + +namespace { +template <typename T, typename Trait> +void +Copy(T * destination, const T * source, size_t count, Trait) +{ + for (size_t i = 0; i < count; i++) { + destination[i] = source[i]; + } +} + +template <typename T> +void +Copy(T * destination, const T * source, size_t count, std::true_type) +{ + PodCopy(destination, source, count); +} +} // namespace + +/** + * This allows copying a number of elements from a `source` pointer to a + * `destination` pointer, using `memcpy` if it is safe to do so, or a loop that + * calls the constructors and destructors otherwise. + */ +template <typename T> +void +Copy(T * destination, const T * source, size_t count) +{ + assert(destination && source); + Copy(destination, source, count, typename std::is_trivial<T>::type()); +} + +namespace { +template <typename T, typename Trait> +void +ConstructDefault(T * destination, size_t count, Trait) +{ + for (size_t i = 0; i < count; i++) { + destination[i] = T(); + } +} + +template <typename T> +void +ConstructDefault(T * destination, size_t count, std::true_type) +{ + PodZero(destination, count); +} +} // namespace + +/** + * This allows zeroing (using memset) or default-constructing a number of + * elements calling the constructors and destructors if necessary. + */ +template <typename T> +void +ConstructDefault(T * destination, size_t count) +{ + assert(destination); + ConstructDefault(destination, count, typename std::is_arithmetic<T>::type()); +} + +template <typename T> class auto_array { +public: + explicit auto_array(uint32_t capacity = 0) + : data_(capacity ? new T[capacity] : nullptr), capacity_(capacity), + length_(0) + { + } + + ~auto_array() { delete[] data_; } + + /** Get a constant pointer to the underlying data. */ + T * data() const { return data_; } + + T * end() const { return data_ + length_; } + + const T & at(size_t index) const + { + assert(index < length_ && "out of range"); + return data_[index]; + } + + T & at(size_t index) + { + assert(index < length_ && "out of range"); + return data_[index]; + } + + /** Get how much underlying storage this auto_array has. */ + size_t capacity() const { return capacity_; } + + /** Get how much elements this auto_array contains. */ + size_t length() const { return length_; } + + /** Keeps the storage, but removes all the elements from the array. */ + void clear() { length_ = 0; } + + /** Change the storage of this auto array, copying the elements to the new + * storage. + * @returns true in case of success + * @returns false if the new capacity is not big enough to accomodate for the + * elements in the array. + */ + bool reserve(size_t new_capacity) + { + if (new_capacity < length_) { + return false; + } + T * new_data = new T[new_capacity]; + if (data_ && length_) { + PodCopy(new_data, data_, length_); + } + capacity_ = new_capacity; + delete[] data_; + data_ = new_data; + + return true; + } + + /** Append `length` elements to the end of the array, resizing the array if + * needed. + * @parameter elements the elements to append to the array. + * @parameter length the number of elements to append to the array. + */ + void push(const T * elements, size_t length) + { + if (length_ + length > capacity_) { + reserve(length_ + length); + } + PodCopy(data_ + length_, elements, length); + length_ += length; + } + + /** Append `length` zero-ed elements to the end of the array, resizing the + * array if needed. + * @parameter length the number of elements to append to the array. + */ + void push_silence(size_t length) + { + if (length_ + length > capacity_) { + reserve(length + length_); + } + PodZero(data_ + length_, length); + length_ += length; + } + + /** Prepend `length` zero-ed elements to the end of the array, resizing the + * array if needed. + * @parameter length the number of elements to prepend to the array. + */ + void push_front_silence(size_t length) + { + if (length_ + length > capacity_) { + reserve(length + length_); + } + PodMove(data_ + length, data_, length_); + PodZero(data_, length); + length_ += length; + } + + /** Return the number of free elements in the array. */ + size_t available() const { return capacity_ - length_; } + + /** Copies `length` elements to `elements` if it is not null, and shift + * the remaining elements of the `auto_array` to the beginning. + * @parameter elements a buffer to copy the elements to, or nullptr. + * @parameter length the number of elements to copy. + * @returns true in case of success. + * @returns false if the auto_array contains less than `length` elements. */ + bool pop(T * elements, size_t length) + { + if (length > length_) { + return false; + } + if (elements) { + PodCopy(elements, data_, length); + } + PodMove(data_, data_ + length, length_ - length); + + length_ -= length; + + return true; + } + + void set_length(size_t length) + { + assert(length <= capacity_); + length_ = length; + } + +private: + /** The underlying storage */ + T * data_; + /** The size, in number of elements, of the storage. */ + size_t capacity_; + /** The number of elements the array contains. */ + size_t length_; +}; + +struct auto_array_wrapper { + virtual void push(void * elements, size_t length) = 0; + virtual size_t length() = 0; + virtual void push_silence(size_t length) = 0; + virtual bool pop(size_t length) = 0; + virtual void * data() = 0; + virtual void * end() = 0; + virtual void clear() = 0; + virtual bool reserve(size_t capacity) = 0; + virtual void set_length(size_t length) = 0; + virtual ~auto_array_wrapper() {} +}; + +template <typename T> +struct auto_array_wrapper_impl : public auto_array_wrapper { + auto_array_wrapper_impl() {} + + explicit auto_array_wrapper_impl(uint32_t size) : ar(size) {} + + void push(void * elements, size_t length) override + { + ar.push(static_cast<T *>(elements), length); + } + + size_t length() override { return ar.length(); } + + void push_silence(size_t length) override { ar.push_silence(length); } + + bool pop(size_t length) override { return ar.pop(nullptr, length); } + + void * data() override { return ar.data(); } + + void * end() override { return ar.end(); } + + void clear() override { ar.clear(); } + + bool reserve(size_t capacity) override { return ar.reserve(capacity); } + + void set_length(size_t length) override { ar.set_length(length); } + + ~auto_array_wrapper_impl() { ar.clear(); } + +private: + auto_array<T> ar; +}; + +extern "C" { +size_t +cubeb_sample_size(cubeb_sample_format format); +} + +using auto_lock = std::lock_guard<owned_critical_section>; +#endif // __cplusplus + +#endif /* CUBEB_UTILS */ |