From 9cf53942f5772eb7b928955f6e7e0ba950381bfc Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 4 Mar 2023 22:26:03 -0800 Subject: [PATCH] dictionary: Get rid of case indexes. Dictionary index (the index into the variables in the dictionary) and case index (the index into struct ccase for a variable from the dictionary) have always been independent, but they are *usually* the same. It is much cleaner to have an invariant that they are *always* the same. This commit makes that the case. --- src/data/case-map.c | 8 +- src/data/case.c | 20 ++-- src/data/caseinit.c | 2 +- src/data/csv-file-writer.c | 2 +- src/data/dataset.c | 60 +++++++--- src/data/dataset.h | 1 + src/data/dictionary.c | 115 +++++--------------- src/data/dictionary.h | 4 +- src/data/por-file-writer.c | 2 +- src/data/subcase.c | 6 +- src/data/sys-file-private.c | 2 +- src/data/transformations.c | 13 +++ src/data/transformations.h | 1 + src/data/vardict.h | 7 -- src/data/variable.c | 11 -- src/data/variable.h | 1 - src/language/commands/autorecode.c | 4 +- src/language/commands/data-list.c | 4 +- src/language/commands/examine.c | 2 +- src/language/commands/get-data.c | 4 +- src/language/commands/jonckheere-terpstra.c | 2 +- src/language/commands/rank.c | 4 +- src/language/commands/roc.c | 2 +- src/language/commands/sort-variables.c | 3 +- src/math/order-stats.c | 4 +- src/ui/gui/find-dialog.c | 2 +- src/ui/gui/marshaller-list | 3 +- src/ui/gui/psppire-data-sheet.c | 2 +- src/ui/gui/psppire-data-store.c | 30 +++-- src/ui/gui/psppire-data-store.h | 1 + src/ui/gui/psppire-dict.c | 38 +++++-- 31 files changed, 179 insertions(+), 181 deletions(-) diff --git a/src/data/case-map.c b/src/data/case-map.c index 528643b304..214abaf844 100644 --- a/src/data/case-map.c +++ b/src/data/case-map.c @@ -215,7 +215,7 @@ case_map_stage_create (const struct dictionary *dict) stage_var = xmalloc (sizeof *stage_var); stage_var->var = var; - stage_var->case_index = var_get_case_index (var); + stage_var->case_index = var_get_dict_index (var); hmap_insert (&stage->stage_vars, &stage_var->hmap_node, hash_pointer (var, 0)); } @@ -281,10 +281,10 @@ case_map_stage_get_case_map (const struct case_map_stage *stage) const struct variable *var = dict_get_var (stage->dict, i); const struct stage_var *stage_var = case_map_stage_find_var (stage, var); - if (var_get_case_index (var) != stage_var->case_index) + if (var_get_dict_index (var) != stage_var->case_index) identity_map = false; - insert_mapping (map, stage_var->case_index, var_get_case_index (var)); + insert_mapping (map, stage_var->case_index, var_get_dict_index (var)); } if (identity_map) @@ -311,7 +311,7 @@ case_map_by_name (const struct dictionary *old, struct variable *nv = dict_get_var (new, i); struct variable *ov = dict_lookup_var_assert (old, var_get_name (nv)); assert (var_get_width (nv) == var_get_width (ov)); - insert_mapping (map, var_get_case_index (ov), var_get_case_index (nv)); + insert_mapping (map, var_get_dict_index (ov), var_get_dict_index (nv)); } return map; } diff --git a/src/data/case.c b/src/data/case.c index a70179f855..9f1c404193 100644 --- a/src/data/case.c +++ b/src/data/case.c @@ -265,7 +265,7 @@ const union value * case_data (const struct ccase *c, const struct variable *v) { assert_variable_matches_case (c, v); - return &c->values[var_get_case_index (v)]; + return &c->values[var_get_dict_index (v)]; } /* Returns a pointer to the `union value' used for the element of @@ -288,7 +288,7 @@ case_data_rw (struct ccase *c, const struct variable *v) { assert_variable_matches_case (c, v); assert (!case_is_shared (c)); - return &c->values[var_get_case_index (v)]; + return &c->values[var_get_dict_index (v)]; } /* Returns a pointer to the `union value' used for the @@ -311,7 +311,7 @@ double case_num (const struct ccase *c, const struct variable *v) { assert_variable_matches_case (c, v); - return c->values[var_get_case_index (v)].f; + return c->values[var_get_dict_index (v)].f; } /* Returns the numeric value of the `union value' in C numbered @@ -332,7 +332,7 @@ case_num_rw (struct ccase *c, const struct variable *v) { assert_variable_matches_case (c, v); assert (!case_is_shared (c)); - return &c->values[var_get_case_index (v)].f; + return &c->values[var_get_dict_index (v)].f; } /* Returns a pointer to the `double' in the `union value' in C numbered IDX. @@ -356,7 +356,7 @@ const uint8_t * case_str (const struct ccase *c, const struct variable *v) { assert_variable_matches_case (c, v); - return c->values[var_get_case_index (v)].s; + return c->values[var_get_dict_index (v)].s; } /* Returns the string value of the `union value' in C numbered @@ -377,7 +377,7 @@ struct substring case_ss (const struct ccase *c, const struct variable *v) { assert_variable_matches_case (c, v); - return ss_buffer (CHAR_CAST (char *, c->values[var_get_case_index (v)].s), + return ss_buffer (CHAR_CAST (char *, c->values[var_get_dict_index (v)].s), var_get_width (v)); } @@ -403,7 +403,7 @@ uint8_t * case_str_rw (struct ccase *c, const struct variable *v) { assert_variable_matches_case (c, v); - size_t idx = var_get_case_index (v); + size_t idx = var_get_dict_index (v); assert (!case_is_shared (c)); return c->values[idx].s; } @@ -513,9 +513,9 @@ case_size (const struct caseproto *proto) static void assert_variable_matches_case (const struct ccase *c, const struct variable *v) { - size_t case_idx = var_get_case_index (v); - assert (case_idx < caseproto_get_n_widths (c->proto)); - assert (caseproto_get_width (c->proto, case_idx) == var_get_width (v)); + size_t var_idx = var_get_dict_index (v); + assert (var_idx < caseproto_get_n_widths (c->proto)); + assert (caseproto_get_width (c->proto, var_idx) == var_get_width (v)); } /* Internal helper function for case_copy(). */ diff --git a/src/data/caseinit.c b/src/data/caseinit.c index 3efe128efd..1d6f98c0ee 100644 --- a/src/data/caseinit.c +++ b/src/data/caseinit.c @@ -135,7 +135,7 @@ init_list_mark (struct init_list *list, const struct init_list *exclude, for (size_t i = 0; i < n_vars; i++) { struct variable *v = dict_get_var (d, i); - size_t case_index = var_get_case_index (v); + size_t case_index = var_get_dict_index (v); struct init_value *iv; /* Only include the correct class. */ diff --git a/src/data/csv-file-writer.c b/src/data/csv-file-writer.c index 3b76b36b53..279c63685d 100644 --- a/src/data/csv-file-writer.c +++ b/src/data/csv-file-writer.c @@ -118,7 +118,7 @@ csv_writer_open (struct file_handle *fh, const struct dictionary *dict, struct csv_var *cv = &w->csv_vars[i]; cv->width = var_get_width (var); - cv->case_index = var_get_case_index (var); + cv->case_index = var_get_dict_index (var); cv->format = var_get_print_format (var); if (opts->recode_user_missing) diff --git a/src/data/dataset.c b/src/data/dataset.c index c74715ae9b..72dfb8b41f 100644 --- a/src/data/dataset.c +++ b/src/data/dataset.c @@ -68,6 +68,7 @@ struct dataset { struct caseinit *caseinit; struct trns_chain permanent_trns_chain; struct dictionary *permanent_dict; + struct variable *order_var; struct casewriter *sink; struct trns_chain temporary_trns_chain; bool temporary; @@ -369,6 +370,28 @@ dataset_delete_vars (struct dataset *ds, struct variable **vars, size_t n) caseinit_mark_as_preinited (ds->caseinit, ds->dict); } +void +dataset_reorder_vars (struct dataset *ds, struct variable **vars, size_t n) +{ + assert (!proc_in_temporary_transformations (ds)); + assert (!proc_has_transformations (ds)); + assert (n <= dict_get_n_vars (ds->dict)); + + caseinit_mark_for_init (ds->caseinit, ds->dict); + ds->source = caseinit_translate_casereader_to_init_vars ( + ds->caseinit, dict_get_proto (ds->dict), ds->source); + caseinit_clear (ds->caseinit); + caseinit_mark_as_preinited (ds->caseinit, ds->dict); + + struct case_map_stage *stage = case_map_stage_create (ds->dict); + dict_reorder_vars (ds->dict, vars, n); + ds->source = case_map_create_input_translator ( + case_map_stage_get_case_map (stage), ds->source); + case_map_stage_destroy (stage); + caseinit_clear (ds->caseinit); + caseinit_mark_as_preinited (ds->caseinit, ds->dict); +} + /* Returns a number unique to DS. It can be used to distinguish one dataset from any other within a given program run, even datasets that do not exist at the same time. */ @@ -570,8 +593,12 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_) /* Write case to replacement dataset. */ ds->cases_written++; if (ds->sink != NULL) - casewriter_write (ds->sink, - case_map_execute (ds->compactor, case_ref (c))); + { + if (ds->order_var) + *case_num_rw (c, ds->order_var) = case_nr; + casewriter_write (ds->sink, + case_map_execute (ds->compactor, case_ref (c))); + } /* Execute temporary transformations. */ if (ds->temporary_trns_chain.n) @@ -662,6 +689,7 @@ proc_commit (struct dataset *ds) dict_clear_vectors (ds->dict); ds->permanent_dict = NULL; + ds->order_var = NULL; return ok; } @@ -835,24 +863,26 @@ store_case_num (void *var_, struct ccase **cc, casenumber case_num) return TRNS_CONTINUE; } -/* Add a variable which we can sort by to get back the original order. */ +/* Add a variable $ORDERING which we can sort by to get back the original order. */ struct variable * add_permanent_ordering_transformation (struct dataset *ds) { - struct variable *temp_var = dict_create_var_assert (ds->dict, "$ORDER", 0); - struct variable *order_var - = (proc_in_temporary_transformations (ds) - ? dict_clone_var_in_place_assert (ds->permanent_dict, temp_var) - : temp_var); + struct dictionary *d = ds->permanent_dict ? ds->permanent_dict : ds->dict; + struct variable *order_var = dict_create_var_assert (d, "$ORDER", 0); + ds->order_var = order_var; - static const struct trns_class trns_class = { - .name = "ordering", - .execute = store_case_num - }; - const struct transformation t = { .class = &trns_class, .aux = order_var }; - trns_chain_append (&ds->permanent_trns_chain, &t); + if (ds->permanent_dict) + { + order_var = dict_create_var_assert (ds->dict, "$ORDER", 0); + static const struct trns_class trns_class = { + .name = "ordering", + .execute = store_case_num + }; + const struct transformation t = { .class = &trns_class, .aux = order_var }; + trns_chain_prepend (&ds->temporary_trns_chain, &t); + } - return temp_var; + return order_var; } /* Causes output from the next procedure to be discarded, instead diff --git a/src/data/dataset.h b/src/data/dataset.h index 1938bd7f80..40f4d60b5b 100644 --- a/src/data/dataset.h +++ b/src/data/dataset.h @@ -97,6 +97,7 @@ bool dataset_transform_source (struct dataset *, const struct casereader_translator_class *, void *aux); void dataset_delete_vars (struct dataset *, struct variable **, size_t n); +void dataset_reorder_vars (struct dataset *, struct variable **, size_t n); /* Procedures. */ diff --git a/src/data/dictionary.c b/src/data/dictionary.c index ebc88b4d9b..5c8d6e8dc3 100644 --- a/src/data/dictionary.c +++ b/src/data/dictionary.c @@ -143,13 +143,6 @@ reindex_var (struct dictionary *d, struct vardict_info *vardict, bool skip_callb } } -/* Sets the case_index in V's vardict to CASE_INDEX. */ -static void -set_var_case_index (struct variable *v, int case_index) -{ - var_get_vardict (v)->case_index = case_index; -} - /* Removes the dictionary variables with indexes from FROM to TO (exclusive) from name_map. */ static void @@ -236,16 +229,8 @@ invalidate_proto (struct dictionary *d) void dict_dump (const struct dictionary *d) { - int i; - for (i = 0 ; i < d->n_vars ; ++i) - { - const struct variable *v = d->vars[i].var; - printf ("Name: %s;\tdict_idx: %zu; case_idx: %zu\n", - var_get_name (v), - var_get_dict_index (v), - var_get_case_index (v)); - - } + for (size_t i = 0; i < d->n_vars; ++i) + printf ("%zu: %s\n", i, var_get_name (d->vars[i].var)); } /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever @@ -306,8 +291,6 @@ dict_clone (const struct dictionary *s) for (size_t j = 0; j < var_get_n_short_names (sv); j++) var_set_short_name (dv, j, var_get_short_name (sv, j)); - - var_get_vardict (dv)->case_index = var_get_vardict (sv)->case_index; } d->n_splits = s->n_splits; @@ -532,7 +515,7 @@ void dict_delete_var (struct dictionary *d, struct variable *v) { dict_delete_var__ (d, v, false); - dict_compact_values (d); + invalidate_proto (d); } @@ -548,7 +531,7 @@ dict_delete_vars (struct dictionary *d, while (count-- > 0) dict_delete_var (d, *vars++); - dict_compact_values (d); + invalidate_proto (d); } /* Deletes the COUNT variables in D starting at index IDX. This @@ -565,19 +548,12 @@ dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count) { assert (idx + count <= d->n_vars); - /* We need to store the variable and the corresponding case_index - for the delete callbacks later. We store them in a linked list.*/ - struct delvar { - struct ll ll; - struct variable *var; - }; - struct ll_list list = LL_INITIALIZER (list); + struct variable **vars = xnmalloc (count, sizeof *vars); - for (size_t i = idx; i < idx + count; i++) + for (size_t i = 0; i < count; i++) { - struct delvar *dv = xmalloc (sizeof (struct delvar)); - assert (dv); - struct variable *v = d->vars[i].var; + struct variable *v = d->vars[idx + i].var; + vars[i] = v; dict_unset_split_var (d, v, false); dict_unset_mrset_var (d, v); @@ -588,9 +564,6 @@ dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count) if (d->filter == v) dict_set_filter (d, NULL); - - dv->var = v; - ll_push_tail (&list, (struct ll *)dv); } dict_clear_vectors (d); @@ -608,19 +581,17 @@ dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count) /* Now issue the variable delete callbacks and delete the variables. The vardict is not valid at this point - anymore. That is the reason why we stored the - caseindex before reindexing. */ + anymore. */ if (d->callbacks && d->callbacks->vars_deleted) d->callbacks->vars_deleted (d, idx, count, d->cb_data); - for (size_t vi = idx; vi < idx + count; vi++) + for (size_t i = 0; i < count; i++) { - struct delvar *dv = (struct delvar *) ll_pop_head (&list); - var_clear_vardict (dv->var); - var_unref (dv->var); - free (dv); + var_clear_vardict (vars[i]); + var_unref (vars[i]); } + free (vars); - dict_compact_values (d); + invalidate_proto (d); } /* Deletes scratch variables from dictionary D. */ @@ -637,7 +608,7 @@ dict_delete_scratch_vars (struct dictionary *d) else i++; - dict_compact_values (d); + invalidate_proto (d); } @@ -787,11 +758,8 @@ dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars, } static struct variable * -add_var_with_case_index (struct dictionary *d, struct variable *v, - int case_index) +add_var (struct dictionary *d, struct variable *v) { - struct vardict_info *vardict; - /* Update dictionary. */ if (d->n_vars >= d->allocated_vars) { @@ -807,12 +775,13 @@ add_var_with_case_index (struct dictionary *d, struct variable *v, } } - vardict = &d->vars[d->n_vars++]; - vardict->dict = d; - vardict->var = v; + struct vardict_info *vardict = &d->vars[d->n_vars++]; + *vardict = (struct vardict_info) { + .dict = d, + .var = v, + }; hmap_insert (&d->name_map, &vardict->name_node, utf8_hash_case_string (var_get_name (v), 0)); - vardict->case_index = case_index; var_set_vardict (v, vardict); if (d->changed) d->changed (d, d->changed_data); @@ -824,12 +793,6 @@ add_var_with_case_index (struct dictionary *d, struct variable *v, return v; } -static struct variable * -add_var (struct dictionary *d, struct variable *v) -{ - return add_var_with_case_index (d, v, dict_get_n_vars (d)); -} - /* Creates and returns a new variable in D with the given NAME and WIDTH. Returns a null pointer if the given NAME would duplicate that of an existing variable in the dictionary. */ @@ -898,15 +861,6 @@ dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var, return add_var (d, new_var); } -struct variable * -dict_clone_var_in_place_assert (struct dictionary *d, - const struct variable *old_var) -{ - assert (dict_lookup_var (d, var_get_name (old_var)) == NULL); - return add_var_with_case_index (d, var_clone (old_var), - var_get_case_index (old_var)); -} - /* Returns the variable named NAME in D, or a null pointer if no variable has that name. */ struct variable * @@ -959,6 +913,9 @@ dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index) unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1); move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index); reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false); + + if (d->callbacks && d->callbacks->var_moved) + d->callbacks->var_moved (d, new_index, old_index, d->cb_data); } /* Reorders the variables in D, placing the COUNT variables @@ -1395,34 +1352,12 @@ dict_get_proto (const struct dictionary *d_) { short int *widths = xnmalloc (d->n_vars, sizeof *widths); for (size_t i = 0; i < d->n_vars; i++) - widths[i] = -1; - for (size_t i = 0; i < d->n_vars; i++) - { - const struct variable *var = d->vars[i].var; - size_t case_idx = var_get_case_index (var); - assert (case_idx < d->n_vars); - assert (widths[case_idx] == -1); - widths[case_idx] = var_get_width (var); - } - + widths[i] = var_get_width (d->vars[i].var); d->proto = caseproto_from_widths (widths, d->n_vars); } return d->proto; } -/* Reassigns values in dictionary D so that fragmentation is - eliminated. */ -void -dict_compact_values (struct dictionary *d) -{ - for (size_t i = 0; i < d->n_vars; i++) - { - struct variable *v = d->vars[i].var; - set_var_case_index (v, i); - } - invalidate_proto (d); -} - /* Returns the number of values occupied by the variables in dictionary D. All variables are considered if EXCLUDE_CLASSES is 0, or it may contain one or more of DC_ORDINARY, DC_SYSTEM, diff --git a/src/data/dictionary.h b/src/data/dictionary.h index d6823ed854..efb587cf75 100644 --- a/src/data/dictionary.h +++ b/src/data/dictionary.h @@ -65,9 +65,6 @@ struct variable *dict_clone_var_as_assert (struct dictionary *, const struct variable *, const char *); -struct variable *dict_clone_var_in_place_assert (struct dictionary *, - const struct variable *); - /* Deleting variables. */ void dict_delete_var (struct dictionary *, struct variable *); void dict_delete_vars (struct dictionary *, @@ -204,6 +201,7 @@ struct dict_callbacks { void (*var_added) (struct dictionary *, int, void *); void (*vars_deleted) (struct dictionary *, int dict_index, unsigned int n, void *); + void (*var_moved) (struct dictionary *, int new_dict_index, int old_dict_index, void *); void (*var_changed) (struct dictionary *, int, unsigned int, const struct variable *, void *); void (*weight_changed) (struct dictionary *, int, void *); void (*filter_changed) (struct dictionary *, int, void *); diff --git a/src/data/por-file-writer.c b/src/data/por-file-writer.c index fee6b1aff8..3d9b4b3fb3 100644 --- a/src/data/por-file-writer.c +++ b/src/data/por-file-writer.c @@ -130,7 +130,7 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict, const struct variable *dv = dict_get_var (dict, i); struct pfm_var *pv = &w->vars[i]; pv->width = MIN (var_get_width (dv), MAX_POR_WIDTH); - pv->case_index = var_get_case_index (dv); + pv->case_index = var_get_dict_index (dv); } w->digits = opts.digits; diff --git a/src/data/subcase.c b/src/data/subcase.c index ca4992ae60..9c2fa7a9ec 100644 --- a/src/data/subcase.c +++ b/src/data/subcase.c @@ -97,7 +97,7 @@ subcase_uninit (struct subcase *sc) bool subcase_contains_var (const struct subcase *sc, const struct variable *var) { - return subcase_contains (sc, var_get_case_index (var)); + return subcase_contains (sc, var_get_dict_index (var)); } /* Returns true if CASE_INDEX already has a field in SC, @@ -152,7 +152,7 @@ void subcase_add_var_always (struct subcase *sc, const struct variable *var, enum subcase_direction direction) { - return subcase_add_always (sc, var_get_case_index (var), + return subcase_add_always (sc, var_get_dict_index (var), var_get_width (var), direction); } @@ -170,7 +170,7 @@ subcase_add_vars_always (struct subcase *sc, for (i = 0; i < n_vars; i++) { struct subcase_field *field = &sc->fields[sc->n_fields++]; - field->case_index = var_get_case_index (vars[i]); + field->case_index = var_get_dict_index (vars[i]); field->width = var_get_width (vars[i]); field->direction = SC_ASCEND; } diff --git a/src/data/sys-file-private.c b/src/data/sys-file-private.c index 74b0208b93..88bac17294 100644 --- a/src/data/sys-file-private.c +++ b/src/data/sys-file-private.c @@ -232,7 +232,7 @@ sfm_dictionary_to_sfm_vars (const struct dictionary *dict, sv = &(*sfm_vars)[(*sfm_n_vars)++]; sv->var_width = width; sv->segment_width = width == 0 ? 0 : used_bytes; - sv->case_index = var_get_case_index (dv); + sv->case_index = var_get_dict_index (dv); sv->offset = sfm_segment_offset (width, j); sv->padding = padding; } diff --git a/src/data/transformations.c b/src/data/transformations.c index f1cfaf47c9..fdb2cb84bd 100644 --- a/src/data/transformations.c +++ b/src/data/transformations.c @@ -21,6 +21,7 @@ #include #include +#include "libpspp/array.h" #include "libpspp/str.h" #include "gl/xalloc.h" @@ -53,6 +54,18 @@ trns_chain_clear (struct trns_chain *chain) return ok; } +void +trns_chain_prepend (struct trns_chain *chain, const struct transformation *t) +{ + if (chain->n >= chain->allocated) + chain->xforms = x2nrealloc (chain->xforms, &chain->allocated, + sizeof *chain->xforms); + + insert_element (chain->xforms, 1, sizeof *chain->xforms, 0); + chain->xforms[0] = *t; + chain->n++; +} + void trns_chain_append (struct trns_chain *chain, const struct transformation *t) { diff --git a/src/data/transformations.h b/src/data/transformations.h index dd8c29d0c8..de8135e6ac 100644 --- a/src/data/transformations.h +++ b/src/data/transformations.h @@ -64,6 +64,7 @@ bool trns_chain_uninit (struct trns_chain *); bool trns_chain_clear (struct trns_chain *); +void trns_chain_prepend (struct trns_chain *, const struct transformation *); void trns_chain_append (struct trns_chain *, const struct transformation *); void trns_chain_splice (struct trns_chain *, struct trns_chain *); diff --git a/src/data/vardict.h b/src/data/vardict.h index ecef88274b..ae74b1cf5c 100644 --- a/src/data/vardict.h +++ b/src/data/vardict.h @@ -29,7 +29,6 @@ struct vardict_info struct dictionary *dict; struct variable *var; struct hmap_node name_node; /* In struct dictionary's name_map. */ - int case_index; /* Index into case of variable data. */ }; /* Called by dictionary code, defined in variable.c. */ @@ -43,12 +42,6 @@ void dict_var_changed (const struct variable *v, unsigned int what, struct varia int vardict_get_dict_index (const struct vardict_info *); -static inline int -vardict_get_case_index (const struct vardict_info *vardict) -{ - return vardict->case_index; -} - static inline struct dictionary * vardict_get_dictionary (const struct vardict_info *vardict) { diff --git a/src/data/variable.c b/src/data/variable.c index 7d5286fb48..b90b32a31c 100644 --- a/src/data/variable.c +++ b/src/data/variable.c @@ -1221,17 +1221,6 @@ var_get_dict_index (const struct variable *v) assert (var_has_vardict (v)); return vardict_get_dict_index (v->vardict); } - -/* Returns V's index within the case represented by its - dictionary, that is, the value for which "case_data_idx (case, - index)" will return the data for V in that case. - V must be in a dictionary. */ -size_t -var_get_case_index (const struct variable *v) -{ - assert (var_has_vardict (v)); - return vardict_get_case_index (v->vardict); -} /* Returns variable V's attribute set. The caller may examine or modify the attribute set, but must not destroy it. Destroying diff --git a/src/data/variable.h b/src/data/variable.h index 4a1ac6f81a..97079e667e 100644 --- a/src/data/variable.h +++ b/src/data/variable.h @@ -199,7 +199,6 @@ void var_clear_short_names (struct variable *); /* Relationship with dictionary. */ size_t var_get_dict_index (const struct variable *); -size_t var_get_case_index (const struct variable *); /* Custom attributes. */ struct attrset *var_get_attributes (const struct variable *); diff --git a/src/language/commands/autorecode.c b/src/language/commands/autorecode.c index c854e0c2c2..775b11e835 100644 --- a/src/language/commands/autorecode.c +++ b/src/language/commands/autorecode.c @@ -244,7 +244,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds) struct arc_spec *spec = &arc->specs[i]; spec->width = var_get_width (src_vars[i]); - spec->src_idx = var_get_case_index (src_vars[i]); + spec->src_idx = var_get_dict_index (src_vars[i]); spec->src_name = xstrdup (var_get_name (src_vars[i])); spec->format = var_get_print_format (src_vars[i]); @@ -336,7 +336,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds) /* Create destination variable. */ struct variable *dst = dict_create_var_assert (dict, dst_names[i], 0); - spec->dst_idx = var_get_case_index (dst); + spec->dst_idx = var_get_dict_index (dst); var_set_label (dst, spec->label); /* Set print format. */ diff --git a/src/language/commands/data-list.c b/src/language/commands/data-list.c index cdc540bb23..35f153e4f8 100644 --- a/src/language/commands/data-list.c +++ b/src/language/commands/data-list.c @@ -420,7 +420,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict, } data_parser_add_fixed_field (parser, *f, - var_get_case_index (v), + var_get_dict_index (v), var_get_name (v), record, column); column += f->w; @@ -516,7 +516,7 @@ parse_free (struct lexer *lexer, struct dictionary *dict, var_set_both_formats (v, output); data_parser_add_delimited_field (parser, - input, var_get_case_index (v), + input, var_get_dict_index (v), var_get_name (v)); } } diff --git a/src/language/commands/examine.c b/src/language/commands/examine.c index 0840e96def..a9a426ee01 100644 --- a/src/language/commands/examine.c +++ b/src/language/commands/examine.c @@ -1716,7 +1716,7 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) if (examine.id_var) { - examine.id_idx = var_get_case_index (examine.id_var); + examine.id_idx = var_get_dict_index (examine.id_var); examine.id_width = var_get_width (examine.id_var); } diff --git a/src/language/commands/get-data.c b/src/language/commands/get-data.c index b74b0fa802..377e40c555 100644 --- a/src/language/commands/get-data.c +++ b/src/language/commands/get-data.c @@ -594,10 +594,10 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds) var_set_both_formats (v, output); if (type == DP_DELIMITED) data_parser_add_delimited_field (parser, input, - var_get_case_index (v), + var_get_dict_index (v), name); else - data_parser_add_fixed_field (parser, input, var_get_case_index (v), + data_parser_add_fixed_field (parser, input, var_get_dict_index (v), name, record, fc); free (name); name = NULL; diff --git a/src/language/commands/jonckheere-terpstra.c b/src/language/commands/jonckheere-terpstra.c index b0385fa577..f8f4fbbecb 100644 --- a/src/language/commands/jonckheere-terpstra.c +++ b/src/language/commands/jonckheere-terpstra.c @@ -194,7 +194,7 @@ void variance_calculation (struct casereader *ir, const struct variable *var, struct ccase *c; const struct variable *wv = dict_get_weight (dict); const int w_idx = wv ? - var_get_case_index (wv) : + var_get_dict_index (wv) : caseproto_get_n_widths (casereader_get_proto (r)) ; r = sort_execute_1var (r, var); diff --git a/src/language/commands/rank.c b/src/language/commands/rank.c index 3157153b53..26de7bed81 100644 --- a/src/language/commands/rank.c +++ b/src/language/commands/rank.c @@ -1022,7 +1022,7 @@ rank_cmd (struct dataset *ds, const struct rank *cmd) $ORDER). */ struct rank_trns *trns = xmalloc (sizeof *trns); *trns = (struct rank_trns) { - .order_case_idx = var_get_case_index (order_var), + .order_case_idx = var_get_dict_index (order_var), .input_vars = xnmalloc (cmd->n_vars, sizeof *trns->input_vars), .n_input_vars = cmd->n_vars, .n_funcs = cmd->n_rs, @@ -1045,7 +1045,7 @@ rank_cmd (struct dataset *ds, const struct rank *cmd) var_set_label (var, rs->dest_labels[i]); var_set_measure (var, rank_measures[rs->rfunc]); - iv->output_var_indexes[j] = var_get_case_index (var); + iv->output_var_indexes[j] = var_get_dict_index (var); } } free (outputs); diff --git a/src/language/commands/roc.c b/src/language/commands/roc.c index d73f5da9f8..cb835967db 100644 --- a/src/language/commands/roc.c +++ b/src/language/commands/roc.c @@ -432,7 +432,7 @@ process_group (const struct variable *var, struct casereader *reader, struct casereader *r1 = casereader_create_distinct (sort_execute_1var (reader, var), var, w); - const int weight_idx = w ? var_get_case_index (w) : + const int weight_idx = w ? var_get_dict_index (w) : caseproto_get_n_widths (casereader_get_proto (r1)) - 1; struct ccase *c1; diff --git a/src/language/commands/sort-variables.c b/src/language/commands/sort-variables.c index 58e833e9e7..446bb6a70d 100644 --- a/src/language/commands/sort-variables.c +++ b/src/language/commands/sort-variables.c @@ -272,7 +272,8 @@ cmd_sort_variables (struct lexer *lexer, struct dataset *ds) size_t n_vars; dict_get_vars_mutable (d, &vars, &n_vars, 0); sort (vars, n_vars, sizeof *vars, compare_vars, &c); - dict_reorder_vars (d, CONST_CAST (struct variable *const *, vars), n_vars); + proc_execute (ds); + dataset_reorder_vars (ds, vars, n_vars); free (vars); result = CMD_SUCCESS; diff --git a/src/math/order-stats.c b/src/math/order-stats.c index 3f6b8fcfbb..050a7f5be4 100644 --- a/src/math/order-stats.c +++ b/src/math/order-stats.c @@ -176,6 +176,6 @@ order_stats_accumulate (struct order_stats **os, size_t n_os, exclude, NULL, NULL); order_stats_accumulate_idx (os, n_os, reader, - weight_var ? var_get_case_index (weight_var) : -1, - var_get_case_index (data_var)); + weight_var ? var_get_dict_index (weight_var) : -1, + var_get_dict_index (data_var)); } diff --git a/src/ui/gui/find-dialog.c b/src/ui/gui/find-dialog.c index 104afba89b..3562885a83 100644 --- a/src/ui/gui/find-dialog.c +++ b/src/ui/gui/find-dialog.c @@ -757,7 +757,7 @@ find_value (const struct find_dialog *fd, casenumber current_row, i != ip->end (current_row, fd->data); ip->next (&i, fd->data)) { - datasheet_get_value (fd->data, i, var_get_case_index (var), &val); + datasheet_get_value (fd->data, i, var_get_dict_index (var), &val); if (comparator_compare (cmptr, &val)) { diff --git a/src/ui/gui/marshaller-list b/src/ui/gui/marshaller-list index 422c9c72b0..6fec906c09 100644 --- a/src/ui/gui/marshaller-list +++ b/src/ui/gui/marshaller-list @@ -4,4 +4,5 @@ BOOLEAN:INT,INT VOID:POINTER,INT,INT VOID:INT,UINT,POINTER VOID:UINT,UINT,UINT -VOID:INT,UINT \ No newline at end of file +VOID:INT,INT +VOID:INT,UINT diff --git a/src/ui/gui/psppire-data-sheet.c b/src/ui/gui/psppire-data-sheet.c index c3e1fc2b24..8073bb0229 100644 --- a/src/ui/gui/psppire-data-sheet.c +++ b/src/ui/gui/psppire-data-sheet.c @@ -223,7 +223,7 @@ psppire_data_sheet_insert_new_variable_at_posn (PsppireDataSheet *sheet, posn, NULL); psppire_data_store_insert_value (data_store, var_get_width(v), - var_get_case_index (v)); + var_get_dict_index (v)); ssw_sheet_scroll_to (SSW_SHEET (sheet), posn, -1); diff --git a/src/ui/gui/psppire-data-store.c b/src/ui/gui/psppire-data-store.c index 0a6614a641..173bf0e10f 100644 --- a/src/ui/gui/psppire-data-store.c +++ b/src/ui/gui/psppire-data-store.c @@ -253,7 +253,7 @@ __get_value (GtkTreeModel *tree_model, g_value_init (value, G_TYPE_VARIANT); - const union value *val = case_data_idx (cc, var_get_case_index (variable)); + const union value *val = case_data_idx (cc, var_get_dict_index (variable)); GVariant *vv = value_variant_new (val, var_get_width (variable)); @@ -373,6 +373,17 @@ delete_variables_callback (GObject *obj, gint dict_index, unsigned int n, gpoint psppire_data_store_delete_values (store, dict_index, n); } +/* + A callback which occurs after variables have been deleted. + */ +static void +move_variable_callback (GObject *obj, gint new_dict_index, int old_dict_index, gpointer data) +{ + PsppireDataStore *store = PSPPIRE_DATA_STORE (data); + + datasheet_move_columns (store->datasheet, old_dict_index, new_dict_index, 1); +} + struct resize_datum_aux { const struct dictionary *dict; @@ -406,7 +417,7 @@ variable_changed_callback (GObject *obj, gint var_num, guint what, const struct if (what & VAR_TRAIT_WIDTH) { - int posn = var_get_case_index (variable); + int posn = var_get_dict_index (variable); struct resize_datum_aux aux; aux.old_variable = oldvar; aux.new_variable = variable; @@ -428,7 +439,7 @@ insert_variable_callback (GObject *obj, gint var_num, gpointer data) store = PSPPIRE_DATA_STORE (data); variable = psppire_dict_get_variable (store->dict, var_num); - posn = var_get_case_index (variable); + posn = var_get_dict_index (variable); psppire_data_store_insert_value (store, var_get_width (variable), posn); } @@ -517,6 +528,11 @@ psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *di G_CALLBACK (delete_variables_callback), data_store); + data_store->dict_handler_id [VARIABLE_MOVED] = + g_signal_connect (dict, "variable-moved", + G_CALLBACK (move_variable_callback), + data_store); + data_store->dict_handler_id [VARIABLE_CHANGED] = g_signal_connect (dict, "variable-changed", G_CALLBACK (variable_changed_callback), @@ -609,7 +625,7 @@ psppire_data_store_get_value (PsppireDataStore *store, int width = var_get_width (var); value_init (val, width); - datasheet_get_value (store->datasheet, row, var_get_case_index (var), val); + datasheet_get_value (store->datasheet, row, var_get_dict_index (var), val); return TRUE; } @@ -667,7 +683,7 @@ psppire_data_store_set_string (PsppireDataStore *store, if (row == n_cases) psppire_data_store_insert_new_case (store, row); - case_index = var_get_case_index (var); + case_index = var_get_dict_index (var); if (use_value_label) { const struct val_labs *vls = var_get_value_labels (var); @@ -800,7 +816,7 @@ psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum, if (casenum == n_cases) psppire_data_store_insert_new_case (ds, casenum); - ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var), + ok = datasheet_put_value (ds->datasheet, casenum, var_get_dict_index (var), v); if (ok) { @@ -893,7 +909,7 @@ psppire_data_store_filtered (PsppireDataStore *ds, g_return_val_if_fail (var_is_numeric (filter), FALSE); value_init (&val, 0); if (! datasheet_get_value (ds->datasheet, row, - var_get_case_index (filter), + var_get_dict_index (filter), &val)) return FALSE; diff --git a/src/ui/gui/psppire-data-store.h b/src/ui/gui/psppire-data-store.h index 87bdefd14e..33d82395e0 100644 --- a/src/ui/gui/psppire-data-store.h +++ b/src/ui/gui/psppire-data-store.h @@ -58,6 +58,7 @@ enum dict_signal_handler { VARIABLE_INSERTED, VARIABLE_CHANGED, VARIABLES_DELETED, + VARIABLE_MOVED, n_dict_signals }; diff --git a/src/ui/gui/psppire-dict.c b/src/ui/gui/psppire-dict.c index 0ed6841131..32a5cc13e2 100644 --- a/src/ui/gui/psppire-dict.c +++ b/src/ui/gui/psppire-dict.c @@ -51,6 +51,7 @@ enum { VARIABLE_CHANGED, VARIABLE_INSERTED, VARIABLES_DELETED, + VARIABLE_MOVED, WEIGHT_CHANGED, FILTER_CHANGED, @@ -203,6 +204,18 @@ psppire_dict_class_init (PsppireDictClass *class) G_TYPE_INT, G_TYPE_UINT); + signals [VARIABLE_MOVED] = + g_signal_new ("variable-moved", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + psppire_marshal_VOID__INT_INT, + G_TYPE_NONE, + 2, + G_TYPE_INT, + G_TYPE_INT); + signals [WEIGHT_CHANGED] = g_signal_new ("weight-changed", G_TYPE_FROM_CLASS (class), @@ -255,7 +268,7 @@ psppire_dict_dispose (GObject *object) /* Pass on callbacks from src/data/dictionary, as signals in the Gtk library */ static void -addcb (struct dictionary *d, int idx, void *pd) +var_added_callback (struct dictionary *d, int idx, void *pd) { PsppireDict *dict = PSPPIRE_DICT (pd); @@ -267,14 +280,20 @@ addcb (struct dictionary *d, int idx, void *pd) } static void -delcb (struct dictionary *d, int dict_idx, unsigned int n, void *pd) +vars_deleted_callback (struct dictionary *d, int dict_idx, unsigned int n, void *pd) { g_signal_emit (pd, signals [VARIABLES_DELETED], 0, dict_idx, n); g_signal_emit_by_name (pd, "items-changed", dict_idx, 1, 0); } static void -mutcb (struct dictionary *d, int idx, unsigned int what, const struct variable *oldvar, void *pd) +var_moved_callback (struct dictionary *d, int new_dict_index, int old_dict_index, void *pd) +{ + g_signal_emit (pd, signals [VARIABLE_MOVED], 0, new_dict_index, old_dict_index); +} + +static void +var_changed_callback (struct dictionary *d, int idx, unsigned int what, const struct variable *oldvar, void *pd) { g_signal_emit (pd, signals [VARIABLE_CHANGED], 0, idx, what, oldvar); g_signal_emit_by_name (pd, "items-changed", idx, 1, 1); @@ -300,12 +319,13 @@ split_changed_callback (struct dictionary *d, void *pd) static const struct dict_callbacks gui_callbacks = { - addcb, - delcb, - mutcb, - weight_changed_callback, - filter_changed_callback, - split_changed_callback + .var_added = var_added_callback, + .vars_deleted = vars_deleted_callback, + .var_moved = var_moved_callback, + .var_changed = var_changed_callback, + .weight_changed = weight_changed_callback, + .filter_changed = filter_changed_callback, + .split_changed = split_changed_callback }; static void -- 2.30.2