X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Faggregate.c;h=044297462c982a2d395a6ef66c9d26780015163d;hb=3e2cb3dda617f6d2a97e5df635d592a691d3c9b0;hp=4a4417165f5aa6a0b1b4b4b6f778d20400b1a128;hpb=888d0f91d57e0c3c5a4206c30ac71eb87bf44227;p=pspp diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index 4a4417165f..044297462c 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -1,6 +1,5 @@ /* PSPP - computes sample statistics. Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. - Written by Ben Pfaff . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -27,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -64,17 +64,17 @@ struct agr_var struct agr_var *next; /* Next in list. */ /* Collected during parsing. */ - struct variable *src; /* Source variable. */ + const struct variable *src; /* Source variable. */ struct variable *dest; /* Target variable. */ int function; /* Function. */ - int include_missing; /* 1=Include user-missing values. */ + enum mv_class exclude; /* Classes of missing values to exclude. */ union agr_argument arg[2]; /* Arguments. */ /* Accumulated during AGGREGATE execution. */ double dbl[3]; int int1, int2; char *string; - int missing; + bool saw_missing; struct moments1 *moments; }; @@ -93,36 +93,36 @@ struct agr_func { const char *name; /* Aggregation function name. */ size_t n_args; /* Number of arguments. */ - int alpha_type; /* When given ALPHA arguments, output type. */ + enum var_type alpha_type; /* When given ALPHA arguments, output type. */ struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */ }; /* Attributes of aggregation functions. */ static const struct agr_func agr_func_tab[] = { - {"", 0, -1, {0, 0, 0}}, - {"SUM", 0, -1, {FMT_F, 8, 2}}, - {"MEAN", 0, -1, {FMT_F, 8, 2}}, - {"SD", 0, -1, {FMT_F, 8, 2}}, - {"MAX", 0, ALPHA, {-1, -1, -1}}, - {"MIN", 0, ALPHA, {-1, -1, -1}}, - {"PGT", 1, NUMERIC, {FMT_F, 5, 1}}, - {"PLT", 1, NUMERIC, {FMT_F, 5, 1}}, - {"PIN", 2, NUMERIC, {FMT_F, 5, 1}}, - {"POUT", 2, NUMERIC, {FMT_F, 5, 1}}, - {"FGT", 1, NUMERIC, {FMT_F, 5, 3}}, - {"FLT", 1, NUMERIC, {FMT_F, 5, 3}}, - {"FIN", 2, NUMERIC, {FMT_F, 5, 3}}, - {"FOUT", 2, NUMERIC, {FMT_F, 5, 3}}, - {"N", 0, NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, NUMERIC, {FMT_F, 7, 0}}, - {"NMISS", 0, NUMERIC, {FMT_F, 7, 0}}, - {"NUMISS", 0, NUMERIC, {FMT_F, 7, 0}}, - {"FIRST", 0, ALPHA, {-1, -1, -1}}, - {"LAST", 0, ALPHA, {-1, -1, -1}}, - {NULL, 0, -1, {-1, -1, -1}}, - {"N", 0, NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, NUMERIC, {FMT_F, 7, 0}}, + {"", 0, -1, {0, 0, 0}}, + {"SUM", 0, -1, {FMT_F, 8, 2}}, + {"MEAN", 0, -1, {FMT_F, 8, 2}}, + {"SD", 0, -1, {FMT_F, 8, 2}}, + {"MAX", 0, VAR_STRING, {-1, -1, -1}}, + {"MIN", 0, VAR_STRING, {-1, -1, -1}}, + {"PGT", 1, VAR_NUMERIC, {FMT_F, 5, 1}}, + {"PLT", 1, VAR_NUMERIC, {FMT_F, 5, 1}}, + {"PIN", 2, VAR_NUMERIC, {FMT_F, 5, 1}}, + {"POUT", 2, VAR_NUMERIC, {FMT_F, 5, 1}}, + {"FGT", 1, VAR_NUMERIC, {FMT_F, 5, 3}}, + {"FLT", 1, VAR_NUMERIC, {FMT_F, 5, 3}}, + {"FIN", 2, VAR_NUMERIC, {FMT_F, 5, 3}}, + {"FOUT", 2, VAR_NUMERIC, {FMT_F, 5, 3}}, + {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, + {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, + {"NMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, + {"NUMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, + {"FIRST", 0, VAR_STRING, {-1, -1, -1}}, + {"LAST", 0, VAR_STRING, {-1, -1, -1}}, + {NULL, 0, -1, {-1, -1, -1}}, + {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, + {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, }; /* Missing value types. */ @@ -141,7 +141,7 @@ struct agr_proc /* Break variables. */ struct sort_criteria *sort; /* Sort criteria. */ - struct variable **break_vars; /* Break variables. */ + const struct variable **break_vars; /* Break variables. */ size_t break_var_cnt; /* Number of break variables. */ struct ccase break_case; /* Last values of break variables. */ @@ -164,12 +164,6 @@ static bool aggregate_single_case (struct agr_proc *agr, const struct ccase *input, struct ccase *output); static void dump_aggregate_info (struct agr_proc *agr, struct ccase *output); - -/* Aggregating to the active file. */ -static bool agr_to_active_file (const struct ccase *, void *aux, const struct dataset *); - -/* Aggregating to a system file. */ -static bool presorted_agr_to_sysfile (const struct ccase *, void *aux, const struct dataset *); /* Parsing. */ @@ -188,7 +182,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) memset(&agr, 0 , sizeof (agr)); agr.missing = ITEMWISE; case_nullify (&agr.break_case); - + agr.dict = dict_create (); agr.src_dict = dict; dict_set_label (agr.dict, dict_get_label (dict)); @@ -272,6 +266,8 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) /* Output to active file or external file? */ if (out_file == NULL) { + struct ccase *c; + /* The active file will be replaced by the aggregated data, so TEMPORARY is moot. */ proc_cancel_temporary_transformations (ds); @@ -282,14 +278,26 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) goto error; } - agr.sink = create_case_sink (&storage_sink_class, agr.dict, NULL); + agr.sink = create_case_sink (&storage_sink_class, agr.dict, + dataset_get_casefile_factory (ds), + NULL); if (agr.sink->class->open != NULL) agr.sink->class->open (agr.sink); proc_set_sink (ds, - create_case_sink (&null_sink_class, - dict, NULL)); - if (!procedure (ds, agr_to_active_file, &agr)) + create_case_sink (&null_sink_class, dict, + dataset_get_casefile_factory (ds), + NULL)); + proc_open (ds); + while (proc_read (ds, &c)) + if (aggregate_single_case (&agr, c, &agr.agr_case)) + if (!agr.sink->class->write (agr.sink, &agr.agr_case)) + { + proc_close (ds); + goto error; + } + if (!proc_close (ds)) goto error; + if (agr.case_cnt > 0) { dump_aggregate_info (&agr, &agr.agr_case); @@ -297,11 +305,9 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) goto error; } discard_variables (ds); - dict_destroy (dict); dataset_set_dict (ds, agr.dict); agr.dict = NULL; - proc_set_source (ds, - agr.sink->class->make_source (agr.sink)); + proc_set_source (ds, agr.sink->class->make_source (agr.sink)); free_case_sink (agr.sink); } else @@ -338,7 +344,17 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) else { /* Active file is already sorted. */ - if (!procedure (ds, presorted_agr_to_sysfile, &agr)) + struct ccase *c; + + proc_open (ds); + while (proc_read (ds, &c)) + if (aggregate_single_case (&agr, c, &agr.agr_case)) + if (!any_writer_write (agr.writer, &agr.agr_case)) + { + proc_close (ds); + goto error; + } + if (!proc_close (ds)) goto error; } @@ -374,13 +390,13 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s size_t n_dest; struct string function_name; - int include_missing; + enum mv_class exclude; const struct agr_func *function; int func_index; union agr_argument arg[2]; - struct variable **src; + const struct variable **src; size_t n_src; size_t i; @@ -393,6 +409,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s n_src = 0; arg[0].c = NULL; arg[1].c = NULL; + ds_init_empty (&function_name); /* Parse the list of target variables. */ while (!lex_match (lexer, '=')) @@ -433,14 +450,14 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s goto error; } - include_missing = 0; + exclude = MV_ANY; - ds_init_string (&function_name, lex_tokstr (lexer)); + ds_assign_string (&function_name, lex_tokstr (lexer)); ds_chomp (&function_name, '.'); if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.') - include_missing = 1; + exclude = MV_SYSTEM; for (function = agr_func_tab; function->name; function++) if (!strcasecmp (function->name, ds_cstr (&function_name))) @@ -479,7 +496,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s else if (function->n_args) pv_opts |= PV_SAME_TYPE; - if (!parse_variables (lexer, dict, &src, &n_src, pv_opts)) + if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts)) goto error; } @@ -494,15 +511,17 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s if (lex_token (lexer) == T_STRING) { arg[i].c = ds_xstrdup (lex_tokstr (lexer)); - type = ALPHA; + type = VAR_STRING; } else if (lex_is_number (lexer)) { arg[i].f = lex_tokval (lexer); - type = NUMERIC; - } else { - msg (SE, _("Missing argument %d to %s."), i + 1, - function->name); + type = VAR_NUMERIC; + } + else + { + msg (SE, _("Missing argument %d to %s."), + (int) i + 1, function->name); goto error; } @@ -587,12 +606,12 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s v->string = xmalloc (var_get_width (src[i])); } - if (function->alpha_type == ALPHA) + if (function->alpha_type == VAR_STRING) destvar = dict_clone_var (agr->dict, v->src, dest[i]); else { assert (var_is_numeric (v->src) - || function->alpha_type == NUMERIC); + || function->alpha_type == VAR_NUMERIC); destvar = dict_create_var (agr->dict, dest[i], 0); if (destvar != NULL) { @@ -633,7 +652,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s v->dest = destvar; } - v->include_missing = include_missing; + v->exclude = exclude; if (v->src != NULL) { @@ -771,12 +790,10 @@ accumulate_aggregate_info (struct agr_proc *agr, for (iter = agr->agr_vars; iter; iter = iter->next) if (iter->src) { - const union value *v = case_data (input, iter->src->fv); + const union value *v = case_data (input, iter->src); int src_width = var_get_width (iter->src); - if (iter->include_missing - ? var_is_numeric (iter->src) && v->f == SYSMIS - : var_is_value_missing (iter->src, v)) + if (var_is_value_missing (iter->src, v, iter->exclude)) { switch (iter->function) { @@ -789,7 +806,7 @@ accumulate_aggregate_info (struct agr_proc *agr, iter->int1++; break; } - iter->missing = 1; + iter->saw_missing = true; continue; } @@ -942,10 +959,10 @@ dump_aggregate_info (struct agr_proc *agr, struct ccase *output) for (i = 0; i < agr->break_var_cnt; i++) { - struct variable *v = agr->break_vars[i]; + const struct variable *v = agr->break_vars[i]; size_t value_cnt = var_get_value_cnt (v); - memcpy (case_data_rw (output, value_idx), - case_data (&agr->break_case, v->fv), + memcpy (case_data_rw_idx (output, value_idx), + case_data (&agr->break_case, v), sizeof (union value) * value_cnt); value_idx += value_cnt; } @@ -956,9 +973,9 @@ dump_aggregate_info (struct agr_proc *agr, struct ccase *output) for (i = agr->agr_vars; i; i = i->next) { - union value *v = case_data_rw (output, i->dest->fv); + union value *v = case_data_rw (output, i->dest); - if (agr->missing == COLUMNWISE && i->missing != 0 + if (agr->missing == COLUMNWISE && i->saw_missing && (i->function & FUNC) != N && (i->function & FUNC) != NU && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS) { @@ -1072,7 +1089,7 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) for (iter = agr->agr_vars; iter; iter = iter->next) { - iter->missing = 0; + iter->saw_missing = false; iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0; iter->int1 = iter->int2 = 0; switch (iter->function) @@ -1100,31 +1117,3 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) } } } - -/* Aggregate each case as it comes through. Cases which aren't needed - are dropped. - Returns true if successful, false if an I/O error occurred. */ -static bool -agr_to_active_file (const struct ccase *c, void *agr_, const struct dataset *ds UNUSED) -{ - struct agr_proc *agr = agr_; - - if (aggregate_single_case (agr, c, &agr->agr_case)) - return agr->sink->class->write (agr->sink, &agr->agr_case); - - return true; -} - -/* Aggregate the current case and output it if we passed a - breakpoint. */ -static bool -presorted_agr_to_sysfile (const struct ccase *c, void *agr_, - const struct dataset *ds UNUSED) -{ - struct agr_proc *agr = agr_; - - if (aggregate_single_case (agr, c, &agr->agr_case)) - return any_writer_write (agr->writer, &agr->agr_case); - - return true; -}