aboutsummaryrefslogtreecommitdiff
path: root/src/ring.c
diff options
context:
space:
mode:
authorLudvig Gunne Lindström <ludviggunnelindstrom@gmail.com>2026-07-17 11:42:57 +0200
committerLudvig Gunne Lindström <ludviggunnelindstrom@gmail.com>2026-11-08 14:05:19 +0100
commitfd27bacdd9c97f696938b12d2a437da4e514c26f (patch)
tree2d676bb280b35420a2c105676b0e66fe5b91958d /src/ring.c
downloadmelisma-fd27bacdd9c97f696938b12d2a437da4e514c26f.tar.gz
Diffstat (limited to 'src/ring.c')
-rw-r--r--src/ring.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/ring.c b/src/ring.c
new file mode 100644
index 0000000..0bb1553
--- /dev/null
+++ b/src/ring.c
@@ -0,0 +1,158 @@
+/*
+ * melisma - extensible and scriptable audio engine
+ * Copyright (C) 2026 Ludvig Gunne Lindström
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "mem.h"
+#include "melisma/ring.h"
+
+struct ml_ring
+{
+ _Atomic size_t head;
+ _Atomic size_t tail;
+ size_t len;
+ uint8_t data[];
+};
+
+
+ml_ring *ml_ring_init(size_t len)
+{
+ size_t size = sizeof(ml_ring) + len;
+ ml_ring *r = scalloc(1,size);
+ r->len = len;
+ return r;
+}
+
+void ml_ring_free(ml_ring *r)
+{
+ free(r);
+}
+
+int ml_ring_empty(ml_ring *r)
+{
+ size_t head = atomic_load_explicit(&r->head,memory_order_relaxed);
+ size_t tail = atomic_load_explicit(&r->tail,memory_order_acquire);
+ return tail == head;
+}
+
+int ml_ring_has_space(ml_ring *r, size_t len)
+{
+ size_t head = atomic_load_explicit(&r->head,memory_order_acquire);
+ size_t tail = atomic_load_explicit(&r->tail,memory_order_relaxed);
+ size_t used = tail >= head ? tail - head : r->len - head + tail;
+ size_t free = r->len - 1 - used;
+ return free >= len;
+}
+
+int ml_ring_put(ml_ring *r, uint8_t c)
+{
+ size_t tail = atomic_load_explicit(&r->tail,memory_order_relaxed);
+ size_t head = atomic_load_explicit(&r->head,memory_order_acquire);
+ size_t new_tail = (tail + 1) % r->len;
+
+ if (new_tail == head)
+ {
+ return -1;
+ }
+
+ r->data[tail] = c;
+ atomic_store_explicit(&r->tail,new_tail,memory_order_release);
+
+ return 0;
+}
+
+int ml_ring_get(ml_ring *r, uint8_t *c)
+{
+ size_t tail = atomic_load_explicit(&r->tail,memory_order_acquire);
+ size_t head = atomic_load_explicit(&r->head,memory_order_relaxed);
+ size_t new_head = (head + 1) % r->len;
+
+ if (head == tail)
+ {
+ return -1;
+ }
+
+ *c = r->data[head];
+ atomic_store_explicit(&r->head,new_head,memory_order_release);
+
+ return 0;
+}
+
+size_t ml_ring_write(ml_ring *r, const void *ptr, size_t len)
+{
+ size_t l = 0;
+ const uint8_t *uptr = ptr;
+
+ for (; l < len; l++)
+ {
+ if (ml_ring_put(r,uptr[l]) < 0)
+ {
+ break;
+ }
+ }
+
+ return l;
+}
+
+size_t ml_ring_read(ml_ring *r, void *ptr, size_t len)
+{
+ size_t l = 0;
+ uint8_t *uptr = ptr;
+
+ for (; l < len; l++)
+ {
+ if (ml_ring_get(r,&uptr[l]) < 0)
+ {
+ break;
+ }
+ }
+
+ return l;
+}
+
+void ml_ring_put_blocking(ml_ring *r, uint8_t c)
+{
+ while (ml_ring_put(r,c) < 0)
+ ;
+}
+
+uint8_t ml_ring_get_blocking(ml_ring *r)
+{
+ uint8_t c;
+ while (ml_ring_get(r,&c) < 0)
+ ;
+ return c;
+}
+
+void ml_ring_write_blocking(ml_ring *r, const void *ptr, size_t len)
+{
+ const uint8_t *uptr = ptr;
+
+ while (len--)
+ {
+ ml_ring_put_blocking(r,*(uptr++));
+ }
+}
+
+void ml_ring_read_blocking(ml_ring *r, void *ptr, size_t len)
+{
+ uint8_t *uptr = ptr;
+
+ while (len--)
+ {
+ *(uptr++) = ml_ring_get_blocking(r);
+ }
+}