6c427df5bc4dedcbdca0413cb62357b2300fe257
[pspp] / src / case.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include "case.h"
22 #include <limits.h>
23 #include <stdlib.h>
24 #include "val.h"
25 #include "alloc.h"
26 #include "str.h"
27
28 #ifdef GLOBAL_DEBUGGING
29 #undef NDEBUG
30 #else
31 #define NDEBUG
32 #endif
33 #include <assert.h>
34
35 void
36 case_unshare (struct ccase *c) 
37 {
38   struct case_data *cd;
39   
40   assert (c != NULL);
41   assert (c->this == c);
42   assert (c->case_data != NULL);
43   assert (c->case_data->ref_cnt > 1);
44
45   cd = c->case_data;
46   cd->ref_cnt--;
47   case_create (c, c->case_data->value_cnt);
48   memcpy (c->case_data->values, cd->values,
49           sizeof *cd->values * cd->value_cnt); 
50 }
51
52 static inline size_t
53 case_size (size_t value_cnt) 
54 {
55   return (offsetof (struct case_data, values)
56           + value_cnt * sizeof (union value));
57 }
58
59 #ifdef GLOBAL_DEBUGGING
60 void
61 case_nullify (struct ccase *c) 
62 {
63   c->case_data = NULL;
64   c->this = c;
65 }
66 #endif /* GLOBAL_DEBUGGING */
67
68 #ifdef GLOBAL_DEBUGGING
69 int
70 case_is_null (const struct ccase *c) 
71 {
72   return c->case_data == NULL;
73 }
74 #endif /* GLOBAL_DEBUGGING */
75
76 void
77 case_create (struct ccase *c, size_t value_cnt) 
78 {
79   if (!case_try_create (c, value_cnt))
80     out_of_memory ();
81 }
82
83 #ifdef GLOBAL_DEBUGGING
84 void
85 case_clone (struct ccase *clone, const struct ccase *orig)
86 {
87   assert (orig != NULL);
88   assert (orig->this == orig);
89   assert (orig->case_data != NULL);
90   assert (orig->case_data->ref_cnt > 0);
91   assert (clone != NULL);
92
93   if (clone != orig) 
94     {
95       *clone = *orig;
96       clone->this = clone;
97     }
98   orig->case_data->ref_cnt++;
99 }
100 #endif /* GLOBAL_DEBUGGING */
101
102 #ifdef GLOBAL_DEBUGGING
103 void
104 case_move (struct ccase *dst, struct ccase *src) 
105 {
106   assert (src != NULL);
107   assert (src->this == src);
108   assert (src->case_data != NULL);
109   assert (src->case_data->ref_cnt > 0);
110   assert (dst != NULL);
111
112   *dst = *src;
113   dst->this = dst;
114   case_nullify (src);
115 }
116 #endif /* GLOBAL_DEBUGGING */
117
118 #ifdef GLOBAL_DEBUGGING
119 void
120 case_destroy (struct ccase *c) 
121 {
122   struct case_data *cd;
123   
124   assert (c != NULL);
125   assert (c->this == c);
126
127   cd = c->case_data;
128   if (cd != NULL && --cd->ref_cnt == 0) 
129     {
130       memset (cd->values, 0xcc, sizeof *cd->values * cd->value_cnt);
131       cd->value_cnt = 0xdeadbeef;
132       free (cd); 
133     }
134 }
135 #endif /* GLOBAL_DEBUGGING */
136
137 int
138 case_try_create (struct ccase *c, size_t value_cnt) 
139 {
140   c->case_data = malloc (case_size (value_cnt));
141   if (c->case_data != NULL) 
142     {
143 #ifdef GLOBAL_DEBUGGING
144       c->this = c;
145 #endif
146       c->case_data->value_cnt = value_cnt;
147       c->case_data->ref_cnt = 1;
148       return 1;
149     }
150   else 
151     {
152 #ifdef GLOBAL_DEBUGGING
153       c->this = c;
154 #endif
155       return 0;
156     }
157 }
158
159 int
160 case_try_clone (struct ccase *clone, const struct ccase *orig) 
161 {
162   case_clone (clone, orig);
163   return 1;
164 }
165
166 #ifdef GLOBAL_DEBUGGING
167 void
168 case_copy (struct ccase *dst, size_t dst_idx,
169            const struct ccase *src, size_t src_idx,
170            size_t value_cnt)
171 {
172   assert (dst != NULL);
173   assert (dst->this == dst);
174   assert (dst->case_data != NULL);
175   assert (dst->case_data->ref_cnt > 0);
176   assert (dst_idx + value_cnt <= dst->case_data->value_cnt);
177
178   assert (src != NULL);
179   assert (src->this == src);
180   assert (src->case_data != NULL);
181   assert (src->case_data->ref_cnt > 0);
182   assert (src_idx + value_cnt <= dst->case_data->value_cnt);
183
184   if (dst->case_data->ref_cnt > 1)
185     case_unshare (dst);
186   if (dst->case_data != src->case_data || dst_idx != src_idx) 
187     memmove (dst->case_data->values + dst_idx,
188              src->case_data->values + src_idx,
189              sizeof *dst->case_data->values * value_cnt); 
190 }
191 #endif /* GLOBAL_DEBUGGING */
192
193 #ifdef GLOBAL_DEBUGGING
194 size_t
195 case_serial_size (size_t value_cnt) 
196 {
197   return value_cnt * sizeof (union value);
198 }
199 #endif /* GLOBAL_DEBUGGING */
200
201 #ifdef GLOBAL_DEBUGGING
202 void
203 case_serialize (const struct ccase *c, void *output,
204                 size_t output_size UNUSED) 
205 {
206   assert (c != NULL);
207   assert (c->this == c);
208   assert (c->case_data != NULL);
209   assert (c->case_data->ref_cnt > 0);
210   assert (output_size == case_serial_size (c->case_data->value_cnt));
211   assert (output != NULL || output_size == 0);
212
213   memcpy (output, c->case_data->values,
214           case_serial_size (c->case_data->value_cnt));
215 }
216 #endif /* GLOBAL_DEBUGGING */
217
218 #ifdef GLOBAL_DEBUGGING
219 void
220 case_unserialize (struct ccase *c, const void *input,
221                   size_t input_size UNUSED) 
222 {
223   assert (c != NULL);
224   assert (c->this == c);
225   assert (c->case_data != NULL);
226   assert (c->case_data->ref_cnt > 0);
227   assert (input_size == case_serial_size (c->case_data->value_cnt));
228   assert (input != NULL || input_size == 0);
229
230   if (c->case_data->ref_cnt > 1)
231     case_unshare (c);
232   memcpy (c->case_data->values, input,
233           case_serial_size (c->case_data->value_cnt));
234 }
235 #endif /* GLOBAL_DEBUGGING */
236
237 #ifdef GLOBAL_DEBUGGING
238 const union value *
239 case_data (const struct ccase *c, size_t idx) 
240 {
241   assert (c != NULL);
242   assert (c->this == c);
243   assert (c->case_data != NULL);
244   assert (c->case_data->ref_cnt > 0);
245   assert (idx < c->case_data->value_cnt);
246
247   return &c->case_data->values[idx];
248 }
249 #endif /* GLOBAL_DEBUGGING */
250
251 #ifdef GLOBAL_DEBUGGING
252 double
253 case_num (const struct ccase *c, size_t idx) 
254 {
255   assert (c != NULL);
256   assert (c->this == c);
257   assert (c->case_data != NULL);
258   assert (c->case_data->ref_cnt > 0);
259   assert (idx < c->case_data->value_cnt);
260
261   return c->case_data->values[idx].f;
262 }
263 #endif /* GLOBAL_DEBUGGING */
264
265 #ifdef GLOBAL_DEBUGGING
266 const char *
267 case_str (const struct ccase *c, size_t idx) 
268 {
269   assert (c != NULL);
270   assert (c->this == c);
271   assert (c->case_data != NULL);
272   assert (c->case_data->ref_cnt > 0);
273   assert (idx < c->case_data->value_cnt);
274
275   return c->case_data->values[idx].s;
276 }
277 #endif /* GLOBAL_DEBUGGING */
278
279 #ifdef GLOBAL_DEBUGGING
280 union value *
281 case_data_rw (struct ccase *c, size_t idx) 
282 {
283   assert (c != NULL);
284   assert (c->this == c);
285   assert (c->case_data != NULL);
286   assert (c->case_data->ref_cnt > 0);
287   assert (idx < c->case_data->value_cnt);
288
289   if (c->case_data->ref_cnt > 1)
290     case_unshare (c);
291   return &c->case_data->values[idx];
292 }
293 #endif /* GLOBAL_DEBUGGING */