char *documents; /* Documents, as a string. */
struct vector **vector; /* Vectors of variables. */
size_t vector_cnt; /* Number of vectors. */
+ const struct dict_callbacks *callbacks; /* Callbacks on dictionary
+ modification */
+ void *cb_data ; /* Data passed to callbacks */
};
+
+/* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
+ the dictionary or any of the variables it contains are modified.
+ Each callback will get passed CALLBACK_DATA.
+ Any callback may be NULL, in which case it'll be ignored.
+*/
+void
+dict_set_callbacks (struct dictionary *dict,
+ const struct dict_callbacks *callbacks,
+ void *callback_data)
+{
+ dict->callbacks = callbacks;
+ dict->cb_data = callback_data;
+}
+
+
/* Creates and returns a new dictionary. */
struct dictionary *
-dict_create (void)
+dict_create (void)
{
- struct dictionary *d = xmalloc (sizeof *d);
-
+ struct dictionary *d = xzalloc (sizeof *d);
+
d->var = NULL;
d->var_cnt = d->var_cap = 0;
d->name_tab = hsh_create (8, compare_vars_by_name, hash_var_by_name,
/* Creates and returns a (deep) copy of an existing
dictionary. */
struct dictionary *
-dict_clone (const struct dictionary *s)
+dict_clone (const struct dictionary *s)
{
struct dictionary *d;
size_t i;
d = dict_create ();
- for (i = 0; i < s->var_cnt; i++)
+ for (i = 0; i < s->var_cnt; i++)
{
struct variable *sv = s->var[i];
struct variable *dv = dict_clone_var_assert (d, sv, var_get_name (sv));
d->next_value_idx = s->next_value_idx;
d->split_cnt = s->split_cnt;
- if (d->split_cnt > 0)
+ if (d->split_cnt > 0)
{
d->split = xnmalloc (d->split_cnt, sizeof *d->split);
- for (i = 0; i < d->split_cnt; i++)
+ for (i = 0; i < d->split_cnt; i++)
d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
}
- if (s->weight != NULL)
+ if (s->weight != NULL)
d->weight = dict_lookup_var_assert (d, var_get_name (s->weight));
- if (s->filter != NULL)
+ if (s->filter != NULL)
d->filter = dict_lookup_var_assert (d, var_get_name (s->filter));
d->case_limit = s->case_limit;
/* Clears the contents from a dictionary without destroying the
dictionary itself. */
void
-dict_clear (struct dictionary *d)
+dict_clear (struct dictionary *d)
{
/* FIXME? Should we really clear case_limit, label, documents?
Others are necessarily cleared by deleting all the variables.*/
for (i = 0; i < d->var_cnt; i++)
{
var_clear_vardict (d->var[i]);
- var_destroy (d->var[i]);
+ var_destroy (d->var[i]);
}
free (d->var);
d->var = NULL;
/* Destroys the aux data for every variable in D, by calling
var_clear_aux() for each variable. */
void
-dict_clear_aux (struct dictionary *d)
+dict_clear_aux (struct dictionary *d)
{
int i;
-
+
assert (d != NULL);
-
+
for (i = 0; i < d->var_cnt; i++)
var_clear_aux (d->var[i]);
}
void
dict_destroy (struct dictionary *d)
{
- if (d != NULL)
+ if (d != NULL)
{
dict_clear (d);
hsh_destroy (d->name_tab);
/* Returns the number of variables in D. */
size_t
-dict_get_var_cnt (const struct dictionary *d)
+dict_get_var_cnt (const struct dictionary *d)
{
assert (d != NULL);
must be between 0 and the count returned by
dict_get_var_cnt(), exclusive. */
struct variable *
-dict_get_var (const struct dictionary *d, size_t idx)
+dict_get_var (const struct dictionary *d, size_t idx)
{
assert (d != NULL);
assert (idx < d->var_cnt);
{
size_t count;
size_t i;
-
+
assert (d != NULL);
assert (vars != NULL);
assert (cnt != NULL);
assert ((exclude_classes & ~((1u << DC_ORDINARY)
| (1u << DC_SYSTEM)
| (1u << DC_SCRATCH))) == 0);
-
+
count = 0;
for (i = 0; i < d->var_cnt; i++)
{
if (!(exclude_classes & (1u << class)))
count++;
}
-
+
*vars = xnmalloc (count, sizeof **vars);
*cnt = 0;
- for (i = 0; i < d->var_cnt; 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];
+ (*vars)[(*cnt)++] = d->var[i];
}
assert (*cnt == count);
}
static struct variable *
-add_var (struct dictionary *d, struct variable *v)
+add_var (struct dictionary *d, struct variable *v)
{
/* Add dictionary info to variable. */
struct vardict_info vdi;
vdi.case_index = d->next_value_idx;
vdi.dict_index = d->var_cnt;
+ vdi.dict = d;
var_set_vardict (v, &vdi);
/* Update dictionary. */
- if (d->var_cnt >= d->var_cap)
+ if (d->var_cnt >= d->var_cap)
{
- d->var_cap = 8 + 2 * d->var_cap;
+ d->var_cap = 8 + 2 * d->var_cap;
d->var = xnrealloc (d->var, d->var_cap, sizeof *d->var);
}
d->var[d->var_cnt++] = v;
hsh_force_insert (d->name_tab, v);
+ if ( d->callbacks && d->callbacks->var_added )
+ d->callbacks->var_added (d, d->next_value_idx, d->cb_data);
+
d->next_value_idx += var_get_value_cnt (v);
return v;
bool
dict_contains_var (const struct dictionary *d, const struct variable *v)
{
- if (var_has_vardict (v))
+ if (var_has_vardict (v))
{
const struct vardict_info *vdi = var_get_vardict (v);
return (vdi->dict_index >= 0
&& vdi->dict_index < d->var_cnt
- && d->var[vdi->dict_index] == v);
+ && d->var[vdi->dict_index] == v);
}
else
return false;
{
struct vardict_info vdi = *var_get_vardict (v);
vdi.dict_index = dict_index;
- var_set_vardict (v, &vdi);
+ var_set_vardict (v, &vdi);
}
/* Sets the case_index in V's vardict to DICT_INDEX. */
{
struct vardict_info vdi = *var_get_vardict (v);
vdi.case_index = case_index;
- var_set_vardict (v, &vdi);
+ var_set_vardict (v, &vdi);
}
/* Re-sets the dict_index in the dictionary variables with
indexes from FROM to TO (exclusive). */
static void
-reindex_vars (struct dictionary *d, size_t from, size_t to)
+reindex_vars (struct dictionary *d, size_t from, size_t to)
{
size_t i;
-
+
for (i = from; i < to; i++)
set_var_dict_index (d->var[i], i);
}
/* Update name hash. */
hsh_force_delete (d->name_tab, v);
+
/* Free memory. */
var_clear_vardict (v);
var_destroy (v);
+
+ if (d->callbacks && d->callbacks->var_deleted )
+ d->callbacks->var_deleted (d, dict_index, d->cb_data);
}
/* Deletes the COUNT variables listed in VARS from D. This is
/* Changes the name of V in D to name NEW_NAME. Assert-fails if
a variable named NEW_NAME is already in D, except that
NEW_NAME may be the same as V's existing name. */
-void
+void
dict_rename_var (struct dictionary *d, struct variable *v,
- const char *new_name)
+ const char *new_name)
{
assert (!strcasecmp (var_get_name (v), new_name)
|| dict_lookup_var (d, new_name) == NULL);
if (get_algorithm () == ENHANCED)
var_clear_short_name (v);
+
+ if ( d->callbacks && d->callbacks->var_changed )
+ d->callbacks->var_changed (d, var_get_dict_index (v), d->cb_data);
}
/* Renames COUNT variables specified in VARS to the names given
/* Get rid of hash table. */
hsh_destroy (short_names);
}
+
+
+/* Called from variable.c to notify the dictionary that some property of
+ the variable has changed */
+void
+dict_var_changed (const struct variable *v)
+{
+ if ( var_has_vardict (v))
+ {
+ const struct vardict_info *vdi = var_get_vardict (v);
+ struct dictionary *d;
+
+ d = vdi->dict;
+
+ if ( d->callbacks && d->callbacks->var_changed )
+ d->callbacks->var_changed (d, var_get_dict_index (v), d->cb_data);
+ }
+}