Files
mr-library/kernel/kfifo.c

194 lines
4.6 KiB
C

/**
* @copyright (c) 2024, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <kernel/mr_kfifo.h>
#include <libc/mr_string.h>
#include <libc/mr_malloc.h>
/* Kfifo align macro function */
#define KFIFO_ALIGN_POW2_UP(_size) \
(((_size) & ((_size) - 1)) ? (1U << mr_fls32(_size)) : (_size))
#define KFIFO_ALIGN_POW2_DOWN(_size) \
(1U << (mr_fls32(_size) - 1))
mr_uint32_t mr_kfifo_init(mr_kfifo_t *kfifo, void *buf, mr_uint32_t size,
mr_uint32_t elem_size) {
/* Check arguments */
if ((!buf) || (size < 2) || (elem_size == 0) || (elem_size > size)) {
return 0;
}
/* Align size(down to power of 2) */
size = KFIFO_ALIGN_POW2_DOWN(size / elem_size);
/* Init kfifo */
kfifo->buf = buf;
kfifo->mask = size - 1;
kfifo->in = kfifo->out = 0;
kfifo->elem_size = elem_size;
return size;
}
mr_uint32_t mr_kfifo_alloc(mr_kfifo_t *kfifo, mr_uint32_t size,
mr_uint32_t elem_size) {
void *buf;
/* Check arguments */
if ((size == 0) || (elem_size == 0) || (elem_size > size)) {
return 0;
}
/* Align size(up to power of 2) */
size = KFIFO_ALIGN_POW2_UP(size);
/* Allocate buffer */
if (kfifo->buf) {
buf = mr_realloc(kfifo->buf, size);
} else {
buf = mr_malloc(size);
}
if (!buf) {
/* Not enough memory */
return 0;
}
/* Init kfifo */
return mr_kfifo_init(kfifo, buf, size, elem_size);
}
void mr_kfifo_free(mr_kfifo_t *kfifo) {
/* Check need to free */
if (!kfifo->buf) {
return;
}
/* Free buffer */
mr_free(kfifo->buf);
kfifo->buf = MR_NULL;
}
mr_uint32_t mr_kfifo_push(mr_kfifo_t *kfifo, const void *data) {
mr_uint32_t in;
/* Check if kfifo is full */
if (mr_kfifo_is_full(kfifo)) {
return 0;
}
/* Get in index */
in = kfifo->in & kfifo->mask;
if (kfifo->elem_size != 1) {
in *= kfifo->elem_size;
}
/* Push data */
mr_memcpy((mr_uint8_t *)kfifo->buf + in, data, kfifo->elem_size);
kfifo->in += 1;
return 1;
}
mr_uint32_t mr_kfifo_pop(mr_kfifo_t *kfifo, void *data) {
mr_uint32_t out;
/* Check if kfifo is empty */
if (mr_kfifo_is_empty(kfifo)) {
return 0;
}
/* Get out index */
out = kfifo->out & kfifo->mask;
if (kfifo->elem_size != 1) {
out *= kfifo->elem_size;
}
/* Pop data */
mr_memcpy(data, (mr_uint8_t *)kfifo->buf + out, kfifo->elem_size);
kfifo->out += 1;
return 1;
}
mr_uint32_t mr_kfifo_in(mr_kfifo_t *kfifo, const void *buf, mr_uint32_t num) {
mr_uint32_t avail, num2, in, size, n;
/* Limit number */
avail = mr_kfifo_avail(kfifo);
if (num > avail) {
num = avail;
}
if (num == 0) {
return 0;
}
num2 = num;
/* Get in index */
in = kfifo->in & kfifo->mask;
size = kfifo->mask + 1;
if (kfifo->elem_size != 1) {
in *= kfifo->elem_size;
size *= kfifo->elem_size;
num *= kfifo->elem_size;
}
n = MR_MIN(num, size - in);
/* Push buffer */
mr_memcpy((mr_uint8_t *)kfifo->buf + in, buf, n);
mr_memcpy(kfifo->buf, ((mr_uint8_t *)buf) + n, num - n);
kfifo->in += num2;
return num2;
}
mr_uint32_t mr_kfifo_in_overwrite(mr_kfifo_t *kfifo, const void *buf,
mr_uint32_t num) {
mr_uint32_t capacity, avail;
/* Limit number */
capacity = kfifo->mask + 1;
if (num > capacity) {
buf = ((mr_uint8_t *)buf) + ((num - capacity) * kfifo->elem_size);
num = capacity;
}
/* Limit size */
avail = mr_kfifo_avail(kfifo);
if (num > avail) {
mr_kfifo_skip(kfifo, num - avail);
}
/* Push buffer */
return mr_kfifo_in(kfifo, buf, num);
}
mr_uint32_t mr_kfifo_peek(mr_kfifo_t *kfifo, void *buf, mr_uint32_t num) {
mr_uint32_t avail, num2, out, size, n;
/* Limit number */
avail = mr_kfifo_len(kfifo);
if (num > avail) {
num = avail;
}
if (num == 0) {
return 0;
}
num2 = num;
/* Get out index */
out = kfifo->out & kfifo->mask;
size = kfifo->mask + 1;
if (kfifo->elem_size != 1) {
out *= kfifo->elem_size;
size *= kfifo->elem_size;
num *= kfifo->elem_size;
}
/* Peek buffer */
n = MR_MIN(num, size - out);
mr_memcpy(buf, (mr_uint8_t *)kfifo->buf + out, n);
mr_memcpy((mr_uint8_t *)buf + n, kfifo->buf, num - n);
return num2;
}