#include <libpspp/misc.h>
#include <libpspp/str.h>
+#include "minmax.h"
+
#include "gettext.h"
#define _(msgid) gettext (msgid)
size_t vector_cnt; /* Number of vectors. */
};
-/* Active file dictionary. */
-struct dictionary *default_dict;
-
/* Creates and returns a new dictionary. */
struct dictionary *
dict_create (void)
for (i = 0; i < s->var_cnt; i++)
{
struct variable *sv = s->var[i];
- struct variable *dv = dict_clone_var_assert (d, sv, sv->name);
- var_set_short_name (dv, sv->short_name);
+ struct variable *dv = dict_clone_var_assert (d, sv, var_get_name (sv));
+ var_set_short_name (dv, var_get_short_name (sv));
}
d->next_value_idx = s->next_value_idx;
{
d->split = xnmalloc (d->split_cnt, sizeof *d->split);
for (i = 0; i < d->split_cnt; i++)
- d->split[i] = dict_lookup_var_assert (d, s->split[i]->name);
+ d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
}
if (s->weight != NULL)
- d->weight = dict_lookup_var_assert (d, s->weight->name);
+ d->weight = dict_lookup_var_assert (d, var_get_name (s->weight));
if (s->filter != NULL)
- d->filter = dict_lookup_var_assert (d, s->filter->name);
+ d->filter = dict_lookup_var_assert (d, var_get_name (s->filter));
d->case_limit = s->case_limit;
dict_set_label (d, dict_get_label (s));
struct variable *v = d->var[i];
var_clear_aux (v);
val_labs_destroy (v->val_labs);
+ var_clear_label (v);
free (v->label);
free (v);
}
count = 0;
for (i = 0; i < d->var_cnt; i++)
- if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name))))
- count++;
-
+ {
+ enum dict_class class = dict_class_from_id (var_get_name (d->var[i]));
+ if (!(exclude_classes & (1u << class)))
+ count++;
+ }
+
*vars = xnmalloc (count, sizeof **vars);
*cnt = 0;
- for (i = 0; i < d->var_cnt; i++)
- if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name))))
- (*vars)[(*cnt)++] = d->var[i];
+ for (i = 0; i < d->var_cnt; i++)
+ {
+ enum dict_class class = dict_class_from_id (var_get_name (d->var[i]));
+ if (!(exclude_classes & (1u << class)))
+ (*vars)[(*cnt)++] = d->var[i];
+ }
assert (*cnt == count);
}
/* Allocate and initialize variable. */
v = xmalloc (sizeof *v);
- str_copy_trunc (v->name, sizeof v->name, name);
- v->type = width == 0 ? NUMERIC : ALPHA;
+ var_set_name (v, name);
v->width = width;
v->fv = d->next_value_idx;
- v->nv = width_to_bytes(width) / MAX_SHORT_STRING ;
- v->leave = dict_class_from_id (v->name) == DC_SCRATCH;
+ v->leave = dict_class_from_id (var_get_name (v)) == DC_SCRATCH;
v->index = d->var_cnt;
mv_init (&v->miss, width);
- if (v->type == NUMERIC)
+ if (var_is_numeric (v))
{
- v->print = f8_2;
+ v->print = fmt_for_output (FMT_F, 8, 2);
v->alignment = ALIGN_RIGHT;
v->display_width = 8;
v->measure = MEASURE_SCALE;
}
else
{
- v->print = make_output_format (FMT_A, v->width, 0);
+ v->print = fmt_for_output (FMT_A, var_get_width (v), 0);
v->alignment = ALIGN_LEFT;
v->display_width = 8;
v->measure = MEASURE_NOMINAL;
}
v->write = v->print;
- v->val_labs = val_labs_create (v->width);
+ v->val_labs = val_labs_create (var_get_width (v));
v->label = NULL;
var_clear_short_name (v);
v->aux = NULL;
d->var_cnt++;
hsh_force_insert (d->name_tab, v);
- d->next_value_idx += v->nv;
+ d->next_value_idx += var_get_value_cnt (v);
return v;
}
assert (strlen (name) >= 1);
assert (strlen (name) <= LONG_NAME_LEN);
- nv = dict_create_var (d, name, ov->width);
+ nv = dict_create_var (d, name, var_get_width (ov));
if (nv == NULL)
return NULL;
short_name[] is intentionally not copied, because there is
no reason to give a new variable with potentially a new name
the same short name. */
- nv->leave = ov->leave;
- mv_copy (&nv->miss, &ov->miss);
- nv->print = ov->print;
- nv->write = ov->write;
+ nv->leave = var_get_leave (ov);
+ var_set_missing_values (nv, var_get_missing_values (ov));
+ var_set_print_format (nv, var_get_print_format (ov));
+ var_set_write_format (nv, var_get_write_format (ov));
val_labs_destroy (nv->val_labs);
nv->val_labs = val_labs_copy (ov->val_labs);
- if (ov->label != NULL)
- nv->label = xstrdup (ov->label);
- nv->measure = ov->measure;
- nv->display_width = ov->display_width;
- nv->alignment = ov->alignment;
+ var_set_label (nv, var_get_label (ov));
+ var_set_measure (nv, var_get_measure (ov));
+ var_set_display_width (nv, var_get_display_width (ov));
+ var_set_alignment (nv, var_get_alignment (ov));
return nv;
}
/* Compares two double pointers to variables, which should point
to elements of a struct dictionary's `var' member array. */
static int
-compare_var_ptrs (const void *a_, const void *b_, void *aux UNUSED)
+compare_var_ptrs (const void *a_, const void *b_, const void *aux UNUSED)
{
struct variable *const *a = a_;
struct variable *const *b = b_;
/* Deletes variable V from dictionary D and frees V.
This is a very bad idea if there might be any pointers to V
- from outside D. In general, no variable in default_dict
- should be deleted when any transformations are active, because
+ from outside D. In general, no variable in should be deleted when
+ any transformations are active on the dictionary's dataset, because
those transformations might reference the deleted variable.
The safest time to delete a variable is just after a procedure
has been executed, as done by MODIFY VARS.
assert (d != NULL);
for (i = 0; i < d->var_cnt; )
- if (dict_class_from_id (d->var[i]->name) == DC_SCRATCH)
+ if (dict_class_from_id (var_get_name (d->var[i])) == DC_SCRATCH)
dict_delete_var (d, d->var[i]);
else
i++;
move_element (d->var, d->var_cnt, sizeof *d->var, v->index, new_index);
- min_idx = min (v->index, new_index);
- max_idx = max (v->index, new_index);
+ min_idx = MIN (v->index, new_index);
+ max_idx = MAX (v->index, new_index);
for (i = min_idx; i <= max_idx; i++)
d->var[i]->index = i;
}
assert (new_name != NULL);
assert (var_is_plausible_name (new_name, false));
assert (dict_contains_var (d, v));
- assert (!compare_var_names (v->name, new_name, NULL)
+ assert (!compare_var_names (var_get_name (v), new_name, NULL)
|| dict_lookup_var (d, new_name) == NULL);
hsh_force_delete (d->name_tab, v);
- str_copy_trunc (v->name, sizeof v->name, new_name);
+ var_set_name (v, new_name);
hsh_force_insert (d->name_tab, v);
if (get_algorithm () == ENHANCED)
assert (d->var[vars[i]->index] == vars[i]);
assert (var_is_plausible_name (new_names[i], false));
hsh_force_delete (d->name_tab, vars[i]);
- old_names[i] = xstrdup (vars[i]->name);
- strcpy (vars[i]->name, new_names[i]);
+ old_names[i] = xstrdup (var_get_name (vars[i]));
+ var_set_name (vars[i], new_names[i]);
}
/* Add the renamed variables back into the name hash,
for (i = 0; i < count; i++)
{
- strcpy (vars[i]->name, old_names[i]);
+ var_set_name (vars[i], old_names[i]);
hsh_force_insert (d->name_tab, vars[i]);
}
/* Returns the value of D's weighting variable in case C, except that a
negative weight is returned as 0. Returns 1 if the dictionary is
unweighted. Will warn about missing, negative, or zero values if
- warn_on_invalid is nonzero. The function will set warn_on_invalid to zero
+ warn_on_invalid is true. The function will set warn_on_invalid to false
if an invalid weight is found. */
double
dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
- int *warn_on_invalid)
+ bool *warn_on_invalid)
{
assert (d != NULL);
assert (c != NULL);
else
{
double w = case_num (c, d->weight->fv);
- if (w < 0.0 || mv_is_num_missing (&d->weight->miss, w))
+ if (w < 0.0 || var_is_num_missing (d->weight, w))
w = 0.0;
if ( w == 0.0 && *warn_on_invalid ) {
- *warn_on_invalid = 0;
+ *warn_on_invalid = false;
msg (SW, _("At least one case in the data file had a weight value "
"that was user-missing, system-missing, zero, or "
"negative. These case(s) were ignored."));
{
assert (d != NULL);
assert (v == NULL || dict_contains_var (d, v));
- assert (v == NULL || v->type == NUMERIC);
+ assert (v == NULL || var_is_numeric (v));
d->weight = v;
}
{
struct variable *v = d->var[i];
- if (dict_class_from_id (v->name) != DC_SCRATCH)
+ if (dict_class_from_id (var_get_name (v)) != DC_SCRATCH)
{
v->fv = d->next_value_idx;
- d->next_value_idx += v->nv;
+ d->next_value_idx += var_get_value_cnt (v);
i++;
}
else
cnt = 0;
for (i = 0; i < d->var_cnt; i++)
- if (dict_class_from_id (d->var[i]->name) != DC_SCRATCH)
- cnt += d->var[i]->nv;
+ if (dict_class_from_id (var_get_name (d->var[i])) != DC_SCRATCH)
+ cnt += var_get_value_cnt (d->var[i]);
return cnt;
}
{
struct variable *v = d->var[i];
- if (dict_class_from_id (v->name) != DC_SCRATCH)
+ if (dict_class_from_id (var_get_name (v)) != DC_SCRATCH)
{
idx_to_fv[i] = next_value_idx;
- next_value_idx += v->nv;
+ next_value_idx += var_get_value_cnt (v);
}
else
idx_to_fv[i] = -1;
}
/* Returns true if a case for dictionary D would be smaller after
- compaction, false otherwise. Compacting a case eliminates
+ 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: compaction could
+ from dictionary D would *change* the case: compacting could
rearrange values even if it didn't reduce space
requirements. */
bool
-dict_needs_compaction (const struct dictionary *d)
+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 (v->fv != case_idx)
+ return true;
+ case_idx += var_get_value_cnt (v);
+ }
+ return false;
+}
\f
/* How to copy a contiguous range of values between cases. */
struct copy_map
{
struct variable *v = d->var[i];
- if (dict_class_from_id (v->name) == DC_SCRATCH)
+ if (dict_class_from_id (var_get_name (v)) == DC_SCRATCH)
continue;
if (map != NULL && map->src_idx + map->cnt == v->fv)
- map->cnt += v->nv;
+ map->cnt += var_get_value_cnt (v);
else
{
if (compactor->map_cnt == map_allocated)
map = &compactor->maps[compactor->map_cnt++];
map->src_idx = v->fv;
map->dst_idx = value_idx;
- map->cnt = v->nv;
+ map->cnt = var_get_value_cnt (v);
}
- value_idx += v->nv;
+ value_idx += var_get_value_cnt (v);
}
return compactor;
/* Compares two strings. */
static int
-compare_strings (const void *a, const void *b, void *aux UNUSED)
+compare_strings (const void *a, const void *b, const void *aux UNUSED)
{
return strcmp (a, b);
}
/* Hashes a string. */
static unsigned
-hash_string (const void *s, void *aux UNUSED)
+hash_string (const void *s, const void *aux UNUSED)
{
return hsh_hash_string (s);
}
for (i = 0; i < d->var_cnt; i++)
{
struct variable *v = d->var[i];
- if (strlen (v->name) <= SHORT_NAME_LEN)
- var_set_short_name (v, v->name);
- else if (dict_lookup_var (d, v->short_name) != NULL)
+ const char *short_name = var_get_short_name (v);
+ if (strlen (var_get_name (v)) <= SHORT_NAME_LEN)
+ var_set_short_name (v, var_get_name (v));
+ else if (short_name != NULL && dict_lookup_var (d, short_name) != NULL)
var_clear_short_name (v);
}
for (i = 0; i < d->var_cnt; i++)
{
struct variable *v = d->var[i];
- if (v->short_name[0] && hsh_insert (short_names, v->short_name) != NULL)
+ const char *name = var_get_short_name (v);
+ if (name != NULL && hsh_insert (short_names, (char *) name) != NULL)
var_clear_short_name (v);
}
for (i = 0; i < d->var_cnt; i++)
{
struct variable *v = d->var[i];
- if (v->short_name[0] == '\0')
+ const char *name = var_get_short_name (v);
+ if (name == NULL)
{
- int sfx;
-
- /* Form initial short_name. */
- var_set_short_name (v, v->name);
+ /* Form initial short_name from the variable name, then
+ try _A, _B, ... _AA, _AB, etc., if needed.*/
+ int trial = 0;
+ do
+ {
+ if (trial == 0)
+ var_set_short_name (v, var_get_name (v));
+ else
+ var_set_short_name_suffix (v, var_get_name (v), trial - 1);
- /* Try _A, _B, ... _AA, _AB, etc., if needed. */
- for (sfx = 0; hsh_insert (short_names, v->short_name) != NULL; sfx++)
- var_set_short_name_suffix (v, v->name, sfx);
+ trial++;
+ }
+ while (hsh_insert (short_names, (char *) var_get_short_name (v))
+ != NULL);
}
}