aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-26 16:37:53 +0100
committereunhhu <[email protected]>2026-09-26 16:37:53 +0100
commit382cb351d5fe30b6d8e86860f14025d6ca2dce29 (patch)
tree56156b885a4ffac8f995f1f0149771a27d019260
parent92f5545efb7aab0b3a4a4c73a65364ef519cd5d4 (diff)
downloadpure-382cb351d5fe30b6d8e86860f14025d6ca2dce29.tar.gz
pure-382cb351d5fe30b6d8e86860f14025d6ca2dce29.zip
Find a list item's stored offset only when the list is stored
Every insert, remove and set computed the item's offset in the draft, linear in the items before it, even for a list without a draft: building a list in memory (reading a stored one, migrating a record, or a list that is not stored) was quadratic. The offset is now found where the draft is spliced.
-rw-r--r--prototypes/connections/module-list.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/prototypes/connections/module-list.c b/prototypes/connections/module-list.c
index 2aa9b3d..8ac44c1 100644
--- a/prototypes/connections/module-list.c
+++ b/prototypes/connections/module-list.c
@@ -99,10 +99,12 @@ static unsigned char *encode_cell(const PureList *list, unsigned field, PureCell
return out;
}
-/* Replace [offset, offset + remove) of the draft; nothing to do without one. */
-static PureResult mirror(PureList *list, size_t offset, size_t remove, const unsigned char *bytes, size_t size) {
+/* Replace remove bytes of the draft, within bytes into the item at `at` (or
+ * after the last item), with bytes; nothing to do without a draft. */
+static PureResult mirror(PureList *list, size_t at, size_t within, size_t remove, const unsigned char *bytes,
+ size_t size) {
if (!list->draft) return PURE_OK;
- return pure_draft_splice(list->draft, offset, remove, (PureSpan){bytes, size});
+ return pure_draft_splice(list->draft, item_offset(list, at) + within, remove, (PureSpan){bytes, size});
}
void pure_list_mirror(PureList *list, PureDraft *draft, size_t header) {
@@ -117,7 +119,7 @@ PURE_COLD PureResult pure_list_write(PureList *list) {
if (size && !bytes) return PURE_ALLOCATION;
for (size_t i = 0; i < list->count; ++i)
for (unsigned f = 0; f < list->fields; ++f) at = encode_cell(list, f, list->items[i][f], at);
- PureResult result = mirror(list, list->header, 0, bytes, size);
+ PureResult result = mirror(list, 0, 0, 0, bytes, size);
free(bytes);
return result;
}
@@ -183,7 +185,7 @@ PureResult pure_list_insert(PureList *list, size_t at, const PureCell *cells, Pu
free_item(list, item);
return PURE_ALLOCATION;
}
- PureResult result = mirror(list, item_offset(list, at), 0, bytes, size);
+ PureResult result = mirror(list, at, 0, 0, bytes, size);
free(bytes);
if (result != PURE_OK) {
if (undo) --undo->count;
@@ -198,7 +200,7 @@ PureResult pure_list_remove(PureList *list, size_t at, PureUndo *undo) {
if (at >= list->count) return PURE_NOT_FOUND;
if (!log_change(undo, (Entry){.change = REMOVED, .list = list, .at = at, .item = list->items[at]}))
return PURE_ALLOCATION;
- PureResult result = mirror(list, item_offset(list, at), item_bytes(list, list->items[at]), NULL, 0);
+ PureResult result = mirror(list, at, 0, item_bytes(list, list->items[at]), NULL, 0);
if (result != PURE_OK) { --undo->count; return result; }
take(list, at);
return PURE_OK;
@@ -217,9 +219,9 @@ PureResult pure_list_set(PureList *list, size_t at, unsigned field, PureCell val
free(copy.text);
return PURE_ALLOCATION;
}
- size_t offset = list->draft ? item_offset(list, at) : 0;
- for (unsigned f = 0; list->draft && f < field; ++f) offset += cell_bytes(list, f, item[f]);
- PureResult result = mirror(list, offset, cell_bytes(list, field, item[field]), bytes, size);
+ size_t within = 0;
+ for (unsigned f = 0; f < field; ++f) within += cell_bytes(list, f, item[f]);
+ PureResult result = mirror(list, at, within, cell_bytes(list, field, item[field]), bytes, size);
free(bytes);
if (result != PURE_OK) {
--undo->count;