cringbuffer.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright: SPDX-License-Identifier: GPL-3.0-only
  2. #include "cringbuffer.h"
  3. #include "cringbuffer_internal.h"
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. #include <string.h>
  7. #define MIN(a,b) (((a)<(b))?(a):(b))
  8. #define MAX(a,b) (((a)>(b))?(a):(b))
  9. // this allows user to use their own
  10. // custom memory allocation functions
  11. #ifdef RBUF_CUSTOM_MALLOC
  12. #include "ringbuffer_pal.h"
  13. #else
  14. #define crbuf_malloc(...) malloc(__VA_ARGS__)
  15. #define crbuf_free(...) free(__VA_ARGS__)
  16. #endif
  17. rbuf_t rbuf_create(size_t size)
  18. {
  19. rbuf_t buffer = crbuf_malloc(sizeof(struct rbuf_t) + size);
  20. if (!buffer)
  21. return NULL;
  22. memset(buffer, 0, sizeof(struct rbuf_t));
  23. buffer->data = ((char*)buffer) + sizeof(struct rbuf_t);
  24. buffer->head = buffer->data;
  25. buffer->tail = buffer->data;
  26. buffer->size = size;
  27. buffer->end = buffer->data + size;
  28. return buffer;
  29. }
  30. void rbuf_free(rbuf_t buffer)
  31. {
  32. crbuf_free(buffer);
  33. }
  34. void rbuf_flush(rbuf_t buffer)
  35. {
  36. buffer->head = buffer->data;
  37. buffer->tail = buffer->data;
  38. buffer->size_data = 0;
  39. }
  40. char *rbuf_get_linear_insert_range(rbuf_t buffer, size_t *bytes)
  41. {
  42. *bytes = 0;
  43. if (buffer->head == buffer->tail && buffer->size_data)
  44. return NULL;
  45. *bytes = ((buffer->head >= buffer->tail) ? buffer->end : buffer->tail) - buffer->head;
  46. return buffer->head;
  47. }
  48. char *rbuf_get_linear_read_range(rbuf_t buffer, size_t *bytes)
  49. {
  50. *bytes = 0;
  51. if(buffer->head == buffer->tail && !buffer->size_data)
  52. return NULL;
  53. *bytes = ((buffer->tail >= buffer->head) ? buffer->end : buffer->head) - buffer->tail;
  54. return buffer->tail;
  55. }
  56. int rbuf_bump_head(rbuf_t buffer, size_t bytes)
  57. {
  58. size_t free_bytes = rbuf_bytes_free(buffer);
  59. if (bytes > free_bytes)
  60. return 0;
  61. int i = buffer->head - buffer->data;
  62. buffer->head = &buffer->data[(i + bytes) % buffer->size];
  63. buffer->size_data += bytes;
  64. return 1;
  65. }
  66. int rbuf_bump_tail(rbuf_t buffer, size_t bytes)
  67. {
  68. if(!rbuf_bump_tail_noopt(buffer, bytes))
  69. return 0;
  70. // if tail catched up with head
  71. // start writing buffer from beggining
  72. // this is not necessary (rbuf must work well without it)
  73. // but helps to optimize big writes as rbuf_get_linear_insert_range
  74. // will return bigger continuous region
  75. if(buffer->tail == buffer->head) {
  76. assert(buffer->size_data == 0);
  77. rbuf_flush(buffer);
  78. }
  79. return 1;
  80. }
  81. size_t rbuf_get_capacity(rbuf_t buffer)
  82. {
  83. return buffer->size;
  84. }
  85. size_t rbuf_bytes_available(rbuf_t buffer)
  86. {
  87. return buffer->size_data;
  88. }
  89. size_t rbuf_bytes_free(rbuf_t buffer)
  90. {
  91. return buffer->size - buffer->size_data;
  92. }
  93. size_t rbuf_push(rbuf_t buffer, const char *data, size_t len)
  94. {
  95. size_t to_cpy;
  96. char *w_ptr = rbuf_get_linear_insert_range(buffer, &to_cpy);
  97. if(!to_cpy)
  98. return to_cpy;
  99. to_cpy = MIN(to_cpy, len);
  100. memcpy(w_ptr, data, to_cpy);
  101. rbuf_bump_head(buffer, to_cpy);
  102. if(to_cpy < len)
  103. to_cpy += rbuf_push(buffer, &data[to_cpy], len - to_cpy);
  104. return to_cpy;
  105. }
  106. size_t rbuf_pop(rbuf_t buffer, char *data, size_t len)
  107. {
  108. size_t to_cpy;
  109. const char *r_ptr = rbuf_get_linear_read_range(buffer, &to_cpy);
  110. if(!to_cpy)
  111. return to_cpy;
  112. to_cpy = MIN(to_cpy, len);
  113. memcpy(data, r_ptr, to_cpy);
  114. rbuf_bump_tail(buffer, to_cpy);
  115. if(to_cpy < len)
  116. to_cpy += rbuf_pop(buffer, &data[to_cpy], len - to_cpy);
  117. return to_cpy;
  118. }
  119. static inline void rbuf_ptr_inc(rbuf_t buffer, const char **ptr)
  120. {
  121. (*ptr)++;
  122. if(*ptr >= buffer->end)
  123. *ptr = buffer->data;
  124. }
  125. int rbuf_memcmp(rbuf_t buffer, const char *haystack, const char *needle, size_t needle_bytes)
  126. {
  127. const char *end = needle + needle_bytes;
  128. // as head==tail can mean 2 things here
  129. if (haystack == buffer->head && buffer->size_data) {
  130. if (*haystack != *needle)
  131. return (*haystack - *needle);
  132. rbuf_ptr_inc(buffer, &haystack);
  133. needle++;
  134. }
  135. while (haystack != buffer->head && needle != end) {
  136. if (*haystack != *needle)
  137. return (*haystack - *needle);
  138. rbuf_ptr_inc(buffer, &haystack);
  139. needle++;
  140. }
  141. return 0;
  142. }
  143. int rbuf_memcmp_n(rbuf_t buffer, const char *to_cmp, size_t to_cmp_bytes)
  144. {
  145. return rbuf_memcmp(buffer, buffer->tail, to_cmp, to_cmp_bytes);
  146. }
  147. char *rbuf_find_bytes(rbuf_t buffer, const char *needle, size_t needle_bytes, int *found_idx)
  148. {
  149. const char *ptr = buffer->tail;
  150. *found_idx = 0;
  151. if (!rbuf_bytes_available(buffer))
  152. return NULL;
  153. if (buffer->head == buffer->tail && buffer->size_data) {
  154. if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
  155. return (char *)ptr;
  156. rbuf_ptr_inc(buffer, &ptr);
  157. (*found_idx)++;
  158. }
  159. while (ptr != buffer->head)
  160. {
  161. if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
  162. return (char *)ptr;
  163. rbuf_ptr_inc(buffer, &ptr);
  164. (*found_idx)++;
  165. }
  166. return NULL;
  167. }