[qwaq] Create some ring-buffer macros

I expect I will need several messaging buffers, and ring buffers tend to
be quite robust. Replacing the event buffer code with the macros made
testing easy.
This commit is contained in:
Bill Currie 2020-02-28 22:27:29 +09:00
parent 6a58dcdddd
commit 644ef93dde
2 changed files with 62 additions and 11 deletions

View file

@ -28,7 +28,7 @@ int main (int argc, string *argv)
ch = event.e.key; ch = event.e.key;
mvwprintf (win, 1, 1, "key: %d\n", ch); mvwprintf (win, 1, 1, "key: %d\n", ch);
} else if (event.event_type == qe_mouse) { } else if (event.event_type == qe_mouse) {
mvwprintf (win, 1, 2, "mouse: %d %d %d\n", mvwprintf (win, 1, 2, "mouse: %2d %2d %08x\n",
event.e.mouse.x, event.e.mouse.x,
event.e.mouse.y, event.e.mouse.y,
event.e.mouse.buttons); event.e.mouse.buttons);

View file

@ -48,6 +48,61 @@
#define QUEUE_MASK (QUEUE_SIZE - 1) #define QUEUE_MASK (QUEUE_SIZE - 1)
#define MOUSE_MOVES "\033[?1003h" // Make the terminal report mouse movements #define MOUSE_MOVES "\033[?1003h" // Make the terminal report mouse movements
#define RING_BUFFER(type, size) \
struct { \
type buffer[size]; \
unsigned head; \
unsigned tail; \
}
#define RB_buffer_size(ring_buffer) \
({ __auto_type rb = (ring_buffer); \
sizeof (rb->buffer) / sizeof (rb->buffer[0]); \
})
#define RB_SPACE_AVAILABLE(ring_buffer) \
({ __auto_type rb = &(ring_buffer); \
(rb->tail + RB_buffer_size(rb) - rb->head - 1) % RB_buffer_size(rb);\
})
#define RB_DATA_AVAILABLE(ring_buffer) \
({ __auto_type rb = &(ring_buffer); \
(rb->head + RB_buffer_size (rb) - rb->tail) % RB_buffer_size (rb); \
})
#define RB_WRITE_DATA(ring_buffer, data, count) \
({ __auto_type rb = &(ring_buffer); \
typeof (&rb->buffer[0]) d = (data); \
unsigned c = (count); \
unsigned h = rb->head; \
rb->head = (h + c) % RB_buffer_size (rb); \
if (c > RB_buffer_size (rb) - h) { \
memcpy (rb->buffer + h, d, \
(RB_buffer_size (rb) - h) * sizeof (rb->buffer[0])); \
c -= RB_buffer_size (rb) - h; \
d += RB_buffer_size (rb) - h; \
h = 0; \
} \
memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \
})
#define RB_READ_DATA(ring_buffer, data, count) \
({ __auto_type rb = &(ring_buffer); \
typeof (&rb->buffer[0]) d = (data); \
unsigned c = (count); \
unsigned oc = c; \
unsigned t = rb->tail; \
if (c > RB_buffer_size (rb) - t) { \
memcpy (d, rb->buffer + t, \
(RB_buffer_size (rb) - t) * sizeof (rb->buffer[0])); \
c -= RB_buffer_size (rb) - t; \
d += RB_buffer_size (rb) - t; \
t = 0; \
} \
memcpy (d, rb->buffer + t, c * sizeof (rb->buffer[0])); \
rb->tail = (t + oc) % RB_buffer_size (rb); \
})
typedef struct window_s { typedef struct window_s {
WINDOW *win; WINDOW *win;
} window_t; } window_t;
@ -57,9 +112,7 @@ typedef struct qwaq_resources_s {
int initialized; int initialized;
dstring_t *print_buffer; dstring_t *print_buffer;
PR_RESMAP (window_t) window_map; PR_RESMAP (window_t) window_map;
qwaq_event_t event_queue[QUEUE_SIZE]; RING_BUFFER (qwaq_event_t, QUEUE_SIZE) event_queue;
unsigned queue_head;
unsigned queue_tail;
} qwaq_resources_t; } qwaq_resources_t;
static window_t * static window_t *
@ -92,7 +145,7 @@ window_index (qwaq_resources_t *res, window_t *win)
PR_RESINDEX (res->window_map, win); PR_RESINDEX (res->window_map, win);
} }
static always_inline window_t * static always_inline window_t * __attribute__((pure))
get_window (qwaq_resources_t *res, const char *name, int handle) get_window (qwaq_resources_t *res, const char *name, int handle)
{ {
window_t *window = window_get (res, handle); window_t *window = window_get (res, handle);
@ -198,19 +251,17 @@ bi_wgetch (progs_t *pr)
static void static void
add_event (qwaq_resources_t *res, qwaq_event_t *event) add_event (qwaq_resources_t *res, qwaq_event_t *event)
{ {
if (((res->queue_head - res->queue_tail) & QUEUE_MASK) != QUEUE_MASK) { if (RB_SPACE_AVAILABLE (res->event_queue) >= 1) {
res->event_queue[res->queue_head] = *event; RB_WRITE_DATA (res->event_queue, event, 1);
res->queue_head = (res->queue_head + 1) & QUEUE_MASK;
} }
} }
static int static int
get_event (qwaq_resources_t *res, qwaq_event_t *event) get_event (qwaq_resources_t *res, qwaq_event_t *event)
{ {
if (res->queue_head != res->queue_tail) { if (RB_DATA_AVAILABLE (res->event_queue) >= 1) {
if (event) { if (event) {
*event = res->event_queue[res->queue_tail]; RB_READ_DATA (res->event_queue, event, 1);
res->queue_tail = (res->queue_tail + 1) & QUEUE_MASK;
} }
return 1; return 1;
} }