aboutsummaryrefslogtreecommitdiffstats
path: root/core/module.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-05 17:38:03 +0100
committereunhhu <[email protected]>2026-10-05 17:38:03 +0100
commitb81d8bc8249ee35e87ea630413a311460e85eec0 (patch)
treeed13ff46346e7bf25e695e73ed927358bdc6fb30 /core/module.c
parentf7d369e77d999a0e60f3de2b5511b99c81b266bb (diff)
downloadpure-b81d8bc8249ee35e87ea630413a311460e85eec0.tar.gz
pure-b81d8bc8249ee35e87ea630413a311460e85eec0.zip
Text keys (023): a list knows the text field it is keyed by; an event's list keyed by a text is HASHED from its first item, its table's slots holding the texts' hashes (FNV-1a), a match the key cell's bytes too; HAS and a field by key read the table; its order made by a merge sort (the first eight bytes as a number, then all). A FIND whose index only an ITEM_SET of its list takes, the code between in a line finding by key alone, sets the item where it was found (PLAN_ROW: a HASHED list's slot, no position made). words 453 to 217 ms (5.8x C)
text_keys_equivalence: adds, has, fields by key, sets where found, positions, runs, removes and clears against a tree keyed by the text
Diffstat (limited to 'core/module.c')
-rw-r--r--core/module.c58
1 files changed, 51 insertions, 7 deletions
diff --git a/core/module.c b/core/module.c
index bc9fb8f..2228725 100644
--- a/core/module.c
+++ b/core/module.c
@@ -1371,6 +1371,48 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule
if (op->op == PURE_OP_LIST_FIND && next->op == PURE_OP_ITEM_GET && list_of(next->arg) == op->arg && !landed[pc + 1])
op->plan |= PLAN_JOINED;
}
+ /* A FIND whose index waits on the stack for an ITEM_SET of its list,
+ * the code between in a line (no jump in or out) that touches no list but
+ * to find by key (joined, or HAS): the item is set where it was found, a
+ * HASHED list's slot, no position made (PLAN_ROW, docs/design/023). */
+ for (uint32_t pc = 0; pc < out->code_count; ++pc) {
+ PureOp *find = &out->code[pc];
+ if (find->op != PURE_OP_LIST_FIND || find->plan & PLAN_JOINED) continue;
+ int height = 1;
+ for (uint32_t at = pc + 1; at < out->code_count && height >= 1 && !landed[at]; ++at) {
+ const PureOp *o = &out->code[at];
+ int pops = -1, pushes = 1;
+ switch (o->op) {
+ case PURE_OP_CONST: case PURE_OP_LOAD: case PURE_OP_LOCAL_LOAD: case PURE_OP_TEXT_CONST: case PURE_OP_TEXT_LOAD:
+ case PURE_OP_FIELD: case PURE_OP_LIST_COUNT:
+ pops = 0;
+ break;
+ case PURE_OP_NEG: case PURE_OP_NOT: case PURE_OP_FLOOR: case PURE_OP_NUM_TEXT: case PURE_OP_I64_NEG:
+ case PURE_OP_I64_FROM: case PURE_OP_NUM_FROM: case PURE_OP_LIST_HAS:
+ pops = 1;
+ break;
+ case PURE_OP_ADD: case PURE_OP_SUB: case PURE_OP_MUL: case PURE_OP_DIV: case PURE_OP_MIN: case PURE_OP_MAX:
+ case PURE_OP_MOD: case PURE_OP_AND: case PURE_OP_OR: case PURE_OP_LT: case PURE_OP_LE: case PURE_OP_GT:
+ case PURE_OP_GE: case PURE_OP_EQ: case PURE_OP_NE: case PURE_OP_CONCAT: case PURE_OP_TEXT_COMPARE:
+ case PURE_OP_I64_ADD: case PURE_OP_I64_SUB: case PURE_OP_I64_MUL: case PURE_OP_I64_DIV: case PURE_OP_I64_MOD:
+ case PURE_OP_I64_MIN: case PURE_OP_I64_MAX: case PURE_OP_I64_COMPARE:
+ pops = 2;
+ break;
+ case PURE_OP_LIST_FIND: /* joined: its ITEM_GET with it (a key in, the field out) */
+ if (o->plan & PLAN_JOINED && !landed[at + 1]) pops = 1, ++at;
+ break;
+ case PURE_OP_ITEM_SET:
+ if (height == 2 && list_of(o->arg) == find->arg) {
+ find->plan |= PLAN_ROW;
+ out->code[at].plan |= PLAN_ROW;
+ }
+ break;
+ default: break;
+ }
+ if (pops < 0) break;
+ height += pushes - pops;
+ }
+ }
free(landed);
/* The lists an index state refers to: their inserts tell where (move_indices). */
for (uint32_t i = 0; i < out->states; ++i)
@@ -2822,10 +2864,10 @@ static inline __attribute__((always_inline)) int step(Frame *frame, const PureOp
Held before = list_held(app, app->lists[list]);
PureSpan span = {0};
status = op->plan & PLAN_TEXT ? contiguous(app, arena, value.bytes, &span) : PURE_OK;
- if (status == PURE_OK)
- status = pure_list_set(app->lists[list], at, field,
- (PureCell){.i64 = value.i64, .text = (unsigned char *)span.data, .size = span.size},
- undo_for(app, list));
+ PureCell cell = {.i64 = value.i64, .text = (unsigned char *)span.data, .size = span.size};
+ if (status == PURE_OK) /* where its FIND found it (PLAN_ROW: a HASHED list's slot), else its position */
+ status = op->plan & PLAN_ROW ? pure_list_set_row(app->lists[list], at, field, cell, undo_for(app, list))
+ : pure_list_set(app->lists[list], at, field, cell, undo_for(app, list));
arena->used = mark;
if (status != PURE_OK) REFUSED;
if (!grows(app, before, list_held(app, app->lists[list]))) { kind = PURE_FAULT_MEMORY; FAILED; }
@@ -2912,12 +2954,14 @@ static inline __attribute__((always_inline)) int step(Frame *frame, const PureOp
else if ((status = keep_bytes(arena, value.text, value.size, &top->bytes)) != PURE_OK) STOPPED(status);
NEXT;
}
- /* An event's list keeps its keys as a set: HAS asks it alone (020). */
- if (op->op == PURE_OP_LIST_HAS && pure_list_contains(app->lists[arg], cell.num, &found)) {
+ /* An event's list keeps its keys as a set: HAS asks it alone (020); a text key's HASHED list, its table. */
+ if (op->op == PURE_OP_LIST_HAS && (op->plan & PLAN_TEXT ? pure_list_contains_text(app->lists[arg], cell, &found)
+ : pure_list_contains(app->lists[arg], cell.num, &found))) {
+ arena->used = mark;
top->num = found;
NEXT;
}
- size_t at = pure_list_seek(app->lists[arg], key, cell, &found);
+ size_t at = op->plan & PLAN_ROW ? pure_list_find_row(app->lists[arg], key, cell, &found) : pure_list_seek(app->lists[arg], key, cell, &found);
arena->used = mark;
if (op->op == PURE_OP_LIST_HAS) { top->num = found; NEXT; }
if (!found) { kind = PURE_FAULT_NOT_FOUND; FAILED; }