diff options
| author | eunhhu <[email protected]> | 2026-10-18 23:54:06 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-18 23:54:06 +0100 |
| commit | d7caf4dfb1947d8f804e3d8ae7ef066c6e3b8fb7 (patch) | |
| tree | 6c5b8bc47b5ce60cb9021377c1d2dc3c3469972e /core | |
| parent | ff2e0823e97d10477341192d72f5d9e61d9d5bad (diff) | |
| download | pure-d7caf4dfb1947d8f804e3d8ae7ef066c6e3b8fb7.tar.gz pure-d7caf4dfb1947d8f804e3d8ae7ef066c6e3b8fb7.zip | |
027's 4f-3a: no fixed count of inputs, views (the load's columns among them, in u16s), handlers or message fields: the header's u16s alone; a message's fields at most 64 (PURE_MESSAGE_FIELDS: a send pushes them all, as the stored sends' shapes hold them), outputs at most 255 (the store names them in a byte's count: the links and the outbox's image), the numbers of outputs a module dropped carried within it; an app's numbers of each input (last sent, saved, where the event began) in a block sized to its module's inputs (by_input), a replace laying the new one first and filling it by output name; image headers sized to the module (header_room); a view's arguments u32, a made column's field u16; pure-serve's timers grow to the module's inputs, its outlets and known senders its own count (OUTLETS, 32), a list view's JSON keys its columns on the stack for 64, else on the heap; unit test: 40 inputs and 70 views, the last of each used; counts: b40 against b39b within 0.01% with batches and without but BFS +0.09%; the bank's queries (s39b and s40 in turns, three each) in_credit -0.64%, per_branch -0.37%, field +0.34%, the rest within 0.22%; 008 and 027
Diffstat (limited to 'core')
| -rw-r--r-- | core/module-save.c | 53 | ||||
| -rw-r--r-- | core/module.c | 98 | ||||
| -rw-r--r-- | core/module.h | 22 | ||||
| -rw-r--r-- | core/test-module.c | 20 |
4 files changed, 129 insertions, 64 deletions
diff --git a/core/module-save.c b/core/module-save.c index 63553e0..19e9684 100644 --- a/core/module-save.c +++ b/core/module-save.c @@ -156,8 +156,17 @@ PURE_COLD PureResult pure_save_open_text(PureApp *app, const PureModule *m, uint /* ---- Lists: images and the log */ -enum { OUTPUTS_NAMED = 1 + PURE_MODULE_INPUTS * (2 + PURE_MODULE_NAME) + PURE_MODULE_FIELDS * (2 + PURE_MODULE_NAME), - IMAGE_HEADER = 6 + PURE_MODULE_RECORDS * (1 + PURE_RECORD_FIELDS * (3 + PURE_MODULE_NAME)) + 8 + OUTPUTS_NAMED }; +/* A runtime list's image header at most (its three fields at most); and what any of m's takes at most (027's 4f-3a): a + * record graph's, or the outbox's naming m's outputs. */ +enum { RUNTIME_HEADER = 4 + 1 + 3 * (2 + PURE_MODULE_NAME) + 8 }; +static size_t header_room(const PureModule *m) { + size_t records = 6 + 8 + 1, outbox = RUNTIME_HEADER + 1; + for (uint32_t r = 0; r < m->records; ++r) records += 1 + (size_t)m->record[r].count * (3 + PURE_MODULE_NAME); + for (uint32_t i = 0; i < m->inputs; ++i) + if (m->input[i].kind == PURE_KIND_OUTPUT) + outbox += 2 + PURE_MODULE_NAME + (size_t)m->input[i].field_count * (2 + PURE_MODULE_NAME); + return records > outbox ? records : outbox; +} static size_t header_of(unsigned count, const uint8_t *text, const char (*names)[PURE_MODULE_NAME], uint64_t seq, unsigned char *out) { @@ -270,7 +279,7 @@ static size_t outbox_header(const PureModule *m, uint64_t seq, unsigned char *ou /* What an output's sends were laid out with, as a store names it: its * fields (laid out), or their types alone (named false: links before PLK4). */ -typedef struct { char name[PURE_MODULE_NAME]; PureField fields[PURE_MODULE_FIELDS]; uint32_t count; bool named; } SentShape; +typedef struct { char name[PURE_MODULE_NAME]; PureField fields[PURE_MESSAGE_FIELDS]; uint32_t count; bool named; } SentShape; /* The outputs an outbox image names (at, size bytes): how many, or -1 when * they are not well formed; shapes (when not NULL) takes them. */ @@ -282,7 +291,7 @@ static int read_outputs(const unsigned char *at, size_t size, SentShape *shapes, size_t length = k < size ? at[k] : 0; if (!length || length >= PURE_MODULE_NAME || size - k < 2 + length) return -1; unsigned fields = at[k + 1 + length]; - if (fields > PURE_MODULE_FIELDS) return -1; + if (fields > PURE_MESSAGE_FIELDS) return -1; if (shapes) { memcpy(shapes[t].name, at + k + 1, length); shapes[t].name[length] = 0; @@ -473,9 +482,12 @@ static PureResult write_image(const char *directory, const char *name, const uns } PureResult pure_save_image(PureApp *app, const PureModule *m, uint32_t state, const PureList *list) { - unsigned char header[IMAGE_HEADER]; + unsigned char *header = malloc(header_room(m)); + if (!header) return PURE_ALLOCATION; size_t header_size = image_header(m, m->state_ref[state], app->seq, header); - return write_image(directory_of(app), m->state_names[state], header, header_size, list); + PureResult result = write_image(directory_of(app), m->state_names[state], header, header_size, list); + free(header); + return result; } PURE_COLD PureResult pure_save_open_list(PureApp *app, const PureModule *m, uint32_t state, PureList **out, @@ -597,7 +609,7 @@ PURE_COLD PureResult pure_save_open_runtime(PureApp *app, uint32_t place, PureLi *saved = (PureSaved){0}; *out = NULL; if (!directory_of(app)) return PURE_STORE_ERROR; - unsigned char *bytes = NULL, header[IMAGE_HEADER]; + unsigned char *bytes = NULL, header[RUNTIME_HEADER]; size_t size = 0, length = runtime_header(place, 0, header) - 8, at = length + 8; PureResult result = pure_image_read(directory_of(app), name, &bytes, &size); bool image = result == PURE_OK; @@ -648,11 +660,14 @@ PURE_COLD PureResult pure_save_open_runtime(PureApp *app, uint32_t place, PureLi } PureResult pure_save_runtime_image(PureApp *app, const PureModule *m, uint32_t place, const PureList *list) { - unsigned char header[IMAGE_HEADER]; + unsigned char *header = malloc(header_room(m)); + if (!header) return PURE_ALLOCATION; size_t header_size = place == PURE_LIST_OUTBOX ? outbox_header(m, app->seq, header) : runtime_header(place, app->seq, header); - return write_image(directory_of(app), runtime_lists[place - PURE_LIST_HEARD].name, header, header_size, - list ? list : stored_list(app, place)); + PureResult result = write_image(directory_of(app), runtime_lists[place - PURE_LIST_HEARD].name, header, header_size, + list ? list : stored_list(app, place)); + free(header); + return result; } /* ---- Checkpoints */ @@ -661,7 +676,7 @@ struct PureCheckpoint { PureSnapshot *snapshot; uint32_t state; char name[PURE_MODULE_NAME], *directory; - unsigned char header[IMAGE_HEADER]; + unsigned char *header; /* header_room's */ size_t header_size, logged; uint64_t seq, since; }; @@ -690,8 +705,10 @@ PureCheckpoint *pure_app_checkpoint(PureApp *app) { const char *directory = directory_of(app); size_t length = strlen(directory) + 1; if (c && (c->directory = malloc(length))) memcpy(c->directory, directory, length); - if (!c || !c->directory || !(c->snapshot = pure_save_snapshot(app, pick >= PURE_LIST_HEARD ? pick : UINT32_MAX))) { - if (c) free(c->directory); + if (c) c->header = malloc(header_room(m)); + if (!c || !c->directory || !c->header || + !(c->snapshot = pure_save_snapshot(app, pick >= PURE_LIST_HEARD ? pick : UINT32_MAX))) { + if (c) free(c->directory), free(c->header); free(c); return NULL; } @@ -727,7 +744,7 @@ void pure_app_checkpointed(PureApp *app, PureCheckpoint *c, PureResult result) { } if (app->checkpoint == c) app->checkpoint = NULL; pure_snapshot_release(c->snapshot); - free(c->directory); + free(c->directory), free(c->header); free(c); } @@ -819,11 +836,10 @@ static bool same_version(PureVersion a, PureVersion b) { return a.ref == b.ref & static unsigned char *encode_links(const PureApp *app, size_t *size) { const PureModule *m = app->module; unsigned outputs = 0; - uint8_t table[PURE_MODULE_INPUTS]; size_t total = 4 + 1; for (uint32_t i = 0; i < m->inputs; ++i) if (m->input[i].kind == PURE_KIND_OUTPUT) { - table[i] = (uint8_t)outputs++; + ++outputs; total += 2 + strlen(m->input_names[i]) + 8; for (uint32_t f = 0; f < m->input[i].field_count; ++f) total += 2 + strlen(m->field[m->input[i].field_start + f].name); @@ -859,7 +875,6 @@ static unsigned char *encode_links(const PureApp *app, size_t *size) { *at++ = 0; at = put_le(at, app->carried[c].last, 8); } - (void)table; *size = (size_t)(at - bytes); return bytes; } @@ -938,7 +953,7 @@ PURE_COLD PureResult pure_save_open_links(PureApp *app, const PureModule *m, boo memcpy(linked[t].name, name, length + 1); linked[t].count = fields; linked[t].named = named; - if (fields > PURE_MODULE_FIELDS) result = PURE_STORE_ERROR; + if (fields > PURE_MESSAGE_FIELDS) result = PURE_STORE_ERROR; for (unsigned f = 0; f < fields && result == PURE_OK; ++f) { /* its type, then (PLK4) its name */ size_t named_length = named && size - at >= 2 ? bytes[at + 1] : 0; if (size - at < (named ? 2 + named_length : 1) || named_length >= PURE_MODULE_NAME) { @@ -1035,7 +1050,7 @@ PURE_COLD PureResult pure_save_open_links(PureApp *app, const PureModule *m, boo free(linked); free(bytes); app->sent_saved = pure_list_count(app->outbox); - memcpy(app->saved_sent, app->last_sent, sizeof(app->saved_sent)); + memcpy(app->saved_sent, app->last_sent, m->inputs * sizeof(*app->saved_sent)); return result; } diff --git a/core/module.c b/core/module.c index 3bc98f2..ba44a85 100644 --- a/core/module.c +++ b/core/module.c @@ -244,10 +244,10 @@ static uint8_t field_kind(uint8_t type) { PureResult pure_send_recast(const PureField *from, uint32_t from_count, const PureField *to, uint32_t to_count, PureSpan payload, unsigned char **out, size_t *size) { - FieldValue was[PURE_MODULE_FIELDS], now[PURE_MODULE_FIELDS]; + FieldValue was[PURE_MESSAGE_FIELDS], now[PURE_MESSAGE_FIELDS]; *out = NULL; *size = 0; - if (from_count > PURE_MODULE_FIELDS || to_count > PURE_MODULE_FIELDS || !read_fields(from, from_count, payload, was)) + if (from_count > PURE_MESSAGE_FIELDS || to_count > PURE_MESSAGE_FIELDS || !read_fields(from, from_count, payload, was)) return PURE_STORE_ERROR; size_t total = 0; for (uint32_t g = 0; g < to_count; ++g) { @@ -644,7 +644,7 @@ PURE_COLD static const char *verify_code(const PureModule *m, PureBlock block, i } } /* Operand types, bottom to top; record operations take their fields. */ - unsigned char need[PURE_MODULE_FIELDS + 2]; + unsigned char need[PURE_MESSAGE_FIELDS + 2]; unsigned pops = signature[op->op].pops; memcpy(need, signature[op->op].in, sizeof(signature[op->op].in)); if (op->op == PURE_OP_SEND) { @@ -1710,10 +1710,8 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule out->record_fields = (uint16_t)read16(p + 34); out->functions = (uint16_t)read16(p + 36); out->state_words = (uint16_t)((out->states + 63) / 64 + !out->states); - if (out->inputs > PURE_MODULE_INPUTS || - out->views > PURE_MODULE_VIEWS || out->handlers > PURE_MODULE_HANDLERS || - out->code_count > PURE_MODULE_CODE || strings > PURE_MODULE_STRINGS || - out->fields > PURE_MODULE_FIELDS || out->constants > PURE_MODULE_CONSTANTS || constant_bytes > PURE_MODULE_CONSTANT_BYTES || + if (out->code_count > PURE_MODULE_CODE || strings > PURE_MODULE_STRINGS || + out->constants > PURE_MODULE_CONSTANTS || constant_bytes > PURE_MODULE_CONSTANT_BYTES || out->records > PURE_MODULE_RECORDS || out->record_fields > PURE_MODULE_RECORD_FIELDS || out->functions > PURE_MODULE_FUNCTIONS) { result = PURE_LIMIT; @@ -1761,7 +1759,7 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule if (v[4] == PURE_VIEW_LIST && !read16(v + 6) && record && record <= out->records) made += read16(p + records_at + (size_t)(record - 1) * RECORD_BYTES + 6); } - if (out->views + made > PURE_MODULE_VIEWS) REFUSE("views and their columns", out->views); + if (out->views + made > UINT16_MAX) REFUSE("views and their columns", out->views); /* (numbered in u16s) */ size_t capacity = out->views + made; if (!make_tables(out, capacity, signatures)) { result = PURE_ALLOCATION; @@ -1822,9 +1820,11 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule } uint32_t next_field = 0; const unsigned char *fields = at + (size_t)out->inputs * INPUT_BYTES; + unsigned outputs = 0; /* a store names them by a byte's count (the links, the outbox's image): 255 at most */ for (uint32_t i = 0; i < out->inputs; ++i, at += INPUT_BYTES) { PureInputShape *shape = &out->input[i]; shape->kind = at[4]; + if (shape->kind == PURE_KIND_OUTPUT && ++outputs > UINT8_MAX) REFUSE("outputs past 255", i); shape->binding = at[5]; shape->field_start = (uint16_t)read16(at + 12); shape->field_count = (uint16_t)read16(at + 14); @@ -1848,7 +1848,7 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule shape->view = arguments || shape->binding == PURE_BIND_POINT ? read32(at + 8) : 0; if ((shape->kind != PURE_KIND_MESSAGE && shape->kind != PURE_KIND_OUTPUT && !arguments) || (read32(at + 8) && !arguments && !shape->binding) || shape->field_start != next_field || - shape->field_count > out->fields - next_field) REFUSE("message shape", i); + shape->field_count > out->fields - next_field || shape->field_count > PURE_MESSAGE_FIELDS) REFUSE("message shape", i); /* A binding's fields: a key's and a timer's none, a text's one text, a frame's one number, a pointing's one u32. */ static const uint8_t bound_field[] = {[PURE_BIND_TEXT] = PURE_FIELD_TEXT, [PURE_BIND_FRAME] = PURE_FIELD_NUMBER, [PURE_BIND_POINT] = PURE_FIELD_U32}; @@ -1991,7 +1991,7 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule out->view_table[c] = (uint16_t)(i + 1); out->view_list[c] = out->view_list[i]; out->view_record[c] = (uint16_t)(out->view_type[c] == PURE_VIEW_LIST ? nested_record(out, field) + 1 : 0); - out->view_field[c] = (uint8_t)(f + 1); + out->view_field[c] = (uint16_t)(f + 1); out->view_computed[c] = out->view_computed[i]; out->view_code[c] = (PureBlock){0, 0}; } @@ -2008,7 +2008,7 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule if (shape->view >= out->views || out->view_table[shape->view] || out->view_arguments[shape->view]) REFUSE("arguments", i); snprintf(path, sizeof(path), "%s.args", out->view_names[shape->view]); if (strcmp(path, out->input_names[i])) REFUSE("arguments", i); - out->view_arguments[shape->view] = (uint8_t)(i + 1); + out->view_arguments[shape->view] = i + 1; } for (uint32_t i = 0; i < out->views; ++i) if (out->view_table[i]) out->view_arguments[i] = out->view_arguments[out->view_table[i] - 1]; @@ -2289,7 +2289,7 @@ size_t pure_module_fields(const PureModule *m, uint32_t input, unsigned char out /* Fields as a sender names them, laid out: their count, or -1 when they are * not well named (no rows: a sender sends none). */ static int named_fields(const unsigned char *bytes, size_t size, PureField *fields) { - if (!size || bytes[0] > PURE_MODULE_FIELDS) return -1; + if (!size || bytes[0] > PURE_MESSAGE_FIELDS) return -1; unsigned count = bytes[0]; size_t at = 1; for (unsigned f = 0; f < count; ++f) { @@ -2309,7 +2309,7 @@ static int named_fields(const unsigned char *bytes, size_t size, PureField *fiel } bool pure_module_takes(const PureModule *m, uint32_t input, const unsigned char *fields, size_t size) { - PureField sent[PURE_MODULE_FIELDS]; + PureField sent[PURE_MESSAGE_FIELDS]; int count = named_fields(fields, size, sent); if (count < 0) return false; const PureInputShape *s = &m->input[input]; @@ -2327,7 +2327,7 @@ bool pure_module_takes(const PureModule *m, uint32_t input, const unsigned char PureResult pure_module_recast(const PureModule *m, uint32_t input, const unsigned char *fields, size_t size, PureSpan payload, unsigned char **out, size_t *out_size) { - PureField sent[PURE_MODULE_FIELDS]; + PureField sent[PURE_MESSAGE_FIELDS]; int count = named_fields(fields, size, sent); *out = NULL; *out_size = 0; @@ -5012,10 +5012,10 @@ static void close_burst(PureApp *app, bool keep) { static void settle_links(PureApp *app, bool saved) { if (saved) { app->sent_saved = app->outbox ? pure_list_count(app->outbox) : 0; - memcpy(app->saved_sent, app->last_sent, sizeof(app->saved_sent)); + memcpy(app->saved_sent, app->last_sent, app->module->inputs * sizeof(*app->saved_sent)); } else { app->sent_saved = app->durable_sent_saved; - memcpy(app->last_sent, app->saved_sent, sizeof(app->last_sent)); + memcpy(app->last_sent, app->saved_sent, app->module->inputs * sizeof(*app->last_sent)); } app->links_changed = false; } @@ -5161,6 +5161,7 @@ void pure_app_stop(PureApp *app) { free(app->nested.shared); pure_draft_close(app->stored_values); free(app->carried); + free(app->by_input); pure_draft_close(app->stored_links); pure_draft_close(app->stored_seq); pure_save_close_start(app); @@ -5178,8 +5179,7 @@ void pure_app_stop(PureApp *app) { /* Where one event began inside the burst: a failed event returns there. */ typedef struct { /* (each state's text version and list journal length in the app's marked_texts, marked_lists) */ size_t heard, outbox; /* stored lists' journal lengths */ - size_t undo, sent_saved; - uint64_t last_sent[PURE_MODULE_INPUTS]; + size_t undo, sent_saved; /* (each output's last number in the app's marked_sent) */ bool opened; } Mark; @@ -5194,7 +5194,7 @@ static void mark_event(PureApp *app, Mark *mark) { mark->outbox = app->outbox ? pure_list_changes(app->outbox).size : 0; mark->undo = app->undo.count; mark->sent_saved = app->sent_saved; - memcpy(mark->last_sent, app->last_sent, sizeof(mark->last_sent)); + memcpy(app->marked_sent, app->last_sent, app->module->inputs * sizeof(*app->marked_sent)); } static void undo_event(PureApp *app, const Mark *mark) { @@ -5206,7 +5206,7 @@ static void undo_event(PureApp *app, const Mark *mark) { if (app->outbox) pure_list_forget(app->outbox, mark->outbox); pure_undo_rollback(&app->undo, mark->undo); app->sent_saved = mark->sent_saved; - memcpy(app->last_sent, mark->last_sent, sizeof(app->last_sent)); + memcpy(app->last_sent, app->marked_sent, app->module->inputs * sizeof(*app->last_sent)); if (mark->opened) close_burst(app, true); /* nothing happened: release the holds */ } @@ -5375,7 +5375,7 @@ static PureFault place_fields(const PureModule *m, const PureInputShape *shape, } int pure_module_arguments(const PureModule *m, uint32_t view) { - return view < m->views && m->view_arguments[view] ? m->view_arguments[view] - 1 : -1; + return view < m->views && m->view_arguments[view] ? (int)m->view_arguments[view] - 1 : -1; } PureResult pure_app_arguments(PureApp *app, uint32_t view, PureSpan payload, const uint32_t *placed) { @@ -5400,7 +5400,7 @@ static PureResult message(PureApp *app, uint32_t input, PureSpan payload, const app->fault_pc = UINT32_MAX; if (input >= m->inputs || m->input[input].kind != PURE_KIND_MESSAGE || (payload.size && !payload.data)) return PURE_INVALID; const PureInputShape *shape = &m->input[input]; - uint32_t spans[PURE_MODULE_FIELDS][2]; + uint32_t spans[PURE_MESSAGE_FIELDS][2]; PureFault wrong = place_fields(m, shape, payload, placed, spans); if (wrong != PURE_FAULT_NONE) return fault(app, wrong, UINT32_MAX); /* Its rows fill their lists (emptied when the event ends); rows that are not whole fail it. Rows whose records hold @@ -6193,10 +6193,26 @@ static bool same_fields(const PureModule *old, uint32_t from, const PureModule * * app->why says), and otherwise keeps its number for later. *changed: an * output of module is laid out otherwise than old's (or old has none of * that name), so the outbox's image, which names them, is written again. */ +/* A block of each input's numbers for inputs of them, zeroed, its arrays to be laid out in app (by_input_of); NULL without + * room (027's 4f-3a). */ +static uint64_t *by_input_block(uint32_t inputs) { return calloc(3 * (size_t)inputs + 1, sizeof(uint64_t)); } +static void by_input_of(PureApp *app, uint64_t *block, uint32_t inputs) { + free(app->by_input); + app->by_input = block; + app->last_sent = block, app->saved_sent = block + inputs, app->marked_sent = block + 2 * (size_t)inputs; +} + +/* An output's sends and numbers carried to module by name; applied (apply), its numbers in block (by_input_block's, + * for module's inputs, which it then holds). */ PURE_COLD static PureResult remap_outputs(PureApp *app, const PureModule *old, const PureModule *module, bool apply, - PureList **recast, bool *changed) { - int map[PURE_MODULE_INPUTS]; - bool differs[PURE_MODULE_INPUTS] = {false}, recasting = false; + PureList **recast, bool *changed, uint64_t *block) { + int *map = malloc((old->inputs + 1) * sizeof(*map)); + bool *differs = calloc(old->inputs + 1, sizeof(*differs)), recasting = false; + if (!map || !differs) { + free(map), free(differs); + if (apply) by_input_of(app, block, module->inputs); /* (the numbers start again) */ + return PURE_ALLOCATION; + } for (uint32_t i = 0; i < old->inputs; ++i) { map[i] = -1; if (old->input[i].kind != PURE_KIND_OUTPUT) continue; @@ -6222,11 +6238,15 @@ PURE_COLD static PureResult remap_outputs(PureApp *app, const PureModule *old, c if (i < 0 || map[i] < 0) { snprintf(app->why, sizeof(app->why), "sends wait on the output '%s', which this module does not have", name); + free(map), free(differs); return PURE_CONFLICT; } recasting = recasting || differs[i]; } - if (!recasting) return PURE_OK; + if (!recasting) { + free(map), free(differs); + return PURE_OK; + } PureList *made = pure_runtime_list_new(PURE_LIST_OUTBOX); PureResult result = made ? PURE_OK : PURE_ALLOCATION; for (size_t s = 0; result == PURE_OK && s < count; ++s) { @@ -6246,6 +6266,7 @@ PURE_COLD static PureResult remap_outputs(PureApp *app, const PureModule *old, c if (result == PURE_OK) result = pure_list_insert(made, s, item, NULL); free(bytes); } + free(map), free(differs); if (result != PURE_OK) { pure_list_free(made); return result; @@ -6253,7 +6274,9 @@ PURE_COLD static PureResult remap_outputs(PureApp *app, const PureModule *old, c *recast = made; return PURE_OK; } - uint64_t last[PURE_MODULE_INPUTS] = {0}, saved[PURE_MODULE_INPUTS] = {0}; + uint64_t *last = block, *saved = block + module->inputs; + unsigned outputs = 0; /* the store names them and those carried by a byte's count: 255 in all at most */ + for (uint32_t k = 0; k < module->inputs; ++k) outputs += module->input[k].kind == PURE_KIND_OUTPUT; for (uint32_t i = 0; i < old->inputs; ++i) { if (old->input[i].kind != PURE_KIND_OUTPUT || !app->last_sent[i]) continue; if (map[i] >= 0) { @@ -6261,8 +6284,9 @@ PURE_COLD static PureResult remap_outputs(PureApp *app, const PureModule *old, c saved[map[i]] = app->saved_sent[i]; continue; } - struct PureCarried *grown = realloc(app->carried, (app->carried_count + 1) * sizeof(*grown)); - if (!grown) continue; /* its numbers would start again: kept only while memory allows */ + struct PureCarried *grown = outputs + app->carried_count < UINT8_MAX ? + realloc(app->carried, (app->carried_count + 1) * sizeof(*grown)) : NULL; + if (!grown) continue; /* its numbers would start again: kept only while memory and the store's count allow */ app->carried = grown; memcpy(grown[app->carried_count].name, old->input_names[i], PURE_MODULE_NAME); grown[app->carried_count++].last = app->last_sent[i]; @@ -6275,8 +6299,8 @@ PURE_COLD static PureResult remap_outputs(PureApp *app, const PureModule *old, c app->carried[c] = app->carried[--app->carried_count]; app->links_changed = true; } - memcpy(app->last_sent, last, sizeof(last)); - memcpy(app->saved_sent, saved, sizeof(saved)); + free(map), free(differs); + by_input_of(app, block, module->inputs); return PURE_OK; } @@ -6305,10 +6329,12 @@ PURE_COLD static PureResult open_module(PureApp *app, const PureModule *module) PureSaved *listed = calloc(states + 1, sizeof(*listed)); bool *rewrite = calloc(states + 1, sizeof(*rewrite)); size_t **moved = calloc(states + 1, sizeof(*moved)); - if (!kept || !listed || !rewrite || !moved || !lay_app(&next, states)) { - free(kept), free(listed), free(rewrite), free(moved), free(next.states); + uint64_t *numbers = by_input_block(module->inputs); /* each input's numbers: the app's from now on */ + if (!kept || !listed || !rewrite || !moved || !numbers || !lay_app(&next, states)) { + free(kept), free(listed), free(rewrite), free(moved), free(numbers), free(next.states); return PURE_ALLOCATION; } + if (!old) by_input_of(app, numbers, module->inputs), numbers = NULL; /* (the stored numbers are read into them) */ PureValue *values = next.values; PureDraft **texts = next.texts, **list_drafts = next.list_drafts; PureList **lists = next.lists; @@ -6396,7 +6422,7 @@ PURE_COLD static PureResult open_module(PureApp *app, const PureModule *module) PureList *recast = NULL; /* the outbox, its sends laid out with module's fields */ bool outputs_changed = false; if (result == PURE_OK) - result = old ? remap_outputs(app, old, module, false, &recast, &outputs_changed) : + result = old ? remap_outputs(app, old, module, false, &recast, &outputs_changed, NULL) : stored ? pure_save_open_links(app, module, &heard_moved, &sent_moved) : PURE_OK; heard.rewrite = heard.rewrite || (heard_moved && lists_stored); sent.rewrite = sent.rewrite || (sent_moved && lists_stored); @@ -6445,7 +6471,7 @@ PURE_COLD static PureResult open_module(PureApp *app, const PureModule *module) pure_list_free(lists[i]); pure_draft_close(list_drafts[i]); } - free(kept), free(listed), free(rewrite), free(moved), free(next.states); + free(kept), free(listed), free(rewrite), free(moved), free(numbers), free(next.states); return result; } for (uint32_t i = 0; old && i < old->states; ++i) { @@ -6490,7 +6516,7 @@ PURE_COLD static PureResult open_module(PureApp *app, const PureModule *module) if (module->state_type[i] == PURE_STATE_LIST && module->state_flags[i] & PURE_LIST_ROWS >> 8) (void)pure_list_arrays(lists[i]); /* in arrays, not a tree, while it can (021) */ } - if (old) remap_outputs(app, old, module, true, NULL, NULL); + if (old) remap_outputs(app, old, module, true, NULL, NULL, numbers); if (recast) { /* in the place of the outbox, its sends now the new module's */ pure_list_free(app->outbox); app->outbox = recast; diff --git a/core/module.h b/core/module.h index 645fb71..8de3e33 100644 --- a/core/module.h +++ b/core/module.h @@ -14,10 +14,10 @@ * belongs to), stack heights and the stack at every join, forward-only * branches, names, records, tables, constants and effects. */ enum { - PURE_MODULE_INPUTS = 32, PURE_MODULE_VIEWS = 64, - PURE_MODULE_HANDLERS = 64, PURE_MODULE_CODE = 65535, PURE_MODULE_STACK = 64, + PURE_MODULE_CODE = 65535, PURE_MODULE_STACK = 64, PURE_MODULE_NAME = 32, PURE_MODULE_STRINGS = 32768, PURE_MODULE_HEADER = 38, - PURE_MODULE_FIELDS = 64, PURE_MODULE_CONSTANTS = 4096, + /* A message's fields at most: a send pushes them all (the stack's), a width of the stored sends too (027's 4f-3a). */ + PURE_MESSAGE_FIELDS = PURE_MODULE_STACK, PURE_MODULE_CONSTANTS = 4096, PURE_MODULE_CONSTANT_BYTES = 1 << 20, PURE_MODULE_RECORDS = 16, PURE_MODULE_RECORD_FIELDS = 128, PURE_RECORD_FIELDS = 16, PURE_MODULE_JOINS = 8 }; @@ -403,11 +403,11 @@ typedef struct { uint16_t *view_table; /* a column's list view + 1, or 0 */ uint16_t *view_list; /* the list state of a list view over one, or its column's */ uint16_t *view_record; /* a list view's or a list column's items' record + 1 (a map's: 0) */ - uint8_t *view_field; /* a column the load made: its item's field + 1 (read as it is), or 0 */ + uint16_t *view_field; /* a column the load made: its item's field + 1 (read as it is), or 0 */ bool *view_computed; /* a list view whose code leaves its list (a column's: its view's) */ PureBlock *view_code; uint8_t *view_plan; /* a table's filter runs a leaf of its list at once (as a fold may) */ - uint8_t *view_arguments; /* the input of a view's arguments + 1 (a column's: its table's), or 0 */ + uint32_t *view_arguments; /* the input of a view's arguments + 1 (a column's: its table's), or 0 */ /* Set at load: a view's code computes (its locals and loops: a body), and the event's lists it changes (a set of * states, state_words for each view). */ bool *view_body; @@ -469,7 +469,7 @@ uint32_t pure_module_shape(const PureModule *, uint32_t input); /* An input's (or output's) fields as a sender names them to a receiver: u8 * count, each field's {u8 type, u8 name length, name}. Its size (at most * PURE_FIELDS_NAMED), written to out. */ -enum { PURE_FIELDS_NAMED = 1 + PURE_MODULE_FIELDS * (2 + PURE_MODULE_NAME) }; +enum { PURE_FIELDS_NAMED = 1 + PURE_MESSAGE_FIELDS * (2 + PURE_MODULE_NAME) }; size_t pure_module_fields(const PureModule *, uint32_t input, unsigned char out[PURE_FIELDS_NAMED]); /* Whether input takes messages laid out with the fields named (as * pure_module_fields names them): it has every one by name, of the same type @@ -585,7 +585,7 @@ typedef struct { PureList *outbox; size_t sent_saved, durable_sent_saved, durable_outbox; uint64_t sends_gone; /* how many ever left it: a host's places in it move back at most that many */ - uint64_t last_sent[PURE_MODULE_INPUTS], saved_sent[PURE_MODULE_INPUTS]; + uint64_t *last_sent, *saved_sent; /* each input's (by_input), an output's numbers */ struct PureCarried { char name[PURE_MODULE_NAME]; uint64_t last; } *carried; unsigned carried_count; /* The last number delivered from each source: a list of {source (text), @@ -602,7 +602,7 @@ typedef struct { * none), where their fields are, and a count of the times they were given. */ unsigned argued; PureSpan arguments; - uint32_t argument_spans[PURE_MODULE_FIELDS][2]; + uint32_t argument_spans[PURE_MESSAGE_FIELDS][2]; uint64_t arguments_given; /* Passes over lists that answer shaped folds, by the list's version. */ struct PurePass *passes; @@ -622,8 +622,12 @@ typedef struct { struct { unsigned char **blocks; size_t *sizes; unsigned count, at; size_t used; } calls; struct PureSpare { PureList **lists; unsigned count, capacity; } *spare; PureValue *pending; /* the values an event works on until it ends */ - PureVersion *marked_texts; /* where the event running began: each text's version, each stored list's journal */ + PureVersion *marked_texts; /* where the event running began: each text's version, each stored list's journal, */ size_t *marked_lists; + /* Each input's: its last number sent and as saved, and where the event running began; one block (by_input) for + * the inputs of the module it was laid out for (027's 4f-3a). */ + uint64_t *marked_sent; + void *by_input; } PureApp; PureResult pure_app_start(PureApp *, const PureModule *, PureData data); diff --git a/core/test-module.c b/core/test-module.c index 14a2335..4eabdfc 100644 --- a/core/test-module.c +++ b/core/test-module.c @@ -570,6 +570,26 @@ static void rejections(void) { CHECK(pure_app_start(&wide, &module_a, (PureData){0}) == PURE_OK && press(&wide, 0) == PURE_OK && press(&wide, 0) == PURE_OK && wide.values[MANY - 1].num == 2 && wide.values[0].num == 0); pure_app_stop(&wide); + /* Nor of inputs, views or handlers (027's 4f-3a): 40 messages (the last counted), 70 views (the last its count). */ + enum { INPUTS = 40, VIEWS = 70 }; + static I messages[INPUTS]; + static V views[VIEWS]; + static char message_names[INPUTS][8], view_names[VIEWS][8]; + for (unsigned i = 0; i < INPUTS; ++i) { + snprintf(message_names[i], 8, "m%u", i); + messages[i] = (I){message_names[i], NULL, PURE_KIND_MESSAGE, NULL, 0}; + } + for (unsigned i = 0; i < VIEWS; ++i) snprintf(view_names[i], 8, "v%u", i), views[i] = (V){view_names[i], 4, 1}; + static const O counted[] = {{L, 0, 0}, {C, 0, 1}, {ADD, 0, 0}, {ST, 0, 0}, {L, 0, 0}}; + static const H last[] = {{1 + 2 * (INPUTS - 1), 0, 4}}; + CHECK(load((Spec){s1, 1, messages, INPUTS, views, VIEWS, last, 1, counted, 5, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, + NULL, 0}, &module_a) == PURE_OK && module_a.inputs == INPUTS && module_a.views == VIEWS); + CHECK(pure_app_start(&wide, &module_a, (PureData){0}) == PURE_OK); + CHECK(pure_app_message(&wide, INPUTS - 1, (PureSpan){0}) == PURE_OK && pure_app_message(&wide, 0, (PureSpan){0}) == PURE_OK && + pure_app_view(&wide, VIEWS - 1, &(double){0})); + double shown; + CHECK(pure_app_view(&wide, VIEWS - 1, &shown) && shown == 1); + pure_app_stop(&wide); static unsigned char bytes[65536]; size_t size = build(bytes, (Spec){s1, 1, i1, 0, clash, 0, none, 0, load_a, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0}); CHECK(pure_module_load(bytes, size - 1, &module_a, error, sizeof(error)) == PURE_INVALID); |
