dictionary: Get rid of case indexes.
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 5 Mar 2023 06:26:03 +0000 (22:26 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 5 Mar 2023 19:24:28 +0000 (11:24 -0800)
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.

31 files changed:
src/data/case-map.c
src/data/case.c
src/data/caseinit.c
src/data/csv-file-writer.c
src/data/dataset.c
src/data/dataset.h
src/data/dictionary.c
src/data/dictionary.h
src/data/por-file-writer.c
src/data/subcase.c
src/data/sys-file-private.c
src/data/transformations.c
src/data/transformations.h
src/data/vardict.h
src/data/variable.c
src/data/variable.h
src/language/commands/autorecode.c
src/language/commands/data-list.c
src/language/commands/examine.c
src/language/commands/get-data.c
src/language/commands/jonckheere-terpstra.c
src/language/commands/rank.c
src/language/commands/roc.c
src/language/commands/sort-variables.c
src/math/order-stats.c
src/ui/gui/find-dialog.c
src/ui/gui/marshaller-list
src/ui/gui/psppire-data-sheet.c
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-data-store.h
src/ui/gui/psppire-dict.c

index 528643b304de2619bd5e700cd4462264a875a3f0..214abaf84478174ce73620cb2caca2be604bd93a 100644 (file)
@@ -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;
 }
index a70179f855bf9114df1c8eb667ac630f892e376b..9f1c404193911651e9192277b42204bd3ca15d70 100644 (file)
@@ -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(). */
index 3efe128efd205c7f618e712a3d6386d5e127c912..1d6f98c0eea7478948b63810a6c4215c50e1d3e9 100644 (file)
@@ -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. */
index 3b76b36b53e213ecf7b1f2ec7825795da91be370..279c63685d15c0b150862b17cc49072c6f353f7b 100644 (file)
@@ -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)
index c74715ae9b4e5e86b30571a760446ad21c1fd4c0..72dfb8b41f54db04f27e790c84b751a3b838856e 100644 (file)
@@ -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;
 }
 \f
 /* Causes output from the next procedure to be discarded, instead
index 1938bd7f809130cd97d2b5889e80ec48455a346d..40f4d60b5bb878c4c8fd6100e404615efc6e0415 100644 (file)
@@ -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);
 \f
 /* Procedures. */
 
index ebc88b4d9b9765f64306c9a4a2f86644859f3586..5c8d6e8dc313f156c664db1417b9b4cf9f7a398a 100644 (file)
@@ -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);
 }
 
 \f
@@ -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,
index d6823ed854ae9008f9663e60e39dde80906972ee..efb587cf75af20da71685ee670be2cf49c5fe762 100644 (file)
@@ -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 *);
index fee6b1aff8223b64bb6f5f23c50aa70c2cd4a117..3d9b4b3fb3aed6f3b9483b4e2fee950516166214 100644 (file)
@@ -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;
index ca4992ae6030d91bd4f5b4f38a8c0d4583075b2b..9c2fa7a9ecb9f1daa64bc69402b3c8544894ecfb 100644 (file)
@@ -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;
     }
index 74b0208b9387e9804f6ae725c1cf771ce3de9672..88bac17294700d1d41b8dd94197146da9e1a1ace 100644 (file)
@@ -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;
             }
index f1cfaf47c9688c5d51cd273d7d623b34292d3449..fdb2cb84bd7f854bc3c16a8d32c3968e0ceceace 100644 (file)
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include <stdlib.h>
 
+#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)
 {
index dd8c29d0c873c2b048d9953c47b3e2d3d86a9212..de8135e6ac48e409438990036b97a65e0c766ded 100644 (file)
@@ -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 *);
 
index ecef88274bf26bfc13c063906f142fc098307a6a..ae74b1cf5c755a190d2ffd6d931e26b1022d485b 100644 (file)
@@ -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)
 {
index 7d5286fb48933015adf7c42d21713dfcb1f181ff..b90b32a31ca9053fe818f58931959a4d0c01291b 100644 (file)
@@ -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);
-}
 \f
 /* Returns variable V's attribute set.  The caller may examine or
    modify the attribute set, but must not destroy it.  Destroying
index 4a1ac6f81acc81920a9d34c5c9208a6ee9e8681d..97079e667e1056f2c53564f8a2c819e2f2938660 100644 (file)
@@ -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 *);
index c854e0c2c25b43f6c712cda4073c52920c0a1b77..775b11e835cdcfef66404d4e225a3101049ea87a 100644 (file)
@@ -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. */
index cdc540bb2348dfa71b4d0451d20dd351c378981f..35f153e4f8c7cc17dc9bd67489c530640c0f765f 100644 (file)
@@ -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));
        }
     }
index 0840e96def627814d6feceff6ffe84e6f0596ae6..a9a426ee01a65fc03a986d3629fc9913656640b2 100644 (file)
@@ -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);
     }
 
index b74b0fa80286959f24ceb7bb882ae80b376592bf..377e40c555554792a18ff12b35129a8843c70226 100644 (file)
@@ -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;
index b0385fa577bc5fba89fdac23734c6fcddb5666f3..f8f4fbbecbfe44755e3c85dc4cf9480fad19d94c 100644 (file)
@@ -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);
index 3157153b5389ddbeb3db3918a2db5d1de67dc8ec..26de7bed81776d8e113b7676b9c544ea8f4f1cbe 100644 (file)
@@ -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);
index d73f5da9f843bacf0ff7302df0077454a407aa98..cb835967dba618a8fa2aeddc831d6f1d284c9da7 100644 (file)
@@ -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;
index 58e833e9e7a59f6f5f57ecf8d0f198ef34b036a1..446bb6a70dcff76dd84ac02564fe38cbc457138f 100644 (file)
@@ -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;
index 3f6b8fcfbb64d9538ff56b38bd2bc03c52198590..050a7f5be405fea162b105d84214f1c77c2b9a3c 100644 (file)
@@ -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));
 }
index 104afba89b5602fa5e4f626a2800272e5f43521e..3562885a831f3e797ae7634f98d1ef165b728579 100644 (file)
@@ -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))
          {
index 422c9c72b03e3e9cf32cf70cf4e59d021cfa9f3b..6fec906c0989aafc6489eadb168d864d22f5aee3 100644 (file)
@@ -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
index c3e1fc2b2465f0e60c4cfd95239212d9ef8da894..8073bb0229a26fbd8da68135b0ca8b16d79d3457 100644 (file)
@@ -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);
 
index 0a6614a641e5e70b59f028719bcec94e311541fc..173bf0e10f5a6efb602f8cbfc90abf51815d7bcd 100644 (file)
@@ -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;
 
index 87bdefd14ed5adccd0d722847f00d3e203a1b62c..33d82395e01e42187bd3a4c171aa5cdbbc4ca09f 100644 (file)
@@ -58,6 +58,7 @@ enum dict_signal_handler {
   VARIABLE_INSERTED,
   VARIABLE_CHANGED,
   VARIABLES_DELETED,
+  VARIABLE_MOVED,
   n_dict_signals
 };
 
index 0ed6841131d46f0d5bd435df65188d6ea73999a2..32a5cc13e26fa40d4c477023984c23d109141c77 100644 (file)
@@ -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