From 2a88ed46e4bf5a240b9fe425598edf6bb158d66b Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 24 Jan 2021 11:35:26 -0800 Subject: [PATCH] llx: Introduce new iteration macros and some users. --- src/libpspp/llx.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/output/driver.c | 21 ++++++++------------- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/libpspp/llx.h b/src/libpspp/llx.h index 80a8a83806..8f01c70f24 100644 --- a/src/libpspp/llx.h +++ b/src/libpspp/llx.h @@ -313,5 +313,50 @@ llx_data (const struct llx *llx) { return llx->data; } +/* Iteration helper macros. */ + +/* Sets "struct llx *" NODE to each object in LIST in turn, in forward or + reverse order. + + Behavior is undefined if NODE is removed from the list between + loop iterations. */ +#define llx_for_each(NODE, LIST) \ + for ((NODE) = llx_head (LIST); \ + (NODE) != llx_null (LIST); \ + (NODE) = llx_next (NODE)) +#define llx_for_each_reverse(NODE, LIST) \ + for ((NODE) = llx_tail (LIST); \ + (NODE) != llx_null (LIST); \ + (NODE) = llx_prev (NODE)) + +/* Sets "struct llx *" NODE to each object in LIST in turn, in forward or + reverse order. NEXT (or PREV) must be another "struct llx *" variable. + + Behavior is well-defined even if NODE is removed from the list between + iterations. */ +#define llx_for_each_safe(NODE, NEXT, LIST) \ + for (NODE = llx_head (LIST); \ + ((NODE) != llx_null (LIST) \ + ? ((NEXT) = llx_next (NODE), 1) \ + : 0); \ + (NODE) = (NEXT)) +#define llx_for_each_reverse_safe(NODE, PREV, LIST) \ + for (NODE = llx_tail (LIST); \ + ((NODE) != llx_null (LIST) \ + ? ((PREV) = llx_prev (NODE), 1) \ + : 0); \ + (NODE) = (PREV)) + +/* Sets DATA to the data from each object in LIST in turn, in forward or + reverse order. Each object is removed from LIST before its loop + iteration. */ +#define llx_for_each_preremove(DATA, LIST, MANAGER) \ + while (!llx_is_empty (LIST) \ + ? ((DATA) = llx_pop_head (LIST, MANAGER), 1) \ + : 0) +#define llx_for_each_reverse_preremove(DATA, LIST, MANAGER) \ + while (!llx_is_empty (LIST) \ + ? ((DATA) = llx_pop_tail (LIST, MANAGER), 1) \ + : 0) #endif /* llx.h */ diff --git a/src/output/driver.c b/src/output/driver.c index 6f5d4633ce..7c0bff8bf5 100644 --- a/src/output/driver.c +++ b/src/output/driver.c @@ -110,13 +110,11 @@ void output_engine_pop (void) { struct ll *head = ll_pop_head (&engine_stack); - struct output_engine *e =ll_data (head, struct output_engine, ll); + struct output_engine *e = ll_data (head, struct output_engine, ll); - while (!llx_is_empty (&e->drivers)) - { - struct output_driver *d = llx_pop_head (&e->drivers, &llx_malloc_mgr); - output_driver_destroy (d); - } + struct output_driver *d; + llx_for_each_preremove (d, &e->drivers, &llx_malloc_mgr) + output_driver_destroy (d); output_item_unref (e->deferred_text); free (e->command_name); free (e->title); @@ -141,13 +139,10 @@ static void output_submit__ (struct output_engine *e, struct output_item *item) { struct llx *llx, *next; - - for (llx = llx_head (&e->drivers); llx != llx_null (&e->drivers); llx = next) + llx_for_each_safe (llx, next, &e->drivers) { struct output_driver *d = llx_data (llx); - next = llx_next (llx); - enum settings_output_type type = SETTINGS_OUTPUT_RESULT; switch (item->type) { @@ -299,11 +294,11 @@ void output_flush (void) { struct output_engine *e = engine_stack_top (); - struct llx *llx; flush_deferred_text (e); - for (llx = llx_head (&e->drivers); llx != llx_null (&e->drivers); - llx = llx_next (llx)) + + struct llx *llx; + llx_for_each (llx, &e->drivers) { struct output_driver *d = llx_data (llx); if (d->device_type & SETTINGS_DEVICE_TERMINAL && d->class->flush != NULL) -- 2.30.2