aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-19 07:59:15 +0100
committereunhhu <[email protected]>2026-10-19 07:59:15 +0100
commit1c1133ce8258dad367aad3b7c8eee0083aecf772 (patch)
treec939ae2e9ba6a2a220f1633fef107f9514ebb55b
parentf1bb9de4ac72136a1b0722ce77ac4ea6fd4fa413 (diff)
downloadpure-1c1133ce8258dad367aad3b7c8eee0083aecf772.tar.gz
pure-1c1133ce8258dad367aad3b7c8eee0083aecf772.zip
A list value of numbers copied whole (140's LIST_VALUE review, no new opcode, no change to what a module means): nest() made every list value item by item into a new tree (64 ns an item, 250 ns a copy fixed); an event's list in FLAT arrays, not keyed, its cells numbers, bools and integers, is now copied column by column (pure_list_copied: 600 items 38,268 to 985 ns, 60 items 3,926 to 324); UAX #14's nine lists a line 6,917 to 6,445 ns a code point (-6.8%, the same instructions); JSON tree's, HTTP's and inflate's (trees: texts or lists in their records, or few) as they were; copied_lists in test-module (random lists against item by item, then each changed apart; trees, keys and texts not copied so)
-rw-r--r--core/module-list.c24
-rw-r--r--core/module-list.h4
-rw-r--r--core/module.c7
-rw-r--r--core/test-module.c73
4 files changed, 105 insertions, 3 deletions
diff --git a/core/module-list.c b/core/module-list.c
index 2f2c359..91dd378 100644
--- a/core/module-list.c
+++ b/core/module-list.c
@@ -1800,6 +1800,30 @@ bool pure_list_arrays(PureList *list) {
unsigned pure_list_form(const PureList *list) { return list->form; }
+PureList *pure_list_copied(const PureList *from) {
+ const Layout *l = &from->layout;
+ if (from->form != FLAT || !from->arrays || from->pack || from->copy || l->key >= 0) return NULL;
+ for (unsigned f = 0; f < l->fields; ++f)
+ if (pure_cell_text(l->kinds[f]) || l->kinds[f] == PURE_CELL_LIST) return NULL;
+ PureList *list = pure_list_new(l->fields, l->kinds);
+ if (!list || !pure_list_arrays(list)) {
+ pure_list_free(list);
+ return NULL;
+ }
+ for (unsigned f = 0; f < l->fields; ++f) { /* its widths as they are: narrowed or widened by what it holds */
+ list->width[f] = from->width[f];
+ if (!from->count || !from->width[f]) continue;
+ if (!(list->columns[f] = malloc(from->count * from->width[f]))) {
+ pure_list_free(list);
+ return NULL;
+ }
+ memcpy(list->columns[f], from->columns[f], from->count * from->width[f]);
+ }
+ list->count = list->room = from->count;
+ list->bytes = from->bytes;
+ return list;
+}
+
bool pure_list_cells(PureList *list, PureCells *out) {
if (list->form != FLAT && !(list->form == DENSE && pure_list_full(list))) return false;
const Layout *l = &list->layout;
diff --git a/core/module-list.h b/core/module-list.h
index 13c2550..98fd5d7 100644
--- a/core/module-list.h
+++ b/core/module-list.h
@@ -214,6 +214,10 @@ bool pure_list_takes(const PureList *, int key, size_t n, const double *keys, si
size_t pure_list_add_many(PureList *, size_t n, const double *const *fields);
/* What it keeps its items in now: 0 a tree, 1 FLAT arrays, 2 DENSE (for tests and counts). */
unsigned pure_list_form(const PureList *);
+/* A new event's list with the items of one in FLAT arrays, not keyed, its cells numbers, bools and integers: its
+ * columns copied whole (what inserting its items one by one into a new list gives, in its form). NULL for any other
+ * list (copy it item by item) or without memory. */
+PureList *pure_list_copied(const PureList *);
/* Field of the item whose key_field is key, in a list ordered by key_field
* (seek, then get, as one: a DENSE list reads it at its key); false when no
* item has key. */
diff --git a/core/module.c b/core/module.c
index 3a6c4b5..f970daf 100644
--- a/core/module.c
+++ b/core/module.c
@@ -2668,10 +2668,11 @@ static uint64_t nest(PureApp *app, uint32_t record, const PureList *from) {
app->nested.shared = shared;
app->nested.capacity = capacity;
}
- PureList *list = new_list(m, record, false);
- if (!list) return 0;
+ PureList *list = from && !m->record_nested[record] ? pure_list_copied(from) : NULL; /* numbers in arrays: at once */
+ size_t at = list ? pure_list_count(from) : 0;
+ if (!list && !(list = new_list(m, record, false))) return 0;
const PureRecord *r = &m->record[record];
- for (size_t at = 0, count = from ? pure_list_count(from) : 0; at < count; ++at) {
+ for (size_t count = from ? pure_list_count(from) : 0; at < count; ++at) {
PureCell cells[PURE_RECORD_FIELDS];
for (unsigned f = 0; f < r->count; ++f) cells[f] = pure_list_get(from, at, f);
if (pure_list_insert(list, at, cells, NULL) != PURE_OK) { pure_list_free(list); return 0; }
diff --git a/core/test-module.c b/core/test-module.c
index 9762c48..d43d766 100644
--- a/core/test-module.c
+++ b/core/test-module.c
@@ -1583,6 +1583,78 @@ static void text_keys_equivalence(void) {
CHECK(hashed > 8000);
}
+/* Two lists of fields cells each (no text): the same items, every cell (its bits). */
+static void same_cells(const PureList *a, const PureList *b, unsigned fields) {
+ CHECK(pure_list_count(a) == pure_list_count(b) && pure_list_size(a) == pure_list_size(b));
+ for (size_t i = 0; i < pure_list_count(a); ++i)
+ for (unsigned f = 0; f < fields; ++f) CHECK(pure_list_get(a, i, f).i64 == pure_list_get(b, i, f).i64);
+}
+
+/* An event's list in FLAT arrays copied whole (pure_list_copied, after 140's LIST_VALUE review): random lists of
+ * numbers (narrow and wide), bools and integers, the copy the same as one made item by item, and each changed apart
+ * after (the copy grows and widens as a list does; neither sees the other's changes). A list in a tree, keyed, or
+ * with texts is not copied so. */
+static void copied_lists(void) {
+ static const uint8_t fields[4] = {PURE_CELL_NUMBER, PURE_CELL_BOOL, PURE_CELL_INTEGER, PURE_CELL_NUMBER};
+ uint32_t seed = 0x636f7079u;
+ unsigned copies = 0;
+ for (unsigned round = 0; round < 300; ++round) {
+ PureList *a = pure_list_new(4, fields);
+ CHECK(a && pure_list_arrays(a));
+ unsigned changes = next_random(&seed) % (round % 10 == 0 ? 3000 : 60);
+ for (unsigned c = 0; c < changes; ++c) {
+ uint32_t r = next_random(&seed);
+ size_t n = pure_list_count(a);
+ PureCell cells[4] = {{.num = some_number(round, r)}, {.num = r % 2}, {.i64 = (int64_t)r * (r % 3 ? 1 : -977)},
+ {.num = some_number(round + 1, r >> 5)}};
+ if (r % 7 == 0 && n) CHECK(pure_list_remove(a, r % n, NULL) == PURE_OK);
+ else if (r % 11 == 0 && n) CHECK(pure_list_set(a, r % n, 3, (PureCell){.num = 1e300 / (1 + r % 9)}, NULL) == PURE_OK);
+ else CHECK(pure_list_insert(a, r % 5 ? n : r % (n + 1), cells, NULL) == PURE_OK);
+ }
+ if (pure_list_form(a) != 1) { /* a tree since (moved too much): not copied so */
+ CHECK(!pure_list_copied(a));
+ pure_list_free(a);
+ continue;
+ }
+ PureList *copy = pure_list_copied(a), *each = pure_list_new(4, fields);
+ CHECK(copy && each && pure_list_arrays(each) && pure_list_form(copy) == 1);
+ for (size_t i = 0; i < pure_list_count(a); ++i) {
+ PureCell cells[4];
+ for (unsigned f = 0; f < 4; ++f) cells[f] = pure_list_get(a, i, f);
+ CHECK(pure_list_insert(each, i, cells, NULL) == PURE_OK);
+ }
+ same_cells(copy, each, 4);
+ same_cells(copy, a, 4);
+ for (unsigned c = 0; c < 40; ++c) { /* apart: the copy and the one made item by item alike, the list otherwise */
+ uint32_t r = next_random(&seed);
+ PureCell cells[4] = {{.num = 1.5 * r}, {.num = 1}, {.i64 = -(int64_t)r}, {.num = -0.0}};
+ size_t n = pure_list_count(copy);
+ if (r % 3 == 0 && n) {
+ CHECK(pure_list_set(copy, r % n, 0, cells[0], NULL) == PURE_OK);
+ CHECK(pure_list_set(each, r % n, 0, cells[0], NULL) == PURE_OK);
+ } else {
+ CHECK(pure_list_insert(copy, n, cells, NULL) == PURE_OK && pure_list_insert(each, n, cells, NULL) == PURE_OK);
+ }
+ if (pure_list_count(a)) CHECK(pure_list_remove(a, 0, NULL) == PURE_OK);
+ }
+ same_cells(copy, each, 4);
+ pure_list_free(a);
+ pure_list_free(each);
+ pure_list_free(copy);
+ ++copies;
+ }
+ CHECK(copies > 200);
+ static const uint8_t texts[2] = {PURE_CELL_NUMBER, PURE_CELL_TEXT};
+ PureList *t = pure_list_new(2, texts), *k = pure_list_new(4, fields), *tree = pure_list_new(4, fields);
+ CHECK(t && k && tree && pure_list_arrays(t) && pure_list_keyed(k, 0) == PURE_OK && pure_list_arrays(k));
+ CHECK(pure_list_insert(t, 0, (PureCell[]){{.num = 1}, {.text = (unsigned char *)"x", .size = 1}}, NULL) == PURE_OK);
+ CHECK(pure_list_insert(tree, 0, (PureCell[]){{.num = 1}, {.num = 0}, {.i64 = 2}, {.num = 3}}, NULL) == PURE_OK);
+ CHECK(!pure_list_copied(t) && !pure_list_copied(k) && !pure_list_copied(tree)); /* texts, a key, a tree */
+ pure_list_free(t);
+ pure_list_free(k);
+ pure_list_free(tree);
+}
+
static void arrays_equivalence(void) {
static const uint8_t fields[3] = {PURE_CELL_NUMBER, PURE_CELL_TEXT, PURE_CELL_NUMBER};
uint32_t seed = 0x61727261u;
@@ -7475,6 +7547,7 @@ int main(void) {
keyed_journal();
text_keys_equivalence();
arrays_equivalence();
+ copied_lists();
packed_lists();
folds();
filters();