X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fprocedure.c;h=6690490f30681ef129ab34cb86b033a5159aa701;hb=c17ea35a73b7a690a54c5c6a213de19f0376e74f;hp=46a18bb463297fdf735a6e30a2d2207c0dc45e9a;hpb=92c09e564002d356d20fc1e2e131027ef89f6748;p=pspp diff --git a/src/data/procedure.c b/src/data/procedure.c index 46a18bb463..6690490f30 100644 --- a/src/data/procedure.c +++ b/src/data/procedure.c @@ -1,20 +1,18 @@ -/* PSPP - computes sample statistics. +/* PSPP - a program for statistical analysis. Copyright (C) 1997-9, 2000, 2006, 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 @@ -39,6 +37,7 @@ #include #include + struct dataset { /* Cases are read from source, their transformation variables are initialized, @@ -63,6 +62,11 @@ struct dataset { /* Callback which occurs whenever the DICT is replaced by a new one */ replace_dictionary_callback *replace_dict; + /* Callback which occurs whenever the transformation chain(s) have + been modified */ + transformation_change_callback_func *xform_callback; + void *xform_callback_aux; + /* If true, cases are discarded instead of being written to sink. */ bool discard_output; @@ -84,14 +88,15 @@ struct dataset { struct ccase *lag_cases; /* Lagged cases managed by deque. */ /* Procedure data. */ - enum + enum { - PROC_COMMITTED, - PROC_OPEN, - PROC_CLOSED + PROC_COMMITTED, /* No procedure in progress. */ + PROC_OPEN, /* proc_open called, casereader still open. */ + PROC_CLOSED /* casereader from proc_open destroyed, + but proc_commit not yet called. */ } proc_state; - size_t cases_written; /* Cases output so far. */ + casenumber cases_written; /* Cases output so far. */ bool ok; /* Error status. */ }; /* struct dataset */ @@ -163,15 +168,15 @@ proc_open (struct dataset *ds) ds->permanent_dict = ds->dict; /* Prepare sink. */ - if (!ds->discard_output) + if (!ds->discard_output) { ds->compactor = (dict_compacting_would_shrink (ds->permanent_dict) ? dict_make_compactor (ds->permanent_dict) : NULL); ds->sink = autopaging_writer_create (dict_get_compacted_value_cnt ( - ds->permanent_dict)); + ds->permanent_dict)); } - else + else { ds->compactor = NULL; ds->sink = NULL; @@ -193,29 +198,26 @@ proc_open (struct dataset *ds) &proc_casereader_class, ds); } +/* Returns true if a procedure is in progress, that is, if + proc_open has been called but proc_commit has not. */ bool -proc_is_open (const struct dataset *ds) +proc_is_open (const struct dataset *ds) { return ds->proc_state != PROC_COMMITTED; } -/* Reads the next case from dataset DS, which must have been - opened for reading with proc_open. - Returns true if successful, in which case a pointer to the - case is stored in *C. - Return false at end of file or if a read error occurs. In - this case a null pointer is stored in *C. */ +/* "read" function for procedure casereader. */ static bool proc_casereader_read (struct casereader *reader UNUSED, void *ds_, - struct ccase *c) + struct ccase *c) { struct dataset *ds = ds_; enum trns_result retval = TRNS_DROP_CASE; assert (ds->proc_state == PROC_OPEN); - for (;;) + for (;;) { - size_t case_nr; + casenumber case_nr; assert (retval == TRNS_DROP_CASE || retval == TRNS_ERROR); if (retval == TRNS_ERROR) @@ -227,22 +229,21 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_, if (!casereader_read (ds->source, c)) return false; case_resize (c, dict_get_next_value_idx (ds->dict)); - caseinit_init_reinit_vars (ds->caseinit, c); - caseinit_init_left_vars (ds->caseinit, c); + caseinit_init_vars (ds->caseinit, c); /* Execute permanent transformations. */ case_nr = ds->cases_written + 1; retval = trns_chain_execute (ds->permanent_trns_chain, TRNS_CONTINUE, - c, &case_nr); + c, case_nr); caseinit_update_left_vars (ds->caseinit, c); - if (retval != TRNS_CONTINUE) + if (retval != TRNS_CONTINUE) { case_destroy (c); - continue; + continue; } - + /* Write case to collection of lagged cases. */ - if (ds->n_lag > 0) + if (ds->n_lag > 0) { while (deque_count (&ds->lag) >= ds->n_lag) case_destroy (&ds->lag_cases[deque_pop_back (&ds->lag)]); @@ -251,10 +252,10 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_, /* Write case to replacement active file. */ ds->cases_written++; - if (ds->sink != NULL) + if (ds->sink != NULL) { struct ccase tmp; - if (ds->compactor != NULL) + if (ds->compactor != NULL) { case_create (&tmp, dict_get_compacted_value_cnt (ds->dict)); dict_compactor_compact (ds->compactor, &tmp, c); @@ -268,7 +269,7 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_, if (ds->temporary_trns_chain != NULL) { retval = trns_chain_execute (ds->temporary_trns_chain, TRNS_CONTINUE, - c, &ds->cases_written); + c, ds->cases_written); if (retval != TRNS_CONTINUE) { case_destroy (c); @@ -280,11 +281,7 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_, } } -/* Closes dataset DS for reading. - Returns true if successful, false if an I/O error occurred - while reading or closing the data set. - If DS has not been opened, returns true without doing - anything else. */ +/* "destroy" function for procedure casereader. */ static void proc_casereader_destroy (struct casereader *reader, void *ds_) { @@ -309,7 +306,7 @@ proc_casereader_destroy (struct casereader *reader, void *ds_) false, but the replacement active file may still be untainted.) */ bool -proc_commit (struct dataset *ds) +proc_commit (struct dataset *ds) { assert (ds->proc_state == PROC_CLOSED); ds->proc_state = PROC_COMMITTED; @@ -322,24 +319,24 @@ proc_commit (struct dataset *ds) /* Dictionary from before TEMPORARY becomes permanent. */ proc_cancel_temporary_transformations (ds); - if (!ds->discard_output) + if (!ds->discard_output) { /* Finish compacting. */ - if (ds->compactor != NULL) + if (ds->compactor != NULL) { dict_compactor_destroy (ds->compactor); dict_compact_values (ds->dict); ds->compactor = NULL; } - + /* Old data sink becomes new data source. */ - if (ds->sink != NULL) + if (ds->sink != NULL) ds->source = casewriter_make_reader (ds->sink); } - else + else { ds->source = NULL; - ds->discard_output = false; + ds->discard_output = false; } ds->sink = NULL; if ( ds->replace_source) ds->replace_source (ds->source); @@ -352,7 +349,8 @@ proc_commit (struct dataset *ds) return proc_cancel_all_transformations (ds) && ds->ok; } -static struct casereader_class proc_casereader_class = +/* Casereader class for procedure execution. */ +static struct casereader_class proc_casereader_class = { proc_casereader_read, proc_casereader_destroy, @@ -392,6 +390,10 @@ proc_capture_transformations (struct dataset *ds) assert (ds->temporary_trns_chain == NULL); chain = ds->permanent_trns_chain; ds->cur_trns_chain = ds->permanent_trns_chain = trns_chain_create (); + + if ( ds->xform_callback) + ds->xform_callback (false, ds->xform_callback_aux); + return chain; } @@ -402,6 +404,8 @@ void add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *free, void *aux) { trns_chain_append (ds->cur_trns_chain, NULL, proc, free, aux); + if ( ds->xform_callback) + ds->xform_callback (true, ds->xform_callback_aux); } /* Adds a transformation that processes a case with PROC and @@ -416,6 +420,9 @@ add_transformation_with_finalizer (struct dataset *ds, trns_free_func *free, void *aux) { trns_chain_append (ds->cur_trns_chain, finalize, proc, free, aux); + + if ( ds->xform_callback) + ds->xform_callback (true, ds->xform_callback_aux); } /* Returns the index of the next transformation. @@ -450,6 +457,9 @@ proc_start_temporary_transformations (struct dataset *ds) trns_chain_finalize (ds->permanent_trns_chain); ds->temporary_trns_chain = ds->cur_trns_chain = trns_chain_create (); + + if ( ds->xform_callback) + ds->xform_callback (true, ds->xform_callback_aux); } } @@ -491,6 +501,10 @@ proc_cancel_temporary_transformations (struct dataset *ds) trns_chain_destroy (ds->temporary_trns_chain); ds->temporary_trns_chain = NULL; + if ( ds->xform_callback) + ds->xform_callback (!trns_chain_is_empty (ds->permanent_trns_chain), + ds->xform_callback_aux); + return true; } else @@ -508,23 +522,35 @@ proc_cancel_all_transformations (struct dataset *ds) ok = trns_chain_destroy (ds->temporary_trns_chain) && ok; ds->permanent_trns_chain = ds->cur_trns_chain = trns_chain_create (); ds->temporary_trns_chain = NULL; + if ( ds->xform_callback) + ds->xform_callback (false, ds->xform_callback_aux); + return ok; } /* Initializes procedure handling. */ struct dataset * -create_dataset (replace_source_callback *rps, - replace_dictionary_callback *rds) +create_dataset (transformation_change_callback_func *cb, void *aux) { struct dataset *ds = xzalloc (sizeof(*ds)); ds->dict = dict_create (); ds->caseinit = caseinit_create (); - ds->replace_source = rps; - ds->replace_dict = rds; + ds->xform_callback = cb; + ds->xform_callback_aux = aux; proc_cancel_all_transformations (ds); return ds; } + +void +dataset_add_transform_change_callback (struct dataset *ds, + transformation_change_callback_func *cb, + void *aux) +{ + ds->xform_callback = cb; + ds->xform_callback_aux = aux; +} + /* Finishes up procedure handling. */ void destroy_dataset (struct dataset *ds) @@ -533,13 +559,16 @@ destroy_dataset (struct dataset *ds) dict_destroy (ds->dict); caseinit_destroy (ds->caseinit); trns_chain_destroy (ds->permanent_trns_chain); + + if ( ds->xform_callback) + ds->xform_callback (false, ds->xform_callback_aux); free (ds); } /* Causes output from the next procedure to be discarded, instead of being preserved for use as input for the next procedure. */ void -proc_discard_output (struct dataset *ds) +proc_discard_output (struct dataset *ds) { ds->discard_output = true; } @@ -555,7 +584,7 @@ proc_discard_active_file (struct dataset *ds) fh_set_default_handle (NULL); ds->n_lag = 0; - + casereader_destroy (ds->source); ds->source = NULL; if ( ds->replace_source) ds->replace_source (NULL); @@ -568,7 +597,7 @@ proc_discard_active_file (struct dataset *ds) void proc_set_active_file (struct dataset *ds, struct casereader *source, - struct dictionary *dict) + struct dictionary *dict) { assert (ds->proc_state == PROC_COMMITTED); assert (ds->dict != dict); @@ -585,7 +614,7 @@ proc_set_active_file (struct dataset *ds, /* Replaces the active file's data by READER without replacing the associated dictionary. */ bool -proc_set_active_file_data (struct dataset *ds, struct casereader *reader) +proc_set_active_file_data (struct dataset *ds, struct casereader *reader) { casereader_destroy (ds->source); ds->source = reader; @@ -600,7 +629,7 @@ proc_set_active_file_data (struct dataset *ds, struct casereader *reader) /* Returns true if an active file data source is available, false otherwise. */ bool -proc_has_active_file (const struct dataset *ds) +proc_has_active_file (const struct dataset *ds) { return ds->source != NULL; } @@ -609,23 +638,23 @@ proc_has_active_file (const struct dataset *ds) discards it and returns false. If not, returns true without doing anything. */ bool -dataset_end_of_command (struct dataset *ds) +dataset_end_of_command (struct dataset *ds) { - if (ds->source != NULL) + if (ds->source != NULL) { - if (casereader_error (ds->source)) + if (casereader_error (ds->source)) { proc_discard_active_file (ds); return false; } - else + else { const struct taint *taint = casereader_get_taint (ds->source); taint_reset_successor_taint ((struct taint *) taint); assert (!taint_has_tainted_successor (taint)); } } - return true; + return true; } static trns_proc_func case_limit_trns_proc; @@ -706,7 +735,13 @@ dataset_dict (const struct dataset *ds) return ds->dict; } -void +const struct casereader * +dataset_source (const struct dataset *ds) +{ + return ds->source; +} + +void dataset_need_lag (struct dataset *ds, int n_before) { ds->n_lag = MAX (ds->n_lag, n_before);