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)
{
#include <string.h>
#include "data/case.h"
+#include "data/casereader.h"
#include "data/dictionary.h"
#include "data/value.h"
#include "data/variable.h"
}
/* 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. */
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;
}
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);
}
+\f
+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);
+}
#ifndef DATA_CASEINIT_H
#define DATA_CASEINIT_H 1
+struct caseproto;
struct dictionary;
struct ccase;
/* 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 */
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;
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
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 *);
\f
/* Creation and destruction. */
{
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;
}
}
{
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);
}
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);
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;
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++)
{
{
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);
}