117 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: MIT */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include "ringbuf.h"
 | |
| 
 | |
| #ifdef DEBUG
 | |
| #define DEBUG_PRINT(fmt, ...) printf(fmt, __VA_ARGS__)
 | |
| #else
 | |
| #define DEBUG_PRINT(fmt, ...)
 | |
| #endif
 | |
| 
 | |
| void
 | |
| rb_init(struct RingBuf *rb, rb_size_t capacity, ALLOC_T malloc_fn,
 | |
|         rb_size_t struct_size)
 | |
| {
 | |
|   rb->struct_size = struct_size;
 | |
|   rb->capacity = capacity;
 | |
|   rb->buffer = malloc_fn(capacity * struct_size); /* Calloc? */
 | |
|   rb->buffer_end = rb->buffer + (capacity * struct_size);
 | |
|   rb->count = 0;
 | |
|   rb->write_head = rb->buffer;
 | |
|   rb->read_head = rb->buffer;
 | |
| }
 | |
| 
 | |
| void
 | |
| rb_destroy(struct RingBuf *rb, FREE_T free_fn)
 | |
| {
 | |
|   free_fn(rb->buffer);
 | |
| }
 | |
| 
 | |
| void
 | |
| rb_clear(struct RingBuf *rb)
 | |
| {
 | |
|   rb->count = 0;
 | |
|   rb->write_head = rb->buffer;
 | |
|   rb->read_head = rb->buffer;
 | |
| }
 | |
| 
 | |
| enum WriteResult
 | |
| rb_push_back(struct RingBuf *rb, const void *item, MEMCPY_T memcpy_fn)
 | |
| {
 | |
|   if(rb->count == rb->capacity)
 | |
|     return Full;
 | |
| 
 | |
|   memcpy_fn(rb->write_head, item, rb->struct_size);
 | |
| 
 | |
|   // Advance the write head
 | |
|   rb->write_head = (char *)rb->write_head + rb->struct_size;
 | |
| 
 | |
|   if(rb->write_head == rb->buffer_end)
 | |
|     rb->write_head = rb->buffer;
 | |
| 
 | |
|   rb->count++;
 | |
|   return WriteOk;
 | |
| }
 | |
| 
 | |
| enum WriteResult
 | |
| rb_push_many(struct RingBuf *rb, const void *items, MEMCPY_T memcpy_fn,
 | |
|              rb_size_t n)
 | |
| {
 | |
|   if(rb->count + n > rb->capacity)
 | |
|     return Full; // Perhaps rename to InsufficientSpace
 | |
| 
 | |
|   // If the write head will move past the end of the buffer
 | |
|   // we need to to the write in two steps.
 | |
|   void *end = (char *)rb->write_head + rb->struct_size * n;
 | |
| 
 | |
|   if(end > rb->buffer_end) {
 | |
| 
 | |
|     // Calculate the number of items that can be written in the first chunk
 | |
|     rb_size_t first_chunk = (char *)rb->buffer_end - (char *)rb->write_head;
 | |
| 
 | |
|     DEBUG_PRINT("Multi-chunk write. First chunk: %d\n", first_chunk);
 | |
| 
 | |
|     // Write the first chunk
 | |
|     memcpy_fn(rb->write_head, items, rb->struct_size * first_chunk);
 | |
| 
 | |
|     // Set the write head to the beginning of the buffer
 | |
|     rb->write_head = rb->buffer;
 | |
|     rb->count += first_chunk;
 | |
|     n -= first_chunk;
 | |
|   } else {
 | |
|     DEBUG_PRINT("Single-chunk write. No need to wrap around.%s\n", "");
 | |
|   }
 | |
| 
 | |
|   DEBUG_PRINT("Writing %d items\n", n);
 | |
|   memcpy_fn(rb->write_head, items, rb->struct_size * n);
 | |
|   if(rb->write_head == rb->buffer_end)
 | |
|     rb->write_head = rb->buffer;
 | |
| 
 | |
|   // Advance the write head
 | |
|   rb->write_head = (char *)rb->write_head + rb->struct_size * n;
 | |
|   rb->count += n;
 | |
| 
 | |
|   return WriteOk;
 | |
| }
 | |
| 
 | |
| enum ReadResult
 | |
| rb_pop_front(struct RingBuf *rb, void *item, MEMCPY_T memcpy_fn)
 | |
| {
 | |
|   if(rb->count == 0)
 | |
|     return Empty;
 | |
| 
 | |
|   memcpy_fn(item, rb->read_head, rb->struct_size);
 | |
| 
 | |
|   // Advance the read head
 | |
|   rb->read_head = (char *)rb->read_head + rb->struct_size;
 | |
| 
 | |
|   if(rb->read_head == rb->buffer_end)
 | |
|     rb->read_head = rb->buffer;
 | |
| 
 | |
|   rb->count--;
 | |
|   return ReadOk;
 | |
| }
 | 
