зеркало из https://github.com/mozilla/cubeb.git
Add an auto pointer and an auto array class
The auto pointer frees in the dtor. The auto array has a number of feature that are useful to work with real-time streaming audio: push back and pop front (because we're dealing with temporal data), insert silence, auto resize, no compaction when it's resized down, bound check, direct internal access to work nicely with other APIs.
This commit is contained in:
Родитель
c438f775a6
Коммит
1f13325871
|
@ -47,6 +47,8 @@ test/test_tone
|
|||
test/test_tone.exe
|
||||
test/test_devices
|
||||
test/test_devices.exe
|
||||
test/test_utils
|
||||
test/test_utils.exe
|
||||
include/cubeb/cubeb-stdint.h
|
||||
test-suite.log
|
||||
test/test_sanity.log
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
AUTOMAKE_OPTIONS = foreign 1.10 dist-bzip2 subdir-objects
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(top_srcdir)/src
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(top_srcdir)/src -std=c++11
|
||||
AM_CFLAGS = -ansi -std=gnu99 -Wall -Wextra -Wno-long-long -O2 -g -Wno-unused-parameter
|
||||
|
||||
SUBDIRS = docs
|
||||
|
@ -80,6 +80,7 @@ check_PROGRAMS = test/test_sanity \
|
|||
test/test_audio \
|
||||
test/test_latency \
|
||||
test/test_devices \
|
||||
test/test_utils \
|
||||
$(NULL)
|
||||
|
||||
test_test_sanity_SOURCES = test/test_sanity.cpp
|
||||
|
@ -97,7 +98,10 @@ test_test_latency_LDADD = -lm src/libcubeb.la $(platform_lib)
|
|||
test_test_devices_SOURCES = test/test_devices.cpp
|
||||
test_test_devices_LDADD = -lm src/libcubeb.la $(platform_lib)
|
||||
|
||||
TESTS = test/test_sanity
|
||||
|
||||
test_test_resampler_SOURCES = test/test_utils.cpp
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
DISTCLEANFILES = include/cubeb/cubeb-stdint.h
|
||||
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/** Similar to memcpy, but accounts for the size of an element. */
|
||||
template<typename T>
|
||||
void PodCopy(T * destination, const T * source, size_t count)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
memset(destination, 0, count * sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class auto_array
|
||||
{
|
||||
public:
|
||||
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_;
|
||||
}
|
||||
|
||||
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 resize(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_) {
|
||||
resize(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(size_t length)
|
||||
{
|
||||
if (length_ + length > capacity_) {
|
||||
resize(length + length_);
|
||||
}
|
||||
PodZero(data_ + length_, 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;
|
||||
}
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class auto_ptr
|
||||
{
|
||||
public:
|
||||
auto_ptr(T * ptr)
|
||||
: ptr(ptr)
|
||||
{}
|
||||
~auto_ptr()
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
T * get() const
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
T* operator->() const {
|
||||
assert(ptr && "null pointer dereference.");
|
||||
return ptr;
|
||||
}
|
||||
operator bool() const
|
||||
{
|
||||
return !!ptr;
|
||||
}
|
||||
private:
|
||||
T * ptr;
|
||||
};
|
||||
|
||||
#endif /* CUBEB_UTILS */
|
|
@ -0,0 +1,80 @@
|
|||
#include <cassert>
|
||||
#include "cubeb_utils.h"
|
||||
|
||||
int test_auto_array()
|
||||
{
|
||||
auto_array<uint32_t> array;
|
||||
auto_array<uint32_t> array2(10);
|
||||
uint32_t a[10];
|
||||
|
||||
assert(array2.length() == 0);
|
||||
assert(array2.capacity() == 10);
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < 10; i++) {
|
||||
a[i] = i;
|
||||
}
|
||||
|
||||
assert(array.capacity() == 0);
|
||||
assert(array.length() == 0);
|
||||
|
||||
array.push(a, 10);
|
||||
|
||||
assert(!array.resize(9));
|
||||
|
||||
for (uint32_t i = 0; i < 10; i++) {
|
||||
assert(array.data()[i] == i);
|
||||
}
|
||||
|
||||
assert(array.capacity() == 10);
|
||||
assert(array.length() == 10);
|
||||
|
||||
uint32_t b[10];
|
||||
|
||||
array.pop(b, 5);
|
||||
|
||||
assert(array.capacity() == 10);
|
||||
assert(array.length() == 5);
|
||||
for (uint32_t i = 0; i < 5; i++) {
|
||||
assert(b[i] == i);
|
||||
assert(array.data()[i] == 5 + i);
|
||||
}
|
||||
uint32_t* bb = b + 5;
|
||||
array.pop(bb, 5);
|
||||
|
||||
assert(array.capacity() == 10);
|
||||
assert(array.length() == 0);
|
||||
for (uint32_t i = 0; i < 5; i++) {
|
||||
assert(bb[i] == 5 + i);
|
||||
}
|
||||
|
||||
assert(!array.pop(nullptr, 1));
|
||||
|
||||
array.push(a, 10);
|
||||
array.push(a, 10);
|
||||
|
||||
for (uint32_t j = 0; j < 2; j++) {
|
||||
for (uint32_t i = 0; i < 10; i++) {
|
||||
assert(array.data()[10 * j + i] == i);
|
||||
}
|
||||
}
|
||||
assert(array.length() == 20);
|
||||
assert(array.capacity() == 20);
|
||||
array.pop(nullptr, 5);
|
||||
|
||||
for (uint32_t i = 0; i < 5; i++) {
|
||||
assert(array.data()[i] == 5 + i);
|
||||
}
|
||||
|
||||
assert(array.length() == 15);
|
||||
assert(array.capacity() == 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
test_auto_array();
|
||||
return 0;
|
||||
}
|
Загрузка…
Ссылка в новой задаче