Change "union value" to dynamically allocate long strings.
[pspp-builds.git] / src / data / casereader-translator.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007, 2009 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18 #include <data/val-type.h>
19 #include <data/casereader.h>
20 #include <stdlib.h>
21
22 #include <data/casereader-provider.h>
23 #include <libpspp/taint.h>
24
25 #include "xalloc.h"
26
27 /* Casereader that applies a user-supplied function to translate
28    each case into another in an arbitrary fashion. */
29
30 /* A translating casereader. */
31 struct casereader_translator
32   {
33     struct casereader *subreader; /* Source of input cases. */
34
35     struct ccase *(*translate) (struct ccase *input, void *aux);
36     bool (*destroy) (void *aux);
37     void *aux;
38   };
39
40 static const struct casereader_class casereader_translator_class;
41
42 /* Creates and returns a new casereader whose cases are produced
43    by reading from SUBREADER and passing through TRANSLATE, which
44    must return the translated case, and populate it based on
45    INPUT and auxiliary data AUX.  TRANSLATE must destroy its
46    input case.
47
48    The cases returned by TRANSLATE must match OUTPUT_PROTO.
49
50    When the translating casereader is destroyed, DESTROY will be
51    called to allow any state maintained by TRANSLATE to be freed.
52
53    After this function is called, SUBREADER must not ever again
54    be referenced directly.  It will be destroyed automatically
55    when the translating casereader is destroyed. */
56 struct casereader *
57 casereader_create_translator (struct casereader *subreader,
58                               const struct caseproto *output_proto,
59                               struct ccase *(*translate) (struct ccase *input,
60                                                           void *aux),
61                               bool (*destroy) (void *aux),
62                               void *aux)
63 {
64   struct casereader_translator *ct = xmalloc (sizeof *ct);
65   struct casereader *reader;
66   ct->subreader = casereader_rename (subreader);
67   ct->translate = translate;
68   ct->destroy = destroy;
69   ct->aux = aux;
70   reader = casereader_create_sequential (
71     NULL, output_proto, casereader_get_case_cnt (ct->subreader),
72     &casereader_translator_class, ct);
73   taint_propagate (casereader_get_taint (ct->subreader),
74                    casereader_get_taint (reader));
75   return reader;
76 }
77
78 /* Internal read function for translating casereader. */
79 static struct ccase *
80 casereader_translator_read (struct casereader *reader UNUSED,
81                             void *ct_)
82 {
83   struct casereader_translator *ct = ct_;
84   struct ccase *tmp = casereader_read (ct->subreader);
85   if (tmp)
86     tmp = ct->translate (tmp, ct->aux);
87   return tmp;
88 }
89
90 /* Internal destroy function for translating casereader. */
91 static void
92 casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
93 {
94   struct casereader_translator *ct = ct_;
95   casereader_destroy (ct->subreader);
96   ct->destroy (ct->aux);
97   free (ct);
98 }
99
100 /* Casereader class for translating casereader. */
101 static const struct casereader_class casereader_translator_class =
102   {
103     casereader_translator_read,
104     casereader_translator_destroy,
105     NULL,
106     NULL,
107   };
108
109 \f
110
111 struct casereader_append_numeric
112 {
113   struct caseproto *proto;
114   casenumber n;
115   new_value_func *func;
116   void *aux;
117   void (*destroy) (void *aux);
118 };
119
120 static bool can_destroy (void *can_);
121
122 static struct ccase *can_translate (struct ccase *, void *can_);
123
124 /* Creates and returns a new casereader whose cases are produced
125    by reading from SUBREADER and appending an additional value,
126    generated by FUNC.  AUX is an optional parameter which
127    gets passed to FUNC. FUNC will also receive N as it, which is
128    the ordinal number of the case in the reader.  DESTROY is an
129    optional parameter used to destroy AUX.
130
131    After this function is called, SUBREADER must not ever again
132    be referenced directly.  It will be destroyed automatically
133    when the translating casereader is destroyed. */
134 struct casereader *
135 casereader_create_append_numeric (struct casereader *subreader,
136                                   new_value_func func, void *aux,
137                                   void (*destroy) (void *aux))
138 {
139   struct casereader_append_numeric *can = xmalloc (sizeof *can);
140   can->proto = caseproto_ref (casereader_get_proto (subreader));
141   can->proto = caseproto_add_width (can->proto, 0);
142   can->n = 0;
143   can->aux = aux;
144   can->func = func;
145   can->destroy = destroy;
146   return casereader_create_translator (subreader, can->proto,
147                                        can_translate, can_destroy, can);
148 }
149
150
151 static struct ccase *
152 can_translate (struct ccase *c, void *can_)
153 {
154   struct casereader_append_numeric *can = can_;
155   double new_value = can->func (c, can->n++, can->aux);
156   c = case_unshare_and_resize (c, can->proto);
157   case_data_rw_idx (c, caseproto_get_n_widths (can->proto) - 1)->f = new_value;
158   return c;
159 }
160
161 static bool
162 can_destroy (void *can_)
163 {
164   struct casereader_append_numeric *can = can_;
165   if (can->destroy)
166     can->destroy (can->aux);
167   caseproto_unref (can->proto);
168   free (can);
169   return true;
170 }
171
172 \f
173
174 struct arithmetic_sequence
175 {
176   double first;
177   double increment;
178 };
179
180 static double
181 next_arithmetic (const struct ccase *c UNUSED,
182                  casenumber n,
183                  void *aux)
184 {
185   struct arithmetic_sequence *as = aux;
186   return n * as->increment + as->first;
187 }
188
189 /* Creates and returns a new casereader whose cases are produced
190    by reading from SUBREADER and appending an additional value,
191    which takes the value FIRST in the first case, FIRST +
192    INCREMENT in the second case, FIRST + INCREMENT * 2 in the
193    third case, and so on.
194
195    After this function is called, SUBREADER must not ever again
196    be referenced directly.  It will be destroyed automatically
197    when the translating casereader is destroyed. */
198 struct casereader *
199 casereader_create_arithmetic_sequence (struct casereader *subreader,
200                                        double first, double increment)
201 {
202   struct arithmetic_sequence *as = xzalloc (sizeof *as);
203   as->first = first;
204   as->increment = increment;
205   return casereader_create_append_numeric (subreader, next_arithmetic,
206                                            as, free);
207 }
208
209
210 \f
211
212 struct casereader_append_rank
213 {
214   struct casereader *clone;
215   casenumber n;
216   const struct variable *var;
217   const struct variable *weight;
218   struct caseproto *proto;
219   casenumber n_common;
220   double mean_rank;
221   double cc;
222   distinct_func *distinct;
223   void *aux;
224   enum rank_error *err;
225   double prev_value;
226 };
227
228 static bool car_destroy (void *car_);
229
230 static struct ccase *car_translate (struct ccase *input, void *car_);
231
232 /* Creates and returns a new casereader whose cases are produced
233    by reading from SUBREADER and appending an additional value,
234    which is the rank of the observation.   W is the weight variable
235    of the dictionary containing V, or NULL if there is no weight
236    variable.
237
238    The following preconditions must be met:
239
240    1.    SUBREADER must be sorted on V.
241
242    2.    The weight variables, must be non-negative.
243
244    If either of these preconditions are not satisfied, then the rank
245    variables may not be correct.  In this case, if ERR is non-null,
246    it will be set according to the erroneous conditions encountered.
247
248    If DISTINCT_CALLBACK is non-null, then  it will be called exactly
249    once for every case containing a distinct value of V.  AUX is
250    an auxilliary pointer passed to DISTINCT_CALLBACK.
251
252    After this function is called, SUBREADER must not ever again
253    be referenced directly.  It will be destroyed automatically
254    when the translating casereader is destroyed. */
255 struct casereader *
256 casereader_create_append_rank (struct casereader *subreader,
257                                const struct variable *v,
258                                const struct variable *w,
259                                enum rank_error *err,
260                                distinct_func *distinct_callback,
261                                void *aux
262                                )
263 {
264   struct casereader_append_rank *car = xmalloc (sizeof *car);
265   car->proto = caseproto_ref (casereader_get_proto (subreader));
266   car->proto = caseproto_add_width (car->proto, 0);
267   car->weight = w;
268   car->var = v;
269   car->n = 0;
270   car->n_common = 1;
271   car->cc = 0.0;
272   car->clone = casereader_clone (subreader);
273   car->distinct = distinct_callback;
274   car->aux = aux;
275   car->err = err;
276   car->prev_value = SYSMIS;
277
278   return casereader_create_translator (subreader, car->proto,
279                                        car_translate, car_destroy, car);
280 }
281
282
283 static bool
284 car_destroy (void *car_)
285 {
286   struct casereader_append_rank *car = car_;
287   casereader_destroy (car->clone);
288   caseproto_unref (car->proto);
289   free (car);
290   return true;
291 }
292
293 static struct ccase *
294 car_translate (struct ccase *input, void *car_)
295 {
296   struct casereader_append_rank *car = car_;
297
298   const double value = case_data (input, car->var)->f;
299
300   if ( car->prev_value != SYSMIS)
301     {
302       if (car->err && value < car->prev_value)
303         *car->err |= RANK_ERR_UNSORTED;
304     }
305
306   if ( car->n_common == 1)
307     {
308       double vxx = SYSMIS;
309       casenumber k = 0;
310       double weight = 1.0;
311       if (car->weight)
312         {
313           weight = case_data (input, car->weight)->f;
314           if ( car->err && weight < 0 )
315             *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
316         }
317
318       do
319         {
320           struct ccase *c = casereader_peek (car->clone, car->n + ++k);
321           if (c == NULL)
322             break;
323           vxx = case_data (c, car->var)->f;
324
325           if ( vxx == value)
326             {
327               if (car->weight)
328                 {
329                   double w = case_data (c, car->weight)->f;
330
331                   if ( car->err && w < 0 )
332                     *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
333
334                   weight += w;
335                 }
336               else
337                 weight += 1.0;
338               car->n_common++;
339             }
340           case_unref (c);
341         }
342       while (vxx == value);
343       car->mean_rank = car->cc + (weight + 1) / 2.0;
344       car->cc += weight;
345
346       if (car->distinct)
347         car->distinct (value, car->n_common, weight, car->aux);
348     }
349   else
350     car->n_common--;
351
352   car->n++;
353
354   input = case_unshare_and_resize (input, car->proto);
355   case_data_rw_idx (input, caseproto_get_n_widths (car->proto) - 1)->f
356     = car->mean_rank;
357   car->prev_value = value;
358   return input;
359 }
360
361