X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=inline;f=src%2Fdata%2Fsubcase.c;h=f87093cd18413cbf97351ffdac019e807db33191;hb=bfd019e1c9272143a637747cf8dbd66774696483;hp=3e019c7c8497bf3340bf1dc2cce256fe6d85aad4;hpb=ed09f0f21add5e56e8395a5e8589cda6f96420bf;p=pspp
diff --git a/src/data/subcase.c b/src/data/subcase.c
index 3e019c7c84..f87093cd18 100644
--- a/src/data/subcase.c
+++ b/src/data/subcase.c
@@ -1,5 +1,5 @@
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 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
@@ -15,13 +15,18 @@
along with this program. If not, see . */
#include
-#include
+
+#include "data/subcase.h"
+
#include
-#include
-#include
-#include
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+
+#include "gl/xalloc.h"
+
+static void invalidate_proto (struct subcase *sc);
/* Initializes SC as a subcase that contains no fields. */
void
@@ -29,7 +34,7 @@ subcase_init_empty (struct subcase *sc)
{
sc->fields = NULL;
sc->n_fields = 0;
- sc->n_values = 0;
+ sc->proto = NULL;
}
/* Initializes SC as a subcase with fields extracted from the
@@ -42,14 +47,13 @@ subcase_init_vars (struct subcase *sc,
sc->fields = xnmalloc (n_vars, sizeof *sc->fields);
sc->n_fields = n_vars;
- sc->n_values = 0;
+ sc->proto = NULL;
for (i = 0; i < n_vars; i++)
{
struct subcase_field *field = &sc->fields[i];
field->case_index = var_get_case_index (vars[i]);
field->width = var_get_width (vars[i]);
field->direction = SC_ASCEND;
- sc->n_values += value_cnt_from_width (field->width);
}
}
@@ -63,12 +67,22 @@ subcase_init_var (struct subcase *sc, const struct variable *var,
subcase_add_var (sc, var, direction);
}
+
+void
+subcase_init (struct subcase *sc, int index, int width,
+ enum subcase_direction direction)
+{
+ subcase_init_empty (sc);
+ subcase_add (sc, index, width, direction);
+}
+
+
/* Removes all the fields from SC. */
void
subcase_clear (struct subcase *sc)
{
sc->n_fields = 0;
- sc->n_values = 0;
+ invalidate_proto (sc);
}
/* Initializes SC with the same fields as ORIG. */
@@ -77,7 +91,7 @@ subcase_clone (struct subcase *sc, const struct subcase *orig)
{
sc->fields = xmemdup (orig->fields, orig->n_fields * sizeof *orig->fields);
sc->n_fields = orig->n_fields;
- sc->n_values = orig->n_values;
+ sc->proto = orig->proto ? caseproto_ref (orig->proto) : NULL;
}
/* Frees the memory owned by SC (but not SC itself). */
@@ -85,6 +99,29 @@ void
subcase_destroy (struct subcase *sc)
{
free (sc->fields);
+ caseproto_unref (sc->proto);
+}
+
+/* Returns true if VAR already has a field in SC,
+ false otherwise. */
+bool
+subcase_contains_var (const struct subcase *sc, const struct variable *var)
+{
+ return subcase_contains (sc, var_get_case_index (var));
+}
+
+/* Returns true if CASE_INDEX already has a field in SC,
+ false otherwise. */
+bool
+subcase_contains (const struct subcase *sc, int case_index)
+{
+ size_t i;
+
+ for (i = 0; i < sc->n_fields; i++)
+ if (sc->fields[i].case_index == case_index)
+ return true;
+
+ return false;
}
/* Add a field for VAR to SC, with DIRECTION as the sort order.
@@ -94,21 +131,95 @@ bool
subcase_add_var (struct subcase *sc, const struct variable *var,
enum subcase_direction direction)
{
- size_t case_index = var_get_case_index (var);
- struct subcase_field *field;
- size_t i;
+ if (!subcase_contains_var (sc, var))
+ {
+ subcase_add_var_always (sc, var, direction);
+ return true;
+ }
+ else
+ return false;
+}
- for (i = 0; i < sc->n_fields; i++)
- if (sc->fields[i].case_index == case_index)
- return false;
+/* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the sort order.
+ Returns true if successful, false if CASE_INDEX already has a field
+ in SC. */
+bool
+subcase_add (struct subcase *sc, int case_index, int width,
+ enum subcase_direction direction)
+{
+ if (!subcase_contains (sc, case_index))
+ {
+ subcase_add_always (sc, case_index, width, direction);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Add a field for VAR to SC, with DIRECTION as the sort order,
+ regardless of whether VAR already has a field in SC. */
+void
+subcase_add_var_always (struct subcase *sc, const struct variable *var,
+ enum subcase_direction direction)
+{
+ return subcase_add_always (sc, var_get_case_index (var),
+ var_get_width (var), direction);
+}
+
+/* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the
+ sort order, regardless of whether CASE_INDEX already has a
+ field in SC. */
+void
+subcase_add_always (struct subcase *sc, int case_index, int width,
+ enum subcase_direction direction)
+{
+ struct subcase_field *field;
sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
field = &sc->fields[sc->n_fields++];
field->case_index = case_index;
- field->width = var_get_width (var);
+ field->width = width;
field->direction = direction;
- sc->n_values += value_cnt_from_width (field->width);
- return true;
+ invalidate_proto (sc);
+}
+
+/* Adds a field to SC for each column in PROTO, so that SC
+ contains all of the columns in PROTO in the same order as a
+ case conforming to PROTO. The fields are added with
+ ascending direction. */
+void
+subcase_add_proto_always (struct subcase *sc, const struct caseproto *proto)
+{
+ size_t n = caseproto_get_n_widths (proto);
+ size_t i;
+
+ sc->fields = xnrealloc (sc->fields, sc->n_fields + n, sizeof *sc->fields);
+ for (i = 0; i < n; i++)
+ {
+ struct subcase_field *field = &sc->fields[sc->n_fields++];
+ field->case_index = i;
+ field->width = caseproto_get_width (proto, i);
+ field->direction = SC_ASCEND;
+ }
+ invalidate_proto (sc);
+}
+
+/* Obtains a caseproto for a case described by SC. The caller
+ must not modify or unref the returned case prototype. */
+const struct caseproto *
+subcase_get_proto (const struct subcase *sc_)
+{
+ struct subcase *sc = CONST_CAST (struct subcase *, sc_);
+
+ if (sc->proto == NULL)
+ {
+ size_t i;
+
+ sc->proto = caseproto_create ();
+ for (i = 0; i < sc->n_fields; i++)
+ sc->proto = caseproto_add_width (sc->proto, sc->fields[i].width);
+ }
+ return sc->proto;
}
/* Returns true if and only if A and B are conformable, which
@@ -121,7 +232,7 @@ subcase_conformable (const struct subcase *a, const struct subcase *b)
if (a == b)
return true;
- if (a->n_values != b->n_values || a->n_fields != b->n_fields)
+ if (a->n_fields != b->n_fields)
return false;
for (i = 0; i < a->n_fields; i++)
if (a->fields[i].width != b->fields[i].width)
@@ -130,7 +241,7 @@ subcase_conformable (const struct subcase *a, const struct subcase *b)
}
/* Copies the fields represented by SC from C into VALUES.
- VALUES must have space for at least subcase_get_n_values(SC)
+ VALUES must have space for at least subcase_get_n_fields(SC)
array elements. */
void
subcase_extract (const struct subcase *sc, const struct ccase *c,
@@ -141,13 +252,13 @@ subcase_extract (const struct subcase *sc, const struct ccase *c,
for (i = 0; i < sc->n_fields; i++)
{
const struct subcase_field *field = &sc->fields[i];
- value_copy (values, case_data_idx (c, field->case_index), field->width);
- values += value_cnt_from_width (field->width);
+ union value *value = &values[i];
+ value_copy (value, case_data_idx (c, field->case_index), field->width);
}
}
/* Copies the data in VALUES into the fields in C represented by
- SC. VALUES must have at least subcase_get_n_values(SC) array
+ SC. VALUES must have at least subcase_get_n_fields(SC) array
elements, and C must be large enough to contain all the fields
in SC. */
void
@@ -159,16 +270,18 @@ subcase_inject (const struct subcase *sc,
for (i = 0; i < sc->n_fields; i++)
{
const struct subcase_field *field = &sc->fields[i];
- value_copy (case_data_rw_idx (c, field->case_index), values,
+ const union value *value = &values[i];
+ value_copy (case_data_rw_idx (c, field->case_index), value,
field->width);
- values += value_cnt_from_width (field->width);
}
}
/* Copies the fields in SRC represented by SRC_SC into the
corresponding fields in DST respresented by DST_SC. SRC_SC
and DST_SC must be conformable (as tested by
- subcase_conformable()). */
+ subcase_conformable()).
+
+ DST must not be shared. */
void
subcase_copy (const struct subcase *src_sc, const struct ccase *src,
const struct subcase *dst_sc, struct ccase *dst)
@@ -226,11 +339,11 @@ subcase_compare_3way_xc (const struct subcase *sc,
for (i = 0; i < sc->n_fields; i++)
{
const struct subcase_field *field = &sc->fields[i];
- int cmp = value_compare_3way (a, case_data_idx (b, field->case_index),
+ int cmp = value_compare_3way (&a[i],
+ case_data_idx (b, field->case_index),
field->width);
if (cmp != 0)
return field->direction == SC_ASCEND ? cmp : -cmp;
- a += value_cnt_from_width (field->width);
}
return 0;
}
@@ -259,16 +372,9 @@ subcase_compare_3way_xx (const struct subcase *sc,
for (i = 0; i < sc->n_fields; i++)
{
const struct subcase_field *field = &sc->fields[i];
- size_t n_values;
- int cmp;
-
- cmp = value_compare_3way (a, b, field->width);
+ int cmp = value_compare_3way (a++, b++, field->width);
if (cmp != 0)
return field->direction == SC_ASCEND ? cmp : -cmp;
-
- n_values = value_cnt_from_width (field->width);
- a += n_values;
- b += n_values;
}
return 0;
}
@@ -316,3 +422,11 @@ subcase_equal_xx (const struct subcase *sc,
return subcase_compare_3way_xx (sc, a, b) == 0;
}
+/* Discards SC's case prototype. (It will be recreated if needed
+ again later.) */
+static void
+invalidate_proto (struct subcase *sc)
+{
+ caseproto_unref (sc->proto);
+ sc->proto = NULL;
+}