1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <data/case-matcher.h>
23 #include <data/case.h>
24 #include <data/subcase.h>
25 #include <data/value.h>
26 #include <libpspp/assertion.h>
30 struct case_matcher_input
32 struct subcase by_vars;
39 struct case_matcher_input *inputs;
40 size_t n_inputs, allocated_inputs;
41 union value *by_values;
44 /* Creates and returns a new case matcher. */
46 case_matcher_create (void)
48 struct case_matcher *cm = xmalloc (sizeof *cm);
51 cm->allocated_inputs = 0;
56 /* Adds a new input file to case matcher CM.
57 case_matcher_match() will compare the variables specified in
58 BY in case *DATA and set *IS_MINIMAL appropriately.
59 (The caller may change the case that *DATA points to from one
62 All of the BY subcases provided to this function for a given
63 CM must be conformable (see subcase_conformable()). */
65 case_matcher_add_input (struct case_matcher *cm, const struct subcase *by,
66 struct ccase **data, bool *is_minimal)
68 struct case_matcher_input *input;
70 if (cm->n_inputs == 0)
72 cm->by_values = xmalloc (sizeof *cm->by_values
73 * subcase_get_n_fields (by));
74 caseproto_init_values (subcase_get_proto (by), cm->by_values);
77 assert (subcase_conformable (by, &cm->inputs[0].by_vars));
79 if (cm->n_inputs >= cm->allocated_inputs)
80 cm->inputs = x2nrealloc (cm->inputs, &cm->allocated_inputs,
82 input = &cm->inputs[cm->n_inputs++];
83 subcase_clone (&input->by_vars, by);
85 input->is_minimal = is_minimal;
88 /* Destroys case matcher CM. */
90 case_matcher_destroy (struct case_matcher *cm)
96 if (cm->by_values != NULL)
98 caseproto_destroy_values (subcase_get_proto (&cm->inputs[0].by_vars),
100 free (cm->by_values);
102 for (i = 0; i < cm->n_inputs; i++)
104 struct case_matcher_input *input = &cm->inputs[i];
105 subcase_destroy (&input->by_vars);
113 compare_BY_3way (struct case_matcher_input *a, struct case_matcher_input *b)
115 return subcase_compare_3way (&a->by_vars, *a->data, &b->by_vars, *b->data);
118 /* Compares the values of the BY variables in all of the nonnull
119 cases provided to case_matcher_add_input() for CM, sets
120 *IS_MINIMAL for each one to true if it has the minimum BY
121 values among those cases or to false if its BY values are
122 greater than the minimum. Also sets *IS_MINIMAL to false for
123 null cases. Sets *BY to the BY values extracted from the
124 minimum case. (The caller must not free *BY.)
126 Returns true if at least one of the cases is nonnull, false
127 if they are all null.*/
129 case_matcher_match (struct case_matcher *cm, union value **by)
131 struct case_matcher_input *file, *min;
134 for (file = cm->inputs; file < &cm->inputs[cm->n_inputs]; file++)
135 if (*file->data != NULL)
137 int cmp = min != NULL ? compare_BY_3way (min, file) : 1;
139 *file->is_minimal = false;
142 *file->is_minimal = true;
148 *file->is_minimal = false;
152 for (file = cm->inputs; file < min; file++)
153 *file->is_minimal = false;
154 subcase_extract (&min->by_vars, *min->data, cm->by_values);