summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile34
-rw-r--r--rb.h49
-rw-r--r--src/rb.c112
3 files changed, 195 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..62eefa6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+CC ?= gcc
+CFLAGS += -W -Wall -std=c99 -Wextra
+CFLAGS += -I./
+CFLAGS += -D _GNU_SOURCE
+NAME = librb.a
+SRC = src/rb.c
+
+AR = ar rc
+
+all: depend $(NAME)
+
+depend: .depend
+
+.depend: $(SRC)
+ @$(RM) .depend
+ @$(CC) $(CFLAGS) -MM $^ > .depend
+
+include .depend
+
+OBJ = $(SRC:.c=.o)
+
+$(NAME): $(OBJ)
+ $(AR) $(NAME) $(OBJ)
+ ranlib $(NAME)
+
+clean:
+ $(RM) $(OBJ)
+
+fclean: clean
+ $(RM) $(NAME)
+
+re: fclean all
+
+.PHONY: all depend clean fclean all re
diff --git a/rb.h b/rb.h
new file mode 100644
index 0000000..f66dba8
--- /dev/null
+++ b/rb.h
@@ -0,0 +1,49 @@
+#ifndef RING_BUFFER_H
+#define RING_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef struct t_ring_buffer {
+ char buffer[8192];
+
+ uint16_t off_r;
+ uint16_t off_w;
+
+ size_t size_filled;
+} t_ring_buffer;
+
+typedef t_ring_buffer t_rb;
+
+static inline size_t rb_get_size(const t_rb *rb)
+{
+ return sizeof(rb->buffer);
+}
+
+/*
+ * initializes rb with default values.
+ * returns 0 on success
+ */
+int rb_init(t_rb *rb);
+
+/* returns an initialized newly allocated ring buffer */
+__attribute((malloc)) t_rb *rb_new(void);
+
+void rb_delete(t_rb **);
+
+/* put n bytes of src into the ring buffer pointed by rb */
+t_rb *rb_put(t_rb *rb, const void *src, size_t n);
+
+/*
+ * take at most n bytes from the ring buffer pointed by rb and
+ * put them into dest
+ */
+size_t rb_get(t_rb *rb, void *dest, size_t n);
+
+/*
+ * like rb_get but does not modify the ring_buffer (the bytes are kept
+ * in the ring_buffer)
+ */
+size_t rb_peek(const t_rb *ring_buffer, void *dest, size_t size);
+
+#endif /* RING_BUFFER_H */
diff --git a/src/rb.c b/src/rb.c
new file mode 100644
index 0000000..505c373
--- /dev/null
+++ b/src/rb.c
@@ -0,0 +1,112 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "rb.h"
+
+#define MAX(_x1, _x2) (((_x1) > (_x2)) ? (_x1) : (_x2))
+#define MIN(_x1, _x2) (((_x1) < (_x2)) ? (_x1) : (_x2))
+
+int rb_init(t_rb *rb)
+{
+ rb->off_r = 0;
+ rb->off_w = 0;
+ rb->size_filled = 0;
+
+ return 0;
+}
+
+t_rb *rb_new(void)
+{
+ t_rb *rb;
+
+ if ((rb = malloc(sizeof(t_rb))) == NULL) {
+ return NULL;
+ }
+
+ rb_init(rb);
+
+ return rb;
+}
+
+void rb_delete(t_rb **rb)
+{
+ free(*rb);
+ *rb = NULL;
+}
+
+t_rb *rb_put(t_rb *rb, const void *src, size_t n)
+{
+ size_t size;
+
+ /* loop until n bytes of src have been written */
+ while (n != 0) {
+ size = MIN(n, rb_get_size(rb) - rb->off_w);
+
+ memcpy(&rb->buffer[rb->off_w], src, size);
+
+ /* if we overrided the data to read, we need to move off_r */
+ if (rb->off_w < rb->off_r && rb->off_w + size > rb->off_r) {
+ rb->off_r = (rb->off_w + size) % rb_get_size(rb);
+ } else if (rb->off_r == rb->off_w
+ && rb->size_filled == rb_get_size(rb))
+ {
+ rb->off_r = (rb->off_w + size) % rb_get_size(rb);
+ }
+
+ /* this will put the offset back to 0 if we reached the end */
+ rb->off_w = (rb->off_w + size) % rb_get_size(rb);
+
+ n -= size;
+ src += size;
+
+ rb->size_filled += size;
+ rb->size_filled = MIN(rb->size_filled, rb_get_size(rb));
+ }
+
+ return rb;
+}
+
+size_t rb_get(t_rb *rb, void *dest, size_t n)
+{
+ size_t size = rb_peek(rb, dest, n);
+
+ rb->size_filled -= size;
+ rb->off_r = (rb->off_r + size) % rb_get_size(rb);
+
+ if (rb->size_filled == 0) {
+ /* optimize space */
+ rb->off_w = rb->off_r = 0;
+ }
+
+ return size;
+}
+
+size_t rb_peek(const t_rb *rb, void *dest, size_t n)
+{
+ uint16_t offset;
+ size_t size;
+ size_t size2;
+
+ if (rb->size_filled == 0 || n == 0) {
+ return 0;
+ }
+
+ size = 0;
+ if (rb->off_r >= rb->off_w) {
+ /* do not try to retrieve too much data */
+ size = MIN(n, rb_get_size(rb) - rb->off_r);
+
+ memcpy(dest, &rb->buffer[rb->off_r], size);
+
+ dest += size;
+ n -= size;
+ }
+
+ offset = (rb->off_r + size) % rb_get_size(rb);
+
+ size2 = MIN(n, (size_t)(rb->off_w - offset));
+
+ memcpy(dest, &rb->buffer[offset], size2);
+
+ return size + size2;
+}