/* PSPP - a program for statistical analysis.
- Copyright (C) 2007, 2009, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <string.h>
#include "data/case.h"
+#include "data/casereader.h"
#include "data/dictionary.h"
#include "data/value.h"
#include "data/variable.h"
struct init_list
{
struct init_value *values;
- size_t cnt;
+ size_t n;
};
/* A bitmap of the "left" status of variables. */
enum leave_class
{
- LEAVE_REINIT = 0x001, /* Reinitalize for every case. */
+ LEAVE_REINIT = 0x001, /* Reinitialize for every case. */
LEAVE_LEFT = 0x002 /* Keep the value from one case to the next. */
};
init_list_create (struct init_list *list)
{
list->values = NULL;
- list->cnt = 0;
+ list->n = 0;
+}
+
+/* Initializes NEW as a copy of OLD. */
+static struct init_list
+init_list_clone (const struct init_list *old)
+{
+ 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 = &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. */
{
struct init_value *iv;
- for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
+ for (iv = &list->values[0]; iv < &list->values[list->n]; iv++)
value_destroy (&iv->value, iv->width);
free (list->values);
}
{
struct init_value value;
value.case_index = case_index;
- return binary_search (list->values, list->cnt, sizeof *list->values,
+ return binary_search (list->values, list->n, sizeof *list->values,
&value, compare_init_values, NULL) != NULL;
}
init_list_mark (struct init_list *list, const struct init_list *exclude,
enum leave_class include, const struct dictionary *d)
{
- size_t var_cnt = dict_get_var_cnt (d);
- size_t i;
+ size_t n_vars = dict_get_n_vars (d);
assert (list != exclude);
- list->values = xnrealloc (list->values, list->cnt + dict_get_var_cnt (d),
+ list->values = xnrealloc (list->values, list->n + dict_get_n_vars (d),
sizeof *list->values);
- for (i = 0; i < var_cnt; i++)
+ for (size_t i = 0; i < n_vars; i++)
{
struct variable *v = dict_get_var (d, i);
- size_t case_index = var_get_case_index (v);
+ size_t case_index = var_get_dict_index (v);
struct init_value *iv;
/* Only include the correct class. */
if (exclude != NULL && init_list_includes (exclude, case_index))
continue;
- iv = &list->values[list->cnt++];
+ iv = &list->values[list->n++];
iv->case_index = case_index;
iv->width = var_get_width (v);
value_init (&iv->value, iv->width);
}
/* Drop duplicates. */
- list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
- compare_init_values, NULL);
+ list->n = sort_unique (list->values, list->n, sizeof *list->values,
+ compare_init_values, NULL);
}
/* Initializes data in case C to the values in the initializer
{
const struct init_value *iv;
- for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
+ for (iv = &list->values[0]; iv < &list->values[list->n]; iv++)
value_copy (case_data_rw_idx (c, iv->case_index), &iv->value, iv->width);
}
{
struct init_value *iv;
- for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
+ for (iv = &list->values[0]; iv < &list->values[list->n]; iv++)
value_copy (&iv->value, case_data_idx (c, iv->case_index), iv->width);
}
\f
return ci;
}
+/* Creates and returns a copy of OLD. */
+struct caseinit *
+caseinit_clone (struct caseinit *old)
+{
+ struct caseinit *new = xmalloc (sizeof *new);
+ *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;
+}
+
/* Clears the contents of case initializer CI. */
void
caseinit_clear (struct caseinit *ci)
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);
+}