ringbuf.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * ringbuf.c - C ring buffer (FIFO) implementation.
  3. *
  4. * Written in 2011 by Drew Hess <dhess-src@bothan.net>.
  5. *
  6. * To the extent possible under law, the author(s) have dedicated all
  7. * copyright and related and neighboring rights to this software to
  8. * the public domain worldwide. This software is distributed without
  9. * any warranty.
  10. *
  11. * You should have received a copy of the CC0 Public Domain Dedication
  12. * along with this software. If not, see
  13. * <http://creativecommons.org/publicdomain/zero/1.0/>.
  14. */
  15. #ifndef KITTY_DEBUG_BUILD
  16. #define NDEBUG 1
  17. #endif
  18. #include "ringbuf.h"
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/types.h>
  23. #include <unistd.h>
  24. #include <sys/param.h>
  25. #include <assert.h>
  26. static size_t
  27. size_t_min(size_t x, size_t y) {
  28. return x > y ? y : x;
  29. }
  30. /*
  31. * The code is written for clarity, not cleverness or performance, and
  32. * contains many assert()s to enforce invariant assumptions and catch
  33. * bugs. Feel free to optimize the code and to remove asserts for use
  34. * in your own projects, once you're comfortable that it functions as
  35. * intended.
  36. */
  37. struct ringbuf_t
  38. {
  39. uint8_t *buf;
  40. uint8_t *head, *tail;
  41. size_t size;
  42. };
  43. ringbuf_t
  44. ringbuf_new(size_t capacity)
  45. {
  46. ringbuf_t rb = malloc(sizeof(struct ringbuf_t));
  47. if (rb) {
  48. /* One byte is used for detecting the full condition. */
  49. rb->size = capacity + 1;
  50. rb->buf = malloc(rb->size);
  51. if (rb->buf)
  52. ringbuf_reset(rb);
  53. else {
  54. free(rb);
  55. return 0;
  56. }
  57. }
  58. return rb;
  59. }
  60. size_t
  61. ringbuf_buffer_size(const struct ringbuf_t *rb)
  62. {
  63. return rb->size;
  64. }
  65. void
  66. ringbuf_reset(ringbuf_t rb)
  67. {
  68. rb->head = rb->tail = rb->buf;
  69. }
  70. void
  71. ringbuf_free(ringbuf_t *rb)
  72. {
  73. assert(rb && *rb);
  74. free((*rb)->buf);
  75. free(*rb);
  76. *rb = 0;
  77. }
  78. size_t
  79. ringbuf_capacity(const struct ringbuf_t *rb)
  80. {
  81. return ringbuf_buffer_size(rb) - 1;
  82. }
  83. /*
  84. * Return a pointer to one-past-the-end of the ring buffer's
  85. * contiguous buffer. You shouldn't normally need to use this function
  86. * unless you're writing a new ringbuf_* function.
  87. */
  88. static const uint8_t *
  89. ringbuf_end(const struct ringbuf_t *rb)
  90. {
  91. return rb->buf + ringbuf_buffer_size(rb);
  92. }
  93. size_t
  94. ringbuf_bytes_free(const struct ringbuf_t *rb)
  95. {
  96. if (rb->head >= rb->tail)
  97. return ringbuf_capacity(rb) - (rb->head - rb->tail);
  98. else
  99. return rb->tail - rb->head - 1;
  100. }
  101. size_t
  102. ringbuf_bytes_used(const struct ringbuf_t *rb)
  103. {
  104. return ringbuf_capacity(rb) - ringbuf_bytes_free(rb);
  105. }
  106. int
  107. ringbuf_is_full(const struct ringbuf_t *rb)
  108. {
  109. return ringbuf_bytes_free(rb) == 0;
  110. }
  111. int
  112. ringbuf_is_empty(const struct ringbuf_t *rb)
  113. {
  114. return ringbuf_bytes_free(rb) == ringbuf_capacity(rb);
  115. }
  116. const void *
  117. ringbuf_tail(const struct ringbuf_t *rb)
  118. {
  119. return rb->tail;
  120. }
  121. const void *
  122. ringbuf_head(const struct ringbuf_t *rb)
  123. {
  124. return rb->head;
  125. }
  126. /*
  127. * Given a ring buffer rb and a pointer to a location within its
  128. * contiguous buffer, return the a pointer to the next logical
  129. * location in the ring buffer.
  130. */
  131. static uint8_t *
  132. ringbuf_nextp(ringbuf_t rb, const uint8_t *p)
  133. {
  134. /*
  135. * The assert guarantees the expression (++p - rb->buf) is
  136. * non-negative; therefore, the modulus operation is safe and
  137. * portable.
  138. */
  139. assert((p >= rb->buf) && (p < ringbuf_end(rb)));
  140. return rb->buf + ((++p - rb->buf) % ringbuf_buffer_size(rb));
  141. }
  142. size_t
  143. ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset)
  144. {
  145. const uint8_t *bufend = ringbuf_end(rb);
  146. size_t bytes_used = ringbuf_bytes_used(rb);
  147. if (offset >= bytes_used)
  148. return bytes_used;
  149. const uint8_t *start = rb->buf +
  150. (((rb->tail - rb->buf) + offset) % ringbuf_buffer_size(rb));
  151. assert(bufend > start);
  152. size_t n = size_t_min(bufend - start, bytes_used - offset);
  153. const uint8_t *found = memchr(start, c, n);
  154. if (found)
  155. return offset + (found - start);
  156. else
  157. return ringbuf_findchr(rb, c, offset + n);
  158. }
  159. size_t
  160. ringbuf_memset(ringbuf_t dst, int c, size_t len)
  161. {
  162. const uint8_t *bufend = ringbuf_end(dst);
  163. size_t nwritten = 0;
  164. size_t count = size_t_min(len, ringbuf_buffer_size(dst));
  165. int overflow = count > ringbuf_bytes_free(dst);
  166. while (nwritten != count) {
  167. /* don't copy beyond the end of the buffer */
  168. assert(bufend > dst->head);
  169. size_t n = size_t_min(bufend - dst->head, count - nwritten);
  170. memset(dst->head, c, n);
  171. dst->head += n;
  172. nwritten += n;
  173. /* wrap? */
  174. if (dst->head == bufend)
  175. dst->head = dst->buf;
  176. }
  177. if (overflow) {
  178. dst->tail = ringbuf_nextp(dst, dst->head);
  179. assert(ringbuf_is_full(dst));
  180. }
  181. return nwritten;
  182. }
  183. void *
  184. ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count)
  185. {
  186. const uint8_t *u8src = src;
  187. const uint8_t *bufend = ringbuf_end(dst);
  188. int overflow = count > ringbuf_bytes_free(dst);
  189. size_t nread = 0;
  190. while (nread != count) {
  191. /* don't copy beyond the end of the buffer */
  192. assert(bufend > dst->head);
  193. size_t n = size_t_min(bufend - dst->head, count - nread);
  194. memcpy(dst->head, u8src + nread, n);
  195. dst->head += n;
  196. nread += n;
  197. /* wrap? */
  198. if (dst->head == bufend)
  199. dst->head = dst->buf;
  200. }
  201. if (overflow) {
  202. dst->tail = ringbuf_nextp(dst, dst->head);
  203. assert(ringbuf_is_full(dst));
  204. }
  205. return dst->head;
  206. }
  207. ssize_t
  208. ringbuf_read(int fd, ringbuf_t rb, size_t count)
  209. {
  210. const uint8_t *bufend = ringbuf_end(rb);
  211. size_t nfree = ringbuf_bytes_free(rb);
  212. /* don't write beyond the end of the buffer */
  213. assert(bufend > rb->head);
  214. count = size_t_min(bufend - rb->head, count);
  215. ssize_t n = read(fd, rb->head, count);
  216. if (n > 0) {
  217. assert(rb->head + n <= bufend);
  218. rb->head += n;
  219. /* wrap? */
  220. if (rb->head == bufend)
  221. rb->head = rb->buf;
  222. /* fix up the tail pointer if an overflow occurred */
  223. if ((size_t)n > nfree) {
  224. rb->tail = ringbuf_nextp(rb, rb->head);
  225. assert(ringbuf_is_full(rb));
  226. }
  227. }
  228. return n;
  229. }
  230. void *
  231. ringbuf_memmove_from(void *dst, ringbuf_t src, size_t count)
  232. {
  233. size_t bytes_used = ringbuf_bytes_used(src);
  234. if (count > bytes_used)
  235. return 0;
  236. uint8_t *u8dst = dst;
  237. const uint8_t *bufend = ringbuf_end(src);
  238. size_t nwritten = 0;
  239. while (nwritten != count) {
  240. assert(bufend > src->tail);
  241. size_t n = size_t_min(bufend - src->tail, count - nwritten);
  242. memcpy(u8dst + nwritten, src->tail, n);
  243. src->tail += n;
  244. nwritten += n;
  245. /* wrap ? */
  246. if (src->tail == bufend)
  247. src->tail = src->buf;
  248. }
  249. assert(count + ringbuf_bytes_used(src) == bytes_used);
  250. return src->tail;
  251. }
  252. unsigned char
  253. ringbuf_move_char(ringbuf_t src) {
  254. assert(!ringbuf_is_empty(src));
  255. const uint8_t *bufend = ringbuf_end(src);
  256. assert(bufend > src->tail);
  257. uint8_t ans = *src->tail;
  258. src->tail += 1;
  259. if (src->tail == bufend)
  260. src->tail = src->buf;
  261. return ans;
  262. }
  263. size_t
  264. ringbuf_memcpy_from(void *dst, const ringbuf_t src, size_t count)
  265. {
  266. size_t bytes_used = ringbuf_bytes_used(src);
  267. if (count > bytes_used) count = bytes_used;
  268. uint8_t *u8dst = dst;
  269. const uint8_t *bufend = ringbuf_end(src);
  270. size_t nwritten = 0;
  271. const uint8_t* tail = src->tail;
  272. while (nwritten != count) {
  273. assert(bufend > tail);
  274. size_t n = size_t_min(bufend - tail, count - nwritten);
  275. memcpy(u8dst + nwritten, tail, n);
  276. tail += n;
  277. nwritten += n;
  278. /* wrap ? */
  279. if (tail == bufend)
  280. tail = src->buf;
  281. }
  282. assert(ringbuf_bytes_used(src) == bytes_used);
  283. return count;
  284. }
  285. ssize_t
  286. ringbuf_write(int fd, ringbuf_t rb, size_t count)
  287. {
  288. size_t bytes_used = ringbuf_bytes_used(rb);
  289. if (count > bytes_used)
  290. return 0;
  291. const uint8_t *bufend = ringbuf_end(rb);
  292. assert(bufend > rb->head);
  293. count = size_t_min(bufend - rb->tail, count);
  294. ssize_t n = write(fd, rb->tail, count);
  295. if (n > 0) {
  296. assert(rb->tail + n <= bufend);
  297. rb->tail += n;
  298. /* wrap? */
  299. if (rb->tail == bufend)
  300. rb->tail = rb->buf;
  301. assert(n + ringbuf_bytes_used(rb) == bytes_used);
  302. }
  303. return n;
  304. }
  305. void *
  306. ringbuf_copy(ringbuf_t dst, ringbuf_t src, size_t count)
  307. {
  308. size_t src_bytes_used = ringbuf_bytes_used(src);
  309. if (count > src_bytes_used)
  310. return 0;
  311. int overflow = count > ringbuf_bytes_free(dst);
  312. const uint8_t *src_bufend = ringbuf_end(src);
  313. const uint8_t *dst_bufend = ringbuf_end(dst);
  314. size_t ncopied = 0;
  315. while (ncopied != count) {
  316. assert(src_bufend > src->tail);
  317. size_t nsrc = size_t_min(src_bufend - src->tail, count - ncopied);
  318. assert(dst_bufend > dst->head);
  319. size_t n = size_t_min(dst_bufend - dst->head, nsrc);
  320. memcpy(dst->head, src->tail, n);
  321. src->tail += n;
  322. dst->head += n;
  323. ncopied += n;
  324. /* wrap ? */
  325. if (src->tail == src_bufend)
  326. src->tail = src->buf;
  327. if (dst->head == dst_bufend)
  328. dst->head = dst->buf;
  329. }
  330. assert(count + ringbuf_bytes_used(src) == src_bytes_used);
  331. if (overflow) {
  332. dst->tail = ringbuf_nextp(dst, dst->head);
  333. assert(ringbuf_is_full(dst));
  334. }
  335. return dst->head;
  336. }