X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdictionary.c;h=9b69c89844a347e041269e783f0a54a9af366e95;hb=ca1feaeed4961242699d0b7ba61def0c58515ddd;hp=dba6bb142a065c564ef0b32577d207338aa06498;hpb=3a7fba81ceae5b049d0f7d671e9e3c3c43bbf703;p=pspp-builds.git diff --git a/src/dictionary.c b/src/dictionary.c index dba6bb14..9b69c898 100644 --- a/src/dictionary.c +++ b/src/dictionary.c @@ -34,7 +34,7 @@ struct dictionary struct variable **var; /* Variables. */ size_t var_cnt, var_cap; /* Number of variables, capacity. */ struct hsh_table *name_tab; /* Variable index by name. */ - int value_cnt; /* Number of `union value's per case. */ + int next_value_idx; /* Index of next `union value' to allocate. */ struct variable **split; /* SPLIT FILE vars. */ size_t split_cnt; /* SPLIT FILE count. */ struct variable *weight; /* WEIGHT variable. */ @@ -46,6 +46,7 @@ struct dictionary size_t vector_cnt; /* Number of vectors. */ }; +/* Creates and returns a new dictionary. */ struct dictionary * dict_create (void) { @@ -54,7 +55,7 @@ dict_create (void) d->var = NULL; d->var_cnt = d->var_cap = 0; d->name_tab = hsh_create (8, compare_variables, hash_variable, NULL, NULL); - d->value_cnt = 0; + d->next_value_idx = 0; d->split = NULL; d->split_cnt = 0; d->weight = NULL; @@ -68,6 +69,8 @@ dict_create (void) return d; } +/* Creates and returns a (deep) copy of an existing + dictionary. */ struct dictionary * dict_clone (const struct dictionary *s) { @@ -79,30 +82,21 @@ dict_clone (const struct dictionary *s) d = dict_create (); for (i = 0; i < s->var_cnt; i++) dict_clone_var (d, s->var[i], s->var[i]->name); - d->value_cnt = s->value_cnt; + d->next_value_idx = s->next_value_idx; d->split_cnt = s->split_cnt; if (d->split_cnt > 0) { d->split = xmalloc (d->split_cnt * sizeof *d->split); for (i = 0; i < d->split_cnt; i++) - { - d->split[i] = dict_lookup_var (d, s->split[i]->name); - assert (d->split[i] != NULL); - } + d->split[i] = dict_lookup_var_assert (d, s->split[i]->name); } if (s->weight != NULL) - { - d->weight = dict_lookup_var (d, s->weight->name); - assert (d->weight != NULL); - } + d->weight = dict_lookup_var_assert (d, s->weight->name); if (s->filter != NULL) - { - d->filter = dict_lookup_var (d, s->filter->name); - assert (d->filter != NULL); - } + d->filter = dict_lookup_var_assert (d, s->filter->name); d->case_limit = s->case_limit; dict_set_label (d, dict_get_label (s)); @@ -115,6 +109,8 @@ dict_clone (const struct dictionary *s) return d; } +/* Clears the contents from a dictionary without destroying the + dictionary itself. */ void dict_clear (struct dictionary *d) { @@ -135,7 +131,7 @@ dict_clear (struct dictionary *d) d->var = NULL; d->var_cnt = d->var_cap = 0; hsh_clear (d->name_tab); - d->value_cnt = 0; + d->next_value_idx = 0; free (d->split); d->split = NULL; d->split_cnt = 0; @@ -149,6 +145,7 @@ dict_clear (struct dictionary *d) dict_clear_vectors (d); } +/* Clears a dictionary and destroys it. */ void dict_destroy (struct dictionary *d) { @@ -160,6 +157,7 @@ dict_destroy (struct dictionary *d) } } +/* Returns the number of variables in D. */ size_t dict_get_var_cnt (const struct dictionary *d) { @@ -168,6 +166,9 @@ dict_get_var_cnt (const struct dictionary *d) return d->var_cnt; } +/* Returns the variable in D with index IDX, which 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) { @@ -177,6 +178,10 @@ dict_get_var (const struct dictionary *d, size_t idx) return d->var[idx]; } +/* Sets *VARS to an array of pointers to variables in D and *CNT + to the number of variables in *D. By default all variables + are returned, but bits may be set in EXCLUDE_CLASSES to + exclude ordinary, system, and/or scratch variables. */ void dict_get_vars (const struct dictionary *d, struct variable ***vars, size_t *cnt, unsigned exclude_classes) @@ -204,6 +209,9 @@ dict_get_vars (const struct dictionary *d, struct variable ***vars, assert (*cnt == count); } +/* 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. */ struct variable * dict_create_var (struct dictionary *d, const char *name, int width) { @@ -225,9 +233,10 @@ dict_create_var (struct dictionary *d, const char *name, int width) v->index = d->var_cnt; v->type = width == 0 ? NUMERIC : ALPHA; v->width = width; - v->fv = d->value_cnt; + v->fv = d->next_value_idx; v->nv = width == 0 ? 1 : DIV_RND_UP (width, 8); - v->left = name[0] == '#'; + v->init = 1; + v->reinit = name[0] != '#'; v->miss_type = MISSING_NONE; if (v->type == NUMERIC) { @@ -241,6 +250,7 @@ dict_create_var (struct dictionary *d, const char *name, int width) v->print.w = v->width; v->print.d = 0; } + v->write = v->print; v->val_labs = val_labs_create (v->width); v->label = NULL; @@ -253,11 +263,24 @@ dict_create_var (struct dictionary *d, const char *name, int width) d->var[v->index] = v; d->var_cnt++; hsh_force_insert (d->name_tab, v); - d->value_cnt += v->nv; + d->next_value_idx += v->nv; + + return v; +} +/* Creates and returns a new variable in D with the given NAME + and WIDTH. Assert-fails if the given NAME would duplicate + that of an existing variable in the dictionary. */ +struct variable * +dict_create_var_assert (struct dictionary *d, const char *name, int width) +{ + struct variable *v = dict_create_var (d, name, width); + assert (v != NULL); return v; } +/* Creates a new variable in D named NAME, as a copy of existing + variable OV, which need not be in D or in any dictionary. */ struct variable * dict_clone_var (struct dictionary *d, const struct variable *ov, const char *name) @@ -273,7 +296,8 @@ dict_clone_var (struct dictionary *d, const struct variable *ov, if (nv == NULL) return NULL; - nv->left = ov->left; + nv->init = 1; + nv->reinit = ov->reinit; nv->miss_type = ov->miss_type; memcpy (nv->missing, ov->missing, sizeof nv->missing); nv->print = ov->print; @@ -286,6 +310,9 @@ dict_clone_var (struct dictionary *d, const struct variable *ov, return nv; } +/* 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 dict_rename_var (struct dictionary *d, struct variable *v, const char *new_name) @@ -306,6 +333,8 @@ dict_rename_var (struct dictionary *d, struct variable *v, hsh_force_insert (d->name_tab, v); } +/* Returns the variable named NAME in D, or a null pointer if no + variable has that name. */ struct variable * dict_lookup_var (const struct dictionary *d, const char *name) { @@ -321,6 +350,17 @@ dict_lookup_var (const struct dictionary *d, const char *name) return hsh_find (d->name_tab, &v); } +/* Returns the variable named NAME in D. Assert-fails if no + variable has that name. */ +struct variable * +dict_lookup_var_assert (const struct dictionary *d, const char *name) +{ + struct variable *v = dict_lookup_var (d, name); + assert (v != NULL); + return v; +} + +/* Returns nonzero if variable V is in dictionary D. */ int dict_contains_var (const struct dictionary *d, const struct variable *v) { @@ -330,8 +370,10 @@ dict_contains_var (const struct dictionary *d, const struct variable *v) return dict_lookup_var (d, v->name) == v; } +/* Compares two double pointers to variables, which should point + to elements of a struct dictionary's `var' member array. */ static int -compare_variable_dblptrs (const void *a_, const void *b_, void *aux unused) +compare_variable_dblptrs (const void *a_, const void *b_, void *aux UNUSED) { struct variable *const *a = a_; struct variable *const *b = b_; @@ -344,12 +386,23 @@ compare_variable_dblptrs (const void *a_, const void *b_, void *aux unused) return 0; } +/* 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 + 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. + + Pointers to V within D are not a problem, because + dict_delete_var() knows to remove V from split variables, + weights, filters, etc. */ void dict_delete_var (struct dictionary *d, struct variable *v) { size_t i; - /* FIXME? Does not sync d->value_cnt. */ assert (d != NULL); assert (v != NULL); assert (dict_contains_var (d, v)); @@ -381,9 +434,10 @@ dict_delete_var (struct dictionary *d, struct variable *v) val_labs_destroy (v->val_labs); free (v->label); free (v); - } +/* Deletes the COUNT variables listed in VARS from D. This is + unsafe; see the comment on dict_delete_var() for details. */ void dict_delete_vars (struct dictionary *d, struct variable *const *vars, size_t count) @@ -397,6 +451,10 @@ dict_delete_vars (struct dictionary *d, dict_delete_var (d, *vars++); } +/* Reorders the variables in D, placing the COUNT variables + listed in ORDER in that order at the beginning of D. The + other variables in D, if any, retain their relative + positions. */ void dict_reorder_vars (struct dictionary *d, struct variable *const *order, size_t count) @@ -428,6 +486,12 @@ dict_reorder_vars (struct dictionary *d, d->var = new_var; } +/* 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 + name that would be duplicated into *ERR_NAME (if ERR_NAME is + non-null). Otherwise, the renaming is successful, and nonzero + is returned. */ int dict_rename_vars (struct dictionary *d, struct variable **vars, char **new_names, @@ -452,6 +516,7 @@ dict_rename_vars (struct dictionary *d, for (i = 0; i < count; i++) { assert (new_names[i] != NULL); + assert (*new_names[i] != '\0'); assert (strlen (new_names[i]) < 9); strcpy (vars[i]->name, new_names[i]); if (hsh_insert (d->name_tab, vars[i]) != NULL) @@ -481,6 +546,8 @@ dict_rename_vars (struct dictionary *d, return success; } +/* Returns the weighting variable in dictionary D, or a null + pointer if the dictionary is unweighted. */ struct variable * dict_get_weight (const struct dictionary *d) { @@ -490,6 +557,9 @@ dict_get_weight (const struct dictionary *d) return d->weight; } +/* 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. */ double dict_get_case_weight (const struct dictionary *d, const struct ccase *c) { @@ -507,6 +577,8 @@ dict_get_case_weight (const struct dictionary *d, const struct ccase *c) } } +/* Sets the weighting variable of D to V, or turning off + weighting if V is a null pointer. */ void dict_set_weight (struct dictionary *d, struct variable *v) { @@ -517,6 +589,8 @@ dict_set_weight (struct dictionary *d, struct variable *v) d->weight = v; } +/* Returns the filter variable in dictionary D (see cmd_filter()) + or a null pointer if the dictionary is unfiltered. */ struct variable * dict_get_filter (const struct dictionary *d) { @@ -526,6 +600,8 @@ dict_get_filter (const struct dictionary *d) return d->filter; } +/* Sets V as the filter variable for dictionary D. Passing a + null pointer for V turn off filtering. */ void dict_set_filter (struct dictionary *d, struct variable *v) { @@ -535,6 +611,8 @@ dict_set_filter (struct dictionary *d, struct variable *v) d->filter = v; } +/* Returns the case limit for dictionary D, or zero if the number + of cases is unlimited (see cmd_n()). */ int dict_get_case_limit (const struct dictionary *d) { @@ -543,6 +621,8 @@ dict_get_case_limit (const struct dictionary *d) return d->case_limit; } +/* Sets CASE_LIMIT as the case limit for dictionary D. Zero for + CASE_LIMIT indicates no limit. */ void dict_set_case_limit (struct dictionary *d, int case_limit) { @@ -552,29 +632,48 @@ dict_set_case_limit (struct dictionary *d, int case_limit) d->case_limit = case_limit; } +/* Returns the index of the next value to be added to D. This + value is the number of `union value's that need to be + allocated to store a case for dictionary D. */ int -dict_get_value_cnt (const struct dictionary *d) +dict_get_next_value_idx (const struct dictionary *d) +{ + assert (d != NULL); + + return d->next_value_idx; +} + +/* Returns the number of bytes needed to store a case for + dictionary D. */ +size_t +dict_get_case_size (const struct dictionary *d) { assert (d != NULL); - return d->value_cnt; + return sizeof (union value) * dict_get_next_value_idx (d); } +/* Reassigns values in dictionary D so that fragmentation is + eliminated. */ void dict_compact_values (struct dictionary *d) { size_t i; - d->value_cnt = 0; + d->next_value_idx = 0; for (i = 0; i < d->var_cnt; i++) { struct variable *v = d->var[i]; - v->fv = d->value_cnt; - d->value_cnt += v->nv; + v->fv = d->next_value_idx; + d->next_value_idx += v->nv; } } +/* 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 + SPLIT FILE vars. */ struct variable *const * dict_get_split_vars (const struct dictionary *d) { @@ -583,6 +682,7 @@ dict_get_split_vars (const struct dictionary *d) return d->split; } +/* Returns the number of SPLIT FILE vars. */ size_t dict_get_split_cnt (const struct dictionary *d) { @@ -591,6 +691,7 @@ dict_get_split_cnt (const struct dictionary *d) return d->split_cnt; } +/* Sets CNT split vars SPLIT in dictionary D. */ void dict_set_split_vars (struct dictionary *d, struct variable *const *split, size_t cnt) @@ -603,6 +704,8 @@ dict_set_split_vars (struct dictionary *d, memcpy (d->split, split, cnt * sizeof *d->split); } +/* Returns the file label for D, or a null pointer if D is + unlabeled (see cmd_file_label()). */ const char * dict_get_label (const struct dictionary *d) { @@ -611,6 +714,8 @@ dict_get_label (const struct dictionary *d) return d->label; } +/* Sets D's file label to LABEL, truncating it to a maximum of 60 + characters. */ void dict_set_label (struct dictionary *d, const char *label) { @@ -629,6 +734,8 @@ dict_set_label (struct dictionary *d, const char *label) } } +/* Returns the documents for D, or a null pointer if D has no + documents (see cmd_document()).. */ const char * dict_get_documents (const struct dictionary *d) { @@ -637,6 +744,8 @@ dict_get_documents (const struct dictionary *d) return d->documents; } +/* Sets the documents for D to DOCUMENTS, or removes D's + documents if DOCUMENT is a null pointer. */ void dict_set_documents (struct dictionary *d, const char *documents) { @@ -649,6 +758,9 @@ dict_set_documents (struct dictionary *d, const char *documents) d->documents = xstrdup (documents); } +/* 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 dict_create_vector (struct dictionary *d, const char *name, @@ -677,6 +789,8 @@ dict_create_vector (struct dictionary *d, return 1; } +/* Returns the vector in D with index IDX, which must be less + than dict_get_vector_cnt (D). */ const struct vector * dict_get_vector (const struct dictionary *d, size_t idx) { @@ -686,6 +800,7 @@ dict_get_vector (const struct dictionary *d, size_t idx) return d->vector[idx]; } +/* Returns the number of vectors in D. */ size_t dict_get_vector_cnt (const struct dictionary *d) { @@ -694,6 +809,8 @@ dict_get_vector_cnt (const struct dictionary *d) return d->vector_cnt; } +/* Looks up and returns the vector within D with the given + NAME. */ const struct vector * dict_lookup_vector (const struct dictionary *d, const char *name) { @@ -708,6 +825,7 @@ dict_lookup_vector (const struct dictionary *d, const char *name) return NULL; } +/* Deletes all vectors from D. */ void dict_clear_vectors (struct dictionary *d) {