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 | |
71 | typedef 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 |
75 | typedef void(*rbuffer_callback)(RBuffer *buf, void *data); |
76 | |
77 | struct 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 | |