X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fvfm.c;h=42e6b7ccd29dfef5e2b5792cbe16c705fdceaec9;hb=d4d9866bb2ec1797b8fb103e7144d0e9ffd1abff;hp=173bbb0f4a00cb33f8c0f9b44084d251bce809ba;hpb=5906e30c29662d12594199e1652ba3a7e5670944;p=pspp-builds.git diff --git a/src/vfm.c b/src/vfm.c index 173bbb0f..42e6b7cc 100644 --- a/src/vfm.c +++ b/src/vfm.c @@ -28,7 +28,6 @@ #include /* Required by SunOS4. */ #endif #include "alloc.h" -#include "approx.h" #include "do-ifP.h" #include "error.h" #include "expr.h" @@ -62,12 +61,6 @@ struct write_case_data /* This is used to read from the active file. */ struct case_stream *vfm_source; -/* `value' indexes to initialize to particular values for certain cases. */ -struct long_vec reinit_sysmis; /* SYSMIS for every case. */ -struct long_vec reinit_blanks; /* Blanks for every case. */ -struct long_vec init_zero; /* Zero for first case only. */ -struct long_vec init_blanks; /* Blanks for first case only. */ - /* This is used to write to the replacement active file. */ struct case_stream *vfm_sink; @@ -77,17 +70,6 @@ struct stream_info vfm_source_info; /* Information about the data sink. */ struct stream_info vfm_sink_info; -/* Filter variable and `value' index. */ -static struct variable *filter_var; -static int filter_index; - -#define FILTERED \ - (filter_index != -1 \ - && (temp_case->data[filter_index].f == 0.0 \ - || temp_case->data[filter_index].f == SYSMIS \ - || is_num_user_missing (temp_case->data[filter_index].f, \ - filter_var))) - /* Nonzero if the case needs to have values deleted before being stored, zero otherwise. */ int compaction_necessary; @@ -122,12 +104,14 @@ static int SPLIT_FILE_procfunc (struct ccase *, void *); static void finish_compaction (void); static void lag_case (void); static int procedure_write_case (struct write_case_data *); +static void clear_temp_case (void); +static int exclude_this_case (void); /* Public functions. */ /* Reads all the cases from the active file, transforms them by the active set of transformations, calls PROCFUNC with CURCASE - set to the case , and writes them to a new active file. + set to the case, and writes them to a new active file. Divides the active file into zero or more series of one or more cases each. BEGINFUNC is called before each series. ENDFUNC is @@ -141,9 +125,13 @@ procedure (void (*beginfunc) (void *), void (*endfunc) (void *), void *aux) { + static int recursive_call; + struct write_case_data procedure_write_data; struct write_case_data split_file_data; + assert (++recursive_call == 1); + if (dict_get_split_cnt (default_dict) == 0) { /* Normally we just use the data passed by the user. */ @@ -171,6 +159,8 @@ procedure (void (*beginfunc) (void *), open_active_file (); vfm_source->read (procedure_write_case, &procedure_write_data); close_active_file (&procedure_write_data); + + assert (--recursive_call == 0); } /* Active file processing support. Subtly different semantics from @@ -247,25 +237,14 @@ process_active_file_write_case (struct write_case_data *data) lag_case (); /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */ - if (not_canceled - && !FILTERED - && (process_if_expr == NULL || - expr_evaluate (process_if_expr, temp_case, NULL) == 1.0)) + if (not_canceled && !exclude_this_case ()) not_canceled = data->procfunc (temp_case, data->aux); case_count++; done: - { - long *lp; + clear_temp_case (); - /* This case is finished. Initialize the variables for the next case. */ - for (lp = reinit_sysmis.vec; *lp != -1;) - temp_case->data[*lp++].f = SYSMIS; - for (lp = reinit_blanks.vec; *lp != -1;) - memset (temp_case->data[*lp++].s, ' ', MAX_SHORT_STRING); - } - return 1; } @@ -301,10 +280,8 @@ prepare_for_writing (void) file--it's just a waste of time and space. */ vfm_sink_info.ncases = 0; - vfm_sink_info.nval = dict_get_value_cnt (default_dict); - vfm_sink_info.case_size = (sizeof (struct ccase) - + ((dict_get_value_cnt (default_dict) - 1) - * sizeof (union value))); + vfm_sink_info.nval = dict_get_next_value_idx (default_dict); + vfm_sink_info.case_size = dict_get_case_size (default_dict); if (vfm_sink == NULL) { @@ -344,14 +321,17 @@ arrange_compaction (void) count_values += v->nv; } } - assert (temporary == 2 || count_values <= dict_get_value_cnt (temp_dict)); + assert (temporary == 2 + || count_values <= dict_get_next_value_idx (temp_dict)); } /* Compaction is only necessary if the number of `value's to output differs from the number already present. */ compaction_nval = count_values; - compaction_necessary = (temporary == 2 - || count_values != dict_get_value_cnt (temp_dict)); + if (temporary == 2 || count_values != dict_get_next_value_idx (temp_dict)) + compaction_necessary = 1; + else + compaction_necessary = 0; if (vfm_sink->init) vfm_sink->init (); @@ -387,62 +367,28 @@ index_to_varname (int ccase_index) } #endif -/* Initializes temp_case from the vectors that say which `value's need - to be initialized just once, and which ones need to be +/* Initializes temp_case from the vectors that say which `value's + need to be initialized just once, and which ones need to be re-initialized before every case. */ static void vector_initialization (void) { - int i; - long *lp; - - /* Just once. */ - for (i = 0; i < init_zero.n; i++) - temp_case->data[init_zero.vec[i]].f = 0.0; - for (i = 0; i < init_blanks.n; i++) - memset (temp_case->data[init_blanks.vec[i]].s, ' ', MAX_SHORT_STRING); - - /* These vectors need to be repeatedly accessed, so we add a - sentinel to (hopefully) improve speed. */ - vec_insert (&reinit_sysmis, -1); - vec_insert (&reinit_blanks, -1); - - for (lp = reinit_sysmis.vec; *lp != -1;) - temp_case->data[*lp++].f = SYSMIS; - for (lp = reinit_blanks.vec; *lp != -1;) - memset (temp_case->data[*lp++].s, ' ', MAX_SHORT_STRING); - -#if DEBUGGING - printf ("vfm: init_zero="); - for (i = 0; i < init_zero.n; i++) - printf ("%s%s", i ? "," : "", index_to_varname (init_zero.vec[i])); - printf (" init_blanks="); - for (i = 0; i < init_blanks.n; i++) - printf ("%s%s", i ? "," : "", index_to_varname (init_blanks.vec[i])); - printf (" reinit_sysmis="); - for (lp = reinit_sysmis.vec; *lp != -1; lp++) - printf ("%s%s", lp != reinit_sysmis.vec ? "," : "", - index_to_varname (*lp)); - printf (" reinit_blanks="); - for (lp = reinit_blanks.vec; *lp != -1; lp++) - printf ("%s%s", lp != reinit_blanks.vec ? "," : "", - index_to_varname (*lp)); - printf ("\n"); -#endif -} - -/* Sets filter_index to an appropriate value. */ -static void -setup_filter (void) -{ - filter_var = dict_get_filter (default_dict); + size_t var_cnt = dict_get_var_cnt (default_dict); + size_t i; - if (filter_var != NULL) + for (i = 0; i < var_cnt; i++) { - assert (filter_var->type == NUMERIC); - filter_index = filter_var->index; - } else { - filter_index = -1; + struct variable *v = dict_get_var (default_dict, i); + + if (v->type == NUMERIC) + { + if (v->reinit) + temp_case->data[v->fv].f = 0.0; + else + temp_case->data[v->fv].f = SYSMIS; + } + else + memset (temp_case->data[v->fv].s, ' ', v->width); } } @@ -459,8 +405,7 @@ setup_lag (void) lag_head = 0; lag_queue = xmalloc (n_lag * sizeof *lag_queue); for (i = 0; i < n_lag; i++) - lag_queue[i] = xmalloc (dict_get_value_cnt (temp_dict) - * sizeof **lag_queue); + lag_queue[i] = xmalloc (dict_get_case_size (temp_dict)); } /* There is a lot of potential confusion in the vfm and related @@ -521,7 +466,6 @@ open_active_file (void) make_temp_case (); vector_initialization (); discard_ctl_stack (); - setup_filter (); setup_lag (); /* Debug output. */ @@ -596,18 +540,12 @@ close_active_file (struct write_case_data *data) process_if_expr = NULL; /* Cancel FILTER if temporary. */ - if (filter_var != NULL && !FILTER_before_TEMPORARY) + if (dict_get_filter (default_dict) != NULL && !FILTER_before_TEMPORARY) dict_set_filter (default_dict, NULL); /* Cancel transformations. */ cancel_transformations (); - /* Clear value-initialization vectors. */ - vec_clear (&init_zero); - vec_clear (&init_blanks); - vec_clear (&reinit_sysmis); - vec_clear (&reinit_blanks); - /* Turn off case limiter. */ dict_set_case_limit (default_dict, 0); @@ -948,7 +886,7 @@ lag_case (void) if (lag_count < n_lag) lag_count++; memcpy (lag_queue[lag_head], temp_case, - sizeof (union value) * dict_get_value_cnt (temp_dict)); + dict_get_case_size (temp_dict)); if (++lag_head >= n_lag) lag_head = 0; } @@ -1038,31 +976,65 @@ procedure_write_case (write_case_data wc_data) /* Call the procedure if there is one and FILTER and PROCESS IF don't prohibit it. */ - if (wc_data->procfunc != NULL - && !FILTERED - && (process_if_expr == NULL || - expr_evaluate (process_if_expr, temp_case, NULL) == 1.0)) + if (wc_data->procfunc != NULL && !exclude_this_case ()) wc_data->procfunc (temp_case, wc_data->aux); case_count++; done: debug_putc ('\n', stdout); - - { - long *lp; - /* This case is finished. Initialize the variables for the next case. */ - for (lp = reinit_sysmis.vec; *lp != -1;) - temp_case->data[*lp++].f = SYSMIS; - for (lp = reinit_blanks.vec; *lp != -1;) - memset (temp_case->data[*lp++].s, ' ', MAX_SHORT_STRING); - } + clear_temp_case (); /* Return previously determined value. */ return more_cases; } +/* Clears the variables in the temporary case that need to be + cleared between processing cases. */ +static void +clear_temp_case (void) +{ + /* FIXME? This is linear in the number of variables, but + doesn't need to be, so it's an easy optimization target. */ + size_t var_cnt = dict_get_var_cnt (default_dict); + size_t i; + + for (i = 0; i < var_cnt; i++) + { + struct variable *v = dict_get_var (default_dict, i); + if (v->init && v->reinit) + { + if (v->type == NUMERIC) + temp_case->data[v->fv].f = SYSMIS; + else + memset (temp_case->data[v->fv].s, ' ', v->width); + } + } +} + +/* Returns nonzero if this case should be exclude as specified on + FILTER or PROCESS IF, otherwise zero. */ +static int +exclude_this_case (void) +{ + /* FILTER. */ + struct variable *filter_var = dict_get_filter (default_dict); + if (filter_var != NULL) + { + double f = temp_case->data[filter_var->fv].f; + if (f == 0.0 || f == SYSMIS || is_num_user_missing (f, filter_var)) + return 1; + } + + /* PROCESS IF. */ + if (process_if_expr != NULL + && expr_evaluate (process_if_expr, temp_case, NULL) != 1.0) + return 1; + + return 0; +} + /* Appends TRNS to t_trns[], the list of all transformations to be performed on data as it is read from the active file. */ void @@ -1124,12 +1096,7 @@ dump_splits (struct ccase *c) assert (v->type == NUMERIC || v->type == ALPHA); tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name); - { - union value val = c->data[v->fv]; - if (v->type == ALPHA) - val.c = c->data[v->fv].s; - data_out (temp_buf, &v->print, &val); - } + data_out (temp_buf, &v->print, &c->data[v->fv]); temp_buf[v->print.w] = 0; tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf); @@ -1181,7 +1148,7 @@ SPLIT_FILE_procfunc (struct ccase *c, void *data_) switch (v->type) { case NUMERIC: - if (approx_ne (c->data[v->fv].f, prev_case->data[v->fv].f)) + if (c->data[v->fv].f != prev_case->data[v->fv].f) goto not_equal; break; case ALPHA: