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 flexifile_in_core(const struct casefile *cf UNUSED)
218 /* Always in memory */
223 flexifile_error (const struct casefile *cf UNUSED )
230 flexifile_create (size_t value_cnt)
232 struct flexifile *ff = xzalloc (sizeof *ff);
233 struct casefile *cf = (struct casefile *) ff;
235 casefile_register (cf, (struct class_casefile *) &class);
237 ff->value_cnt = value_cnt;
239 ff->cases = xzalloc(sizeof (struct ccase *) * CHUNK_SIZE);
240 ff->capacity = CHUNK_SIZE;
245 static const struct class_flexifile class = {
249 flexifile_get_value_cnt,
250 flexifile_get_case_cnt,
251 flexifile_get_reader,
266 static const struct class_flexifilereader class_reader =
269 flexifilereader_get_next_case,
271 flexifilereader_destroy
276 /* Implementations of class methods */
279 impl_get_case(const struct flexifile *ff, unsigned long casenum,
282 if ( casenum >= ff->case_cnt)
285 case_clone (c, &ff->cases[casenum]);
292 dumpcasedata(struct ccase *c)
295 for ( i = 0 ; i < c->case_data->value_cnt * MAX_SHORT_STRING; ++i )
296 putchar(c->case_data->values->s[i]);
302 impl_resize (struct flexifile *ff, int n_values, int posn)
306 for( i = 0 ; i < ff->case_cnt ; ++i )
309 case_create (&c, ff->value_cnt + n_values);
311 case_copy (&c, 0, &ff->cases[i], 0, posn);
313 memset (case_data_rw(&c, posn), ' ', n_values * MAX_SHORT_STRING) ;
314 case_copy (&c, posn + n_values,
315 &ff->cases[i], posn, ff->value_cnt - posn);
317 case_destroy (&ff->cases[i]);
321 ff->value_cnt += n_values;
327 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn)
334 if ( posn > ff->case_cnt )
337 if ( posn >= ff->capacity )
340 case_create(&blank, ff->value_cnt);
342 flexifile_append(CASEFILE(ff), &blank);
344 case_destroy(&blank);
346 /* Shift the existing cases down one */
347 for ( i = ff->case_cnt ; i > posn; --i)
348 case_move(&ff->cases[i], &ff->cases[i-1]);
350 case_clone (&ff->cases[posn], c);
357 impl_delete_cases (struct flexifile *ff, int n_cases, int first)
361 if ( ff->case_cnt < first + n_cases )
364 for ( i = first ; i < first + n_cases; ++i )
365 case_destroy (&ff->cases[i]);
367 /* Shift the cases up by N_CASES */
368 for ( i = first; i < ff->case_cnt - n_cases; ++i )
370 case_move (&ff->cases[i], &ff->cases[i+ n_cases]);
373 ff->case_cnt -= n_cases;