afb72cca1434e7a40dea2a723ba5b7a68bcd8e69
[pspp-builds.git] / src / data / casereader-filter.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20
21 #include <data/casereader.h>
22
23 #include <stdlib.h>
24
25 #include <data/casereader-provider.h>
26 #include <data/casewriter.h>
27 #include <data/variable.h>
28 #include <data/dictionary.h>
29 #include <libpspp/taint.h>
30 #include <libpspp/message.h>
31
32 #include "xalloc.h"
33
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
36
37 /* A casereader that filters data coming from another
38    casereader. */
39 struct casereader_filter
40   {
41     struct casereader *subreader; /* The reader to filter. */
42     bool (*include) (const struct ccase *, void *aux);
43     bool (*destroy) (void *aux);
44     void *aux;
45     struct casewriter *exclude; /* Writer that gets filtered cases, or NULL. */
46   };
47
48 static struct casereader_class casereader_filter_class;
49
50 /* Creates and returns a casereader whose content is a filtered
51    version of the data in SUBREADER.  Only the cases for which
52    INCLUDE returns true will appear in the returned casereader,
53    in the original order.
54
55    If EXCLUDE is non-null, then cases for which INCLUDE returns
56    false are written to EXCLUDE.  These cases will not
57    necessarily be fully written to EXCLUDE until the filtering casereader's
58    cases have been fully read or, if that never occurs, until the
59    filtering casereader is destroyed.
60
61    When the filtering casereader is destroyed, DESTROY will be
62    called to allow any state maintained by INCLUDE to be freed.
63
64    After this function is called, SUBREADER must not ever again
65    be referenced directly.  It will be destroyed automatically
66    when the filtering casereader is destroyed. */
67 struct casereader *
68 casereader_create_filter_func (struct casereader *subreader,
69                                bool (*include) (const struct ccase *,
70                                                 void *aux),
71                                bool (*destroy) (void *aux),
72                                void *aux,
73                                struct casewriter *exclude)
74 {
75   struct casereader_filter *filter = xmalloc (sizeof *filter);
76   struct casereader *reader;
77   filter->subreader = casereader_rename (subreader);
78   filter->include = include;
79   filter->destroy = destroy;
80   filter->aux = aux;
81   filter->exclude = exclude;
82   reader = casereader_create_sequential (
83     NULL, casereader_get_value_cnt (filter->subreader), CASENUMBER_MAX,
84     &casereader_filter_class, filter);
85   taint_propagate (casereader_get_taint (filter->subreader),
86                    casereader_get_taint (reader));
87   return reader;
88 }
89
90 /* Internal read function for filtering casereader. */
91 static bool
92 casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
93                         struct ccase *c)
94
95 {
96   struct casereader_filter *filter = filter_;
97   for (;;)
98     {
99       if (!casereader_read (filter->subreader, c))
100         return false;
101       else if (filter->include (c, filter->aux))
102         return true;
103       else if (filter->exclude != NULL)
104         casewriter_write (filter->exclude, c);
105       else
106         case_destroy (c);
107     }
108 }
109
110 /* Internal destruction function for filtering casereader. */
111 static void
112 casereader_filter_destroy (struct casereader *reader, void *filter_)
113 {
114   struct casereader_filter *filter = filter_;
115
116   /* Make sure we've written everything to the excluded cases
117      casewriter, if there is one. */
118   if (filter->exclude != NULL)
119     {
120       struct ccase c;
121       while (casereader_read (filter->subreader, &c))
122         if (filter->include (&c, filter->aux))
123           case_destroy (&c);
124         else
125           casewriter_write (filter->exclude, &c);
126     }
127
128   casereader_destroy (filter->subreader);
129   if (filter->destroy != NULL && !filter->destroy (filter->aux))
130     casereader_force_error (reader);
131   free (filter);
132 }
133
134 /* Filtering casereader class. */
135 static struct casereader_class casereader_filter_class =
136   {
137     casereader_filter_read,
138     casereader_filter_destroy,
139
140     /* We could in fact delegate clone to the subreader, if the
141        filter function is required to have no memory and if we
142        added reference counting.  But it might be useful to have
143        filter functions with memory and in any case this would
144        require a little extra work. */
145     NULL,
146     NULL,
147   };
148
149 \f
150 /* Casereader for filtering valid weights. */
151
152 /* Weight-filtering data. */
153 struct casereader_filter_weight
154   {
155     const struct variable *weight_var; /* Weight variable. */
156     bool *warn_on_invalid;      /* Have we already issued an error? */
157     bool local_warn_on_invalid; /* warn_on_invalid might point here. */
158   };
159
160 static bool casereader_filter_weight_include (const struct ccase *, void *);
161 static bool casereader_filter_weight_destroy (void *);
162
163 /* Creates and returns a casereader that filters cases from
164    READER by valid weights, that is, any cases with user- or
165    system-missing, zero, or negative weights are dropped.  The
166    weight variable's information is taken from DICT.  If DICT
167    does not have a weight variable, then no cases are filtered
168    out.
169
170    When a case with an invalid weight is encountered,
171    *WARN_ON_INVALID is checked.  If it is true, then an error
172    message is issued and *WARN_ON_INVALID is set false.  If
173    WARN_ON_INVALID is a null pointer, then an internal bool that
174    is initially true is used instead of a caller-supplied bool.
175
176    If EXCLUDE is non-null, then dropped cases are written to
177    EXCLUDE.  These cases will not necessarily be fully written to
178    EXCLUDE until the filtering casereader's cases have been fully
179    read or, if that never occurs, until the filtering casereader
180    is destroyed.
181
182    After this function is called, READER must not ever again be
183    referenced directly.  It will be destroyed automatically when
184    the filtering casereader is destroyed. */
185 struct casereader *
186 casereader_create_filter_weight (struct casereader *reader,
187                                  const struct dictionary *dict,
188                                  bool *warn_on_invalid,
189                                  struct casewriter *exclude)
190 {
191   struct variable *weight_var = dict_get_weight (dict);
192   if (weight_var != NULL)
193     {
194       struct casereader_filter_weight *cfw = xmalloc (sizeof *cfw);
195       cfw->weight_var = weight_var;
196       cfw->warn_on_invalid = (warn_on_invalid
197                                ? warn_on_invalid
198                                : &cfw->local_warn_on_invalid);
199       cfw->local_warn_on_invalid = true;
200       reader = casereader_create_filter_func (reader,
201                                               casereader_filter_weight_include,
202                                               casereader_filter_weight_destroy,
203                                               cfw, exclude);
204     }
205   else
206     reader = casereader_rename (reader);
207   return reader;
208 }
209
210 /* Internal "include" function for weight-filtering
211    casereader. */
212 static bool
213 casereader_filter_weight_include (const struct ccase *c, void *cfw_)
214 {
215   struct casereader_filter_weight *cfw = cfw_;
216   double value = case_num (c, cfw->weight_var);
217   if (value >= 0.0 && !var_is_num_missing (cfw->weight_var, value, MV_ANY))
218     return true;
219   else
220     {
221       if (*cfw->warn_on_invalid)
222         {
223           msg (SW, _("At least one case in the data read had a weight value "
224                      "that was user-missing, system-missing, zero, or "
225                      "negative.  These case(s) were ignored."));
226           *cfw->warn_on_invalid = false;
227         }
228       return false;
229     }
230 }
231
232 /* Internal "destroy" function for weight-filtering
233    casereader. */
234 static bool
235 casereader_filter_weight_destroy (void *cfw_)
236 {
237   struct casereader_filter_weight *cfw = cfw_;
238   free (cfw);
239   return true;
240 }
241 \f
242 /* Casereader for filtering missing values. */
243
244 /* Missing-value filtering data. */
245 struct casereader_filter_missing
246   {
247     struct variable **vars;     /* Variables whose values to filter. */
248     size_t var_cnt;             /* Number of variables. */
249     enum mv_class class;        /* Types of missing values to filter. */
250   };
251
252 static bool casereader_filter_missing_include (const struct ccase *, void *);
253 static bool casereader_filter_missing_destroy (void *);
254
255 /* Creates and returns a casereader that filters out cases from
256    READER that have a missing value in the given CLASS for any of
257    the VAR_CNT variables in VARS.  Only cases that have
258    non-missing values for all of these variables are passed
259    through.
260
261    Ownership of VARS is retained by the caller.
262
263    If EXCLUDE is non-null, then dropped cases are written to
264    EXCLUDE.  These cases will not necessarily be fully written to
265    EXCLUDE until the filtering casereader's cases have been fully
266    read or, if that never occurs, until the filtering casereader
267    is destroyed.
268
269    After this function is called, READER must not ever again
270    be referenced directly.  It will be destroyed automatically
271    when the filtering casereader is destroyed. */
272 struct casereader *
273 casereader_create_filter_missing (struct casereader *reader,
274                                   const struct variable **vars, size_t var_cnt,
275                                   enum mv_class class,
276                                   struct casewriter *exclude)
277 {
278   if (var_cnt > 0 && class != MV_NEVER)
279     {
280       struct casereader_filter_missing *cfm = xmalloc (sizeof *cfm);
281       cfm->vars = xmemdup (vars, sizeof *vars * var_cnt);
282       cfm->var_cnt = var_cnt;
283       cfm->class = class;
284       return casereader_create_filter_func (reader,
285                                             casereader_filter_missing_include,
286                                             casereader_filter_missing_destroy,
287                                             cfm,
288                                             exclude);
289     }
290   else
291     return casereader_rename (reader);
292 }
293
294 /* Internal "include" function for missing value-filtering
295    casereader. */
296 static bool
297 casereader_filter_missing_include (const struct ccase *c, void *cfm_)
298 {
299   const struct casereader_filter_missing *cfm = cfm_;
300   size_t i;
301
302   for (i = 0; i < cfm->var_cnt; i++)
303     {
304       struct variable *var = cfm->vars[i];
305       const union value *value = case_data (c, var);
306       if (var_is_value_missing (var, value, cfm->class))
307         return false;
308     }
309   return true;
310 }
311
312 /* Internal "destroy" function for missing value-filtering
313    casereader. */
314 static bool
315 casereader_filter_missing_destroy (void *cfm_)
316 {
317   struct casereader_filter_missing *cfm = cfm_;
318   free (cfm->vars);
319   free (cfm);
320   return true;
321 }
322 \f
323 /* Case-counting casereader. */
324
325 static bool casereader_counter_include (const struct ccase *, void *);
326
327 /* Creates and returns a new casereader that counts the number of
328    cases that have been read from it.  *COUNTER is initially set
329    to INITIAL_VALUE, then incremented by 1 each time a case is read.
330
331    Counting casereaders must be used very cautiously: if a
332    counting casereader is cloned or if the casereader_peek
333    function is used on it, then the counter's value can be higher
334    than expected because of the buffering that goes on behind the
335    scenes.
336
337    The counter is only incremented as cases are actually read
338    from the casereader.  In particular, if the casereader is
339    destroyed before all cases have been read from the casereader,
340    cases never read will not be included in the count.
341
342    After this function is called, READER must not ever again
343    be referenced directly.  It will be destroyed automatically
344    when the filtering casereader is destroyed. */
345 struct casereader *
346 casereader_create_counter (struct casereader *reader, casenumber *counter,
347                            casenumber initial_value)
348 {
349   *counter = initial_value;
350   return casereader_create_filter_func (reader, casereader_counter_include,
351                                         NULL, counter, NULL);
352 }
353
354 /* Internal "include" function for counting casereader. */
355 static bool
356 casereader_counter_include (const struct ccase *c UNUSED, void *counter_)
357 {
358   casenumber *counter = counter_;
359   ++*counter;
360   return true;
361 }