138 lines
3.2 KiB
C
138 lines
3.2 KiB
C
|
|
/* ring_buffer.c */
|
||
|
|
|
||
|
|
#include "ring_buffer.h"
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
bool rb_init(RingBuffer *rb, size_t capacity, size_t elem_size) {
|
||
|
|
rb->buffer = malloc(capacity * elem_size);
|
||
|
|
if (!rb->buffer) return false;
|
||
|
|
rb->max = capacity;
|
||
|
|
rb->sz = elem_size;
|
||
|
|
rb->head = 0;
|
||
|
|
rb->tail = 0;
|
||
|
|
rb->full = false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rb_free(RingBuffer *rb) {
|
||
|
|
free(rb->buffer);
|
||
|
|
rb->buffer = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rb_reset(RingBuffer *rb) {
|
||
|
|
rb->head = rb->tail = 0;
|
||
|
|
rb->full = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool rb_empty(const RingBuffer *rb) {
|
||
|
|
return (!rb->full && (rb->head == rb->tail));
|
||
|
|
}
|
||
|
|
|
||
|
|
bool rb_full(const RingBuffer *rb) {
|
||
|
|
return rb->full;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool rb_put(RingBuffer *rb, const void *data) {
|
||
|
|
if (rb->full) return false;
|
||
|
|
|
||
|
|
memcpy((char*)rb->buffer + (rb->head * rb->sz), data, rb->sz);
|
||
|
|
rb->head = (rb->head + 1) % rb->max;
|
||
|
|
rb->full = (rb->head == rb->tail);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool rb_get(RingBuffer *rb, void *data) {
|
||
|
|
if (rb_empty(rb)) return false;
|
||
|
|
|
||
|
|
memcpy(data, (char*)rb->buffer + (rb->tail * rb->sz), rb->sz);
|
||
|
|
rb->full = false;
|
||
|
|
rb->tail = (rb->tail + 1) % rb->max;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t rb_size(const RingBuffer *rb) {
|
||
|
|
size_t size = rb->max;
|
||
|
|
|
||
|
|
if (!rb->full) {
|
||
|
|
if (rb->head >= rb->tail) {
|
||
|
|
size = rb->head - rb->tail;
|
||
|
|
} else {
|
||
|
|
size = rb->max + rb->head - rb->tail;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return size;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t rb_get_bulk(RingBuffer *rb, void *data, size_t len) {
|
||
|
|
if (rb_empty(rb)) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t curr_size = rb_size(rb);
|
||
|
|
size_t to_read = len < curr_size ? len : curr_size;
|
||
|
|
|
||
|
|
// 第一次拷贝:从 tail 到缓冲区末尾
|
||
|
|
size_t cnt1 = rb->max - rb->tail;
|
||
|
|
if (cnt1 > to_read) cnt1 = to_read;
|
||
|
|
memcpy(data,
|
||
|
|
(char*)rb->buffer + rb->tail * rb->sz,
|
||
|
|
cnt1 * rb->sz);
|
||
|
|
|
||
|
|
// 第二次拷贝:如果需要,从缓冲区开头继续读取
|
||
|
|
size_t cnt2 = to_read - cnt1;
|
||
|
|
if (cnt2 > 0) {
|
||
|
|
memcpy((char*)data + cnt1 * rb->sz,
|
||
|
|
rb->buffer,
|
||
|
|
cnt2 * rb->sz);
|
||
|
|
}
|
||
|
|
|
||
|
|
rb->tail = (rb->tail + to_read) % rb->max;
|
||
|
|
rb->full = false;
|
||
|
|
|
||
|
|
return to_read;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t rb_put_bulk(RingBuffer *rb, const void *data, size_t len) {
|
||
|
|
// 如果缓冲区已满,直接返回 0
|
||
|
|
if (rb->full) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 计算当前可用空间(元素数)
|
||
|
|
size_t curr_size = rb_size(rb);
|
||
|
|
size_t avail = rb->max - curr_size;
|
||
|
|
// 实际要写入的元素数
|
||
|
|
size_t to_write = len < avail ? len : avail;
|
||
|
|
if (to_write == 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 第一次拷贝:从 head 开始直到缓冲区末尾
|
||
|
|
size_t cnt1 = rb->max - rb->head;
|
||
|
|
if (cnt1 > to_write) {
|
||
|
|
cnt1 = to_write;
|
||
|
|
}
|
||
|
|
memcpy((char*)rb->buffer + rb->head * rb->sz,
|
||
|
|
data,
|
||
|
|
cnt1 * rb->sz);
|
||
|
|
|
||
|
|
// 第二次拷贝:如果还要写入,则回绕到缓冲区开头
|
||
|
|
size_t cnt2 = to_write - cnt1;
|
||
|
|
if (cnt2 > 0) {
|
||
|
|
memcpy(rb->buffer,
|
||
|
|
(const char*)data + cnt1 * rb->sz,
|
||
|
|
cnt2 * rb->sz);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新 head 索引
|
||
|
|
rb->head = (rb->head + to_write) % rb->max;
|
||
|
|
// 如果写满,则置 full
|
||
|
|
if (to_write == avail) {
|
||
|
|
rb->full = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return to_write;
|
||
|
|
}
|