123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- // Copyright: SPDX-License-Identifier: GPL-3.0-only
- #include "cringbuffer.h"
- #include "cringbuffer_internal.h"
- #include <stdlib.h>
- #include <assert.h>
- #include <string.h>
- #define MIN(a,b) (((a)<(b))?(a):(b))
- #define MAX(a,b) (((a)>(b))?(a):(b))
- // this allows user to use their own
- // custom memory allocation functions
- #ifdef RBUF_CUSTOM_MALLOC
- #include "ringbuffer_pal.h"
- #else
- #define crbuf_malloc(...) malloc(__VA_ARGS__)
- #define crbuf_free(...) free(__VA_ARGS__)
- #endif
- rbuf_t rbuf_create(size_t size)
- {
- rbuf_t buffer = crbuf_malloc(sizeof(struct rbuf_t) + size);
- if (!buffer)
- return NULL;
- memset(buffer, 0, sizeof(struct rbuf_t));
- buffer->data = ((char*)buffer) + sizeof(struct rbuf_t);
- buffer->head = buffer->data;
- buffer->tail = buffer->data;
- buffer->size = size;
- buffer->end = buffer->data + size;
- return buffer;
- }
- void rbuf_free(rbuf_t buffer)
- {
- crbuf_free(buffer);
- }
- void rbuf_flush(rbuf_t buffer)
- {
- buffer->head = buffer->data;
- buffer->tail = buffer->data;
- buffer->size_data = 0;
- }
- char *rbuf_get_linear_insert_range(rbuf_t buffer, size_t *bytes)
- {
- *bytes = 0;
- if (buffer->head == buffer->tail && buffer->size_data)
- return NULL;
- *bytes = ((buffer->head >= buffer->tail) ? buffer->end : buffer->tail) - buffer->head;
- return buffer->head;
- }
- char *rbuf_get_linear_read_range(rbuf_t buffer, size_t *bytes)
- {
- *bytes = 0;
- if(buffer->head == buffer->tail && !buffer->size_data)
- return NULL;
- *bytes = ((buffer->tail >= buffer->head) ? buffer->end : buffer->head) - buffer->tail;
- return buffer->tail;
- }
- int rbuf_bump_head(rbuf_t buffer, size_t bytes)
- {
- size_t free_bytes = rbuf_bytes_free(buffer);
- if (bytes > free_bytes)
- return 0;
- int i = buffer->head - buffer->data;
- buffer->head = &buffer->data[(i + bytes) % buffer->size];
- buffer->size_data += bytes;
- return 1;
- }
- int rbuf_bump_tail(rbuf_t buffer, size_t bytes)
- {
- if(!rbuf_bump_tail_noopt(buffer, bytes))
- return 0;
- // if tail catched up with head
- // start writing buffer from beggining
- // this is not necessary (rbuf must work well without it)
- // but helps to optimize big writes as rbuf_get_linear_insert_range
- // will return bigger continuous region
- if(buffer->tail == buffer->head) {
- assert(buffer->size_data == 0);
- rbuf_flush(buffer);
- }
- return 1;
- }
- size_t rbuf_get_capacity(rbuf_t buffer)
- {
- return buffer->size;
- }
- size_t rbuf_bytes_available(rbuf_t buffer)
- {
- return buffer->size_data;
- }
- size_t rbuf_bytes_free(rbuf_t buffer)
- {
- return buffer->size - buffer->size_data;
- }
- size_t rbuf_push(rbuf_t buffer, const char *data, size_t len)
- {
- size_t to_cpy;
- char *w_ptr = rbuf_get_linear_insert_range(buffer, &to_cpy);
- if(!to_cpy)
- return to_cpy;
- to_cpy = MIN(to_cpy, len);
- memcpy(w_ptr, data, to_cpy);
- rbuf_bump_head(buffer, to_cpy);
- if(to_cpy < len)
- to_cpy += rbuf_push(buffer, &data[to_cpy], len - to_cpy);
- return to_cpy;
- }
- size_t rbuf_pop(rbuf_t buffer, char *data, size_t len)
- {
- size_t to_cpy;
- const char *r_ptr = rbuf_get_linear_read_range(buffer, &to_cpy);
- if(!to_cpy)
- return to_cpy;
- to_cpy = MIN(to_cpy, len);
- memcpy(data, r_ptr, to_cpy);
- rbuf_bump_tail(buffer, to_cpy);
- if(to_cpy < len)
- to_cpy += rbuf_pop(buffer, &data[to_cpy], len - to_cpy);
- return to_cpy;
- }
- static inline void rbuf_ptr_inc(rbuf_t buffer, const char **ptr)
- {
- (*ptr)++;
- if(*ptr >= buffer->end)
- *ptr = buffer->data;
- }
- int rbuf_memcmp(rbuf_t buffer, const char *haystack, const char *needle, size_t needle_bytes)
- {
- const char *end = needle + needle_bytes;
- // as head==tail can mean 2 things here
- if (haystack == buffer->head && buffer->size_data) {
- if (*haystack != *needle)
- return (*haystack - *needle);
- rbuf_ptr_inc(buffer, &haystack);
- needle++;
- }
- while (haystack != buffer->head && needle != end) {
- if (*haystack != *needle)
- return (*haystack - *needle);
- rbuf_ptr_inc(buffer, &haystack);
- needle++;
- }
- return 0;
- }
- int rbuf_memcmp_n(rbuf_t buffer, const char *to_cmp, size_t to_cmp_bytes)
- {
- return rbuf_memcmp(buffer, buffer->tail, to_cmp, to_cmp_bytes);
- }
- char *rbuf_find_bytes(rbuf_t buffer, const char *needle, size_t needle_bytes, int *found_idx)
- {
- const char *ptr = buffer->tail;
- *found_idx = 0;
- if (!rbuf_bytes_available(buffer))
- return NULL;
- if (buffer->head == buffer->tail && buffer->size_data) {
- if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
- return (char *)ptr;
- rbuf_ptr_inc(buffer, &ptr);
- (*found_idx)++;
- }
- while (ptr != buffer->head)
- {
- if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
- return (char *)ptr;
- rbuf_ptr_inc(buffer, &ptr);
- (*found_idx)++;
- }
- return NULL;
- }
|