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>
28 #include <libpspp/compiler.h>
31 struct class_flexifile
33 struct class_casefile parent;
35 bool (*get_case) (const struct flexifile *, unsigned long, struct ccase *);
37 bool (*insert_case) (struct flexifile *, struct ccase *, int );
38 bool (*delete_cases) (struct flexifile *, int, int );
40 bool (*resize) (struct flexifile *, int, int );
43 static const struct class_flexifile class;
45 #define CLASS_FLEXIFILE(K) ((struct class_flexifile *) K)
46 #define CONST_CLASS_FLEXIFILE(K) ((const struct class_flexifile *) K)
52 struct casefile cf; /* Parent */
54 size_t value_cnt; /* Case size in `union value's. */
55 unsigned long case_cnt; /* Number of cases stored. */
59 struct ccase *cases; /* Pointer to array of cases. */
60 unsigned long capacity; /* size of array in cases */
63 struct class_flexifilereader
65 struct class_casereader parent ;
68 static const struct class_flexifilereader class_reader;
70 /* For reading out the cases in a flexifile. */
71 struct flexifilereader
73 struct casereader cr; /* Parent */
75 unsigned long case_idx; /* Case number of current case. */
76 bool destructive; /* Is this a destructive reader? */
84 impl_get_case(const struct flexifile *ff, unsigned long casenum,
87 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn);
90 impl_delete_cases (struct flexifile *ff, int n_cases, int first);
93 impl_resize (struct flexifile *ff, int n_values, int posn);
96 /* Gets a case, for which writing may not be safe */
98 flexifile_get_case(const struct flexifile *ff, unsigned long casenum,
101 const struct class_flexifile *class =
102 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
104 return class->get_case(ff, casenum, c);
108 /* Insert N_VALUES before POSN.
109 If N_VALUES is negative, then deleted -N_VALUES instead
112 flexifile_resize (struct flexifile *ff, int n_values, int posn)
114 const struct class_flexifile *class =
115 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
117 return class->resize(ff, n_values, posn);
123 flexifile_insert_case (struct flexifile *ff, struct ccase *c, int posn)
125 const struct class_flexifile *class =
126 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
128 return class->insert_case(ff, c, posn);
133 flexifile_delete_cases (struct flexifile *ff, int n_cases, int first)
135 const struct class_flexifile *class =
136 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
138 return class->delete_cases (ff, n_cases, first);
143 flexifile_get_case_cnt (const struct casefile *cf)
145 return FLEXIFILE(cf)->case_cnt;
149 flexifile_get_value_cnt (const struct casefile *cf)
151 return FLEXIFILE(cf)->value_cnt;
156 flexifile_destroy (struct casefile *cf)
159 for ( i = 0 ; i < FLEXIFILE(cf)->case_cnt; ++i )
160 case_destroy( &FLEXIFILE(cf)->cases[i]);
162 free(FLEXIFILE(cf)->cases);
166 grow(struct flexifile *ff)
168 ff->capacity += CHUNK_SIZE;
169 ff->cases = xrealloc(ff->cases, ff->capacity * sizeof ( *ff->cases) );
173 flexifile_append (struct casefile *cf, const struct ccase *c)
175 struct flexifile *ff = FLEXIFILE(cf);
177 if (ff->case_cnt >= ff->capacity)
180 case_clone (&ff->cases[ff->case_cnt++], c);
186 static struct ccase *
187 flexifilereader_get_next_case (struct casereader *cr)
189 struct flexifilereader *ffr = FLEXIFILEREADER(cr);
190 struct flexifile *ff = FLEXIFILE(casereader_get_casefile(cr));
192 if ( ffr->case_idx >= ff->case_cnt)
195 return &ff->cases[ffr->case_idx++];
199 flexifilereader_destroy(struct casereader *r)
204 static struct casereader *
205 flexifile_get_reader (const struct casefile *cf_)
207 struct casefile *cf = (struct casefile *) cf_;
208 struct flexifilereader *ffr = xzalloc (sizeof *ffr);
209 struct casereader *reader = (struct casereader *) ffr;
211 casereader_register (cf, reader, CLASS_CASEREADER(&class_reader));
217 static struct casereader *
218 flexifilereader_clone (const struct casereader *cr)
220 const struct flexifilereader *ffr = (const struct flexifilereader *) cr;
221 struct flexifilereader *new_ffr = xzalloc (sizeof *new_ffr);
222 struct casereader *new_reader = (struct casereader *) new_ffr;
223 struct casefile *cf = casereader_get_casefile (cr);
225 casereader_register (cf, new_reader, CLASS_CASEREADER(&class_reader));
227 new_ffr->case_idx = ffr->case_idx ;
228 new_ffr->destructive = ffr->destructive ;
235 flexifile_in_core(const struct casefile *cf UNUSED)
237 /* Always in memory */
242 flexifile_error (const struct casefile *cf UNUSED )
249 flexifile_create (size_t value_cnt)
251 struct flexifile *ff = xzalloc (sizeof *ff);
252 struct casefile *cf = (struct casefile *) ff;
254 casefile_register (cf, (struct class_casefile *) &class);
256 ff->value_cnt = value_cnt;
258 ff->cases = xzalloc(sizeof (struct ccase *) * CHUNK_SIZE);
259 ff->capacity = CHUNK_SIZE;
264 static const struct class_flexifile class = {
268 flexifile_get_value_cnt,
269 flexifile_get_case_cnt,
270 flexifile_get_reader,
285 static const struct class_flexifilereader class_reader =
288 flexifilereader_get_next_case,
290 flexifilereader_destroy,
291 flexifilereader_clone
296 /* Implementations of class methods */
299 impl_get_case(const struct flexifile *ff, unsigned long casenum,
302 if ( casenum >= ff->case_cnt)
305 case_clone (c, &ff->cases[casenum]);
312 dumpcasedata(struct ccase *c)
315 for ( i = 0 ; i < c->case_data->value_cnt * MAX_SHORT_STRING; ++i )
316 putchar(c->case_data->values->s[i]);
322 impl_resize (struct flexifile *ff, int n_values, int posn)
326 for( i = 0 ; i < ff->case_cnt ; ++i )
329 case_create (&c, ff->value_cnt + n_values);
331 case_copy (&c, 0, &ff->cases[i], 0, posn);
333 memset (case_data_rw(&c, posn), ' ', n_values * MAX_SHORT_STRING) ;
334 case_copy (&c, posn + n_values,
335 &ff->cases[i], posn, ff->value_cnt - posn);
337 case_destroy (&ff->cases[i]);
341 ff->value_cnt += n_values;
347 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn)
354 if ( posn > ff->case_cnt )
357 if ( posn >= ff->capacity )
360 case_create(&blank, ff->value_cnt);
362 flexifile_append(CASEFILE(ff), &blank);
364 case_destroy(&blank);
366 /* Shift the existing cases down one */
367 for ( i = ff->case_cnt ; i > posn; --i)
368 case_move(&ff->cases[i], &ff->cases[i-1]);
370 case_clone (&ff->cases[posn], c);
377 impl_delete_cases (struct flexifile *ff, int n_cases, int first)
381 if ( ff->case_cnt < first + n_cases )
384 for ( i = first ; i < first + n_cases; ++i )
385 case_destroy (&ff->cases[i]);
387 /* Shift the cases up by N_CASES */
388 for ( i = first; i < ff->case_cnt - n_cases; ++i )
390 case_move (&ff->cases[i], &ff->cases[i+ n_cases]);
393 ff->case_cnt -= n_cases;