From 6953fd7f0ef58595a14548c4262f0e4c65b8939a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 2 Mar 2023 14:25:30 -0800 Subject: [PATCH] caseinit: Introduce new caseinit_translate_casereader_to_init_vars(). --- src/data/case.c | 4 +- src/data/caseinit.c | 93 +++++++++++++++++++++++++++++++++------- src/data/caseinit.h | 9 +++- src/data/caseproto.c | 15 +++++-- src/data/caseproto.h | 7 +-- src/data/casereader.c | 4 +- src/data/casewriter.c | 4 +- src/data/dataset.c | 6 ++- src/language/commands/inpt-pgm.c | 3 +- 9 files changed, 113 insertions(+), 32 deletions(-) diff --git a/src/data/case.c b/src/data/case.c index 742d1f0f2..a70179f85 100644 --- a/src/data/case.c +++ b/src/data/case.c @@ -201,8 +201,8 @@ case_copy (struct ccase *dst, size_t dst_idx, assert (!case_is_shared (dst)); assert (caseproto_range_is_valid (dst->proto, dst_idx, n_values)); assert (caseproto_range_is_valid (src->proto, src_idx, n_values)); - assert (caseproto_equal (dst->proto, dst_idx, src->proto, src_idx, - n_values)); + assert (caseproto_range_equal (dst->proto, dst_idx, src->proto, src_idx, + n_values)); if (dst != src) { diff --git a/src/data/caseinit.c b/src/data/caseinit.c index 815041fd1..3efe128ef 100644 --- a/src/data/caseinit.c +++ b/src/data/caseinit.c @@ -23,6 +23,7 @@ #include #include "data/case.h" +#include "data/casereader.h" #include "data/dictionary.h" #include "data/value.h" #include "data/variable.h" @@ -66,19 +67,17 @@ init_list_create (struct init_list *list) } /* Initializes NEW as a copy of OLD. */ -static void -init_list_clone (struct init_list *new, const struct init_list *old) +static struct init_list +init_list_clone (const struct init_list *old) { - size_t i; - - new->values = xmemdup (old->values, old->n * sizeof *old->values); - new->n = old->n; - - for (i = 0; i < new->n; i++) + struct init_value *values = xmemdup (old->values, + old->n * sizeof *old->values); + for (size_t i = 0; i < old->n; i++) { - struct init_value *iv = &new->values[i]; + struct init_value *iv = &values[i]; value_clone (&iv->value, &iv->value, iv->width); } + return (struct init_list) { .values = values, .n = old->n }; } /* Frees the storage associated with LIST. */ @@ -218,9 +217,11 @@ struct caseinit * caseinit_clone (struct caseinit *old) { struct caseinit *new = xmalloc (sizeof *new); - init_list_clone (&new->preinited_values, &old->preinited_values); - init_list_clone (&new->reinit_values, &old->reinit_values); - init_list_clone (&new->left_values, &old->left_values); + *new = (struct caseinit) { + .preinited_values = init_list_clone (&old->preinited_values), + .reinit_values = init_list_clone (&old->reinit_values), + .left_values = init_list_clone (&old->left_values), + }; return new; } @@ -272,15 +273,75 @@ void caseinit_init_vars (const struct caseinit *ci, struct ccase *c) { init_list_init (&ci->reinit_values, c); +} + +/* Copies the left vars from CI into C. */ +void +caseinit_restore_left_vars (struct caseinit *ci, struct ccase *c) +{ init_list_init (&ci->left_values, c); } -/* Updates the left vars in CI from the data in C, so that the - next call to caseinit_init_vars will store those values in the - next case. */ +/* Copies the left vars from C into CI. */ void -caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c) +caseinit_save_left_vars (struct caseinit *ci, const struct ccase *c) { init_list_update (&ci->left_values, c); } + +struct caseinit_translator + { + struct init_list reinit_values; + struct caseproto *proto; + }; + +static struct ccase * +translate_caseinit (struct ccase *c, void *cit_) +{ + const struct caseinit_translator *cit = cit_; + + c = case_unshare_and_resize (c, cit->proto); + init_list_init (&cit->reinit_values, c); + return c; +} + +static bool +translate_destroy (void *cit_) +{ + struct caseinit_translator *cit = cit_; + + init_list_destroy (&cit->reinit_values); + caseproto_unref (cit->proto); + free (cit); + + return true; +} + +/* Returns a new casereader that yields each case from R, resized to match + OUTPUT_PROTO and initialized from CI as if with caseinit_init_vars(). Takes + ownership of R. + + OUTPUT_PROTO must be conformable with R's prototype. */ +struct casereader * +caseinit_translate_casereader_to_init_vars (struct caseinit *ci, + const struct caseproto *output_proto, + struct casereader *r) +{ + assert (caseproto_is_conformable (casereader_get_proto (r), output_proto)); + if (caseproto_equal (output_proto, casereader_get_proto (r)) + && ci->reinit_values.n == 0) + return casereader_rename (r); + + struct caseinit_translator *cit = xmalloc (sizeof *cit); + *cit = (struct caseinit_translator) { + .reinit_values = init_list_clone (&ci->reinit_values), + .proto = caseproto_ref (output_proto), + }; + + static const struct casereader_translator_class class = { + .translate = translate_caseinit, + .destroy = translate_destroy, + }; + return casereader_translate_stateless (r, output_proto, &class, cit); +} diff --git a/src/data/caseinit.h b/src/data/caseinit.h index 9f5662184..ff79a947f 100644 --- a/src/data/caseinit.h +++ b/src/data/caseinit.h @@ -31,6 +31,7 @@ #ifndef DATA_CASEINIT_H #define DATA_CASEINIT_H 1 +struct caseproto; struct dictionary; struct ccase; @@ -46,6 +47,12 @@ void caseinit_mark_for_init (struct caseinit *, const struct dictionary *); /* Initialize data and copy data from case to case. */ void caseinit_init_vars (const struct caseinit *, struct ccase *); -void caseinit_update_left_vars (struct caseinit *, const struct ccase *); +void caseinit_save_left_vars (struct caseinit *, const struct ccase *); +void caseinit_restore_left_vars (struct caseinit *, struct ccase *); + +/* Translate. */ +struct casereader *caseinit_translate_casereader_to_init_vars ( + struct caseinit *, const struct caseproto *output_proto, + struct casereader *); #endif /* data/caseinit.h */ diff --git a/src/data/caseproto.c b/src/data/caseproto.c index f390c3f87..c47b6ae98 100644 --- a/src/data/caseproto.c +++ b/src/data/caseproto.c @@ -207,9 +207,9 @@ caseproto_is_conformable (const struct caseproto *a, const struct caseproto *b) same as the N widths starting at B_START in B, false if any of the corresponding widths differ. */ bool -caseproto_equal (const struct caseproto *a, size_t a_start, - const struct caseproto *b, size_t b_start, - size_t n) +caseproto_range_equal (const struct caseproto *a, size_t a_start, + const struct caseproto *b, size_t b_start, + size_t n) { size_t i; @@ -221,6 +221,15 @@ caseproto_equal (const struct caseproto *a, size_t a_start, return true; } +/* Returns true if A and B have the same widths, false otherwise. */ +bool +caseproto_equal (const struct caseproto *a, const struct caseproto *b) +{ + return (a == b ? true + : a->n_widths != b->n_widths ? false + : caseproto_range_equal (a, 0, b, 0, a->n_widths)); +} + /* Returns true if an array of values that is to be used for data of the format specified in PROTO needs to be initialized by calling caseproto_init_values, false if that step may be diff --git a/src/data/caseproto.h b/src/data/caseproto.h index e6921888f..37c4e19f1 100644 --- a/src/data/caseproto.h +++ b/src/data/caseproto.h @@ -130,9 +130,10 @@ bool caseproto_range_is_valid (const struct caseproto *, size_t ofs, size_t count); bool caseproto_is_conformable (const struct caseproto *a, const struct caseproto *b); -bool caseproto_equal (const struct caseproto *a, size_t a_start, - const struct caseproto *b, size_t b_start, - size_t n); +bool caseproto_range_equal (const struct caseproto *a, size_t a_start, + const struct caseproto *b, size_t b_start, + size_t n); +bool caseproto_equal (const struct caseproto *, const struct caseproto *); /* Creation and destruction. */ diff --git a/src/data/casereader.c b/src/data/casereader.c index a410afcbc..9a488385a 100644 --- a/src/data/casereader.c +++ b/src/data/casereader.c @@ -73,8 +73,8 @@ casereader_read (struct casereader *reader) { size_t n_widths UNUSED = caseproto_get_n_widths (reader->proto); assert (case_get_n_values (c) >= n_widths); - expensive_assert (caseproto_equal (case_get_proto (c), 0, - reader->proto, 0, n_widths)); + expensive_assert (caseproto_range_equal (case_get_proto (c), 0, + reader->proto, 0, n_widths)); return c; } } diff --git a/src/data/casewriter.c b/src/data/casewriter.c index 768a515e1..51d5e10bf 100644 --- a/src/data/casewriter.c +++ b/src/data/casewriter.c @@ -52,8 +52,8 @@ casewriter_write (struct casewriter *writer, struct ccase *c) { size_t n_widths UNUSED = caseproto_get_n_widths (writer->proto); assert (case_get_n_values (c) >= n_widths); - expensive_assert (caseproto_equal (case_get_proto (c), 0, - writer->proto, 0, n_widths)); + expensive_assert (caseproto_range_equal (case_get_proto (c), 0, + writer->proto, 0, n_widths)); writer->class->write (writer, writer->aux, c); } diff --git a/src/data/dataset.c b/src/data/dataset.c index a816570c0..6ade4b24c 100644 --- a/src/data/dataset.c +++ b/src/data/dataset.c @@ -448,6 +448,8 @@ proc_open_filtering (struct dataset *ds, bool filter) update_last_proc_invocation (ds); caseinit_mark_for_init (ds->caseinit, ds->dict); + ds->source = caseinit_translate_casereader_to_init_vars ( + ds->caseinit, dict_get_proto (ds->dict), ds->source); /* Finish up the collection of transformations. */ add_case_limit_trns (ds); @@ -549,12 +551,12 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_) if (c == NULL) return NULL; c = case_unshare_and_resize (c, dict_get_proto (ds->dict)); - caseinit_init_vars (ds->caseinit, c); + caseinit_restore_left_vars (ds->caseinit, c); /* Execute permanent transformations. */ casenumber case_nr = ds->cases_written + 1; retval = trns_chain_execute (&ds->permanent_trns_chain, case_nr, &c); - caseinit_update_left_vars (ds->caseinit, c); + caseinit_save_left_vars (ds->caseinit, c); if (retval != TRNS_CONTINUE) continue; diff --git a/src/language/commands/inpt-pgm.c b/src/language/commands/inpt-pgm.c index a0e3bab63..b5bd041d7 100644 --- a/src/language/commands/inpt-pgm.c +++ b/src/language/commands/inpt-pgm.c @@ -184,6 +184,7 @@ input_program_casereader_read (struct casereader *reader UNUSED, void *inp_) struct ccase *c = case_create (inp->proto); caseinit_init_vars (inp->init, c); + caseinit_restore_left_vars (inp->init, c); for (size_t i = inp->idx < inp->xforms.n ? inp->idx : 0; ; i++) { @@ -191,7 +192,7 @@ input_program_casereader_read (struct casereader *reader UNUSED, void *inp_) { i = 0; c = case_unshare (c); - caseinit_update_left_vars (inp->init, c); + caseinit_save_left_vars (inp->init, c); caseinit_init_vars (inp->init, c); } -- 2.11.4.GIT