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:
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;
+}