Refactor ring_buffer interface, add a feature and a test.

* Add a RingBuffer typedef.
* Add the ability to force a memcpy by passing a null ptr. In some cases,
  we know we want a memcpy. This allows us to skip a potential
  intermediate memcpy.
* Add a stress test.

Review URL: https://webrtc-codereview.appspot.com/1111004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3567 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andrew@webrtc.org
2013-02-25 17:07:35 +00:00
parent 8a0662306d
commit 9ae1354e25
9 changed files with 224 additions and 84 deletions

View File

@ -13,7 +13,7 @@
#include "ring_buffer.h"
#include <stddef.h> // size_t
#include <stddef.h> // size_t
#include <stdlib.h>
#include <string.h>
@ -22,21 +22,21 @@ enum Wrap {
DIFF_WRAP
};
typedef struct {
struct RingBuffer {
size_t read_pos;
size_t write_pos;
size_t element_count;
size_t element_size;
enum Wrap rw_wrap;
char* data;
} buf_t;
};
// Get address of region(s) from which we can read data.
// If the region is contiguous, |data_ptr_bytes_2| will be zero.
// If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second
// region. Returns room available to be read or |element_count|, whichever is
// smaller.
static size_t GetBufferReadRegions(buf_t* buf,
static size_t GetBufferReadRegions(RingBuffer* buf,
size_t element_count,
void** data_ptr_1,
size_t* data_ptr_bytes_1,
@ -65,23 +65,25 @@ static size_t GetBufferReadRegions(buf_t* buf,
return read_elements;
}
int WebRtc_CreateBuffer(void** handle,
int WebRtc_CreateBuffer(RingBuffer** handle,
size_t element_count,
size_t element_size) {
buf_t* self = NULL;
if (handle == NULL) {
RingBuffer* self = NULL;
if (!handle) {
return -1;
}
if (element_count == 0 || element_size == 0) {
return -1;
}
self = malloc(sizeof(buf_t));
if (self == NULL) {
self = malloc(sizeof(RingBuffer));
if (!self) {
return -1;
}
*handle = self;
self->data = malloc(element_count * element_size);
if (self->data == NULL) {
if (!self->data) {
free(self);
self = NULL;
return -1;
@ -93,10 +95,8 @@ int WebRtc_CreateBuffer(void** handle,
return 0;
}
int WebRtc_InitBuffer(void* handle) {
buf_t* self = (buf_t*) handle;
if (self == NULL) {
int WebRtc_InitBuffer(RingBuffer* self) {
if (!self) {
return -1;
}
@ -110,35 +110,27 @@ int WebRtc_InitBuffer(void* handle) {
return 0;
}
int WebRtc_FreeBuffer(void* handle) {
buf_t* self = (buf_t*) handle;
if (self == NULL) {
return -1;
void WebRtc_FreeBuffer(void* handle) {
RingBuffer* self = (RingBuffer*)handle;
if (!self) {
return;
}
free(self->data);
free(self);
return 0;
}
size_t WebRtc_ReadBuffer(void* handle,
size_t WebRtc_ReadBuffer(RingBuffer* self,
void** data_ptr,
void* data,
size_t element_count) {
buf_t* self = (buf_t*) handle;
if (self == NULL) {
return 0;
}
if (data == NULL) {
return 0;
}
if (data_ptr == NULL) {
return 0;
}
{
void* buf_ptr_1 = NULL;
@ -157,33 +149,35 @@ size_t WebRtc_ReadBuffer(void* handle,
// |data| and point to it.
memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2);
*data_ptr = data;
} else {
buf_ptr_1 = data;
} else if (!data_ptr) {
// No wrap, but a memcpy was requested.
memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
}
if (data_ptr) {
// |buf_ptr_1| == |data| in the case of a wrap.
*data_ptr = buf_ptr_1;
}
// Update read position
WebRtc_MoveReadPtr(handle, (int) read_count);
WebRtc_MoveReadPtr(self, (int) read_count);
return read_count;
}
}
size_t WebRtc_WriteBuffer(void* handle,
size_t WebRtc_WriteBuffer(RingBuffer* self,
const void* data,
size_t element_count) {
buf_t* self = (buf_t*) handle;
if (self == NULL) {
if (!self) {
return 0;
}
if (data == NULL) {
if (!data) {
return 0;
}
{
const size_t free_elements = WebRtc_available_write(handle);
const size_t free_elements = WebRtc_available_write(self);
const size_t write_elements = (free_elements < element_count ? free_elements
: element_count);
size_t n = write_elements;
@ -206,19 +200,16 @@ size_t WebRtc_WriteBuffer(void* handle,
}
}
int WebRtc_MoveReadPtr(void* handle, int element_count) {
buf_t* self = (buf_t*) handle;
if (self == NULL) {
int WebRtc_MoveReadPtr(RingBuffer* self, int element_count) {
if (!self) {
return 0;
}
{
// We need to be able to take care of negative changes, hence use "int"
// instead of "size_t".
const int free_elements = (int) WebRtc_available_write(handle);
const int readable_elements = (int) WebRtc_available_read(handle);
const int free_elements = (int) WebRtc_available_write(self);
const int readable_elements = (int) WebRtc_available_read(self);
int read_pos = (int) self->read_pos;
if (element_count > readable_elements) {
@ -246,10 +237,8 @@ int WebRtc_MoveReadPtr(void* handle, int element_count) {
}
}
size_t WebRtc_available_read(const void* handle) {
const buf_t* self = (buf_t*) handle;
if (self == NULL) {
size_t WebRtc_available_read(const RingBuffer* self) {
if (!self) {
return 0;
}
@ -260,12 +249,10 @@ size_t WebRtc_available_read(const void* handle) {
}
}
size_t WebRtc_available_write(const void* handle) {
const buf_t* self = (buf_t*) handle;
if (self == NULL) {
size_t WebRtc_available_write(const RingBuffer* self) {
if (!self) {
return 0;
}
return self->element_count - WebRtc_available_read(handle);
return self->element_count - WebRtc_available_read(self);
}