void *cb_data ; /* Data passed to callbacks */
};
+/* Print a representation of dictionary D to stdout, for
+ debugging purposes. */
+void
+dict_dump (const struct dictionary *d)
+{
+ int i;
+ for (i = 0 ; i < d->var_cnt ; ++i )
+ {
+ const struct variable *v =
+ d->var[i];
+ printf ("Name: %s;\tdict_idx: %d; case_idx: %d\n",
+ var_get_name (v),
+ var_get_dict_index (v),
+ var_get_case_index (v));
+
+ }
+}
/* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
the dictionary or any of the variables it contains are modified.
while (d->var_cnt > 0 )
{
- struct variable *v = d->var[d->var_cnt - 1];
- int dict_index = var_get_dict_index (v);
- int case_index = var_get_case_index (v);
- int val_cnt = var_get_value_cnt (v);
-
- var_clear_vardict (v);
- var_destroy (v);
-
- d->var_cnt--;
-
- if (d->callbacks && d->callbacks->var_deleted )
- d->callbacks->var_deleted (d,
- dict_index, case_index, val_cnt,
- d->cb_data);
+ dict_delete_var (d, d->var[d->var_cnt - 1]);
}
free (d->var);
struct variable *target ;
struct variable *result ;
- if ( ! var_is_valid_name (name, false))
+ if ( ! var_is_plausible_name (name, false))
return NULL;
target = var_create (name, 0);
var_clear_vardict (v);
var_destroy (v);
+
if (d->callbacks && d->callbacks->var_deleted )
d->callbacks->var_deleted (d, dict_index, case_index, val_cnt, d->cb_data);
}
return sizeof (union value) * dict_get_next_value_idx (d);
}
-/* Deletes scratch variables in dictionary D and reassigns values
- so that fragmentation is eliminated. */
+/* Reassigns values in dictionary D so that fragmentation is
+ eliminated. */
void
dict_compact_values (struct dictionary *d)
{
size_t i;
d->next_value_idx = 0;
- for (i = 0; i < d->var_cnt; )
+ for (i = 0; i < d->var_cnt; i++)
{
struct variable *v = d->var[i];
-
- if (dict_class_from_id (var_get_name (v)) != DC_SCRATCH)
- {
- set_var_case_index (v, d->next_value_idx);
- d->next_value_idx += var_get_value_cnt (v);
- i++;
- }
- else
- dict_delete_var (d, v);
+ set_var_case_index (v, d->next_value_idx);
+ d->next_value_idx += var_get_value_cnt (v);
}
}
-
/*
Reassigns case indices for D, increasing each index above START by
the value PADDING.
}
-/* Returns the number of values that would be used by a case if
- dict_compact_values() were called. */
+/* 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 (1u << DC_ORDINARY),
+ (1u << DC_SYSTEM), or (1u << DC_SCRATCH) to exclude the
+ corresponding type of variable.
+
+ The return value may be less than the number of values in one
+ of dictionary D's cases (as returned by
+ dict_get_next_value_idx) even if E is 0, because there may be
+ gaps in D's cases due to deleted variables. */
size_t
-dict_get_compacted_value_cnt (const struct dictionary *d)
+dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
{
size_t i;
size_t cnt;
- cnt = 0;
- for (i = 0; i < d->var_cnt; i++)
- if (dict_class_from_id (var_get_name (d->var[i])) != DC_SCRATCH)
- cnt += var_get_value_cnt (d->var[i]);
- return cnt;
-}
-
-/* Creates and returns an array mapping from a dictionary index
- to the case index that the corresponding variable will have
- after calling dict_compact_values(). Scratch variables
- receive -1 for case index because dict_compact_values() will
- delete them. */
-int *
-dict_get_compacted_dict_index_to_case_index (const struct dictionary *d)
-{
- size_t i;
- size_t next_value_idx;
- int *map;
+ assert ((exclude_classes & ~((1u << DC_ORDINARY)
+ | (1u << DC_SYSTEM)
+ | (1u << DC_SCRATCH))) == 0);
- map = xnmalloc (d->var_cnt, sizeof *map);
- next_value_idx = 0;
+ cnt = 0;
for (i = 0; i < d->var_cnt; i++)
{
- struct variable *v = d->var[i];
-
- if (dict_class_from_id (var_get_name (v)) != DC_SCRATCH)
- {
- map[i] = next_value_idx;
- next_value_idx += var_get_value_cnt (v);
- }
- else
- map[i] = -1;
- }
- return map;
-}
-
-/* Returns true if a case for dictionary D would be smaller after
- compacting, false otherwise. Compacting a case eliminates
- "holes" between values and after the last value. Holes are
- created by deleting variables (or by scratch variables).
-
- The return value may differ from whether compacting a case
- from dictionary D would *change* the case: compacting could
- rearrange values even if it didn't reduce space
- requirements. */
-bool
-dict_compacting_would_shrink (const struct dictionary *d)
-{
- return dict_get_compacted_value_cnt (d) < dict_get_next_value_idx (d);
-}
-
-/* Returns true if a case for dictionary D would change after
- compacting, false otherwise. Compacting a case eliminates
- "holes" between values and after the last value. Holes are
- created by deleting variables (or by scratch variables).
-
- The return value may differ from whether compacting a case
- from dictionary D would *shrink* the case: compacting could
- rearrange values without reducing space requirements. */
-bool
-dict_compacting_would_change (const struct dictionary *d)
-{
- size_t case_idx;
- size_t i;
-
- case_idx = 0;
- for (i = 0; i < dict_get_var_cnt (d); i++)
- {
- struct variable *v = dict_get_var (d, i);
- if (var_get_case_index (v) != case_idx)
- return true;
- case_idx += var_get_value_cnt (v);
+ enum dict_class class = dict_class_from_id (var_get_name (d->var[i]));
+ if (!(exclude_classes & (1u << class)))
+ cnt += var_get_value_cnt (d->var[i]);
}
- return false;
+ return cnt;
}
\f
-/* How to copy a contiguous range of values between cases. */
-struct copy_map
- {
- size_t src_idx; /* Starting value index in source case. */
- size_t dst_idx; /* Starting value index in target case. */
- size_t cnt; /* Number of values. */
- };
-
-/* How to compact a case. */
-struct dict_compactor
- {
- struct copy_map *maps; /* Array of mappings. */
- size_t map_cnt; /* Number of mappings. */
- };
-
-/* Creates and returns a dict_compactor that can be used to
- compact cases for dictionary D.
-
- Compacting a case eliminates "holes" between values and after
- the last value. Holes are created by deleting variables (or
- by scratch variables). */
-struct dict_compactor *
-dict_make_compactor (const struct dictionary *d)
-{
- struct dict_compactor *compactor;
- struct copy_map *map;
- size_t map_allocated;
- size_t value_idx;
- size_t i;
-
- compactor = xmalloc (sizeof *compactor);
- compactor->maps = NULL;
- compactor->map_cnt = 0;
- map_allocated = 0;
-
- value_idx = 0;
- map = NULL;
- for (i = 0; i < d->var_cnt; i++)
- {
- struct variable *v = d->var[i];
-
- if (dict_class_from_id (var_get_name (v)) == DC_SCRATCH)
- continue;
- if (map != NULL && map->src_idx + map->cnt == var_get_case_index (v))
- map->cnt += var_get_value_cnt (v);
- else
- {
- if (compactor->map_cnt == map_allocated)
- compactor->maps = x2nrealloc (compactor->maps, &map_allocated,
- sizeof *compactor->maps);
- map = &compactor->maps[compactor->map_cnt++];
- map->src_idx = var_get_case_index (v);
- map->dst_idx = value_idx;
- map->cnt = var_get_value_cnt (v);
- }
- value_idx += var_get_value_cnt (v);
- }
-
- return compactor;
-}
-
-/* Compacts SRC by copying it to DST according to the scheme in
- COMPACTOR.
-
- Compacting a case eliminates "holes" between values and after
- the last value. Holes are created by deleting variables (or
- by scratch variables). */
-void
-dict_compactor_compact (const struct dict_compactor *compactor,
- struct ccase *dst, const struct ccase *src)
-{
- size_t i;
-
- for (i = 0; i < compactor->map_cnt; i++)
- {
- const struct copy_map *map = &compactor->maps[i];
- case_copy (dst, map->dst_idx, src, map->src_idx, map->cnt);
- }
-}
-
-/* Destroys COMPACTOR. */
-void
-dict_compactor_destroy (struct dict_compactor *compactor)
-{
- if (compactor != NULL)
- {
- free (compactor->maps);
- free (compactor);
- }
-}
-
/* Returns the SPLIT FILE vars (see cmd_split_file()). Call
dict_get_split_cnt() to determine how many SPLIT FILE vars
there are. Returns a null pointer if and only if there are no
assert (cnt == 0 || split != NULL);
d->split_cnt = cnt;
- d->split = cnt > 0 ? xnrealloc (d->split, cnt, sizeof *d->split) : NULL;
- memcpy (d->split, split, cnt * sizeof *d->split);
+ if ( cnt > 0 )
+ {
+ d->split = xnrealloc (d->split, cnt, sizeof *d->split) ;
+ memcpy (d->split, split, cnt * sizeof *d->split);
+ }
+ else
+ {
+ free (d->split);
+ d->split = NULL;
+ }
if ( d->callbacks && d->callbacks->split_changed )
d->callbacks->split_changed (d, d->cb_data);