diff options
| author | eunhhu <[email protected]> | 2026-09-28 04:31:43 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-28 04:31:43 +0100 |
| commit | eed3b0d022a5145be06d87140a747da1a82f0f9d (patch) | |
| tree | f3abf7322b1ef026c7b37b83d14202828abd52a9 /core/module.h | |
| parent | e5d9b792497ccbc71ccd777497d40c7a8f8c23bf (diff) | |
| download | pure-eed3b0d022a5145be06d87140a747da1a82f0f9d.tar.gz pure-eed3b0d022a5145be06d87140a747da1a82f0f9d.zip | |
Walk a list in a handler, and fill a list with a message's rows
EACH runs the block that follows in a handler once for every item its list
has when it begins, in order, with ROW the item: the block may change
states, the list's items (a field, or removing one) and other lists, but
may not insert into the list it walks, hold another walk or reply, so a
walk runs at most its items times its block. Removing the walked item, or
one before it, moves the walk with it, so no item is skipped. A fold in
the block reads the walked item as OUTER_ROW, as a fold in a column reads
its row. SQL's UPDATE ... WHERE and DELETE ... WHERE are a walk.
A message field may now be rows (type 5, naming a list state): records
laid out as the list's stored form, filling that list, whose flags hold
PURE_LIST_ROWS and whose name is the field's path (order.lines), when the
message arrives; rows that are not whole fail it (limit). A list of rows
is emptied when every event ends, is never saved, and its changes are not
logged for undoing, so a handler walks, folds and counts a message's rows
as any list, and may use one as a scratch table within its event. An
output has no rows. pure_list_clear lets a list's items go.
walks checks a shop against a model over 3,000 random events: orders
whose rows each take stock and are logged, all or nothing (997 applied,
1,322 failed and undone, by an item not stocked or not enough of it), and
a clean that walks the stock removing items (83 while walking, 32 of them
before the walked item). Nine refusals are checked, and 20,000 damaged
walk modules run safely with no rows left after any event; all under
ASan and UBSan too.
Diffstat (limited to 'core/module.h')
| -rw-r--r-- | core/module.h | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/core/module.h b/core/module.h index 2da5c6b..44af5eb 100644 --- a/core/module.h +++ b/core/module.h @@ -38,9 +38,14 @@ typedef enum { PURE_OP_ITEM_GET, PURE_OP_ITEM_SET, PURE_OP_INDEX_LOAD, PURE_OP_INDEX_STORE, PURE_OP_INDEX_MOVE, PURE_OP_INDEX_FIRST, PURE_OP_INDEX_LAST, PURE_OP_INDEX_NUM, PURE_OP_ROW, PURE_OP_PICK, PURE_OP_SLIDE, PURE_OP_FOLD, PURE_OP_TEXT_COMPARE, PURE_OP_LIST_FIND, PURE_OP_LIST_HAS, - PURE_OP_NOW, PURE_OP_FLOOR, PURE_OP_MOD, PURE_OP_SEND, PURE_OP_OUTER_ROW, + PURE_OP_NOW, PURE_OP_FLOOR, PURE_OP_MOD, PURE_OP_SEND, PURE_OP_OUTER_ROW, PURE_OP_EACH, PURE_OP_COUNT } PureOpcode; +/* EACH's argument: the list state (bits 8-15) and the length of the block + * that follows (16-31), run in a handler once for every item the list had + * when it began, in order, with ROW the item; the block may change states, + * the list's items and other lists, but not insert into the list it walks + * (an item it removes, or one before it, moves the walk with it). */ /* FOLD's argument: the kind (bits 0-7), the list state (8-15) and the length * of the block that follows (16-31), run once per item as a column of that * list. count counts the items whose block leaves a non-zero number; sum, @@ -58,19 +63,25 @@ typedef enum { PURE_KIND_KEY = 1, PURE_KIND_MESSAGE = 2, PURE_KIND_TEXT = 3, PUR PURE_KIND_OUTPUT = 5 } PureInputKind; enum { PURE_TIMER_LONGEST = 86400000, PURE_SOURCE = 64 }; /* A message field: a u32le or a binary64 (fixed, at its offset in the - * payload's prefix), or bytes or text of any length. The prefix also holds - * each variable field's u32le length but the last one's (its offset is + * payload's prefix), or bytes, text or rows of any length. The prefix also + * holds each variable field's u32le length but the last one's (its offset is * PURE_FIELD_REST), which takes what follows the others; the variable * fields' bytes follow the prefix in declaration order. A text is UTF-8 and - * a number finite, or the message fails. */ -typedef enum { PURE_FIELD_U32 = 1, PURE_FIELD_BYTES = 2, PURE_FIELD_NUMBER = 3, PURE_FIELD_TEXT = 4 } PureFieldType; + * a number finite, or the message fails. Rows are records of a list of a + * message's rows (rows, a list state), laid out as a list's stored form: a + * message fills that list with them, and fails when they are not whole. */ +typedef enum { PURE_FIELD_U32 = 1, PURE_FIELD_BYTES = 2, PURE_FIELD_NUMBER = 3, PURE_FIELD_TEXT = 4, + PURE_FIELD_ROWS = 5 } PureFieldType; enum { PURE_FIELD_REST = UINT32_MAX }; typedef enum { PURE_STATE_NUM = 0, PURE_STATE_TEXT = 1, PURE_STATE_CURSOR = 2, PURE_STATE_LIST = 3, PURE_STATE_INDEX = 4 } PureStateType; /* A cursor that stays before text inserted at it (a mark); other cursors go - * after it (a caret). */ -enum { PURE_CURSOR_STAYS = 1 }; + * after it (a caret). A list of a message's rows (its state's flags hold + * PURE_LIST_ROWS beside the key byte; its name is the field's path): a + * message's rows field fills it as the message arrives, it is emptied when + * every event ends, and it is never saved nor logged for undoing. */ +enum { PURE_CURSOR_STAYS = 1, PURE_LIST_ROWS = 256 }; /* A table view has one row per item of a list, or per item its filter * keeps; its columns are number or text views evaluated for one row at a * time. */ @@ -91,7 +102,7 @@ typedef enum { typedef struct { double value; uint32_t arg; uint8_t op, plan, shape; } PureOp; typedef struct { uint32_t start, length; } PureBlock; typedef struct { uint32_t event; PureBlock code; } PureHandler; -typedef struct { char name[PURE_MODULE_NAME]; uint8_t type; uint32_t offset; } PureField; +typedef struct { char name[PURE_MODULE_NAME]; uint8_t type; uint16_t rows; uint32_t offset; } PureField; typedef struct { uint8_t kind; bool keyed; @@ -122,7 +133,7 @@ typedef struct { char input_keys[PURE_MODULE_INPUTS][PURE_MODULE_NAME]; uint8_t state_type[PURE_MODULE_STATES]; uint16_t state_ref[PURE_MODULE_STATES]; /* text: constant; cursor: text; list: record; index: list */ - uint8_t state_flags[PURE_MODULE_STATES]; /* cursor: PURE_CURSOR_STAYS */ + uint8_t state_flags[PURE_MODULE_STATES]; /* cursor: PURE_CURSOR_STAYS; list: PURE_LIST_ROWS >> 8 */ /* A keyed list: its key field + 1 (0: none). Its items stay in key order * (numbers by value, texts by bytes), each key once, and keys do not change. */ uint8_t state_key[PURE_MODULE_STATES]; |
