1// Specialized ring buffer. This is basically an array that wraps read/write
2// pointers around the memory region. It should be more efficient than the old
3// RBuffer which required memmove() calls to relocate read/write positions.
4//
5// The main purpose of RBuffer is simplify memory management when reading from
6// uv_stream_t instances:
7//
8// - The event loop writes data to a RBuffer, advancing the write pointer
9// - The main loop reads data, advancing the read pointer
10// - If the buffer becomes full(size == capacity) the rstream is temporarily
11// stopped(automatic backpressure handling)
12//
13// Reference: http://en.wikipedia.org/wiki/Circular_buffer
14#ifndef NVIM_RBUFFER_H
15#define NVIM_RBUFFER_H
16
17#include <stddef.h>
18#include <stdint.h>
19
20// Macros that simplify working with the read/write pointers directly by hiding
21// ring buffer wrap logic. Some examples:
22//
23// - Pass the write pointer to a function(write_data) that incrementally
24// produces data, returning the number of bytes actually written to the
25// ring buffer:
26//
27// RBUFFER_UNTIL_FULL(rbuf, ptr, cnt)
28// rbuffer_produced(rbuf, write_data(state, ptr, cnt));
29//
30// - Pass the read pointer to a function(read_data) that incrementally
31// consumes data, returning the number of bytes actually read from the
32// ring buffer:
33//
34// RBUFFER_UNTIL_EMPTY(rbuf, ptr, cnt)
35// rbuffer_consumed(rbuf, read_data(state, ptr, cnt));
36//
37// Note that the rbuffer_{produced,consumed} calls are necessary or these macros
38// create infinite loops
39#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \
40 for (size_t rcnt = 0, _r = 1; _r; _r = 0) /* NOLINT(readability/braces) */ \
41 for ( /* NOLINT(readability/braces) */ \
42 char *rptr = rbuffer_read_ptr(buf, &rcnt); \
43 buf->size; \
44 rptr = rbuffer_read_ptr(buf, &rcnt))
45
46#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \
47 for (size_t wcnt = 0, _r = 1; _r; _r = 0) /* NOLINT(readability/braces) */ \
48 for ( /* NOLINT(readability/braces) */ \
49 char *wptr = rbuffer_write_ptr(buf, &wcnt); \
50 rbuffer_space(buf); \
51 wptr = rbuffer_write_ptr(buf, &wcnt))
52
53
54// Iteration
55#define RBUFFER_EACH(buf, c, i) \
56 for (size_t i = 0; /* NOLINT(readability/braces) */ \
57 i < buf->size; \
58 i = buf->size) \
59 for (char c = 0; /* NOLINT(readability/braces) */ \
60 i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
61 i++)
62
63#define RBUFFER_EACH_REVERSE(buf, c, i) \
64 for (size_t i = buf->size; /* NOLINT(readability/braces) */ \
65 i != SIZE_MAX; \
66 i = SIZE_MAX) \
67 for (char c = 0; /* NOLINT(readability/braces) */ \
68 i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
69 )
70
71typedef struct rbuffer RBuffer;
72/// Type of function invoked during certain events:
73/// - When the RBuffer switches to the full state
74/// - When the RBuffer switches to the non-full state
75typedef void(*rbuffer_callback)(RBuffer *buf, void *data);
76
77struct rbuffer {
78 rbuffer_callback full_cb, nonfull_cb;
79 void *data;
80 size_t size;
81 // helper memory used to by rbuffer_reset if required
82 char *temp;
83 char *end_ptr, *read_ptr, *write_ptr;
84 char start_ptr[];
85};
86
87#ifdef INCLUDE_GENERATED_DECLARATIONS
88# include "rbuffer.h.generated.h"
89#endif
90
91#endif // NVIM_RBUFFER_H
92