4432579e5d2e1284102a9ab7854d79db3b10d197
[pspp-builds.git] / src / data / case.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2004, 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
19 #include <data/case.h>
20
21 #include <assert.h>
22 #include <limits.h>
23 #include <stddef.h>
24 #include <stdlib.h>
25
26 #include <data/value.h>
27 #include <data/variable.h>
28 #include <libpspp/str.h>
29
30 #include "minmax.h"
31 #include "xalloc.h"
32
33 /* Returns the number of bytes needed by a case with N_VALUES
34    values. */
35 static size_t
36 case_size (size_t n_values)
37 {
38   return offsetof (struct ccase, values) + n_values * sizeof (union value);
39 }
40
41 /* Returns true if case C contains COUNT cases starting at index
42    OFS, false if any of those values are out of range for case
43    C. */
44 static inline bool UNUSED
45 range_is_valid (const struct ccase *c, size_t ofs, size_t count)
46 {
47   return (count <= c->n_values
48           && ofs <= c->n_values
49           && ofs + count <= c->n_values);
50 }
51
52 /* Creates and returns a new case that can store N_VALUES values.
53    The values have indeterminate contents until explicitly
54    written. */
55 struct ccase *
56 case_create (size_t n_values)
57 {
58   struct ccase *c = case_try_create (n_values);
59   if (c == NULL)
60     xalloc_die ();
61   return c;
62 }
63
64 /* Like case_create, but returns a null pointer if not enough
65    memory is available. */
66 struct ccase *
67 case_try_create (size_t n_values)
68 {
69   struct ccase *c = malloc (case_size (n_values));
70   if (c)
71     {
72       c->n_values = n_values;
73       c->ref_cnt = 1;
74     }
75   return c;
76 }
77
78 /* Resizes case C, which must not be shared, to N_VALUES union
79    values.  If N_VALUES is greater than the current size of case
80    C, then the newly added values have indeterminate content that
81    the caller is responsible for initializing.  Returns the new
82    case. */
83 struct ccase *
84 case_resize (struct ccase *c, size_t n_values)
85 {
86   assert (!case_is_shared (c));
87   if (n_values != c->n_values)
88     {
89       c->n_values = n_values;
90       return xrealloc (c, case_size (n_values));
91     }
92   else
93     return c;
94 }
95
96 /* case_unshare_and_resize(C, N) is equivalent to
97    case_resize(case_unshare(C), N), but it is faster if case C is
98    shared.
99
100    Returns the new case.*/
101 struct ccase *
102 case_unshare_and_resize (struct ccase *c, size_t n_values)
103 {
104   if (!case_is_shared (c))
105     return case_resize (c, n_values);
106   else
107     {
108       struct ccase *new = case_create (n_values);
109       case_copy (new, 0, c, 0, MIN (n_values, c->n_values));
110       c->ref_cnt--;
111       return new;
112     }
113 }
114
115 /* Copies N_VALUES values from SRC (starting at SRC_IDX) to DST
116    (starting at DST_IDX).
117
118    DST must not be shared. */
119 void
120 case_copy (struct ccase *dst, size_t dst_idx,
121            const struct ccase *src, size_t src_idx,
122            size_t n_values)
123 {
124   assert (!case_is_shared (dst));
125   assert (range_is_valid (dst, dst_idx, n_values));
126   assert (range_is_valid (src, src_idx, n_values));
127
128   if (dst != src || dst_idx != src_idx)
129     memmove (dst->values + dst_idx, src->values + src_idx,
130              sizeof *dst->values * n_values);
131 }
132
133 /* Copies N_VALUES values out of case C to VALUES, starting at
134    the given START_IDX. */
135 void
136 case_copy_out (const struct ccase *c,
137                size_t start_idx, union value *values, size_t n_values)
138 {
139   assert (range_is_valid (c, start_idx, n_values));
140   memcpy (values, c->values + start_idx, n_values * sizeof *values);
141 }
142
143 /* Copies N_VALUES values from VALUES into case C, starting at
144    the given START_IDX.
145
146    C must not be shared. */
147 void
148 case_copy_in (struct ccase *c,
149               size_t start_idx, const union value *values, size_t n_values)
150 {
151   assert (!case_is_shared (c));
152   assert (range_is_valid (c, start_idx, n_values));
153   memcpy (c->values + start_idx, values, n_values * sizeof *values);
154 }
155
156 /* Returns a pointer to the `union value' used for the
157    element of C for variable V.
158    Case C must be drawn from V's dictionary.
159    The caller must not modify the returned data. */
160 const union value *
161 case_data (const struct ccase *c, const struct variable *v)
162 {
163   return case_data_idx (c, var_get_case_index (v));
164 }
165
166 /* Returns a pointer to the `union value' used for the element of
167    C numbered IDX.  The caller must not modify the returned
168    data. */
169 const union value *
170 case_data_idx (const struct ccase *c, size_t idx)
171 {
172   assert (idx < c->n_values);
173   return &c->values[idx];
174 }
175
176 /* Returns a pointer to the `union value' used for the element of
177    C for variable V.  Case C must be drawn from V's dictionary.
178    The caller is allowed to modify the returned data.
179
180    Case C must not be shared. */
181 union value *
182 case_data_rw (struct ccase *c, const struct variable *v)
183 {
184   return case_data_rw_idx (c, var_get_case_index (v));
185 }
186
187 /* Returns a pointer to the `union value' used for the
188    element of C numbered IDX.
189    The caller is allowed to modify the returned data.
190
191    Case C must not be shared. */
192 union value *
193 case_data_rw_idx (struct ccase *c, size_t idx)
194 {
195   assert (!case_is_shared (c));
196   assert (idx < c->n_values);
197   return &c->values[idx];
198 }
199
200 /* Returns the numeric value of the `union value' in C for
201    variable V.
202    Case C must be drawn from V's dictionary. */
203 double
204 case_num (const struct ccase *c, const struct variable *v)
205 {
206   return case_num_idx (c, var_get_case_index (v));
207 }
208
209 /* Returns the numeric value of the `union value' in C numbered
210    IDX. */
211 double
212 case_num_idx (const struct ccase *c, size_t idx)
213 {
214   assert (idx < c->n_values);
215   return c->values[idx].f;
216 }
217
218 /* Returns the string value of the `union value' in C for
219    variable V.  Case C must be drawn from V's dictionary.  The
220    caller must not modify the return value.
221
222    Like all "union value"s, the return value is not
223    null-terminated. */
224 const char *
225 case_str (const struct ccase *c, const struct variable *v)
226 {
227   return case_str_idx (c, var_get_case_index (v));
228 }
229
230 /* Returns the string value of the `union value' in C numbered
231    IDX.  The caller must not modify the return value.
232
233    Like all "union value"s, the return value is not
234    null-terminated. */
235 const char *
236 case_str_idx (const struct ccase *c, size_t idx)
237 {
238   assert (idx < c->n_values);
239   return c->values[idx].s;
240 }
241
242 /* Compares the values of the N_VARS variables in VP
243    in cases A and B and returns a strcmp()-type result. */
244 int
245 case_compare (const struct ccase *a, const struct ccase *b,
246               const struct variable *const *vp, size_t n_vars)
247 {
248   return case_compare_2dict (a, b, vp, vp, n_vars);
249 }
250
251 /* Compares the values of the N_VARS variables in VAP in case CA
252    to the values of the N_VARS variables in VBP in CB
253    and returns a strcmp()-type result. */
254 int
255 case_compare_2dict (const struct ccase *ca, const struct ccase *cb,
256                     const struct variable *const *vap,
257                     const struct variable *const *vbp,
258                     size_t n_vars)
259 {
260   for (; n_vars-- > 0; vap++, vbp++)
261     {
262       const struct variable *va = *vap;
263       const struct variable *vb = *vbp;
264
265       assert (var_get_width (va) == var_get_width (vb));
266
267       if (var_get_width (va) == 0)
268         {
269           double af = case_num (ca, va);
270           double bf = case_num (cb, vb);
271
272           if (af != bf)
273             return af > bf ? 1 : -1;
274         }
275       else
276         {
277           const char *as = case_str (ca, va);
278           const char *bs = case_str (cb, vb);
279           int cmp = memcmp (as, bs, var_get_width (va));
280
281           if (cmp != 0)
282             return cmp;
283         }
284     }
285   return 0;
286 }
287
288 /* Returns a pointer to the array of `union value's used for C.
289    The caller must *not* modify the returned data.
290
291    This function breaks the case abstraction.  It should *not* be
292    commonly used.  Prefer the other case functions. */
293 const union value *
294 case_data_all (const struct ccase *c)
295 {
296   return c->values;
297 }
298
299 /* Returns a pointer to the array of `union value's used for C.
300    The caller is allowed to modify the returned data.
301
302    Case C must not be shared.
303
304    This function breaks the case abstraction.  It should *not* be
305    commonly used.  Prefer the other case functions. */
306 union value *
307 case_data_all_rw (struct ccase *c)
308 {
309   assert (!case_is_shared (c));
310   return c->values;
311 }
312
313 /* Internal helper function for case_unshare. */
314 struct ccase *
315 case_unshare__ (struct ccase *old)
316 {
317   struct ccase *new = case_create (old->n_values);
318   memcpy (new->values, old->values, old->n_values * sizeof old->values[0]);
319   --old->ref_cnt;
320   return new;
321 }