109 lines
3.1 KiB
C
109 lines
3.1 KiB
C
#include <c_ByteRingBuffer.h>
|
|||
|
|
#include <c_Memory.h>
|
||
|
|
#include <c_Alignment.h>
|
||
|
|
|
||
|
|
c_err_t c_ByteRingBuffer_Init(c_ByteRingBuffer_t* self, c_size_t capacity) {
|
||
|
|
if (!self || capacity == 0) return C_ERR_PARAM;
|
||
|
|
|
||
|
|
self->capacity = capacity;
|
||
|
|
self->head = 0;
|
||
|
|
self->tail = 0;
|
||
|
|
self->is_full = C_FALSE;
|
||
|
|
|
||
|
|
self->buffer = (uint8_t*)C_ALLOC(self->capacity);
|
||
|
|
if (!self->buffer) {
|
||
|
|
self->capacity = 0;
|
||
|
|
return C_ERR_NOMEM;
|
||
|
|
}
|
||
|
|
|
||
|
|
return C_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
void c_ByteRingBuffer_Destroy(c_ByteRingBuffer_t* self) {
|
||
|
|
if (!self) return;
|
||
|
|
|
||
|
|
C_FREE(self->buffer);
|
||
|
|
self->capacity = 0;
|
||
|
|
self->head = 0;
|
||
|
|
self->tail = 0;
|
||
|
|
self->is_full = C_FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Writes a single byte. O(1) performance.
|
||
|
|
c_err_t c_ByteRingBuffer_WriteByte(c_ByteRingBuffer_t* self, uint8_t byte) {
|
||
|
|
if (!self || !self->buffer) return C_ERR_PARAM;
|
||
|
|
if (self->is_full) return C_ERR_FULL;
|
||
|
|
|
||
|
|
self->buffer[self->tail] = byte;
|
||
|
|
self->tail = (self->tail + 1) % self->capacity;
|
||
|
|
|
||
|
|
if (self->tail == self->head) {
|
||
|
|
self->is_full = C_TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return C_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Reads a single byte. O(1) performance.
|
||
|
|
c_err_t c_ByteRingBuffer_ReadByte(c_ByteRingBuffer_t* self, uint8_t* out_byte) {
|
||
|
|
if (!self || !self->buffer || !out_byte) return C_ERR_PARAM;
|
||
|
|
if (c_ByteRingBuffer_IsEmpty(self)) return C_ERR_EMPTY;
|
||
|
|
|
||
|
|
*out_byte = self->buffer[self->head];
|
||
|
|
self->head = (self->head + 1) % self->capacity;
|
||
|
|
self->is_full = C_FALSE;
|
||
|
|
|
||
|
|
return C_ERR_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Writes an entire chunk of bytes. Returns the total number of bytes successfully written.
|
||
|
|
c_size_t c_ByteRingBuffer_WriteBuffer(c_ByteRingBuffer_t* self, const uint8_t* src, c_size_t len) {
|
||
|
|
if (!self || !self->buffer || !src || len == 0) return 0;
|
||
|
|
|
||
|
|
c_size_t bytes_written = 0;
|
||
|
|
while (bytes_written < len && !self->is_full) {
|
||
|
|
self->buffer[self->tail] = src[bytes_written];
|
||
|
|
self->tail = (self->tail + 1) % self->capacity;
|
||
|
|
|
||
|
|
if (self->tail == self->head) {
|
||
|
|
self->is_full = C_TRUE;
|
||
|
|
}
|
||
|
|
bytes_written++;
|
||
|
|
}
|
||
|
|
return bytes_written;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Reads an entire chunk of bytes. Returns the total number of bytes successfully read.
|
||
|
|
c_size_t c_ByteRingBuffer_ReadBuffer(c_ByteRingBuffer_t* self, uint8_t* dest, c_size_t len) {
|
||
|
|
if (!self || !self->buffer || !dest || len == 0) return 0;
|
||
|
|
|
||
|
|
c_size_t bytes_read = 0;
|
||
|
|
while (bytes_read < len && !c_ByteRingBuffer_IsEmpty(self)) {
|
||
|
|
dest[bytes_read] = self->buffer[self->head];
|
||
|
|
self->head = (self->head + 1) % self->capacity;
|
||
|
|
self->is_full = C_FALSE;
|
||
|
|
bytes_read++;
|
||
|
|
}
|
||
|
|
return bytes_read;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_size_t c_ByteRingBuffer_GetSize(const c_ByteRingBuffer_t* self) {
|
||
|
|
if (!self || !self->buffer) return 0;
|
||
|
|
if (self->is_full) return self->capacity;
|
||
|
|
|
||
|
|
if (self->tail >= self->head) {
|
||
|
|
return self->tail - self->head;
|
||
|
|
} else {
|
||
|
|
return self->capacity + self->tail - self->head;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
c_bool_t c_ByteRingBuffer_IsEmpty(const c_ByteRingBuffer_t* self) {
|
||
|
|
if (!self) return C_TRUE;
|
||
|
|
return (self->head == self->tail) && !self->is_full;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_bool_t c_ByteRingBuffer_IsFull(const c_ByteRingBuffer_t* self) {
|
||
|
|
if (!self) return C_FALSE;
|
||
|
|
return self->is_full;
|
||
|
|
}
|