case-map: Identity map is only when there are no changes at all.
[pspp] / src / data / transformations.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2011, 2013 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
19 #include "data/transformations.h"
20
21 #include <assert.h>
22 #include <stdlib.h>
23
24 #include "libpspp/array.h"
25 #include "libpspp/str.h"
26
27 #include "gl/xalloc.h"
28
29 void
30 trns_chain_init (struct trns_chain *chain)
31 {
32   *chain = (struct trns_chain) TRNS_CHAIN_INIT;
33 }
34
35 bool
36 trns_chain_uninit (struct trns_chain *chain)
37 {
38   bool ok = true;
39   for (size_t i = 0; i < chain->n; i++)
40     {
41       struct transformation *xform = &chain->xforms[i];
42       if (xform->class->destroy)
43         ok = xform->class->destroy (xform->aux) && ok;
44     }
45   free (chain->xforms);
46   return ok;
47 }
48
49 bool
50 trns_chain_clear (struct trns_chain *chain)
51 {
52   bool ok = trns_chain_uninit (chain);
53   trns_chain_init (chain);
54   return ok;
55 }
56
57 void
58 trns_chain_prepend (struct trns_chain *chain, const struct transformation *t)
59 {
60   if (chain->n >= chain->allocated)
61     chain->xforms = x2nrealloc (chain->xforms, &chain->allocated,
62                                 sizeof *chain->xforms);
63
64   insert_element (chain->xforms, 1, sizeof *chain->xforms, 0);
65   chain->xforms[0] = *t;
66   chain->n++;
67 }
68
69 void
70 trns_chain_append (struct trns_chain *chain, const struct transformation *t)
71 {
72   if (chain->n >= chain->allocated)
73     chain->xforms = x2nrealloc (chain->xforms, &chain->allocated,
74                                 sizeof *chain->xforms);
75
76   chain->xforms[chain->n++] = *t;
77 }
78
79 void
80 trns_chain_splice (struct trns_chain *dst, struct trns_chain *src)
81 {
82   if (dst->n + src->n >= dst->allocated)
83     {
84       dst->allocated = dst->n + src->n;
85       dst->xforms = xrealloc (dst->xforms,
86                               dst->allocated * sizeof *dst->xforms);
87     }
88
89   memcpy (&dst->xforms[dst->n], src->xforms, src->n * sizeof *src->xforms);
90   dst->n += src->n;
91   src->n = 0;
92 }
93
94 /* Executes the N transformations in XFORMS against case *C passing CASE_NR as
95    the case number.  The transformations may replace *C by a new case.  Returns
96    the result code that caused the transformations to terminate, or
97    TRNS_CONTINUE if the transformations finished due to "falling off the end"
98    of the set of transformations. */
99 enum trns_result
100 trns_chain_execute (const struct trns_chain *chain,
101                     casenumber case_nr, struct ccase **c)
102 {
103   for (size_t i = 0; i < chain->n; i++)
104     {
105       const struct transformation *trns = &chain->xforms[i];
106       int retval = trns->class->execute (trns->aux, c, case_nr);
107       if (retval != TRNS_CONTINUE)
108         return retval;
109     }
110
111   return TRNS_CONTINUE;
112 }