1 /* PSPP - computes sample statistics.
3 Copyright (C) 2006 Free Software Foundation, Inc.
4 Written by John Darrington <john@darrington.wattle.id.au>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include "flexifile.h"
25 #include <data/casefile.h>
26 #include <data/casefile-private.h>
27 #include <data/case.h>
30 struct class_flexifile
32 struct class_casefile parent;
34 bool (*get_case) (const struct flexifile *, unsigned long, struct ccase *);
36 bool (*insert_case) (struct flexifile *, struct ccase *, int );
37 bool (*delete_cases) (struct flexifile *, int, int );
39 bool (*resize) (struct flexifile *, int, int );
42 static const struct class_flexifile class;
44 #define CLASS_FLEXIFILE(K) ((struct class_flexifile *) K)
45 #define CONST_CLASS_FLEXIFILE(K) ((const struct class_flexifile *) K)
51 struct casefile cf; /* Parent */
53 size_t value_cnt; /* Case size in `union value's. */
54 unsigned long case_cnt; /* Number of cases stored. */
58 struct ccase *cases; /* Pointer to array of cases. */
59 unsigned long capacity; /* size of array in cases */
62 struct class_flexifilereader
64 struct class_casereader parent ;
67 static const struct class_flexifilereader class_reader;
69 /* For reading out the cases in a flexifile. */
70 struct flexifilereader
72 struct casereader cr; /* Parent */
74 unsigned long case_idx; /* Case number of current case. */
75 bool destructive; /* Is this a destructive reader? */
83 impl_get_case(const struct flexifile *ff, unsigned long casenum,
86 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn);
89 impl_delete_cases (struct flexifile *ff, int n_cases, int first);
92 impl_resize (struct flexifile *ff, int n_values, int posn);
95 /* Gets a case, for which writing may not be safe */
97 flexifile_get_case(const struct flexifile *ff, unsigned long casenum,
100 const struct class_flexifile *class =
101 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
103 return class->get_case(ff, casenum, c);
107 /* Insert N_VALUES before POSN.
108 If N_VALUES is negative, then deleted -N_VALUES instead
111 flexifile_resize (struct flexifile *ff, int n_values, int posn)
113 const struct class_flexifile *class =
114 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
116 return class->resize(ff, n_values, posn);
122 flexifile_insert_case (struct flexifile *ff, struct ccase *c, int posn)
124 const struct class_flexifile *class =
125 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
127 return class->insert_case(ff, c, posn);
132 flexifile_delete_cases (struct flexifile *ff, int n_cases, int first)
134 const struct class_flexifile *class =
135 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
137 return class->delete_cases (ff, n_cases, first);
142 flexifile_get_case_cnt (const struct casefile *cf)
144 return FLEXIFILE(cf)->case_cnt;
148 flexifile_get_value_cnt (const struct casefile *cf)
150 return FLEXIFILE(cf)->value_cnt;
155 flexifile_destroy (struct casefile *cf)
158 for ( i = 0 ; i < FLEXIFILE(cf)->case_cnt; ++i )
159 case_destroy( &FLEXIFILE(cf)->cases[i]);
161 free(FLEXIFILE(cf)->cases);
165 grow(struct flexifile *ff)
167 ff->capacity += CHUNK_SIZE;
168 ff->cases = xrealloc(ff->cases, ff->capacity * sizeof ( *ff->cases) );
172 flexifile_append (struct casefile *cf, const struct ccase *c)
174 struct flexifile *ff = FLEXIFILE(cf);
176 if (ff->case_cnt >= ff->capacity)
179 case_clone (&ff->cases[ff->case_cnt++], c);
185 static struct ccase *
186 flexifilereader_get_next_case (struct casereader *cr)
188 struct flexifilereader *ffr = FLEXIFILEREADER(cr);
189 struct flexifile *ff = FLEXIFILE(casereader_get_casefile(cr));
191 if ( ffr->case_idx >= ff->case_cnt)
194 return &ff->cases[ffr->case_idx++];
198 flexifilereader_destroy(struct casereader *r)
203 static struct casereader *
204 flexifile_get_reader (const struct casefile *cf_)
206 struct casefile *cf = (struct casefile *) cf_;
207 struct flexifilereader *ffr = xzalloc (sizeof *ffr);
208 struct casereader *reader = (struct casereader *) ffr;
210 casereader_register (cf, reader, CLASS_CASEREADER(&class_reader));
216 static struct casereader *
217 flexifilereader_clone (const struct casereader *cr)
219 const struct flexifilereader *ffr = (const struct flexifilereader *) cr;
220 struct flexifilereader *new_ffr = xzalloc (sizeof *new_ffr);
221 struct casereader *new_reader = (struct casereader *) new_ffr;
222 struct casefile *cf = casereader_get_casefile (cr);
224 casereader_register (cf, new_reader, CLASS_CASEREADER(&class_reader));
226 new_ffr->case_idx = ffr->case_idx ;
227 new_ffr->destructive = ffr->destructive ;
234 flexifile_in_core(const struct casefile *cf UNUSED)
236 /* Always in memory */
241 flexifile_error (const struct casefile *cf UNUSED )
248 flexifile_create (size_t value_cnt)
250 struct flexifile *ff = xzalloc (sizeof *ff);
251 struct casefile *cf = (struct casefile *) ff;
253 casefile_register (cf, (struct class_casefile *) &class);
255 ff->value_cnt = value_cnt;
257 ff->cases = xzalloc(sizeof (struct ccase *) * CHUNK_SIZE);
258 ff->capacity = CHUNK_SIZE;
263 static const struct class_flexifile class = {
267 flexifile_get_value_cnt,
268 flexifile_get_case_cnt,
269 flexifile_get_reader,
284 static const struct class_flexifilereader class_reader =
287 flexifilereader_get_next_case,
289 flexifilereader_destroy,
290 flexifilereader_clone
295 /* Implementations of class methods */
298 impl_get_case(const struct flexifile *ff, unsigned long casenum,
301 if ( casenum >= ff->case_cnt)
304 case_clone (c, &ff->cases[casenum]);
311 dumpcasedata(struct ccase *c)
314 for ( i = 0 ; i < c->case_data->value_cnt * MAX_SHORT_STRING; ++i )
315 putchar(c->case_data->values->s[i]);
321 impl_resize (struct flexifile *ff, int n_values, int posn)
325 for( i = 0 ; i < ff->case_cnt ; ++i )
328 case_create (&c, ff->value_cnt + n_values);
330 case_copy (&c, 0, &ff->cases[i], 0, posn);
332 memset (case_data_rw(&c, posn), ' ', n_values * MAX_SHORT_STRING) ;
333 case_copy (&c, posn + n_values,
334 &ff->cases[i], posn, ff->value_cnt - posn);
336 case_destroy (&ff->cases[i]);
340 ff->value_cnt += n_values;
346 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn)
353 if ( posn > ff->case_cnt )
356 if ( posn >= ff->capacity )
359 case_create(&blank, ff->value_cnt);
361 flexifile_append(CASEFILE(ff), &blank);
363 case_destroy(&blank);
365 /* Shift the existing cases down one */
366 for ( i = ff->case_cnt ; i > posn; --i)
367 case_move(&ff->cases[i], &ff->cases[i-1]);
369 case_clone (&ff->cases[posn], c);
376 impl_delete_cases (struct flexifile *ff, int n_cases, int first)
380 if ( ff->case_cnt < first + n_cases )
383 for ( i = first ; i < first + n_cases; ++i )
384 case_destroy (&ff->cases[i]);
386 /* Shift the cases up by N_CASES */
387 for ( i = first; i < ff->case_cnt - n_cases; ++i )
389 case_move (&ff->cases[i], &ff->cases[i+ n_cases]);
392 ff->case_cnt -= n_cases;