Ignore all files under src/ui/gui/icons except a few actual source files.
[pspp.git] / src / data / case-matcher.c
blob46272bbed693011e14c4d324092932c40e053229
1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009, 2011 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/>. */
17 #include <config.h>
19 #include "data/case-matcher.h"
21 #include <stdlib.h>
23 #include "data/case.h"
24 #include "data/subcase.h"
25 #include "data/value.h"
26 #include "libpspp/assertion.h"
28 #include "gl/xalloc.h"
30 struct case_matcher_input
32 struct subcase by_vars;
33 struct ccase **data;
34 bool *is_minimal;
37 struct case_matcher
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. */
45 struct case_matcher *
46 case_matcher_create (void)
48 struct case_matcher *cm = xmalloc (sizeof *cm);
49 cm->inputs = NULL;
50 cm->n_inputs = 0;
51 cm->allocated_inputs = 0;
52 cm->by_values = NULL;
53 return cm;
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
60 call to the next.)
62 All of the BY subcases provided to this function for a given
63 CM must be conformable (see subcase_conformable()). */
64 void
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);
76 else
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,
81 sizeof *cm->inputs);
82 input = &cm->inputs[cm->n_inputs++];
83 subcase_clone (&input->by_vars, by);
84 input->data = data;
85 input->is_minimal = is_minimal;
88 /* Destroys case matcher CM. */
89 void
90 case_matcher_destroy (struct case_matcher *cm)
92 if (cm != NULL)
94 size_t i;
96 if (cm->by_values != NULL)
98 caseproto_destroy_values (subcase_get_proto (&cm->inputs[0].by_vars),
99 cm->by_values);
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);
107 free (cm->inputs);
108 free (cm);
112 static int
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.*/
128 bool
129 case_matcher_match (struct case_matcher *cm, union value **by)
131 struct case_matcher_input *file, *min;
133 min = NULL;
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;
138 if (cmp < 0)
139 *file->is_minimal = false;
140 else
142 *file->is_minimal = true;
143 if (cmp > 0)
144 min = file;
147 else
148 *file->is_minimal = false;
150 if (min != NULL)
152 for (file = cm->inputs; file < min; file++)
153 *file->is_minimal = false;
154 subcase_extract (&min->by_vars, *min->data, cm->by_values);
155 *by = cm->by_values;
156 return true;
158 else
160 *by = NULL;
161 return false;