Test both compressed and uncompressed system files with very long
[pspp] / src / data / case.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2004, 2007 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 <stdlib.h>
24
25 #include <data/value.h>
26 #include <data/variable.h>
27 #include <libpspp/alloc.h>
28 #include <libpspp/str.h>
29
30 #include "minmax.h"
31
32 /* Reference-counted case implementation. */
33 struct case_data
34   {
35     size_t value_cnt;                   /* Number of values. */
36     unsigned ref_cnt;                   /* Reference count. */
37     union value values[1];              /* Values. */
38   };
39
40 /* Ensures that C does not share data with any other case. */
41 static void
42 case_unshare (struct ccase *c)
43 {
44   if (c->case_data->ref_cnt > 1)
45     {
46       struct case_data *cd = c->case_data;
47       cd->ref_cnt--;
48       case_create (c, cd->value_cnt);
49       memcpy (c->case_data->values, cd->values,
50               sizeof *cd->values * cd->value_cnt);
51     }
52 }
53
54 /* Returns the number of bytes needed by a case with VALUE_CNT
55    values. */
56 static size_t
57 case_size (size_t value_cnt)
58 {
59   return (offsetof (struct case_data, values)
60           + value_cnt * sizeof (union value));
61 }
62
63 /* Initializes C as a null case. */
64 void
65 case_nullify (struct ccase *c)
66 {
67   c->case_data = NULL;
68 }
69
70 /* Returns true iff C is a null case. */
71 bool
72 case_is_null (const struct ccase *c)
73 {
74   return c->case_data == NULL;
75 }
76
77 /* Initializes C as a new case that can store VALUE_CNT values.
78    The values have indeterminate contents until explicitly
79    written. */
80 void
81 case_create (struct ccase *c, size_t value_cnt)
82 {
83   if (!case_try_create (c, value_cnt))
84     xalloc_die ();
85 }
86
87 /* Initializes CLONE as a copy of ORIG. */
88 void
89 case_clone (struct ccase *clone, const struct ccase *orig)
90 {
91   assert (orig->case_data->ref_cnt > 0);
92
93   if (clone != orig)
94     *clone = *orig;
95   orig->case_data->ref_cnt++;
96 #ifdef DEBUGGING
97   case_unshare (clone);
98 #endif
99 }
100
101 /* Replaces DST by SRC and nullifies SRC.
102    DST and SRC must be initialized cases at entry. */
103 void
104 case_move (struct ccase *dst, struct ccase *src)
105 {
106   assert (src->case_data->ref_cnt > 0);
107
108   if (dst != src)
109     {
110       *dst = *src;
111       case_nullify (src);
112     }
113 }
114
115 /* Destroys case C. */
116 void
117 case_destroy (struct ccase *c)
118 {
119   struct case_data *cd;
120
121   cd = c->case_data;
122   if (cd != NULL && --cd->ref_cnt == 0)
123     {
124       memset (cd->values, 0xcc, sizeof *cd->values * cd->value_cnt);
125       cd->value_cnt = 0xdeadbeef;
126       free (cd);
127     }
128 }
129
130 /* Returns the number of union values in C. */
131 size_t
132 case_get_value_cnt (const struct ccase *c)
133 {
134   return c->case_data->value_cnt;
135 }
136
137 /* Resizes case C to NEW_CNT union values. */
138 void
139 case_resize (struct ccase *c, size_t new_cnt)
140 {
141   size_t old_cnt = case_get_value_cnt (c);
142   if (old_cnt != new_cnt)
143     {
144       struct ccase new;
145
146       case_create (&new, new_cnt);
147       case_copy (&new, 0, c, 0, MIN (old_cnt, new_cnt));
148       case_swap (&new, c);
149       case_destroy (&new);
150     }
151 }
152
153 /* Swaps cases A and B. */
154 void
155 case_swap (struct ccase *a, struct ccase *b)
156 {
157   struct case_data *t = a->case_data;
158   a->case_data = b->case_data;
159   b->case_data = t;
160 }
161
162 /* Attempts to create C as a new case that holds VALUE_CNT
163    values.  Returns true if successful, false if memory
164    allocation failed. */
165 bool
166 case_try_create (struct ccase *c, size_t value_cnt)
167 {
168   c->case_data = malloc (case_size (value_cnt));
169   if (c->case_data != NULL)
170     {
171       c->case_data->value_cnt = value_cnt;
172       c->case_data->ref_cnt = 1;
173       return true;
174     }
175
176   return false;
177 }
178
179 /* Tries to initialize CLONE as a copy of ORIG.
180    Returns true if successful, false if memory allocation
181    failed. */
182 bool
183 case_try_clone (struct ccase *clone, const struct ccase *orig)
184 {
185   case_clone (clone, orig);
186   return true;
187 }
188
189 /* Copies VALUE_CNT values from SRC (starting at SRC_IDX) to DST
190    (starting at DST_IDX). */
191 void
192 case_copy (struct ccase *dst, size_t dst_idx,
193            const struct ccase *src, size_t src_idx,
194            size_t value_cnt)
195 {
196   assert (dst->case_data->ref_cnt > 0);
197   assert (dst_idx + value_cnt <= dst->case_data->value_cnt);
198
199   assert (src->case_data->ref_cnt > 0);
200   assert (src_idx + value_cnt <= src->case_data->value_cnt);
201
202   if (dst->case_data != src->case_data || dst_idx != src_idx)
203     {
204       case_unshare (dst);
205       memmove (dst->case_data->values + dst_idx,
206                src->case_data->values + src_idx,
207                sizeof *dst->case_data->values * value_cnt);
208     }
209 }
210
211 /* Copies VALUE_CNT values out of case C to VALUES, starting at
212    the given START_IDX. */
213 void
214 case_copy_out (const struct ccase *c,
215                size_t start_idx, union value *values, size_t value_cnt)
216 {
217   assert (c->case_data->ref_cnt > 0);
218   assert (value_cnt <= c->case_data->value_cnt);
219   assert (start_idx + value_cnt <= c->case_data->value_cnt);
220
221   memcpy (values, c->case_data->values + start_idx,
222           value_cnt * sizeof *values);
223 }
224
225 /* Copies VALUE_CNT values from VALUES into case C, staring at
226    the given START_IDX. */
227 void
228 case_copy_in (struct ccase *c,
229               size_t start_idx, const union value *values, size_t value_cnt)
230 {
231   assert (c->case_data->ref_cnt > 0);
232   assert (value_cnt <= c->case_data->value_cnt);
233   assert (start_idx + value_cnt <= c->case_data->value_cnt);
234
235   case_unshare (c);
236   memcpy (c->case_data->values + start_idx, values,
237           value_cnt * sizeof *values);
238 }
239
240 /* Returns a pointer to the `union value' used for the
241    element of C for variable V.
242    Case C must be drawn from V's dictionary.
243    The caller must not modify the returned data. */
244 const union value *
245 case_data (const struct ccase *c, const struct variable *v)
246 {
247   return case_data_idx (c, var_get_case_index (v));
248 }
249
250 /* Returns the numeric value of the `union value' in C for
251    variable V.
252    Case C must be drawn from V's dictionary. */
253 double
254 case_num (const struct ccase *c, const struct variable *v)
255 {
256   return case_num_idx (c, var_get_case_index (v));
257 }
258
259 /* Returns the string value of the `union value' in C for
260    variable V.
261    Case C must be drawn from V's dictionary.
262    (Note that the value is not null-terminated.)
263    The caller must not modify the return value. */
264 const char *
265 case_str (const struct ccase *c, const struct variable *v)
266 {
267   return case_str_idx (c, var_get_case_index (v));
268 }
269
270 /* Returns a pointer to the `union value' used for the
271    element of C for variable V.
272    Case C must be drawn from V's dictionary.
273    The caller is allowed to modify the returned data. */
274 union value *
275 case_data_rw (struct ccase *c, const struct variable *v)
276 {
277   return case_data_rw_idx (c, var_get_case_index (v));
278 }
279
280 /* Returns a pointer to the `union value' used for the
281    element of C numbered IDX.
282    The caller must not modify the returned data. */
283 const union value *
284 case_data_idx (const struct ccase *c, size_t idx)
285 {
286   assert (c->case_data->ref_cnt > 0);
287   assert (idx < c->case_data->value_cnt);
288
289   return &c->case_data->values[idx];
290 }
291
292 /* Returns the numeric value of the `union value' in C numbered
293    IDX. */
294 double
295 case_num_idx (const struct ccase *c, size_t idx)
296 {
297   assert (c->case_data->ref_cnt > 0);
298   assert (idx < c->case_data->value_cnt);
299
300   return c->case_data->values[idx].f;
301 }
302
303 /* Returns the string value of the `union value' in C numbered
304    IDX.
305    (Note that the value is not null-terminated.)
306    The caller must not modify the return value. */
307 const char *
308 case_str_idx (const struct ccase *c, size_t idx)
309 {
310   assert (c->case_data->ref_cnt > 0);
311   assert (idx < c->case_data->value_cnt);
312
313   return c->case_data->values[idx].s;
314 }
315
316 /* Returns a pointer to the `union value' used for the
317    element of C numbered IDX.
318    The caller is allowed to modify the returned data. */
319 union value *
320 case_data_rw_idx (struct ccase *c, size_t idx)
321 {
322   assert (c->case_data->ref_cnt > 0);
323   assert (idx < c->case_data->value_cnt);
324
325   case_unshare (c);
326   return &c->case_data->values[idx];
327 }
328
329 /* Compares the values of the VAR_CNT variables in VP
330    in cases A and B and returns a strcmp()-type result. */
331 int
332 case_compare (const struct ccase *a, const struct ccase *b,
333               const struct variable *const *vp, size_t var_cnt)
334 {
335   return case_compare_2dict (a, b, vp, vp, var_cnt);
336 }
337
338 /* Compares the values of the VAR_CNT variables in VAP in case CA
339    to the values of the VAR_CNT variables in VBP in CB
340    and returns a strcmp()-type result. */
341 int
342 case_compare_2dict (const struct ccase *ca, const struct ccase *cb,
343                     const struct variable *const *vap,
344                 const struct variable *const *vbp,
345                     size_t var_cnt)
346 {
347   for (; var_cnt-- > 0; vap++, vbp++)
348     {
349       const struct variable *va = *vap;
350       const struct variable *vb = *vbp;
351
352       assert (var_get_width (va) == var_get_width (vb));
353
354       if (var_get_width (va) == 0)
355         {
356           double af = case_num (ca, va);
357           double bf = case_num (cb, vb);
358
359           if (af != bf)
360             return af > bf ? 1 : -1;
361         }
362       else
363         {
364           const char *as = case_str (ca, va);
365           const char *bs = case_str (cb, vb);
366           int cmp = memcmp (as, bs, var_get_width (va));
367
368           if (cmp != 0)
369             return cmp;
370         }
371     }
372   return 0;
373 }
374
375 /* Returns a pointer to the array of `union value's used for C.
376    The caller must *not* modify the returned data.
377
378    NOTE: This function breaks the case abstraction.  It should
379    *not* be used often.  Prefer the other case functions. */
380 const union value *
381 case_data_all (const struct ccase *c)
382 {
383   assert (c->case_data->ref_cnt > 0);
384
385   return c->case_data->values;
386 }
387
388 /* Returns a pointer to the array of `union value's used for C.
389    The caller is allowed to modify the returned data.
390
391    NOTE: This function breaks the case abstraction.  It should
392    *not* be used often.  Prefer the other case functions. */
393 union value *
394 case_data_all_rw (struct ccase *c)
395 {
396   assert (c->case_data->ref_cnt > 0);
397
398   case_unshare (c);
399   return c->case_data->values;
400 }