X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fcasegrouper.c;h=f5974a404b0a6200729548a62a2d67afde684323;hb=29e80fa3921b20d8c24d9f31263d7bfe531ef6ea;hp=eee08700adbae4e2304d30b44d478fafe8c01263;hpb=dc78471910e82d59232ce9b137b7c4fc4992d174;p=pspp-builds.git diff --git a/src/data/casegrouper.c b/src/data/casegrouper.c index eee08700..f5974a40 100644 --- a/src/data/casegrouper.c +++ b/src/data/casegrouper.c @@ -1,20 +1,18 @@ -/* PSPP - computes sample statistics. +/* PSPP - a program for statistical analysis. Copyright (C) 2007 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include @@ -30,23 +28,34 @@ #include "xalloc.h" -struct casegrouper +/* A casegrouper. */ +struct casegrouper { - struct casereader *reader; - struct taint *taint; - + struct casereader *reader; /* Source of input cases. */ + struct taint *taint; /* Error status for casegrouper. */ + + /* Functions for grouping cases. */ bool (*same_group) (const struct ccase *, const struct ccase *, void *aux); void (*destroy) (void *aux); void *aux; }; +/* Creates and returns a new casegrouper that takes its input + from READER. SAME_GROUP is used to decide which cases are in + a group: it returns true if the pair of cases provided are in + the same group, false otherwise. DESTROY will be called when + the casegrouper is destroyed and should free any storage + needed by SAME_GROUP. + + SAME_GROUP may be a null pointer. If so, READER's entire + contents is considered to be a single group. */ struct casegrouper * casegrouper_create_func (struct casereader *reader, bool (*same_group) (const struct ccase *, const struct ccase *, void *aux), void (*destroy) (void *aux), - void *aux) + void *aux) { struct casegrouper *grouper = xmalloc (sizeof *grouper); grouper->reader = casereader_rename (reader); @@ -57,22 +66,26 @@ casegrouper_create_func (struct casereader *reader, return grouper; } -/* FIXME: we really shouldn't need a temporary casewriter for the - common case where we read an entire group's data before going - on to the next. */ +/* Obtains the next group of cases from GROUPER. Returns true if + successful, false if no groups remain. If successful, *READER + is set to the casereader for the new group; otherwise, it is + set to NULL. */ bool casegrouper_get_next_group (struct casegrouper *grouper, struct casereader **reader) { - if (grouper->same_group != NULL) + /* FIXME: we really shouldn't need a temporary casewriter for + the common case where we read an entire group's data before + going on to the next. */ + if (grouper->same_group != NULL) { struct casewriter *writer; struct ccase group_case, tmp; - if (!casereader_read (grouper->reader, &group_case)) + if (!casereader_read (grouper->reader, &group_case)) { *reader = NULL; - return false; + return false; } writer = autopaging_writer_create (casereader_get_value_cnt (grouper->reader)); @@ -85,7 +98,7 @@ casegrouper_get_next_group (struct casegrouper *grouper, struct ccase discard; casereader_read (grouper->reader, &discard); case_destroy (&discard); - casewriter_write (writer, &tmp); + casewriter_write (writer, &tmp); } case_destroy (&tmp); case_destroy (&group_case); @@ -93,23 +106,39 @@ casegrouper_get_next_group (struct casegrouper *grouper, *reader = casewriter_make_reader (writer); return true; } - else + else { - if (grouper->reader != NULL) + if (grouper->reader != NULL) { - *reader = grouper->reader; - grouper->reader = NULL; - return true; + if (!casereader_is_empty (grouper->reader)) + { + *reader = grouper->reader; + grouper->reader = NULL; + return true; + } + else + { + casereader_destroy (grouper->reader); + grouper->reader = NULL; + return false; + } } else - return false; - } + { + *reader = NULL; + return false; + } + } } +/* Destroys GROUPER. Returns false if GROUPER's input casereader + or any state derived from it had become tainted, which means + that an I/O error or other serious error occurred in + processing data derived from GROUPER; otherwise, return true. */ bool -casegrouper_destroy (struct casegrouper *grouper) +casegrouper_destroy (struct casegrouper *grouper) { - if (grouper != NULL) + if (grouper != NULL) { struct taint *taint = grouper->taint; bool ok; @@ -126,35 +155,32 @@ casegrouper_destroy (struct casegrouper *grouper) else return true; } + +/* Casegrouper based on equal values of variables from case to + case. */ -struct casegrouper_vars +/* Casegrouper based on equal variables. */ +struct casegrouper_vars { - const struct variable **vars; - size_t var_cnt; + const struct variable **vars; /* Variables to compare. */ + size_t var_cnt; /* Number of variables. */ }; -static bool -casegrouper_vars_same_group (const struct ccase *a, const struct ccase *b, - void *cv_) -{ - struct casegrouper_vars *cv = cv_; - return case_compare (a, b, cv->vars, cv->var_cnt) == 0; -} - -static void -casegrouper_vars_destroy (void *cv_) -{ - struct casegrouper_vars *cv = cv_; - free (cv->vars); - free (cv); -} +static bool casegrouper_vars_same_group (const struct ccase *, + const struct ccase *, + void *); +static void casegrouper_vars_destroy (void *); +/* Creates and returns a casegrouper that reads data from READER + and breaks it into contiguous groups of cases that have equal + values for the VAR_CNT variables in VARS. If VAR_CNT is 0, + then all the cases will be put in a single group. */ struct casegrouper * casegrouper_create_vars (struct casereader *reader, const struct variable *const *vars, - size_t var_cnt) + size_t var_cnt) { - if (var_cnt > 0) + if (var_cnt > 0) { struct casegrouper_vars *cv = xmalloc (sizeof *cv); cv->vars = xmemdup (vars, sizeof *vars * var_cnt); @@ -168,18 +194,28 @@ casegrouper_create_vars (struct casereader *reader, return casegrouper_create_func (reader, NULL, NULL, NULL); } +/* Creates and returns a casegrouper that reads data from READER + and breaks it into contiguous groups of cases that have equal + values for the SPLIT FILE variables in DICT. If DICT has no + SPLIT FILE variables, then all the cases will be put into a + single group. */ struct casegrouper * casegrouper_create_splits (struct casereader *reader, - const struct dictionary *dict) + const struct dictionary *dict) { return casegrouper_create_vars (reader, dict_get_split_vars (dict), dict_get_split_cnt (dict)); } +/* Creates and returns a casegrouper that reads data from READER + and breaks it into contiguous groups of cases that have equal + values for the variables used for sorting in CO. If CO is + empty (contains no sort keys), then all the cases will be put + into a single group. */ struct casegrouper * casegrouper_create_case_ordering (struct casereader *reader, - const struct case_ordering *co) + const struct case_ordering *co) { const struct variable **vars; size_t var_cnt; @@ -191,3 +227,22 @@ casegrouper_create_case_ordering (struct casereader *reader, return grouper; } + +/* "same_group" function for an equal-variables casegrouper. */ +static bool +casegrouper_vars_same_group (const struct ccase *a, const struct ccase *b, + void *cv_) +{ + struct casegrouper_vars *cv = cv_; + return case_compare (a, b, cv->vars, cv->var_cnt) == 0; +} + +/* "destroy" for an equal-variables casegrouper. */ +static void +casegrouper_vars_destroy (void *cv_) +{ + struct casegrouper_vars *cv = cv_; + free (cv->vars); + free (cv); +} +