circular_buffer.c 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #include "../libnetdata.h"
  2. struct circular_buffer *cbuffer_new(size_t initial, size_t max) {
  3. struct circular_buffer *result = mallocz(sizeof(*result));
  4. result->size = initial;
  5. result->data = mallocz(initial);
  6. result->write = 0;
  7. result->read = 0;
  8. result->max_size = max;
  9. return result;
  10. }
  11. void cbuffer_free(struct circular_buffer *buf) {
  12. freez(buf->data);
  13. freez(buf);
  14. }
  15. static int cbuffer_realloc_unsafe(struct circular_buffer *buf) {
  16. // Check that we can grow
  17. if (buf->size >= buf->max_size)
  18. return 1;
  19. size_t new_size = buf->size * 2;
  20. if (new_size > buf->max_size)
  21. new_size = buf->max_size;
  22. // We know that: size < new_size <= max_size
  23. // For simplicity align the current data at the bottom of the new buffer
  24. char *new_data = mallocz(new_size);
  25. if (buf->read == buf->write)
  26. buf->write = 0; // buffer is empty
  27. else if (buf->read < buf->write) {
  28. memcpy(new_data, buf->data + buf->read, buf->write - buf->read);
  29. buf->write -= buf->read;
  30. } else {
  31. size_t top_part = buf->size - buf->read;
  32. memcpy(new_data, buf->data + buf->read, top_part);
  33. memcpy(new_data + top_part, buf->data, buf->write);
  34. buf->write = top_part + buf->write;
  35. }
  36. buf->read = 0;
  37. // Switch buffers
  38. freez(buf->data);
  39. buf->data = new_data;
  40. buf->size = new_size;
  41. return 0;
  42. }
  43. int cbuffer_add_unsafe(struct circular_buffer *buf, const char *d, size_t d_len) {
  44. size_t len = (buf->write >= buf->read) ? (buf->write - buf->read) : (buf->size - buf->read + buf->write);
  45. while (d_len + len >= buf->size) {
  46. if (cbuffer_realloc_unsafe(buf)) {
  47. return 1;
  48. }
  49. }
  50. // Guarantee: write + d_len cannot hit read
  51. if (buf->write + d_len < buf->size) {
  52. memcpy(buf->data + buf->write, d, d_len);
  53. buf->write += d_len;
  54. }
  55. else {
  56. size_t top_part = buf->size - buf->write;
  57. memcpy(buf->data + buf->write, d, top_part);
  58. memcpy(buf->data, d + top_part, d_len - top_part);
  59. buf->write = d_len - top_part;
  60. }
  61. return 0;
  62. }
  63. // Assume caller does not remove too many bytes (i.e. read will jump over write)
  64. void cbuffer_remove_unsafe(struct circular_buffer *buf, size_t num) {
  65. buf->read += num;
  66. // Assume num < size (i.e. caller cannot remove more bytes than are in the buffer)
  67. if (buf->read >= buf->size)
  68. buf->read -= buf->size;
  69. }
  70. size_t cbuffer_next_unsafe(struct circular_buffer *buf, char **start) {
  71. if (start != NULL)
  72. *start = buf->data + buf->read;
  73. if (buf->read <= buf->write) {
  74. return buf->write - buf->read; // Includes empty case
  75. }
  76. return buf->size - buf->read;
  77. }