/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
#include "algorithm.h"
#include "alloc.h"
#include "case.h"
+#include "cat.h"
+#include "cat-routines.h"
#include "error.h"
#include "hash.h"
#include "misc.h"
d->split_cnt = s->split_cnt;
if (d->split_cnt > 0)
{
- d->split = xmalloc (d->split_cnt * sizeof *d->split);
+ 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);
}
dict_set_documents (d, dict_get_documents (s));
d->vector_cnt = s->vector_cnt;
- d->vector = xmalloc (d->vector_cnt * sizeof *d->vector);
+ d->vector = xnmalloc (d->vector_cnt, sizeof *d->vector);
for (i = 0; i < s->vector_cnt; i++)
{
struct vector *sv = s->vector[i];
dv->idx = i;
strcpy (dv->name, sv->name);
dv->cnt = sv->cnt;
- dv->var = xmalloc (dv->cnt * sizeof *dv->var);
+ dv->var = xnmalloc (dv->cnt, sizeof *dv->var);
for (j = 0; j < dv->cnt; j++)
dv->var[j] = d->var[sv->var[j]->index];
}
if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name))))
count++;
- *vars = xmalloc (count * sizeof **vars);
+ *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))))
assert (d != NULL);
assert (name != NULL);
- assert (strlen (name) >= 1);
- assert (strlen (name) <= LONG_NAME_LEN);
-
assert (width >= 0 && width < 256);
+
+ assert (var_is_valid_name(name,0));
/* Make sure there's not already a variable by that name. */
if (dict_lookup_var (d, name) != NULL)
var_clear_short_name (v);
v->aux = NULL;
v->aux_dtor = NULL;
+ v->obs_vals = NULL;
/* Update dictionary. */
if (d->var_cnt >= d->var_cap)
{
d->var_cap = 8 + 2 * d->var_cap;
- d->var = xrealloc (d->var, d->var_cap * sizeof *d->var);
+ d->var = xnrealloc (d->var, d->var_cap, sizeof *d->var);
}
d->var[v->index] = v;
d->var_cnt++;
return v;
}
-/* Returns nonzero if variable V is in dictionary D. */
-int
+/* Returns true if variable V is in dictionary D,
+ false otherwise. */
+bool
dict_contains_var (const struct dictionary *d, const struct variable *v)
{
assert (d != NULL);
/* Free memory. */
val_labs_destroy (v->val_labs);
+ cat_stored_values_destroy (v);
free (v->label);
free (v);
}
assert (count == 0 || order != NULL);
assert (count <= d->var_cnt);
- new_var = xmalloc (d->var_cnt * sizeof *new_var);
+ new_var = xnmalloc (d->var_cnt, sizeof *new_var);
memcpy (new_var, order, count * sizeof *new_var);
for (i = 0; i < count; i++)
{
/* Renames COUNT variables specified in VARS to the names given
in NEW_NAMES within dictionary D. If the renaming would
- result in a duplicate variable name, returns zero and stores a
+ result in a duplicate variable name, returns false and stores a
name that would be duplicated into *ERR_NAME (if ERR_NAME is
- non-null). Otherwise, the renaming is successful, and nonzero
+ non-null). Otherwise, the renaming is successful, and true
is returned. */
-int
+bool
dict_rename_vars (struct dictionary *d,
struct variable **vars, char **new_names,
size_t count, char **err_name)
{
char **old_names;
size_t i;
- int success = 1;
+ bool success = true;
assert (d != NULL);
assert (count == 0 || vars != NULL);
/* Remove the variables to be renamed from the name hash,
save their names, and rename them. */
- old_names = xmalloc (count * sizeof *old_names);
+ old_names = xnmalloc (count, sizeof *old_names);
for (i = 0; i < count; i++)
{
assert (d->var[vars[i]->index] == vars[i]);
hsh_force_insert (d->name_tab, vars[i]);
}
- success = 0;
+ success = false;
goto done;
}
}
}
}
-/* Copies values from SRC, which represents a case arranged
- according to dictionary D, to DST, which represents a case
- arranged according to the dictionary that will be produced by
- dict_compact_values(D). */
-void
-dict_compact_case (const struct dictionary *d,
- struct ccase *dst, const struct ccase *src)
-{
- size_t i;
- size_t value_idx;
-
- value_idx = 0;
- for (i = 0; i < d->var_cnt; i++)
- {
- struct variable *v = d->var[i];
-
- if (dict_class_from_id (v->name) != DC_SCRATCH)
- {
- case_copy (dst, value_idx, src, v->fv, v->nv);
- value_idx += v->nv;
- }
- }
-}
-
/* Returns the number of values that would be used by a case if
dict_compact_values() were called. */
size_t
size_t next_value_idx;
int *idx_to_fv;
- idx_to_fv = xmalloc (d->var_cnt * sizeof *idx_to_fv);
+ idx_to_fv = xnmalloc (d->var_cnt, sizeof *idx_to_fv);
next_value_idx = 0;
for (i = 0; i < d->var_cnt; i++)
{
return idx_to_fv;
}
+/* Returns true if a case for dictionary D would be smaller after
+ compaction, 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
+ rearrange values even if it didn't reduce space
+ requirements. */
+bool
+dict_needs_compaction (const struct dictionary *d)
+{
+ return dict_get_compacted_value_cnt (d) < dict_get_next_value_idx (d);
+}
+\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 (v->name) == DC_SCRATCH)
+ continue;
+ if (map != NULL && map->src_idx + map->cnt == v->fv)
+ map->cnt += v->nv;
+ 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 = v->fv;
+ map->dst_idx = value_idx;
+ map->cnt = v->nv;
+ }
+ value_idx += v->nv;
+ }
+
+ 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 = xrealloc (d->split, cnt * sizeof *d->split);
+ d->split = xnrealloc (d->split, cnt, sizeof *d->split);
memcpy (d->split, split, cnt * sizeof *d->split);
}
}
/* Creates in D a vector named NAME that contains CNT variables
- VAR (see cmd_vector()). Returns nonzero if successful, or
- zero if a vector named NAME already exists in D. */
-int
+ VAR (see cmd_vector()). Returns true if successful, or
+ false if a vector named NAME already exists in D. */
+bool
dict_create_vector (struct dictionary *d,
const char *name,
struct variable **var, size_t cnt)
assert (cnt > 0);
if (dict_lookup_vector (d, name) != NULL)
- return 0;
+ return false;
- d->vector = xrealloc (d->vector, (d->vector_cnt + 1) * sizeof *d->vector);
+ d->vector = xnrealloc (d->vector, d->vector_cnt + 1, sizeof *d->vector);
vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector);
vector->idx = d->vector_cnt++;
str_copy_trunc (vector->name, sizeof vector->name, name);
- vector->var = xmalloc (cnt * sizeof *var);
+ vector->var = xnmalloc (cnt, sizeof *var);
for (i = 0; i < cnt; i++)
{
assert (dict_contains_var (d, var[i]));
}
vector->cnt = cnt;
- return 1;
+ return true;
}
/* Returns the vector in D with index IDX, which must be less