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"
26 #include <data/casefile.h>
27 #include <data/casefile-private.h>
28 #include <data/case.h>
29 #include <libpspp/compiler.h>
32 struct class_flexifile
34 struct class_casefile parent;
36 bool (*get_case) (const struct flexifile *, unsigned long, struct ccase *);
38 bool (*insert_case) (struct flexifile *, struct ccase *, int );
39 bool (*delete_cases) (struct flexifile *, int, int );
41 bool (*resize) (struct flexifile *, int, int );
44 static const struct class_flexifile class;
46 #define CLASS_FLEXIFILE(K) ((struct class_flexifile *) K)
47 #define CONST_CLASS_FLEXIFILE(K) ((const struct class_flexifile *) K)
53 struct casefile cf; /* Parent */
55 size_t value_cnt; /* Case size in `union value's. */
56 unsigned long case_cnt; /* Number of cases stored. */
60 struct ccase *cases; /* Pointer to array of cases. */
61 unsigned long capacity; /* size of array in cases */
64 struct class_flexifilereader
66 struct class_casereader parent ;
69 static const struct class_flexifilereader class_reader;
71 /* For reading out the cases in a flexifile. */
72 struct flexifilereader
74 struct casereader cr; /* Parent */
76 unsigned long case_idx; /* Case number of current case. */
77 bool destructive; /* Is this a destructive reader? */
85 impl_get_case(const struct flexifile *ff, unsigned long casenum,
88 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn);
91 impl_delete_cases (struct flexifile *ff, int n_cases, int first);
94 impl_resize (struct flexifile *ff, int n_values, int posn);
97 /* Gets a case, for which writing may not be safe */
99 flexifile_get_case(const struct flexifile *ff, unsigned long casenum,
102 const struct class_flexifile *class =
103 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
105 return class->get_case(ff, casenum, c);
109 /* Insert N_VALUES before POSN.
110 If N_VALUES is negative, then deleted -N_VALUES instead
113 flexifile_resize (struct flexifile *ff, int n_values, int posn)
115 const struct class_flexifile *class =
116 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
118 return class->resize(ff, n_values, posn);
124 flexifile_insert_case (struct flexifile *ff, struct ccase *c, int posn)
126 const struct class_flexifile *class =
127 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
129 return class->insert_case(ff, c, posn);
134 flexifile_delete_cases (struct flexifile *ff, int n_cases, int first)
136 const struct class_flexifile *class =
137 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
139 return class->delete_cases (ff, n_cases, first);
144 flexifile_get_case_cnt (const struct casefile *cf)
146 return FLEXIFILE(cf)->case_cnt;
150 flexifile_get_value_cnt (const struct casefile *cf)
152 return FLEXIFILE(cf)->value_cnt;
157 flexifile_destroy (struct casefile *cf)
160 for ( i = 0 ; i < FLEXIFILE(cf)->case_cnt; ++i )
161 case_destroy( &FLEXIFILE(cf)->cases[i]);
163 free(FLEXIFILE(cf)->cases);
167 grow(struct flexifile *ff)
169 ff->capacity += CHUNK_SIZE;
170 ff->cases = xrealloc(ff->cases, ff->capacity * sizeof ( *ff->cases) );
174 flexifile_append (struct casefile *cf, const struct ccase *c)
176 struct flexifile *ff = FLEXIFILE(cf);
178 if (ff->case_cnt >= ff->capacity)
181 case_clone (&ff->cases[ff->case_cnt++], c);
187 static struct ccase *
188 flexifilereader_get_next_case (struct casereader *cr)
190 struct flexifilereader *ffr = FLEXIFILEREADER(cr);
191 struct flexifile *ff = FLEXIFILE(casereader_get_casefile(cr));
193 if ( ffr->case_idx >= ff->case_cnt)
196 return &ff->cases[ffr->case_idx++];
200 flexifilereader_destroy(struct casereader *r)
205 static struct casereader *
206 flexifile_get_reader (const struct casefile *cf_)
208 struct casefile *cf = (struct casefile *) cf_;
209 struct flexifilereader *ffr = xzalloc (sizeof *ffr);
210 struct casereader *reader = (struct casereader *) ffr;
212 casereader_register (cf, reader, CLASS_CASEREADER(&class_reader));
218 static struct casereader *
219 flexifilereader_clone (const struct casereader *cr)
221 const struct flexifilereader *ffr = (const struct flexifilereader *) cr;
222 struct flexifilereader *new_ffr = xzalloc (sizeof *new_ffr);
223 struct casereader *new_reader = (struct casereader *) new_ffr;
224 struct casefile *cf = casereader_get_casefile (cr);
226 casereader_register (cf, new_reader, CLASS_CASEREADER(&class_reader));
228 new_ffr->case_idx = ffr->case_idx ;
229 new_ffr->destructive = ffr->destructive ;
236 flexifile_in_core(const struct casefile *cf UNUSED)
238 /* Always in memory */
243 flexifile_error (const struct casefile *cf UNUSED )
250 flexifile_create (size_t value_cnt)
252 struct flexifile *ff = xzalloc (sizeof *ff);
253 struct casefile *cf = (struct casefile *) ff;
255 casefile_register (cf, (struct class_casefile *) &class);
257 ff->value_cnt = value_cnt;
259 ff->cases = xzalloc(sizeof (struct ccase *) * CHUNK_SIZE);
260 ff->capacity = CHUNK_SIZE;
265 static const struct class_flexifile class = {
269 flexifile_get_value_cnt,
270 flexifile_get_case_cnt,
271 flexifile_get_reader,
286 static const struct class_flexifilereader class_reader =
289 flexifilereader_get_next_case,
291 flexifilereader_destroy,
292 flexifilereader_clone
297 /* Implementations of class methods */
300 impl_get_case(const struct flexifile *ff, unsigned long casenum,
303 if ( casenum >= ff->case_cnt)
306 case_clone (c, &ff->cases[casenum]);
313 dumpcasedata(struct ccase *c)
316 for ( i = 0 ; i < c->case_data->value_cnt * MAX_SHORT_STRING; ++i )
317 putchar(c->case_data->values->s[i]);
323 impl_resize (struct flexifile *ff, int n_values, int posn)
327 for( i = 0 ; i < ff->case_cnt ; ++i )
330 case_create (&c, ff->value_cnt + n_values);
332 case_copy (&c, 0, &ff->cases[i], 0, posn);
334 memset (case_data_rw(&c, posn), ' ', n_values * MAX_SHORT_STRING) ;
335 case_copy (&c, posn + n_values,
336 &ff->cases[i], posn, ff->value_cnt - posn);
338 case_destroy (&ff->cases[i]);
342 ff->value_cnt += n_values;
348 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn)
355 if ( posn > ff->case_cnt )
358 if ( posn >= ff->capacity )
361 case_create(&blank, ff->value_cnt);
363 flexifile_append(CASEFILE(ff), &blank);
365 case_destroy(&blank);
367 /* Shift the existing cases down one */
368 for ( i = ff->case_cnt ; i > posn; --i)
369 case_move(&ff->cases[i], &ff->cases[i-1]);
371 case_clone (&ff->cases[posn], c);
378 impl_delete_cases (struct flexifile *ff, int n_cases, int first)
382 if ( ff->case_cnt < first + n_cases )
385 for ( i = first ; i < first + n_cases; ++i )
386 case_destroy (&ff->cases[i]);
388 /* Shift the cases up by N_CASES */
389 for ( i = first; i < ff->case_cnt - n_cases; ++i )
391 case_move (&ff->cases[i], &ff->cases[i+ n_cases]);
394 ff->case_cnt -= n_cases;