ringbuffer.c (2672B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 /* for ptrdiff_t */ 5 #include <stddef.h> 6 7 #include <string.h> 8 9 #include "ringbuffer.h" 10 11 int init_ringbuffer(struct ringbuffer *r, size_t size) 12 { 13 r->buf = (char*)malloc(size); 14 if (!r->buf) 15 return ERINGBUFFER_ALLOC_FAIL; 16 r->size = size; 17 clear_ringbuffer(r); 18 19 return 0; 20 } 21 22 void free_ringbuffer(struct ringbuffer *r) 23 { 24 free(r->buf); 25 } 26 27 void clear_ringbuffer(struct ringbuffer *r) 28 { 29 r->begin = 0; 30 r->end = 0; 31 } 32 33 size_t ringbuffer_free_space(struct ringbuffer *r) 34 { 35 if (r->begin == 0 && r->end == 0) 36 return r->size; 37 38 if (r->begin < r->end) 39 return r->size - (r->end - r->begin) - 1; 40 else 41 return r->begin - r->end - 1; 42 } 43 44 size_t ringbuffer_data_size(struct ringbuffer *r) 45 { 46 if (r->begin == 0 && r->end == 0) 47 return 0; 48 49 if (r->begin <= r->end) 50 return r->end - r->begin + 1; 51 else 52 return r->size - (r->begin - r->end) + 1; 53 } 54 55 56 void ringbuffer_push(struct ringbuffer *r, const void *data, size_t size) 57 { 58 if (ringbuffer_free_space(r) < size) 59 return; 60 61 if (r->begin == 0 && r->end == 0) { 62 memcpy(r->buf, data, size); 63 r->begin = r->buf; 64 r->end = r->buf + size - 1; 65 return; 66 } 67 68 r->end++; 69 if (r->begin < r->end) { 70 if ((size_t)(r->buf + (ptrdiff_t)r->size - r->begin) >= size) { 71 /* we can fit without cut */ 72 memcpy(r->end, data, size); 73 r->end += size - 1; 74 } else { 75 /* make a cut */ 76 size_t s = r->buf + r->size - r->end; 77 memcpy(r->end, data, s); 78 size -= s; 79 memcpy(r->buf, (char*)data+s, size); 80 r->end = r->buf + size - 1; 81 } 82 } else { 83 memcpy(r->end, data, size); 84 r->end += size - 1; 85 } 86 } 87 88 void ringbuffer_pop(struct ringbuffer *r, void *data, size_t size) 89 { 90 if (ringbuffer_data_size(r) < size) 91 return; 92 93 int need_clear = 0; 94 if (ringbuffer_data_size(r) == size) 95 need_clear = 1; 96 97 if (r->begin < r->end) { 98 if (data) memcpy(data, r->begin, size); 99 r->begin += size; 100 } else { 101 if ((size_t)(r->buf + (ptrdiff_t)r->size - r->begin) >= size) { 102 if (data) memcpy(data, r->begin, size); 103 r->begin += size; 104 } else { 105 size_t s = r->buf + r->size - r->begin; 106 if (data) memcpy(data, r->begin, s); 107 size -= s; 108 if (data) memcpy((char*)data+s, r->buf, size); 109 r->begin = r->buf + size; 110 } 111 } 112 113 if (need_clear) 114 clear_ringbuffer(r); 115 } 116 117 void ringbuffer_read(struct ringbuffer *r, void *data, size_t size) 118 { 119 if (ringbuffer_data_size(r) < size) 120 return; 121 122 if (r->begin < r->end) 123 memcpy(data, r->begin, size); 124 else { 125 if ((size_t)(r->buf + (ptrdiff_t)r->size - r->begin) >= size) 126 memcpy(data, r->begin, size); 127 else { 128 size_t s = r->buf + r->size - r->begin; 129 memcpy(data, r->begin, s); 130 size -= s; 131 memcpy((char*)data+s, r->buf, size); 132 } 133 } 134 } 135