libtabular-c

C tabular formatting library
git clone https://git.sinitax.com/sinitax/libtabular-c
Log | Files | Refs | Submodules | sfeed.txt

commit d8980c2311a26def43e33c05148bb182a975196c
parent d2447a0d18552f18da965f1234005527cd80eb39
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri,  2 Jun 2023 17:38:45 +0200

Add lazy-loading of rows

Diffstat:
Minclude/tabular.h | 46+++++++++++++++++++++++++++++++++++++---------
Mlibtabular.api | 4++++
Msrc/tabular.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
3 files changed, 101 insertions(+), 38 deletions(-)

diff --git a/include/tabular.h b/include/tabular.h @@ -21,6 +21,12 @@ enum { TABULAR_SQUASH_WORDAWARE }; +enum { + TABULAR_ENTRY_HIDDEN, + TABULAR_ENTRY_STR_AVAIL, + TABULAR_ENTRY_HIDDEN_AVAIL, +}; + struct tabular_user { union { void *ptr; @@ -30,36 +36,49 @@ struct tabular_user { struct tabular_entry { char *str; - bool avail; - size_t ulen; + uint32_t flags; + uint32_t ulen; }; struct tabular_row { struct tabular_user user; struct tabular_entry *entries; - struct tabular_row *next; }; struct tabular_col { + struct tabular_user user; + + /* column name displayed in header */ const char *name; - struct tabular_user user; + /* create str entry to display from user objects */ + char *(*to_str)(const struct tabular_user *user_row, + const struct tabular_user *user_col); - char *(*to_str)(const struct tabular_user *id); - bool (*is_hidden)(const struct tabular_user *id); + /* only show content if atleast one row is not 'hidden' */ + bool (*is_hidden)(const struct tabular_user *user_row, + const struct tabular_user *user_col); + /* size restrictions */ size_t minwidth, maxwidth; + + /* whitespace padding */ size_t lpad, rpad; + /* text alignment */ int align; + /* content packing strategy */ int strategy; + /* omiting column due to space disallowed */ bool essential; }; struct tabular_cfg { + struct tabular_user user; + const struct tabular_col *columns; size_t column_count; @@ -81,6 +100,10 @@ struct tabular_cfg { /* total lpad, rpad */ size_t lpad, rpad; + /* lazy load rows */ + struct tabular_row *(*row_gen)(const struct tabular_user *user); + + /* style printing hook for header, separators and content */ bool (*print_style)(FILE *file, const struct tabular_cfg *cfg, const struct tabular_row *row, const struct tabular_col *col); @@ -95,8 +118,13 @@ struct tabular_stats { }; int tabular_format(FILE *file, const struct tabular_cfg *cfg, - struct tabular_stats *stat, struct tabular_row *rows); + struct tabular_stats *stat, struct tabular_row **rows); + +void tabular_load_row_entry_hidden(const struct tabular_cfg *cfg, + struct tabular_row *row, size_t col); +void tabular_load_row_entry_str(const struct tabular_cfg *cfg, + struct tabular_row *row, size_t col); -struct tabular_row **tabular_alloc_row(const struct tabular_cfg *cfg, - int *error, struct tabular_row **rows, struct tabular_user user); +struct tabular_row *tabular_alloc_row(const struct tabular_cfg *cfg, + int *error, struct tabular_user user); int tabular_free_rows(const struct tabular_cfg *cfg, struct tabular_row *rows); diff --git a/libtabular.api b/libtabular.api @@ -1,3 +1,7 @@ tabular_format + +tabular_load_row_entry_str +tabular_load_row_entry_hidden + tabular_alloc_row tabular_free_rows diff --git a/src/tabular.c b/src/tabular.c @@ -51,7 +51,7 @@ static int calc_params_row(const struct tabular_cfg *cfg, struct tabular_stats *stats, struct tabular_row *rows, struct tabular_row *row, struct fmt_state *fmt, size_t limit); static int calc_params(const struct tabular_cfg *cfg, - struct tabular_stats *stat, struct tabular_row *rows, + struct tabular_stats *stat, struct tabular_row **rows, struct fmt_state *fmt); static void output_header(FILE *file, const struct tabular_cfg *cfg, @@ -280,24 +280,19 @@ calc_params_row(const struct tabular_cfg *cfg, struct tabular_stats *stats, if (!copy) return -rc; memcpy(copy, fmt->columns, sizeof(struct col_state) * cfg->column_count); - /* unhide cols and update maxlen */ + /* unhide cols */ for (i = 0; i < cfg->column_count; i++) { - if (fmt->columns[i].hidden && cfg->columns[i].to_str) { - if (cfg->columns[i].is_hidden) { - fmt->columns[i].hidden = - cfg->columns[i].is_hidden(&row->user); - } else { - fmt->columns[i].hidden = false; - } + tabular_load_row_entry_hidden(cfg, row, i); + if (fmt->columns[i].hidden) { + fmt->columns[i].hidden = + (row->entries[i].flags & TABULAR_ENTRY_HIDDEN); } if (fmt->columns[i].hidden) continue; + } - if (!row->entries[i].avail) { - row->entries[i].str = cfg->columns[i].to_str(&row->user); - row->entries[i].ulen = (uint32_t) u8strlen(row->entries[i].str); - row->entries[i].avail = true; - } - + /* update maxlen for visible cols */ + for (i = 0; i < cfg->column_count; i++) { + tabular_load_row_entry_str(cfg, row, i); fmt->columns[i].maxlen = MAX(fmt->columns[i].maxlen, row->entries[i].ulen); } @@ -325,9 +320,9 @@ undo: int calc_params(const struct tabular_cfg *cfg, struct tabular_stats *stats, - struct tabular_row *rows, struct fmt_state *fmt) + struct tabular_row **rows, struct fmt_state *fmt) { - struct tabular_row *row; + struct tabular_row **row; ssize_t first, last; size_t i; int rc; @@ -362,16 +357,18 @@ calc_params(const struct tabular_cfg *cfg, struct tabular_stats *stats, fmt->columns[i].written = 0; } - if (!recalc_cols(cfg, stats, fmt, rows, 0)) { + if (!recalc_cols(cfg, stats, fmt, *rows, 0)) { stats->cols_truncated = true; stats->rows_truncated = true; return 0; } fmt->row_limit = 0; - for (row = rows; row; row = row->next) { - rc = calc_params_row(cfg, stats, rows, - row, fmt, fmt->row_limit + 1); + for (row = rows; ; row = &(*row)->next) { + if (!*row && cfg->row_gen) *row = cfg->row_gen(&cfg->user); + if (!*row) break; + rc = calc_params_row(cfg, stats, *rows, + *row, fmt, fmt->row_limit + 1); if (rc < 0) return rc; if (rc > 0) break; fmt->row_limit++; @@ -553,7 +550,7 @@ output_rows(FILE *file, const struct tabular_cfg *cfg, int tabular_format(FILE *file, const struct tabular_cfg *cfg, - struct tabular_stats *stats, struct tabular_row *rows) + struct tabular_stats *stats, struct tabular_row **rows) { struct fmt_state fmt; size_t i; @@ -582,7 +579,7 @@ tabular_format(FILE *file, const struct tabular_cfg *cfg, rc = calc_params(cfg, stats, rows, &fmt); if (rc) return rc; - rc = output_rows(file, cfg, stats, rows, &fmt); + rc = output_rows(file, cfg, stats, *rows, &fmt); if (rc) return rc; rc = cfg->allocator->free(cfg->allocator, fmt.columns); @@ -591,9 +588,9 @@ tabular_format(FILE *file, const struct tabular_cfg *cfg, return 0; } -struct tabular_row ** -tabular_alloc_row(const struct tabular_cfg *cfg, int *rc, - struct tabular_row **end, struct tabular_user user) +struct tabular_row * +tabular_alloc_row(const struct tabular_cfg *cfg, + int *rc, struct tabular_user user) { struct tabular_row *row; @@ -610,9 +607,7 @@ tabular_alloc_row(const struct tabular_cfg *cfg, int *rc, if (!row->entries) return NULL; memset(row->entries, 0, sizeof(struct tabular_entry) * cfg->column_count); - *end = row; - - return &row->next; + return row; } int @@ -637,3 +632,39 @@ tabular_free_rows(const struct tabular_cfg *cfg, struct tabular_row *rows) return 0; } + +void +tabular_load_row_entry_hidden(const struct tabular_cfg *cfg, + struct tabular_row *row, size_t col) +{ + bool hidden; + + if (row->entries[col].flags & TABULAR_ENTRY_HIDDEN_AVAIL) return; + + if (cfg->columns[col].is_hidden) { + hidden = cfg->columns[col].is_hidden( + &row->user, &cfg->columns[col].user); + } else { + hidden = false; + } + + if (hidden) { + row->entries[col].flags |= TABULAR_ENTRY_HIDDEN; + } else { + row->entries[col].flags &= TABULAR_ENTRY_HIDDEN; + } + + row->entries[col].flags |= TABULAR_ENTRY_HIDDEN_AVAIL; +} + +void +tabular_load_row_entry_str(const struct tabular_cfg *cfg, + struct tabular_row *row, size_t col) +{ + if (row->entries[col].flags & TABULAR_ENTRY_STR_AVAIL) return; + + row->entries[col].str = cfg->columns[col].to_str( + &row->user, &cfg->columns[col].user); + row->entries[col].ulen = (uint32_t) u8strlen(row->entries[col].str); + row->entries[col].flags |= TABULAR_ENTRY_STR_AVAIL; +}