diff options
| author | eunhhu <[email protected]> | 2026-10-05 17:38:03 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-05 17:38:03 +0100 |
| commit | b81d8bc8249ee35e87ea630413a311460e85eec0 (patch) | |
| tree | ed13ff46346e7bf25e695e73ed927358bdc6fb30 /core/module.c | |
| parent | f7d369e77d999a0e60f3de2b5511b99c81b266bb (diff) | |
| download | pure-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.c | 58 |
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; } |
